Windows 10 Domain Join + AAD and MFA Trusted IPs

Background

Those who have rolled out Azure MFA (in the cloud) to non-administrative users are probably well aware of the nifty Trusted IPs feature.   For those that are new to this, the short version is that this capability is designed to make it a little easier on the end user experience by allowing you to define a set of ‘trusted locations’ (e.g. your corporate network) in which MFA is not required.

This capability works via two methods:

  • Defining a set of ‘Trusted” IP addresses.  These IP addresses will be the public facing IP addresses of your Web Proxies and/or network gateways and firewalls
  • Utilising issued claims from Federated Users.   This uses the insidecorporatenetwork = true claim, sent by ADFS, to determine that this user is coming from a ‘trusted location’.  Enabling this capability is discussed in this article.

The Problem

Now, the latter of these is what needs further consideration when you are looking to moving to the ‘modern world’ of Windows 10 and Azure AD (AAD).  Unfortunately, due to some changes made in the way that ‘Win10 Domain Joined with AAD Registration (AAD+DJ) machines performs Single Sign On (SSO) with AAD, the method of utilising federated claims to determine a ‘trusted location’ for MFA will no longer work.

To understand why this is the case, I highly encourage that you first read Jairo Cadena‘s truly excellent blog series that discuss in detail around how Win10 AAD SSO and its associated services works.  The key takeaways from those posts are that Win10 now has this concept of a Primary Refresh Token (PRT) and with this approach to authentication you now have the following changes:

  • The PRT is what is used to obtain access tokens to AAD applications
  • The PRT is cached and has a sliding window lifetime from 14 days up to 90 days
  • The use of the PRT is built into the Windows 10 credential provider.  Both IE and Edge know to utilise the PRT when communicating with AAD
  • It effectively replaces the ADFS with Integrated Windows Auth (IWA) approach to achieve SSO with Azure AD
    • That is, the auth flow is no longer: Browser –> Login to AAD –> Redirect to ADFS –> Perform IWA SSO –> SAML Token provided with claims –> AAD grants access
    • Instead, the auth flow is a lot more streamlined:  Browser –> Login and provide PRT to AAD –> AAD grants access

Hopefully from this auth flow change you can see why Microsoft have done this.  Because the old way relied on IWA to perform ‘seamless’ SSO, it only worked when the device was domain joined and you had line of sight to a DC to perform kerberos.  So when connecting externally, you would always see the prompt from the ADFS forms based authentication.  In the new way, whenever an auth prompt came in from AAD, the credential provider could see this and immediately provide the cached PRT, providing SSO regardless of your network location.  It also meant that you no longer needed a domain joined machine to achieve ‘seamless’ SSO!

The side effect though is that because the SAML token provided by ADFS is no longer involved in gaining access, Azure AD loses visibility on those context based claims like insidecorporatenetwork which subsequently means that specific Trusted IPs feature no longer works.   While this is most commonly used for MFA scenarios, be aware that this will also apply to any Azure AD Conditional Access rules you define that uses the Trusted IPs criteria (e.g. block access to app when external).

Side Note: If you want to confirm this behaviour yourself, simply use a Win10 machine that is both Domain Joined and AAD Registered, perform a fiddler capture, and compare the sign in experience differences between a IE and Edge (i.e. PRT aware) and Chrome (i.e. not PRT aware)

The Solution/Workaround?

So, you might ask, how do you fix this apparent gap in capability?   Does this mean you’re going backwards now?   For any enterprise customer of decent size, managing a set of IP address ranges may not be practical or desireable in order to drive MFA (or conditional access) behaviours between internal and external users.   The federated user claim method was a simple, low admin, way of solving that problem.

To answer this question, I would actually take a step back and look at the underlying problem that you’re trying to solve.  If we remind ourselves of the MFA mantra, the idea is to ensure that the user provides “something they know” (e.g. a secret/password) and “something they have” (e.g. a mobile device) to prove their ‘trustworthiness’.

When we make a decision to allow an MFA bypass for internal users, we are predicating this on the fact that, from a security standpoint, they have met their ‘trustworthiness’ level through a seperate means.  This might be through a security access card that lets them into an office location or utilising a corporate laptop that can perform a VPN connection.  Both of which ultimately lets them connect to the internal network and thus is what you use as your criteria for granting them the luxury of not having to perform another factor of authentication.

