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