AD FS for Windows Server 2016 Best Practices
Written on August 30, 2016

Active Directory Federation Services has come a long way since humble beginnings in Server 2003 with AD FS 1.0. Now available on Windows Server 2016, Microsoft have taken big steps to allow for customization and versatility of the product. There’s a lot you can change, and I’ll attempt to summarise my list of recommended changes below. This is by no means an exhaustive list, but it’s a good place to start for any new deployment. If you’re using Windows Server 2012 R2, you’ll want the AD FS 3 Best Practices post.

Ensure AD FS Farm Behavior Level is set to the highest possible level

Much like Active Directory Domain Services, AD FS now has the concept of a “functional level”. The Farm Behavior Level (FBL) is an integer that dictates the farm’s functional level. You can view the current FBL by running:

Get-AdfsProperties | Select CurrentFarmBehavior

A value of 1 indicates the Windows Server 2012 R2 FBL, and 3 indicates Windows Server 2016. If you have at least one Windows Server 2016 Domain Controller, or have run the Windows Server 2016 AD Prep, and have no Windows Server 2012 R2 federation servers, run the following command to raise the FBL to Windows Server 2016:

Invoke-AdfsFarmBehaviorLevelRaise

Enter Y when prompted, and a few minutes later, AD FS will be upgraded to Windows Server 2016. Validate this using Get-AdfsProperties again:

Get-AdfsProperties | Select CurrentBehaviorLevel

Enable Keep Me Signed In (KMSI)

This will allow your users to receive cookies that last longer than the single session. I’ve written a step-by-step here.

Enable End User Password Change

AD FS has always had a “Change Password” endpoint available, but it’s turned off by default. Run the following commands to enable the endpoint:

Enable-AdfsEndpoint "/adfs/portal/updatepassword/"
Set-AdfsEndpoint "/adfs/portal/updatepassword/" -Proxy:$true
Restart-Service AdfsSrv -Force

If you have more than one AD FS server, you’ll need to restart the service on all of them.

Enable WS-Trust 1.3 for Desktop Client SSO

Microsoft are rolling out ADAL (Active Directory Authentication Library) authentication to Office 2013/2016/ProPlus, and enabling WS-Trust 1.3 will provide you with SSO for this newly enabled technology. Run the following PowerShell command to enable the endpoint for WS-Trust 1.3:

Enable-AdfsEndpoint -TargetAddressPath "/adfs/services/trust/13/windowstransport"

You’ll also want to ensure you have both Forms and Windows Authentication (WIA) enabled in your global authentication policies.

source: http://blogs.msdn.com/b/samueld/archive/2015/06/05/office-modern-auth-amp-adfs-making-it-work.aspx

Enable Password Expiry Notification in Office 365

Office 365 has functionality built in that will prompt users when their password is about to expire. This works well, provided it…you know…knows. We can provide it this information by way of a SAML claim.

Add the following Issuance Transform Rule to your Office 365 relying party trust:

c1:[Type == "http://schemas.microsoft.com/ws/2012/01/passwordexpirationtime"]
=> issue(store = "_PasswordExpiryStore", types = ("http://schemas.microsoft.com/ws/2012/01/passwordexpirationtime", "http://schemas.microsoft.com/ws/2012/01/passwordexpirationdays", "http://schemas.microsoft.com/ws/2012/01/passwordchangeurl"), query = "{0};", param = c1.Value);

You can do this easily by running the following PowerShell:

$msolId = "urn:federation:MicrosoftOnline"
$rptName = "Microsoft Office 365 Identity Platform"
$rptRules = (Get-AdfsRelyingPartyTrust -Identifier $msolId).IssuanceTransformRules
$newRule =  '@RuleTemplate = "LdapClaims" @RuleName = "UPN Claim Rule" c1:[Type == "http://schemas.microsoft.com/ws/2012/01/passwordexpirationtime"] => issue(store = "_PasswordExpiryStore", types = ("http://schemas.microsoft.com/ws/2012/01/passwordexpirationtime","http://schemas.microsoft.com/ws/2012/01/passwordexpirationdays","http://schemas.microsoft.com/ws/2012/01/passwordchangeurl"), query = "{0};", param = c1.Value);'
$rptRules = $rptRules + $newRule
Set-AdfsRelyingPartyTrust -TargetName $rptName -IssuanceTransformRules $rptRules

Enable Authentication Methods References Claim Rule

In a default configuration, if a user is enabled for MFA both on-premises (e.g. x509 certificate or Duo connected to AD FS), and is enabled for MFA in Azure AD, they’ll be prompted to authenticate twice. While this might be seen as “acceptable” by the definition of multifactor authentication (username, password, cert/duo, phone), it’s likely considered overkill in most applications. We can configure an AD FS claim to tell Azure AD whether MFA has been performed or not on-premises quite easily.