So with that in mind, what you could then do is to also expand that critera to include Domain Joined machines.  That is, if a user is utilising a corporate issued device that has been domain joined (and registered to AAD), this can now act as your “something you have” aspect of the MFA mantra to prove your trustworthiness, and so you no longer need to differentiate whether they are actually internal or external anymore.

To achieve this, you’ll need to use Azure AD Conditional Access policies, and modify your Access Grant rules to look something like that below:

Win10PRT1

You’ll also need to perform the steps outlined in the How to configure automatic registration of Windows domain-joined devices with Azure Active Directory article to ensure the devices properly identify themselves as being domain joined.

Side Note:  If you include the Workplace Join packages as outlined above, this approach can also expand to Windows 7 and Windows 8.1 devices.

Side Note 2: You can also include Intune managed mobile devices for your ‘bypass criterias’ if you include the Require device to be marked as compliant critera as well.

Fun Fact: You’ll note that in my image the (preview) reference for ‘require one of the selected controls’ is still there.  This is because until recently (approx. May/June 2017), the MFA or domain joined device criteria didn’t acutally work because of the behaviour/order of how the evaluations were being done.  When AAD was evaluating the domain joined criteria, if it failed it would immediately block access rather then trying the MFA approach next, thus preventing an ‘or’ scenario.   This has now been fixed and I expect the (preview) tag to be removed soon.

Summary

The move to the modern ‘any where, any device’ approach to end user computing means that there is a need to start re-assessing how you approach security.  Old world views of security being defined via network boundaries will eventually disappear and instead you’ll need to consider user-and device based contexts to define when to initiate security controls.

With Windows 10’s approach to authentication with AAD, internal and external access is no longer relevant and should not be used for your criteria in driving MFA or conditional access. Instead, use the device based conditions such as ‘device compliance’ or ‘domain join’ as one of your deciding factors.

Resolving the ‘Double Auth’ prompt issue in ADFS with Azure AD Conditional Access MFA

As mentioned in my previous post, Using ADFS on-premises MFA with Azure AD Conditional Access, if you have implemented Azure AD Conditional Access to enforce MFA for all your Cloud Apps and you are using the SupportsMFA=true parameter to direct MFA execution to your ADFS on-premises MFA server you may have encountered what I call the ‘Double Auth’ prompt issue.

While this doesn’t happen across all Cloud Apps, you will see it on the odd occasion (in particular the Intune Company Portal and Azure AD Powershell Cmdlets) and it has the following symptoms:

  1. User signs into Azure AD App (e.g. Azure AD Powershell with Modern Auth support)
  2. User sees auth prompt, enters their username, which redirects to ADFS
  3. User enters credentials and clicks enter
  4. It looks like it signs in successfully but then ADFS reappears and the user is prompted to enter credentials again.
  5. After the second successful attempt, the user is then prompted for MFA as expected

 

DoubleAuth

Understanding the reason behind why this happens is reliant on two things:

  1. The background I provided in the blog post I referenced above, specifically that when SupportsMFA is being used, two requests to ADFS are sent by Azure AD instead of one as part of the authentication process when MFA is involved.
  2. Configuration and behaviour of the prompt=login behaviour of Azure AD, which is discussed in this Microsoft Docs article.

So to delve into this, let’s crack out our trusty Fiddler tool to look at what’s happening:

DoubleAuth3a.png

Highlighted in the image above is the culprit.  You’ll see in the request strings that the user is being sent to ADFS with two key parameters wauth=… and wfresh=0.  What is happening here is that this particular Azure AD application has decided that as part of sign in, they want to ensure that ‘fresh credentials’ are being provided (say, to ensure the correct user creds are used).  They do this by telling Azure AD to generate a request with prompt=login, however as noted in the article referenced, because some legacy ADFS systems don’t understand this ‘modern’ parameter, the default behaviour is for Azure AD to pre-emptively translate this request into two ‘WS-Fed’ parameters that they can understand.   In particular, wfresh=0 as per the WS-Fed specs means:

…  If specified as “0” it indicates a request for the IP/STS to re-prompt the user for authentication before issuing the token….

