With the recent announcement of General Availability of the Azure AD Conditional Access policies in the Azure Portal, it is a good time to reassess your current MFA policies particularly if you are utilising ADFS with on-premises MFA; either via a third-party provider or with something like Azure MFA Server.
Prior to conditional MFA policies being possible, when utilising on-premises MFA with Office 365 and/or Azure AD the MFA rules were generally enabled on the ADFS relying party trust itself. The main limitation with this, of course, is the inability to define different MFA behaviours for the various services behind that relying party trust. That is, within Office 365 (Exchange Online, Sharepoint Online, Skype for Business Online etc.) or through different Azure AD Apps that may have been added via the app gallery (e.g. ServiceNow, SalesForce etc.). In some circumstances, you may have been able to define some level of granularity utilising custom authorisation claims, such as bypassing MFA for ActiveSync and legacy authentication scenarios, but that method was reliant on special client headers or the authentication endpoints that were being used and hence was quite limited in its use.
Now with Azure AD Conditional Access policies, the definition and logic of when to trigger MFA can, and should, be driven from the Azure AD side given the high level of granularity and varying conditions you can define. This doesn’t mean though that you can’t keep using your on-premises ADFS server to perform the MFA, you’re simply letting Azure AD decide when this should be done.
In this article I’ll show you the method I like to use to ‘migrate’ from on-premises MFA rules to Azure AD Conditional Access. Note that this is only applicable for the MFA rules for your Azure AD/Office 365 relying party trust. If you are using ADFS MFA for other SAML apps on your ADFS farm, they will remain as is.
At a high level, the process is as follows:
- Configure Azure AD to pass ‘MFA execution’ to ADFS using the SupportsMFA parameter
- Port your existing ADFS MFA rules to an Azure AD Conditional Access (CA) Policy
- Configure ADFS to send the relevant claims
- “Cutover” the MFA execution by disabling the ADFS MFA rules and enabling the Azure AD CA policy
The ordering here is important, as by doing it like this, you can avoid accidentally forcing users with a ‘double MFA’ prompt.
Step 1: Using the SupportsMFA parameter
The crux of this configuration is the use of the SupportsMFA parameter within your MSOLDomainFederationSettings configuration.
Setting this parameter to True will tell Azure AD that your federated domain is running an on-premises MFA capability and that whenever it determines a need to perform MFA, it is to send that request to your STS IDP (i.e. ADFS) to execute, instead of triggering its own ‘Azure Cloud MFA’.
To perform this step is a simple MSOL PowerShell command:
Set-MsolDomainFederationSettings -domain yourFederatedDomain.com
Pro Tip: This setting can take up to 15-30 mins to take effect. So make sure you factor in this into your change plan. If you don’t wait for this to kick in before cutting over your users will get ‘double MFA’ prompts.
Step 2: Porting your existing MFA Rules to Azure AD Conditional Access Policies
There’s a whole article in itself talking about what Azure AD CA policies can do nowadays, but for our purposes let’s use the two most common examples of MFA rules:
- Bypass MFA for users that are a member of a group
- Bypass MFA for users on the internal network*
Item 1 is pretty straight forward, just ensure our Azure AD CA policy has the following:
Assignment – Users and Groups:
- Include: All Users
- Exclude: Bypass MFA Security Group (simply reuse the one used for ADFS if it is synced to Azure AD)
Item 2 requires the use of the Trusted Locations feature. Note that at the time of writing, this feature is still the ‘old’ MFA Trusted IPs feature hosted in the Azure Classic Portal.
Note*: If you are using Windows 10 Azure AD Join machines this feature doesn’t work. Why this is the case will be an article in itself, so I’ll add a link here when I’ve written that up.
So within your Azure AD CA policy do the following:
Conditions – Locations:
- Include: All Locations
- Exclude: All Trusted IPs
Then make sure you click on Configure all trusted locations to be taken to the Azure Classic Portal. From there you must set Skip multi-factor authentication for requests from federated users on my intranet
This effectively tells Azure AD that a ‘trusted location’ is any authentication requests that come in with an InsideCorporateNetwork claim.
Note: If you don’t use ADFS or an IDP that can send that claim, you can always use the actual ‘Trusted IP addresses’ method.
Now you can define exactly which Azure AD apps you want MFA to be enabled for, instead of all of them as you had originally.
Pro Tip: If you are going to enable MFA on All Cloud Apps to start off with, check the end of this article for some extra caveats you should consider for, else you’ll start breaking things.
Finally, to make this Azure AD CA policy actually perform MFA, set the access controls:
For now, don’t enable the policy just yet as there is more prep work to be done.
Step 3: Configure ADFS to send all the relevant claims
So now that Azure AD is ready for us, we have to configure ADFS to actually send the appropriate claims across to ‘inform’ it of what is happening or what it is doing.
The first is to make sure we send the InsideCorporateNetwork claim so Azure AD can apply the ‘bypass for all internal users’ rule. This is well documented everywhere, but the short version is, within your Microsoft Office 365 Identity Platform relying party trust in ADFS and Add a new Issuance Transform Rule to pass through the Inside Corproate Network Claim:
Fun fact: The Inside Corporate Network claim is automatically generated by ADFS when it detects that the authentication was performed on the internal ADFS server, rather then through the external ADFS proxy (i.e. WAP). This is why it’s a good idea to always use an ADFS proxy as opposed to simply reverse proxying your ADFS. Without it you can’t easily tell whether it was an ‘internal’ or ‘external’ authentication request (plus its more secure).
The other important claim to send through is the authnmethodsreferences claim. Now you may already have this if you were following some online Microsoft Technet documentation when setting up ADFS MFA. If so, you can skip this step.
This claim is what is generated when ADFS successfully performs MFA. So think of it as a way for ADFS to tell Azure AD that it has performed MFA for the user.
Step 4: “Cutover” the MFA execution
So now that everything is prepared, the ‘cutover’ can be performed by doing the following:
- Disable the MFA rules on the ADFS Relying Party Trust:
Set-AdfsRelyingPartyTrust -TargetName "Microsoft Office 365 Identity Platform" -AdditionalAuthenticationRules $null.
- Enable the Azure AD CA Policy
Now if it all goes as planned, what should happen is this:
- User attempts sign in to an Azure AD application. Since their domain is federated, they are redirected to ADFS to sign in.
- User will perform standard username/password authentication.
- If internal, this is generally ‘SSO’ with Windows Integrated Auth (WIA). Most importantly this user will get a ‘InsideCorporateNetwork’ = true claim
- If external, this is generally a Forms Based credential prompt
- Once successfully authenticated, they will be redirected back to Azure AD with a SAML token. Now is actually when Azure AD will assess the CA policy rules and determines whether the user requires MFA or not.
- If they do, Azure AD actually generates a new ADFS sign in request, this time specifically stating via the wauth parameter to use multipleauthn. This will effectively tell ADFS to execute MFA using its configured providers
- Once the user successfully completes MFA, they will go back to Azure AD with this new SAML token that contains a claim telling Azure AD that MFA has now been performed and subsequently lets the user through
This is what the above flow looks like in Fiddler:
This is what your end-state SAML token should like as well:
The main takeaway is that Step 4 is the new auth flow that is introduced by moving MFA evaluation in to Azure AD. Prior to this, step 2 would have simply perform both username/password authentication and MFA in the same instance rather then over two requests.
Extra Considerations when enabling MFA on All Cloud Apps
If you decide to take a ‘exclusion’ approach to MFA enforcement for Cloud Apps, be very careful with this. In fact you’ll even see Microsoft giving you a little extra warning about this.
The main difference with taking this approach compared to just doing MFA enforcement at the ADFS level is that you are now enforcing MFA on all cloud identities as well! This may very well unintentionally break some things, particularly if you’re using ‘cloud identity’ service accounts (e.g. for provisioning scripts or the like). One thing that will definitely break is the AADConnect account that is created for directory synchronisation.
So at a very minimum, make sure you remember to add the On-Premises Directory Synchronization Service Account(s) into the exclusion list for for your Azure AD MFA CA policy.
The very last thing to call out is that some Azure AD applications, such as the Intune Company Portal and Azure AD Powershell cmdlets, can cause a ‘double ADFS prompt’ when MFA evaluation is being done in Azure AD. The reason for this and the fix is covered in my next article Resolving the ‘double auth’ prompt issue with Azure AD Conditional Access MFA and ADFS so make sure you check that out as well.