Now the following claim will be sent to Azure AD, informing it, if appropriate, that MFA has already been achieved on premises:

<saml:Attribute AttributeName="authnmethodsreferences" AttributeNamespace="http://schemas.microsoft.com/claims">
    <saml:AttributeValue>http://schemas.microsoft.com/claims/multipleauthn</saml:AttributeValue>
</saml:Attribute>

Enable Extranet Lockout

Utilising AD FS Extranet Lockout significantly enhances the protections provided by your Web Application Proxy server(s). Functioning entirely independently of AD password policies, this provides an element of DoS protection with minimal effort.

Get-AdfsProperties | Format-List ExtranetLockoutEnabled,ExtranetLockoutThreshold,ExtranetObservationWindow,ExtranetLockoutRequirePDC

The four returned properties pertain to Extranet Lockout. | Property | Functionality | — | — | ExtranetLockoutEnabled | Does what it says on the box. If set to true, Extranet Lockout is turned on | ExtranetLockoutThreshold | The number of sequential failed logins to permit before locking the user out. Keep in mind that every failed AD FS logon equals a failed Active Directory logon, so it makes sense to have this value set lower than your AD lockout threshold | ExtranetObservationWindow | This is a TimeSpan object that defines how long AD FS will lock a user out for after | ExtranetLockoutRequirePDC | This is a new one in Server 2016. In previous versions of AD FS, Extranet Lockout checked the PDC emulator to determine the number of failed login attempts for a particular account. By changing this setting to false, we can instruct AD FS to contact any DC if the PDC emulator is unavailable, greatly improving the stability of Extranet Lockout (previously, if the PDC emulator was unavailable and Extranet Lockout was enabled, authentications would fail)

The following command will configure Extranet Lockout protection to lock a user out for 10 minutes after 15 failed logins, and will allow the failed login count to be retrieved from a DC other than the PDC emulator:

Set-AdfsProperties -EnableExtranetLockout:$true -ExtranetLockoutThreshold 15 -ExtranetObservationWindow (New-TimeSpan -Minutes 10) -ExtranetLockoutRequirePDC $false

Prevent non-domain joined computers getting the Basic Authentication 401 prompt

This is one that I didn’t even realise could be fixed until I stumbled upon this really clever solution from Mark Southwell over at Kloud. Basically you introduce a special user agent for your domain joined machines, then only issue 401s to browsers presenting that user agent. I have used this setting in the past to enable WIA for non-IE browsers, but this is a whole new way of using the functionality. Check out Mark’s post for specifics: Implementing ADFS V3.0 Forms Authentication in Mixed Environments. Be sure to check out the bottom comment by Robet Carsey as well: this looks like an even better solution.

Extend lifetimes for Token-Signing and Token-Decrypting certificates

One of an AD FS admin’s least favourite tasks has to be updating certificates. These need to be timed well, and planned far in advance. You can reduce the pain of this significantly by increasing the lifetime of your token-signing and token-decrypting certificates. The default validity period for these certs in AD FS is one year. I typically will increase this to 5 years. Check your current validity first:

Get-AdfsProperties | Select CertificateDuration

Change this to a new value (5 years, here) and then regenerate the certificates. Keep in mind, this method will break existing relationships, so only perform it on new servers or during a change window!

Set-AdfsProperties -Certificateduration 1827
Update-AdfsCertificate -CertificateType Token-Decrypting -Urgent
Update-AdfsCertificate -CertificateType Token-Signing -Urgent

Apply modern branding

Microsoft have rebranded the Microsoft Online login pages to be more modern. Consider updating AD FS to use this branding. There’s a good guide here on Microsoft’s GitHub.

Enable sensible logging

AD FS doesn’t log authentication successes or failures by default; these need to be turned on:

Set-ADFSProperties LogLevel Information,Errors,Verbose,Warnings,FailureAudits,SuccessAudits

Then use Group Policy or the following command to enable Success and Failure audit logging:

auditpol.exe /set /subcategory:"Application Generated" /failure:enable /success:enable

Keep on top of patches

As with everything Windows, it’s important to keep up to date with patching. The directory team have been nice to us with AD FS: there’s a TechNet Library page dedicated to this very purpose: Updates for Active Directory Federation Services (AD FS).

Comments/questions

There's no commenting functionality here. If you'd like to comment, please either mention me (@[email protected]) on Mastodon or email me. I don't have any logging or analytics running on this website, so if you found something useful or interesting it would mean a lot to hear from you.