The problem of course is that ADFS sees the wfresh=0 parameter in both requests and will abide by that behaviour by prompting the user for credentials each time!

So, the fix for this is fairly simple and is in fact (very vaguely) called out in the technet article I’ve referenced above – which is to ensure that Azure AD uses the NativeSupport configuration so that it sends the parameter as-is to ADFS to interpret instead of pre-emptively translating it.

The specific command to run is:

Set-MsolDomainFederationSettings –DomainName yourFederatedDomain.com -PromptLoginBehavior NativeSupport

The prerequisite to this fix is to ensure that you are either running:

  • ADFS 2016
  • ADFS 2012 R2 with the July 2016 update rollup

Once this update is applied (remember that these DomainFederationSettings changes can take up to 15-30 mins) you’ll be able to see the difference via Fiddler – ADFS is sent with a prompt=login parameter instead and its only for the first request so  the overall experience is the credential prompt only occurs once.

DoubleAuth4.png

Hope that saves a few hairs for anyone out there who’s come across this issue!

[UPDATE 12/09/17]  Looks like there’s a Microsoft KB article around this issue now!  Helpful for those who need official references:  https://support.microsoft.com/en-us/help/4037806/federated-users-in-azure-active-directory-may-have-to-sign-in-two-time

Using ADFS on-premises MFA with Azure AD Conditional Access

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.

Summary

At a high level, the process is as follows:

  1. Configure Azure AD to pass ‘MFA execution’ to ADFS using the SupportsMFA parameter
  2. Port your existing ADFS MFA rules to an Azure AD Conditional Access (CA) Policy
  3. Configure ADFS to send the relevant claims
  4. “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 -SupportsMFA $true

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:

  1. Bypass MFA for users that are a member of a group
  2. 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)

MFABypass1

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

MFABypass2.png

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

MFABypass3.png

This effectively tells Azure AD that a ‘trusted location’ is any authentication requests that come in with a 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.

MFABypass7.png

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:

MFABypass8.png

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:

MFABypass4

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.

MFABypass6

Step 4: “Cutover” the MFA execution

So now that everything is prepared, the ‘cutover’ can be performed by doing the following:

  1. Disable the MFA rules on the ADFS Relying Party Trust
    Set-AdfsRelyingPartyTrust -TargetName "Microsoft Office 365 Identity Platform" -AdditionalAuthenticationRules $null
  2. Enable the Azure AD CA Policy

Now if it all goes as planned, what should happen is this:

  1. User attempts sign into an Azure AD application.  Since their domain is federated, they are redirected to ADFS to sign in.
  2. 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
  3. 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.
  4. 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
  5. 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:

MFABypass9.png

This is what your end-state SAML token should like as well:

MFABypass10

The main takeaway is that Step 4 is the new auth flow that is introduced by moving MFA evaluation into 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.

MFABypass12

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.

 

Debugging an Office 365 ADFS/SSO issue when accessing Office Store in browser

We recently came across an issue with a customer where they had configured a standard SSO experience with Office 365 using ADFS and it was working perfectly except for a specific use case.   When a user accesses the office store via the Office 365 portal (e.g. portal.office.com/store) they got into an endless SSO login loop.  Specfically, they would see the following:

  1. Connection to Portal.Office.com
  2. Redirection to login.microsoftonline.com
  3. Redirection to adfs.customerdomain.com (automatically signed in because of WIA SSO)
  4. Redirection to login.microsftonline.com
  5. Redirection to Portal.Office.com\Store page but loads partially and then redirection to login.microsoftonline.com
  6. Redirection to adfs.customerdomain.com (automatically signed in because of WIA SSO)
  7. Rinse and repeat steps 4-6 ad nauseum

Normally, steps 1-4 is expected, because what is normally happening here in laymen’s terms are:

  1. Portal.office.com provides a response to the user’s browser saying “please provide sign in credentials, and do so via redirecting to this url”
  2. login.microsoftonline.com provides a reponse to the user’s browser saying “we know you are trying to access @customerdomain.com resources, which is federated, so please connect to adfs.customerdomain.com and get a valid auth token to present to us”
  3. User connects to adfs.customerdomain.com, and because it’s in it’s trusted sites list, and trusted sites is configured to perform windows integrated auth (WIA), the user’s browser uses the computers cached kerberos/ntlm auth token to sign into ADFS.  ADFS responds with a valid SAML token which the user can present to Azure AD.
  4. User connects back to login.microsoftonline.com and presents the auth token.  From there it is validated and an auth token browser cookie is created.
  5. At this point, the user would normally then connect to portal.office.com and access the relevant resources.

