ADFS: Certificate Authentication with Azure AD & Office 365

Howdy folks!

Azure AD just announced GA support for certificate authentication in this blog post! I’ve had a few folks asking me about how to configure ADFS for this. So, here are some instructions and gotchas for it.

Before we get started, do note that certificate authentication partially worked before this recent additional to Azure AD. It worked well on Windows devices (I use it with my smartcard on a regular basis against the ADFS service at our own company). The key capabilities that did not work well were:

  • Native apps on iOS & Android did not support this even with modern authentication. The challenge here was that the browser dialog that the authentication library used on these devices could not access the certificate provisioned to the device (app sandboxing) or the browser dialog did not support client TLS capabilities. This changed with the latest iOS/Android platforms and the authentication support makes full use of these capabilities.
  • EAS access to Exchange Online did not support certificate authentication and only supported HTTP basic authentication.
  • There was no way in Azure AD to revoke a prior session state when the cert (or the device that stores it) gets compromised. Note that this is very important because while ADFS may do the orignial authentication for modern auth apps, subsequent access tokens are obtained by the app from Azure AD by using a refresh token. In this interaction the request does not go back to ADFS.

Well, all of this is fixed now!

A few things to remember:

  • Support for certificate authentication on native apps requires modern authentication. The only exception is EAS for which there is special support in EXO & Azure AD.
  • Certificate authentication for browser apps & native apps is only supported for federated tenants that use ADFS or a 3rd party IDP that supports certificate authentication. [Note:  Using certificate authentication via EAS to EXO is supported for managed domains. However, if the end user were using browser or native apps, they would have to use username/password to login]
  • The Office app needs to have been updated with the latest modern authentication libraries. Not all of them support yet. Please refer to Office documentation or the Azure AD documentation for the list. For now, the list of apps is called out in the blog post.
  • Some of the Office apps (with modern authentication enabled) send 'prompt=login' to Azure AD in their request. By default Azure AD translates this in the request to ADFS to 'wauth=usernamepassworduri' (asks ADFS to do U/P auth) and 'wfresh=0' (asks ADFS to ignore SSO state and do a fresh authentication). For people interested in certificate authentication on these applications, you will need to modify the default Azure AD behavior. Just set the 'PromptLoginBehavior'  in your federated domain settings to be 'Disabled'. See /en-us/windows-server/identity/ad-fs/overview/ad-fs-faq#BKMK_7 for more information and parameter reference.

How do I configure my ADFS for this?

Yay! Now that you are all bought into certificate authentication, let’s get you going and get this configured on ADFS. You can check out the Azure AD configuration in the blog post.

Ensure pre-requisites are met & configured

  • You need ADFS 2012R2 or higher. You will need the Web Application Proxy to support this for extranet access. If you were per-chance using a third party proxy, this is not supported unless they support MS-ADFSPIP protocol document (all the MUST’s).
  • Ensure that all the roots and intermediary certificate authorities are populated correctly on all your ADFS and Web Application Proxy servers. ADFS uses the core windows OS support for this functionality and ensuring that you have the trust chain configured is needed for client TLS to work correctly. Most folks will use group policy to do this. TIP: Ensure that roots & intermediaries are placed correctly in their own stores. Having duplicates or improperly placing them will prevent it from working correctly.
  • Ensure that port 49443 is reachable between the client device and ADFS as well as the client device and WAP servers. This may require additional firewall configuration to allow this traffic to flow between the client and ADFS/WAP servers. This is the default port at ADFS performs user certificate authentication.
  • ADFS 2016 supports a mode that allows user certificate authentication to happen over port 443. This is useful when you have more stringent firewall restrictions. To enable this, you will need your SSL certificate to have certauth.your_adfs_service_name added as an alternate subject name. Also, in this mode, wild card certs with no alt subj name are not supported. To configure this, you can find more info here.
  • Ensure that all revocation endpoints are reachable from the client device (inside or outside your network) as well from each of the ADFS/WAP servers.

Enable Certificate Authentication on ADFS

  • Open up the ADFS Management Console (MMC plug-in) and enable it on the primary authentication policy for extranet and optionally the intranet. Given most of your devices that use certificate authentication are likely to come only from the extranet, you could just enable it for the extranet. The policy should look like this