Now this was certainly the case for the majority of services in Office 365, including the main portal, Exchange Online, Sharepoint etc.   It was just the Office Store that was the problem, and bizarrely it was doing a partial load and then getting into the loop.

The resolution to the problem was discovered by doing a Fiddler trace of the sign in traffic.

First, we confirmed the normal ADFS SSO components were working (highlighted in red)

  1. Connection to login.microsoftonline.com
  2. Redirection to our ADFS servers (sts.{domain}.com) against the WIA path
  3. Connection back to login.microsoftonline.com with the SAML token response
  4. Subsequent connection to portal.office.com/store which is what we’re trying to access

ADFS-SSO-Process

The cause of the looping however can be seen further down in the fiddler trace, shown here:

Store-Office-NoAuth

From this we can see what would be an unexpected connection to a different domain url, store.office.com, and looking at it we see an authentication error, and no auth cookies are being presented to it.

A quick inventory of the configuration on the client gave us the answer as to why.   While the customer had done the common practice of including the key Office 365 URLs into their trusted sites (office365.com, outlook.com, sharepoint.com etc.), they did not include store.office.com.   This in itself is not specifically a problem, BUT they also had ‘mixed’ mode set up where their ‘Internet Zone’ was set to run in Protected Mode, while their ‘Trusted Sites’ and ‘Intranet Zone’ were configured to have Protected Mode turned off.

For a bit of background around what IE Protected Mode is, refer to this article, but the short version is, Protected mode is a security feature in IE which ensures that sites run in an ‘isolated instance’.  An effect of this isolation is that sites in protected mode cannot access the regular cookie cache.

As such, there was a ‘zone mismatch’ between the two, and what effectively was happening was:

  1. ADFS sign in was working as expected, and the user was successfully accessing portal.office.com resources and creating an auth cookie
  2. Portal.office.com/store however was actually loading content that was hosted under the site store.office.com
  3. store.office.com needed authentication credentials in order to correctly serve the content.  But because it was not included in trusted sites, that content request was running in ‘protected mode’.
  4. Because of the isolation, it couldn’t see the valid auth token which was stored in the regular cookie cache, and so triggers an auth sign in request to login.microsoftonline.com to get one.  And thus begins the endless authentication cycle.

The simple fix for this was simply adding the *.office.com into the trusted sites zone to ensure that it did not execute in protected mode.   Once we did it, we could see that when a connection to store.office.com is made, the appropriate auth token is presented and the page load works as expected:

Store-Office-Auth

Now, I’m not personally aware of a Microsoft guidance in terms of what should go into trusted sites for Office 365 functionality, but generally at Kloud we recommend the following to be used to avoid SSO issues:

  • *.sharepoint.com
  • *.office.com
  • *.microsoftonline.com
  • *.lync.com
  • *.outlook.com
  • URL of ADFS Server (e.g. sts.customerdomain.com)

Hopefully that gives you a bit of insight around the thinking, components and tools needed in debugging SSO issues with ADFS and Office 365!

Modern Authentication and MAPI-HTTP

If you haven’t heard, Modern Authentication (aka ADAL), has now officially gone GA (https://blogs.office.com/2015/11/19/updated-office-365-modern-authentication-public-preview/) – which means that if you are utilising Office 365 services, particularly Exchange Online, and Office 2013/2016 as your client, you should really be looking at enabling this functionality for your end users.

For those unfamiliar with Modern Auth, there are numerous benefits, but one of the most obvious for end users is it removes the need for the use of ‘save my credentials’ when signing into Exchange Online and provides a true SSO experience when combined with ADFS Federation.

Now, the process for enabling Modern Auth is very well documented in the above blog post, but the short version is:

  1. Enable Modern Auth on the Tenant side via a powershell command
  2. Enable Modern Auth on the client side via a registry key

What isn’t explicity called out as a pre-requisite however is that your Outlook client also needs to also be running in MAPI over HTTP mode.  Now, for a large percentage of environments, this is probably not an issue – but if you are like a recent customer of ours, you may have specifically disabled the use of MAPI-HTTP.  Now there are a number of valid reasons of why you might have wanted to do this (theirs was they were using an old version of Riverbed that didn’t support optimization using the MAPI-HTTP protocol), but as it turns out, the introduction of the MAPI over HTTP protocol to replace the legacy ‘RPC over HTTP’ protocol over 3 years ago was actually one of the precursors into allowing all this fancy Modern Authentication stuff to work.

For full details around what MAPI-HTTP protocol brought in and the benefits it introduced, I recommend reading this great blog post from the Microsoft Exchange team.

But in short, if you find that you have enabled Modern Auth as per the described steps, and you’re still getting the ‘basic auth prompt’ – I’d go ahead and check to see if the following registry key has been set (via GPO or otherwise)

Key: HKEY_CURRENT_USER\Software\Microsoft\Exchange
DWORD: MapiHttpDisabled
Value: 1

The above needs to either be deleted, or set to ‘0’ in order for Modern Auth to work.  The support article KB2937684 also gives you some more info around ensuring MAPI-HTTP is enabled for your Office 2013/2016 client.

Note that changing this value does not take effect until the client next performs an ‘autodiscover’ to switch over.  Depending on the situation, this may cause the user to see the following pop up:

AdministratorChange

Generally speaking, I’d recommend you test the registry update first with a subset of pilot users, before rolling this out to the wider audience.  Once that is confirmed working, then you can look at rolling out Modern Auth to your end users.

Configuring Intune Service to Service Connector for Exchange Online with a Service Account

If you are considering the use of Intune Conditional Access with Exchange Online it is generally recommended that you configure the Intune Service to Service Connector.  While it is not mandatory, it does provide your Intune Administrators the ability to report on the effectiveness of the Conditional Access Policies on your mobile ActiveSync clients within your Exchange Online environment.  In addition, if you wanted to enforce the use of the Outlook iOS/Android app using Exchange ActiveSync policies, as per my previous blog post here, setting up the connector would allow you to configure the ActiveSync access rules straight from the Intune Admin Portal.

The steps to configure the connector are already covered in the newly reskinned Enterprise Mobility Documentation, with the specific steps located here – but the purpose of today’s blog is to clarify how you would do this “properly” in a Production environment using a Service Account, as the specifics of this are glossed over in the documentation.

If you note the article, you will see a comment that “Microsoft Intune uses the email address of the currently logged in user to set up the connection”.  That means if you executed the steps using your administrative account (which is what most people will end up doing if they weren’t paying attention), Intune will actually configure the connector to use your account from then onwards to perform its regular syncs (every 2 hours for a quick sync, and daily for a full sync).  This is not exactly great, as now this functionality is tied to a specific user, of which that account could be expired, disabled or terminated based on the employment status of that person.   Ideally, you want to be using a Service Account for this purpose.

In order to do this you are going to need the following:

  • A cloud identity to act as the Service Account
  • An Intune License assigned to the Service Account
  • An Exchange Online license assigned to the Service Account

You may question why the licenses are required, but unfortunately that’s just the limitations imposed by Microsoft.  All Intune Administrators (regardless of whether they are Tenant or Service Administrators) must have an Intune license.  Furthermore, the Service to Service Connector requires that the account have a valid email address (and thus a mailbox), necessitating the need for an Exchange Online license.

Step 1 – Grant the Service Account Intune Admin Access

  1. Log into your Intune Management Portal with an admin account that already has Tenant or Service Administrator privileges
  2. Under Admin -> Administrator Management -> Service Administrators add your service account (e.g. svc_Intune_S2S@tenant.onmicrosoft.com)
    Note:  You won’t be able to do this unless the account has an Intune License assigned to it

Step 2 – Grant the Service Account Exchange Admin Access

  1. Log into the Exchange Online Admin Portal with an admin account that has Organization Management privileges
  2. Under Permissions -> Admin Roles create a new role
  3. Provide a relevant Name and Description
  4. Leave the Write Scope as Default
  5. For the Roles ensure that you include:
    • Organization Client Access
    • Recipient Policies
  6. For Members add the service account
    IntuneS2S-RoleGroup

Step 3 – Set up the Intune Service to Service Connector

  1. Log into your Intune Management Portal with the Service Account
  2. Under Admin -> Microsoft Exchange -> Set up Exchange Connection select the Set up Service to Service Connector button at the bottom
    Note:  If the service account doesn’t have an email address (i.e. Exchange Online License with a mailbox), you will get an error indicating so.  Also, if the service account doesn’t have an Intune license assigned, it will throw up an ‘unexpected error’.IntuneS2S-SetUp
  3. Click OK when prompted.  Use this opportunity to verify that the correct account is being used (i.e. you haven’t forgotten to sign out with your original admin account)IntuneS2S-Account
  4. It will take about 10-15 mins for it to verify the account and configure the connection, but once it is successful, you will see a status update with a green tick like below:IntuneS2S-Success

Optional Step – Hide Mailbox of Service Account

Since we’ve had to give the service account an exchange mailbox (which it doesn’t use), it’s probably a good idea to hide it from the GAL so users don’t get confused.

  1. Log into the Exchange Online Admin Portal
  2. Under Recipients -> {Search for user} -> Edit -> General and select Hide from Address lists

And there you have it, a much more secure and cleaner way to configure your Intune Service to Service connector for Exchange Online!

Enforcing Outlook App in Exchange Online and Intune Conditional Access

[UPDATE 23/11/16] Microsoft have announced a new method of doing what I describe in this blog post.  Matt Shadbolt from the Intune Engineering team has a nice blog post that describe how to use this new process, based on Intune MAM policies.  The below information is still useful though if you want to do more specific restrictions (e.g. iOS vs Android native clients).

What is Intune Conditional Access?

Intune Conditional Access is a pretty neat feature that allows administrators to enforce compliance policies to devices prior to allowing them access to sync their mail with Exchange Online.   The requirements and process required to implement his feature is quite well documented within Microsoft’s TechNet library:  Manage email access with Microsoft Intune

In short, what is happening is Microsoft Intune becomes an additional ‘gate’ that’s sits in front of Exchange Online (or Exchange On-Prem via a connector) that requires devices to provide information on its state (e.g. is it registered, managed or compliant) before being allowed through as part of the authentication process.   In its current state, this conditional access feature, for Exchange Online, can supports ‘controlling’ access for clients on mobile devices (i.e. ActiveSync), while for PCs (i.e. Outlook Desktop) and browser based access (i.e. OWA) this is currently in preview.

How Intune Conditional Access works with Mobile Devices with ActiveSync

For mobile devices, ActiveSync is the primary protocol that is used to communicate with Exchange Online and sync the mail to the devices, however it must be noted that there are some variations to how the ActiveSync protocol is implemented.  Most users are familiar with what we call the ‘Native mail client’ on iOS and Android devices and more recently now the Outlook for iOS/Android App.  While both of these utilise ActiveSync, the defining feature of the Outlook App is that it also supports Modern Authentication which is important for the purposes of this blog.   Pretty much all other mail clients utilise ActiveSync with ‘Basic’ authentication which, in simple terms means that they only know to send the username/password to Exchange Online and expect to be let through.  They certainly don’t understand the concept of ‘device compliance’ tokens and other features like Multi-Factor Authentication.

To work around this, Intune Conditional Access takes over and leverages the ActiveSync policies feature of Exchange Online to quarantine these “legacy” ActiveSync clients after they have configured their mail profile and injects a fake email into their inbox indicating that they’ve detected the device as being unmanaged and hence does not meet compliance policies to satisfy the conditional access requirements.  This email then directs the user to enrol and uplift their device to meet the compliancy policy (e.g. PIN locked, not jail broken etc.) before they are allowed to sync.

ActiveSyncEmail

The key take-away from this is that Intune Conditional Access is tightly integrated with the ‘Active Sync Policies’ feature of Exchange Online

For applications that support Modern Authentication however (i.e. Outlook app), the process is a bit more elegant in that the device compliance (and subsequent enrolment processes) are all performed as part of the authentication / sign in procedure.  This is also the same process where MFA prompts can also be initiated.

ModernAuthAppEnrol         MFA

How to enforce the Outlook App when Intune Conditional Access is used

With that bit of backstory covered off, we can now proceed to explain how you would go about configuring the enforcement of the use of the Outlook App with Intune Conditional Access.  There are numerous reasons why you might want to enforce the use of the Outlook App, but some of the key reasons we often see are:

  • ActiveSync mail clients do not support ‘Selective Wipe’ if the email profile is not managed by Intune.  Intune can only manage iOS native mail app profiles.  This leaves Android and third party apps open to data leakage if an employee departs the company with a BYOD device for example (and thus a full wipe is not allowed)
  • ActiveSync mail clients using ‘basic authentication’ cannot support Multi Factor Authentication and thus must use the less secure ‘app passwords’ approach
  • Only the Outlook App, to date, supports Mobile Application Management (MAM) Intune policies, which is a feature that provides Data Loss Protection functionality by keeping company data within ‘managed’ apps

Within Intune, the below image shows what the standard conditional access policy configuration would look like:

IntuneConditionalAccess-ActiveSyncApps

The section highlighted in green is what triggers all ‘Modern Auth’ applications to abide by Intune’s Conditional Access rules.  This includes Outlook for desktop and the Outlook for iOS/Android app.  The section highlighted in red is what controls Intune Conditional Access for all the ‘legacy’ ActiveSync mail clients (i.e. your native mail clients and third party apps).  In order to enforce the use of the Outlook app, we actually have to disable Intune Conditional Access for Exchange ActiveSync apps that use basic authentication.

This may seem weird, but the reason we are doing this is because in order to control what specific ActiveSync clients are allowed to connect to Exchange Online we have to use the Exchange Active Sync Policies feature.  Specifically, we have to configure the Access Rules to block all device families and only allow the Outlook App device family, like below:

ExchangeActiveSyncRules

As noted earlier, when Intune Conditional Access is in play, it actually leverages and takes ownership of this feature, and thus any rules you have configured through that are ignored if the user falls within management under Intune and that conditional access policy is enabled.  So, in effect what we are doing is this:

  1. Enable Intune Conditional Access, but only for ‘Modern Authentication’ Apps.  Do not perform the conditional access checks for ‘legacy’ ActiveSync clients
  2. Configure Exchange Online to block all ActiveSync device clients except the Outlook app

The net effect of doing this is as follows:

  • ‘Legacy’ ActiveSync clients will successfully authenticate but their mail synching is blocked by the access rules configured within Exchange Online
  • Outlook App clients, even though they are still using ActiveSync, still abide by Intune Conditional Access policies because they are using Modern Auth and can successfully connect to Exchange Online after they meet compliance

The next challenge of course is then convincing all your users to stop using their Native Mail Client (or their preferred third party app) and use the Outlook app instead, but that’s a post for another day 🙂

Using saved credentials securely in PowerShell scripts

One of the most common tasks out in the field is the need to run PowerShell scripts that require credentials to be saved in some form of another so that they can be fed into scripts to be executed autonomously.  This is particularly common in cloud environments where the current user context in which the scripts are run (e.g. within a scheduled task) are insufficient or not appropriate for the remote execution.   Office 365 management is a perfect example of this, where often a credential object must be passed in order to connect and execute the cmdlets.

The quick and dirty (and all too common) approach is to simply have some code like the following:

Here we are simply writing the username and password directly into the PowerShell script as plaintext and then creating a PowerShell credential object that can then be passed onto things like Connect-MsolService.

It works, but obviously terribly insecure.  Particularly since these accounts are often high powered administrator accounts.

A better approach is to leverage the inherent ‘secure string’ nature of PowerShell credential objects and the way it represents passwords.  Specifically, you can export the ‘secure string’ into a readable string by doing something like the following:

This will give you a nice long, complex looking string like so (shortened for conciseness):  1000000d08c9ddf0115d1…..d3d491bb6d740864122a041d11

You can store that string into a text file, and when needed, read it back in and reverse it back into a ‘Secure String’ object and feed into a credential object creation by doing the following:

What is effectively happening here is that PowerShell is using the native Windows Data Protection API (DAPI) functionality to encrypt the password from the ‘secure string’ into a text string.  This string can be written to a plain text file, but the way that DAPI works is that the encryption is such that only the original user on the original machine the encryption was performed on can decrypt the string back into a ‘Secure string’ to be reused.

While not a 100% foolproof solution, it is a pretty effective way to secure the password as it reduces the attack vectors significantly.  At a minimum as long as the credentials to the account that originally ran the encryption are protected, even if a would be malicious administrator had access to the machine (and thus would have had access to your plaintext passwords stored in your script), they wouldn’t be able to reverse engineer the password that has been stored.

From that perspective your process to have a PowerShell script with a secure ‘saved’ password would be as follows:

  1. Run the Get-Credential command to prompt an administrator to provide the credentials they wish to save
  2. Convert the secure-string object that is part of that credential object into a text string (which is now encrypted) and store that in a file
  3. For scripts that need the saved credentials, read in the file, decrypt the string and recreate the credential object and feed to the appropriate cmdlets.

There a few key caveats with this approach:

  • The script that runs and reads the saved credentials, must be run on the same machine and in the same user context.
  • This means you can’t just copy the ‘saved credential’ file to other machines and reuse it.
  • In the scenario where your scripts are run as scheduled tasks under a service account, be aware that in order to prompt an admin to provide the credentials in the first place, the service account requires ‘Interactive’ ability.  This means the service account, at least temporarily, needs ‘log on locally’ to give you that interactive session.
  • In order for DAPI to work, the GPO setting Network Access: Do not allow storage of passwords and credentials for network authentication must be set to Disabled (or not configured).  Otherwise the encryption key will only last for the lifetime of the user session (i.e. upon user logoff or a machine reboot, the key is lost and it cannot decrypt the secure string text)

Now, assuming the above caveats are no good for you.  Say, for whatever reason, you can’t give your service accounts the ability to log on locally, even temporarily.  Or, the scripts that need these saved passwords need to be run on a bajillion machines and you can’t afford to log onto each one to create a secure string unique for that machine.  There is one alternative, albeit a less secure one, and realistically speaking, only slightly more secure then storing it as plain text.

In the above example, when you are performing the Convert-FromSecureString cmdlet with no parameters, you are effectively telling PowerShell to do the encryption using DAPI. You can however also provide a specific AES Key for it to use to perform the encryption instead.  In the below example, I’m generating a random AES Key to use:

To re-read the password, the following is done:

In that scenario, the AES Key is your secret, and anyone who knows the AES Key can decrypt your password, so it’s not a great idea to simply embed the AES key into your script.   So for the above example, I export the AES Key as a separate text file, that I would then recommend you secure using something like NTFS ACLs.  That way at a minimum, your security barrier is access to that ‘password file’.

Arguably you could have just done that with a plain text password file, but adding the extra layers of encryption/decryption is intended to stop the generic lazy malicious/curious/whatever administrator (or user!) from easily seeing your passwords.

With this, the AES approach to encrypting your password the process now becomes:

  1. Run the Get-Credential command to prompt an administrator to provide the credentials they wish to save
  2. Generate a random AES Key to convert the secure-string object.  Store the AES key and the secure string text as separate files.  Secure these files with NTFS permissions.
  3. For scripts that need the saved credentials, read in both files and recreate the credential object and feed to the appropriate cmdlets.

The main differences with this approach are:

  • The password files can be generated once and subsequently used on any machine by any user, as long as they can read in the files
  • The security barrier here are the NTFS permissions on the password file.

Script Template

Now, if you’ve made it this far, I congratulate you and reward you with this – all that mumbo jumbo that I spoke about above has been packaged together into a nice, easy to use PowerShell script template. This template is structured so that you can simply embed your core ‘worker’ code into the main function, and the template will handle all the rest.  It includes the following handy features:

  • Two ‘modes’:  One to collect and prepare the credential files (i.e. interactively), and another to execute the core worker code (i.e. the mode you run in the scheduled task)
  • Provides the user the option of which encryption method they wish to use, the more secure DPAPI (default) way or the more flexible AES way.
  • Code will determine automatically which method to use for decryption based on what credential files have been created
  • PLUS all those boring error handling and logging functions are included for no extra charge

Enjoy!

Download Link via GitHub