ADFS-cert-auth

  • Validate that it works. You can use Windows or iOS/Android devices with a browser to check if it works correctly. After browser validation, you can try one of the supported Office apps listed in the blog post to try it out. You are now set. If you are having issues, refer to #1 to check it out.

Send the necessary claims to Azure AD.

Azure AD needs ADFS to send it the issuer and the serial # so that it can revoke or deny authentication in access scenarios for EAS or when a modern auth application attempts to exchange a refresh token for an access token. This way if a device ever gets lost or stolen, the admin can update the CRL and Azure AD will revoke access using the cert authentication.

  • First we need to get ADFS to pass these claims through to the issuance pipeline by adding the following 2 rules in the “Active Directory” Claims Provider trust. This tells ADFS that any time we are authenticating an Active Directory User, to allow this to pass through.

c:[Type == " https://schemas.microsoft.com/ws/2008/06/identity/claims/serialnumber"\]  => issue(claim = c);

c:[Type == " https://schemas.microsoft.com/2012/12/certificatecontext/field/issuer"\]  => issue(claim = c);

  • Now add the same rules in the Azure AD/Office 365 relying party trust.

c:[Type == " https://schemas.microsoft.com/ws/2008/06/identity/claims/serialnumber"\]  => issue(claim = c);

c:[Type == " https://schemas.microsoft.com/2012/12/certificatecontext/field/issuer"\]  => issue(claim = c);

Customize the Sign-In experience

By default ADFS displays "Sign in using an X.509 certificate" when using user certificate authentication. This is not very user friendly. Changing this is simple with powershell. Execute the following command to set it to what you need to be. In this case I'm choosing to keep it simple as "Sign in with a certificate".

Set-AdfsAuthenticationProviderWebContent -Name CertificateAuthentication -DisplayName "Sign in with a certificate"

It would look like this

adfs-cert-auth-user

Note: When both forms and certificate authentication is enabled, ADFS makes this a choice page to select and has a special optimization for username/password form and shows it inline. This was done as username/password case was the most common form and we optimized for this. You can choose to customize this ordering with javascript customizations. For example, let's say that you want certificate authentication only on iOS and Android devices and not for Windows PC's. You can do the following customization with JS:

  • Hide the choice entries (don't disable) when loading up.
  • Detect the platform using the user agent string that is available to JS
  • Auto-click "Cert Auth" link if iOS/Android is detected
  • Auto-click or un-hide other elements if a platform outside of iOS/Android is detected

Tip: The Authenticator application is required for Certificate Based authentication on iOS. So, to ensure that you have a good experience for your end users, you can add additional HTML to the login page to pre-install the authenticator app and add a link to the authenticator app. Also, on iOS, if certificate authentication is used in the additional authentication stage, you will see 2 prompts for the primary authentication stage. This is because, the authenticator application detects for certificate authentication based on a client TLS challenge and reinitiates the entire authentication with the system web view that has access to the user certificates provisioned. We recommend using certificate authentication in the primary stage. 

[Optional] Restrict token issuance based on certificate properties

There’s more fancy stuff you can do. In many cases, customers may have multiple types of user certificates in their environment and may want to restrict this type of access only if the user were using a certificate that was provisioned through an MDM channel or via group policy for Windows Devices. In this case you would,

  • Ensure that there was a distinct issuer or EKU for the certificate template.
  • Pass through these claims as we did in the prior section. The claim type for EKU (issuer is already handled in the prior section) would be “https://schemas.microsoft.com/2012/12/certificatecontext/extension/eku”
  • Add issuance authorization rules on the Azure AD/Office 365 relying party trust to restrict access by checking for the specific EKU or issuer if the user had done certificate authentication.

That’s it! You are all set from the ADFS side. You also want to upload the certificate authority information (and the CRL endpoints) to Azure AD as per instructions in the blog post (or in Azure AD docs)

Azure AD Blog Post announcing GA for Certificate Authentication Support Azure AD Docs for Certificate Authentication Support (Note that this takes you to the iOS instructions and there is a drop down at the top of the page for Android)

That concludes my post. If you have any questions, tweet me @MrADFS.

Thanks

//Sam (@MrADFS)