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.

Office 365 SSO: Configuring multiple Office 365 tenants to use a single AD FS instance

Q: Can multiple Office 365 tenants use a single AD FS instance to provide SSO?

A: Yes

Overview

  • Office 365 tenant 1 is configured with the domain contoso.com
  • Office 365 tenant 2 is configured with the domain sub.contoso.com
  • Single Active Directory Forest with multiple UPNs configured (contoso.com and sub.contoso.com)
  • Single AD FS instance including an AD FS Proxy/Web Application Proxy published with the name sts.contoso.com
  • Two instances of Azure ADConnect configured with container filtering to ensure users are only synchronised to a single tenant

Configuring SSO

The Federation Trust for Tenant 1 is configured by establishing a Remote PowerShell session (with the Azure Active Directory Module loaded) and running the standard ‘Convert-MsolDomainToFederated’ cmdlet:

Convert-MsolDomainToFederated -DomainName contoso.com -SupportMultipleDomain

When it comes to configuring Tenant 2, things become a little more tricky. One of the features of the ‘Convert-MsolDomainToFederated’ cmdlet is that it performs the required configuration on Office 365 as well as the AD FS Farm. If you attempt to run this cmdlet against an AD FS Farm that has a Federation Trust established with a different tenant, it will fail and return an error. Therefore, we need to make use of the ‘Set-MsolDomainAuthentication’ cmdlet which only makes configuration changes to Office 365 and is usually used for establishing Federation Trusts with third party IdPs.

The first step is to export the token-signing certificate from the AD FS farm either via Windows Certificate Manager or via PowerShell:

$certRefs=Get-AdfsCertificate -CertificateType Token-Signing
$certBytes=$certRefs[0].Certificate.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert)
[System.IO.File]::WriteAllBytes("c:\temp\tokensigning.cer", $certBytes)

Next, establish a Remote PowerShell session with Tenant 2 and then run the following script to configure the trust:

$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("C:\temp\tokensigning.cer")
$certData = [system.convert]::tobase64string($cert.rawdata)
$dom="sub.contoso.com"
$url="https://sts.contoso.com/adfs/ls/"
$uri="http://sub.contoso.com/adfs/services/trust/"
$ura="https://sts.contoso.com/adfs/services/trust/2005/usernamemixed"
$logouturl="https://sts.contoso.com/adfs/ls/"
$metadata="https://sts.contoso.com/adfs/services/trust/mex"
#command to enable SSO
Set-MsolDomainAuthentication -DomainName $dom -Authentication Federated -ActiveLogOnUri $ura -PassiveLogOnUri $url -MetadataExchangeUri $metadata -SigningCertificate $certData -IssuerUri $uri -LogOffUri $logouturl -PreferredAuthenticationProtocol WsFed

Once configured, the configuration of both tenants can be validated using the ‘Get-MsolDomainFederationSettings’ cmdlet. The only difference when comparing the tenant configuration should be the ‘FederationBrandName’ and the ‘IssuerUri’ values.

Using Azure SSO Tokens for Multiple AAD Resources From Native Mobile Apps

This blog post is the third in a series that cover Azure Active Directory Single Sign-On (SSO) authentication in native mobile applications.

  1. Authenticating iOS app users with Azure Active Directory
  2. How to Best handle AAD access tokens in native mobile apps
  3. Using Azure SSO tokens for Multiple AAD Resources From Native Mobile Apps (this post)
  4. Sharing Azure SSO access tokens across multiple native mobile apps.

Introduction

In an enterprise context it is highly likely there are multiple web services that your native mobile app needs to consume. I had exactly this scenario at one of my clients who asked if they could maintain the same SSO token in the background in the mobile app and use it for accessing multiple web services. I spent some time digging through the documentation and conducting some experiments to confirm some points and this post is to share my findings.

Cannot Share Azure AD Tokens for Multiple Resources

The first thing that comes to mind is to use the same access token for multiple Azure AD resources. Unfortunately this is not allowed. Azure AD issues a token for a certain resource (which is mapped to an Azure AD app). When we call AcquireToken, we need to provide a single resourceID. The result is the token can only be used for resource matching the supplied identifier.

There are ways where you could use the same token (as we will see later in this post), but it is not recommended as it complicates operations logging, authentication process tracing, etc. Therefore it is better to look at the other options provided by Azure and the ADAL library.

Use Refresh-Token to Acquire Tokens for Multiple Resources

The ADAL library supports acquiring multiple access tokens for multiple resources using a “refresh token”. This means once a user is authenticated, the ADAL’s authentication context is able to generate an access token to multiple resources without authenticating the user again. This is covered briefly by the MSDN documentation. A sample implementation to retrieve this token is shown below.

public async Task<string> RefreshTokens()
{
	var tokenEntry = await tokensRepository.GetTokens();
	var authorizationParameters = new AuthorizationParameters (_controller);

	var result = "Refreshed an existing Token";
	bool hasARefreshToken = true;

	if (tokenEntry == null) 
	{
		var localAuthResult = await _authContext.AcquireTokenAsync (
			resourceId1, 
                        clientId, 
                        new Uri (redirectUrl), 
                        authorizationParameters, 
                        UserIdentifier.AnyUser, 
                        null);

		tokenEntry = new Tokens {
			WebApi1AccessToken = localAuthResult.AccessToken,
			RefreshToken = localAuthResult.RefreshToken,
			Email = localAuthResult.UserInfo.DisplayableId,
			ExpiresOn = localAuthResult.ExpiresOn
		};
		hasARefreshToken = false;
		result = "Acquired a new Token"; 
	} 

	var refreshAuthResult = await _authContext.AcquireTokenByRefreshTokenAsync(
                                tokenEntry.RefreshToken, 
                                clientId, 
                                resourceId2);

	tokenEntry.WebApi2AccessToken = refreshAuthResult.AccessToken;
	tokenEntry.RefreshToken = refreshAuthResult.RefreshToken;
	tokenEntry.ExpiresOn = refreshAuthResult.ExpiresOn;

	if (hasARefreshToken) 
	{
		// this will only be called when we try refreshing the tokens (not when we are acquiring new tokens. 
		refreshAuthResult = await _authContext.AcquireTokenByRefreshTokenAsync (
                                                     refreshAuthResult.RefreshToken, 
                                                     clientId, 
                                                     resourceId1);

		tokenEntry.WebApi1AccessToken = refreshAuthResult.AccessToken;
		tokenEntry.RefreshToken = refreshAuthResult.RefreshToken;
		tokenEntry.ExpiresOn = refreshAuthResult.ExpiresOn;
	}

	await tokensRepository.InsertOrUpdateAsync (tokenEntry);

	return result;
}

As you can see from above, we check if we have an access token from previous calls, and if we do, we refresh the access tokens for both web services. Notice how the _authContext.AcquireTokenByRefreshTokenAsync() method provides an overloading parameter that takes a resourceId. This enables us to get multiple access tokens for multiple resources without having to re-authenticate the user. The rest of the code is similar to what we have seen in the previous two posts.

ADAL Library Can Produce New Tokens For Other Resources

In the previous two posts we looked at ADAL and how it uses the TokenCache. Although ADAL does not support persistent caching of tokens yet on mobile apps, it still uses the TokenCache for in-memory caching. This enables ADAL to generate new access tokens if the AuthenticationContext still exists from previous authentication calls. Remember in the previous post we said it is recommended to keep a reference to the authentication-context? Here it comes in handy as it enables us to generate new access tokens for accessing multiple Azure AD resources.

var localAuthResult = await _authContext.AcquireTokenAsync (
                                   resourceId2, 
                                   clientId, 
                                   new Uri(redirectUrl),
                                   authorizationParameters,
                                   UserIdentifier.AnyUser, 
                                   null
                                 );

Calling AcquireToken() (even with no refresh token) would give us a new access token to the requested resource. This is due to ADAL checking if we have a refresh token in-memory which ADAL then uses that to generate a new access token for the resource.

An alternative

The third alternative is the simplest (but not necessarily the best). In this option, we can use the same access token to consume multiple Azure AD resources. To do this, we need to use the same Azure AD app ID when setting the two APIs for authentication via Azure AD. This requires some understanding of how the Azure AD authentication happens on our web apps.

If you refer to Taiseer Joudeh’s tutorial you will see that in our web app, we need to tell the authentication framework what our Authority is and the Audience (Azure AD App Id). If we set up both of our web APIs to use the same Audience (Azure AD app Id) we link them both into the same Azure AD application which allows use of the same access token to use both web APIs.

// linking our web app authentication to an Azure AD application
private void ConfigureAuth(IAppBuilder app)
{
	app.UseWindowsAzureActiveDirectoryBearerAuthentication(
		new WindowsAzureActiveDirectoryBearerAuthenticationOptions
		{
			Audience = ConfigurationManager.AppSettings["Audience"],
			Tenant = ConfigurationManager.AppSettings["Tenant"]
		});
}
<appSettings>
    <add key="Tenant" value="hasaltaiargmail.onmicrosoft.com" />
    <add key="Audience" value="http://my-Azure-AD-Application-Id" />	
</appSettings>

As I said before, this is very simple and requires less code, but could cause complications in terms of security logging and maintenance. At the end of the day, it depends on your context and what you are trying to achieve.

Conclusion

We looked at how we could use Azure AD SSO with ADAL to access multiple resources from native mobile apps. As we saw, there are three main options, and the choice could be made based on the context of your app. I hope you find this useful and if you have any questions or you need help with some development that you are doing, then just get in touch.

This blog post is the third in a series that cover Azure Active Directory Single Sign On (SSO) Authentication in native mobile applications.

  1. Authenticating iOS app users with Azure Active Directory
  2. How to Best handle AAD access tokens in native mobile apps
  3. Using Azure SSO tokens for Multiple AAD Resources From Native Mobile Apps (this post)
  4. Sharing Azure SSO access tokens across multiple native mobile apps.

How to Best Handle Azure AD Access Tokens in Native Mobile Apps

This blog post is the second in a series that cover Azure Active Directory Single Sign On (SSO) Authentication in native mobile applications.

  1. Authenticating iOS app users with Azure Active Directory
  2. How to Best handle AAD access tokens in native mobile apps (this post)
  3. Using Azure SSO access token for multiple AAD resources from native mobile apps
  4. Sharing Azure SSO access token across multiple native mobile apps.

In my previous post, I talked about authenticating mobile app users using Azure AD SSO. In this post, I will explore how to take this further to persist the access token to interact with Azure AD.

Let’s assume that we have an API and a mobile app that consumes it. In order to secure the interaction between our mobile app and the API, we can register both the app and API with Azure AD and let Azure handle the authentication for us. Let’s take a look.

Securing the Web App

To start with, we will implement an authentication mechanism in our API. We can create use a vanilla Web API project from Visual Studio and implement Azure AD authentication on that. Our focus isn’t on this so for a good reference see Taiseer Joudeh’s detailed tutorial.

Securing the Mobile App

In the previous post, I showed how we could use Azure AD with ADAL to authenticate users on native mobile apps. The remainder of this post will assume that you have followed the previous post and you have this part ready. If you are not sure, please revisit my previous post.

Setting up the Permissions in AAD

We have seen how to secure our apps with AAD, now we need to authorise the mobile app to access our Web API. To do this we first need to expose the webApi permissions on Azure AD. We can navigate to AAD/Applications/our-web-app, then click on download manifest. This will give us a copy of the configuration of this API in AAD (in a simple JSON file). We need to modify the permission section and add the following section to tell Azure AD that this web app can be accessed by other AAD apps.

AAD app manifest configuration

AAD app manifest configuration

appPermissions": [
    {
      "claimValue": "user_impersonation",
      "description": "Allow the application full access to the service on behalf of the signed-in user",
      "directAccessGrantTypes": [],
      "displayName": "Have full access to the service",
      "impersonationAccessGrantTypes": [
        {
          "impersonated": "User",
          "impersonator": "Application"
        }
      ],
      "isDisabled": false,
      "origin": "Application",
      "permissionId": "place a NEW GUID here",
      "resourceScopeType": "Personal",
      "userConsentDescription": "Allow the application full access to the service on your behalf",
      "userConsentDisplayName": "Have full access to the service"
    }
  ]

We can update the file then upload it to update the permissions settings to enable AAD to allow access to this API just like any other permissions that it manages. You could read more on Azure AD impersonation and permission settings on MSDN. Note that you need to choose a NEW GUID for the permission id.

Now we need to configure our native mobile app in Azure AD to have access to our Web API. This is very simple and is shown in the screenshot below. In the list of permissions on the left, we now have more permissions that we can grant to the mobile app. Whatever name you gave to your mobile app will appear there along with the type of permissions that you have configured. In my case, I have named it MobileServices1 and that is what is appearing there.

Azure AD app permission settings

Azure AD app permission settings

Token Expiry and Caching

Setting the permissions and configuration above will allow our mobile app to authenticate users and manage the access of the API. This access is managed by the token that Azure AD issues when a user authenticates successfully. If the mobile app interacts with the API frequently, then we need to always have a valid token for all our requests. The question is how to keep a valid request token in the native mobile app?

The answer is depends on what you are trying to do – if you are implementing a highly secure mobile app you might want to always check with Azure and maybe ask the user to login every time the token expires. AAD access tokens expire after one hour by default. This means the default behaviour would be to ask the user to login every hour which is OK for some mobile apps, but it is certainly not the normal flow you see in many apps. So what should we do if we wanted to only ask the user to login once, or only occasionally (say, once every 3 months)? To do that, we would then need to manage the access tokens and automatically refresh it.

ADAL comes with the TokenCache class that is designed to manage caching of tokens so that consumers don’t need to go back to Azure AD every time the mobile app asks for a new token. Unfortunately for us persistent caching of tokens is not supported in the release this post is based on (ADAL 3.0.11). This means that ADAL will only cache the token in memory which means that once an app restarts (or is backgrounded in iOS) you will lose your access token. Therefore, we need to manage the token, and refresh it on our own in the background.

There are many ways that you could do this, a simple way is to always check token validity before we access the API. If our token isn’t valid then we could check for the Refresh Token. Azure AD gives us a refresh token to use when our access token is about to expire. This means that when we ask AAD for a new token and provide this refresh token, AAD will give us a new token without asking the user to re-authenticate.

By Default, Azure AD refresh tokens are valid for 14 days. This means as long as we refresh the actual token even once in this period then we do not need to re-authenticate. Another security constraint that Azure AD imposes is that the access token can only be refreshed for a maximum period of 90 days (i.e. 90 days after the initial issuance of the access and refresh tokens, the end user will have to sign themselves in again).

Alright, time to write some code. The code snippet below shows how you could structure your API calls from your mobile app. Notice that we always call either AcquireToken() or AcquireTokenByRefreshToken() before every call. This is to ensure that we always have a valid token before we send a request to the API. This could even be optimised further by checking if the access token still valid, then we skip the token refreshing call. I will leave this as an exercise for you to implement. In the next release of ADAL hopefully the TokenCache would be implemented, and then we would not need to do this.


public async Task<string> GetResultFromWebApi(string apiCallPath)
{
	var token = await AcquireOrRefreshToken ();
	using (var httpClient = new HttpClient())
	{
		httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
		HttpResponseMessage response = await httpClient.GetAsync(apiBaseAddress + apiCallPath);
		return await response.Content.ReadAsStringAsync();
	}
}

private async Task<string> AcquireOrRefreshToken()
{
	var refreshToken = _storage.Get<string> (Constants.CacheKeys.RefreshToken);
	AuthenticationResult authResult = null;

	if (string.IsNullOrEmpty (refreshToken)) 
	{
		authResult = await _authContext.AcquireTokenAsync (
			resourceId, clientId, new Uri (redirectUrl), new AuthorizationParameters (_controller), UserIdentifier.AnyUser, null);

	} 
        else 
        {
		authResult = await _authContext.AcquireTokenByRefreshTokenAsync (refreshToken, clientId);
	}

	// when calling refresh token, the UserInfo would be null
	if (authResult.UserInfo != null)
		_storage.Save<string> (Constants.CacheKeys.Email, authResult.UserInfo.DisplayableId);

	_storage.Save<string> (Constants.CacheKeys.Token, authResult.AccessToken);
	_storage.Save<string> (Constants.CacheKeys.ExpireOn, authResult.ExpiresOn.ToString("dd MMM HH:mm:ss"));
	_storage.Save<string> (Constants.CacheKeys.RefreshToken, authResult.RefreshToken);

	return authResult.AccessToken;
}

That’s it! Now your mobile app would keep interacting with the API using a valid token. And if you are concerned about what happens when the user account is disabled, or the password is changed, then well done, you are following the topic properly. Azure AD, would either try to re-authenticate the user again (by showing the login screen), or gives an error. So we need to add some error handling to our code to catch these types of exceptions and handle them properly in the mobile app.

I hope you find this blog post useful and I would love to hear from you if you have a question or comment. In the next blog post, we will look at how we could use the same token for accessing multiple resources registered in Azure AD.

This blog post is the second in a series that cover Azure Active Directory Single Sign On (SSO) Authentication in native mobile applications.

  1. Authenticating iOS app users with Azure Active Directory
  2. How to Best handle AAD access tokens in native mobile apps (this post)
  3. Using Azure SSO access token for multiple AAD resources from native mobile apps
  4. Sharing Azure SSO access token across multiple native mobile apps.

Implementing Azure Active Directory SSO (Single Sign on) in Xamarin iOS apps

This blog post is the first in a series that cover Azure Active Directory Single Sign On (SSO) Authentication in native mobile applications.

  1. Authenticating iOS app users with Azure Active Directory (this post)
  2. How to Best handle AAD access tokens in native mobile apps
  3. Using Azure SSO access token for multiple AAD resources from native mobile apps
  4. Sharing Azure SSO access token across multiple native mobile apps.

Brief Start

Two weeks ago the Azure AD (AAD) team released the Active Directory Authentication Library (ADAL) to enable developers to implement SSO functionality leveraging AAD. This was great news for me as I have few clients who are keen on having this feature in their apps and in this blog post I will share my experience in implementing Azure AD SSO in Xamarin.iOS apps.

Mobile Service vs AAD Authentication

First things first, if you are using Azure Mobile Services, then authentication could be handled for you by Azure Mobile Services itself. All you need to do is to pass a reference of your RootViewController to the library and call LoginAsync() as follows:


// Initialize the Mobile Service client with your URL and key
client = new MobileServiceClient (applicationURL, applicationKey, this);
user = client.LoginAsync (_controller, MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory);

This will return a User object that you can use for future calls. This is slightly different from what we are going to talk about in this blog post. For further details on handling Azure Mobile Services authentication, you can check out this tutorial from the MSDN library.

Azure Active Directory Authentication

This blog post is to show you how you could authenticate users against Azure AD which can be useful in many cases. You may have a mobile app and only want users in Active Directory (on-prem or Azure) to use this app or you might have an API or a website and you share some functionality with your mobile users using a native mobile app. In both cases, you could use ADAL to enable Azure AD to handle the user authentication for you. This is quite handy for the following reasons:

  1. Less code development and maintenance for you as Azure handles it by itself
  2. Guaranteed functionality and less bugs as it is a well structured/tested library from a trusted source (Azure team)
  3. No need to further update your APIs when Azure API/SDKs are changed
  4. Extra features like token caching and token refresh operations.

Lack of Documentation

I have had few issues with the documentation on Azure when trying to implement SSO on Xamarin.iOS – the Azure documentation refers to classes and methods that do not exist in the ADAL. As another example, this tutorial seems to be taken from the native iOS implementation of Azure SSO without any update to match the release of ADAL. Anyway, enough complaining, for this reason we have this blog post. 🙂

Implementation

To implement SSO, I will assume that I have a native app, and I want to authenticate users against my AAD before they can use this app. For that, I would need to first register my native app in Azure AD so it shows as below.

Adding an App to Azure AD

Adding an App to Azure AD

  1. Click Add at the bottom of the screen to open the Add Application dialog
  2. Provide a name for your application registration so you can find it later. Click Next
  3. Provide a unique Redirect URI for your Application. Click the Finish (tick) button. Note that this must be a valid URI and is how Azure AD will identify your application during authentication requests.

Once we have created our application, let’s get the following details:

Authority
This represents the authority of your AAD, and it follows the format of https://login.windows.net/your-tenant-name.

ClientId
This is the unique client identifier of the native mobile app that we just created. See the screenshot below.

Azure AD app configurations

Azure AD app configurations

Redirect Uri
This is the unique redirect Id of the app that we just created as shown in the screenshot above.

Resource Id
This represents the resource URI of the app that we are trying to access. So if we are trying to access some functionality of a web API that is also registered with AAD, then this web app Id in Azure AD.

Once we have all the info above all we need to do is to write few lines of code. First we should install the ADAL Nuget Package in our solution. At the time of writing, the Nuget package version is 3.0.1102… and is in pre-release which means you need to allow pre-release packages in your Nuget settings.

Time to write some code. The small snippet below shows how to authenticate the user and get a token.
For the sake of this blog post, we only need to authenticate the user to azure. We will get the token and save it for future use, I have another post that talks about using this token. You can find it here.

        
const string authority = "https://login.windows.net/your-tenant-name";
const string resourceId = "your-resource-id";
const string clientId = "your-native-app-client-id-on-AAD";
const string redirectUrl = "your-awsome-app-redirect-url-as-on-AAD";

QSTodoService ()
{
    // this line if very important as it enables the ADAL library to do all 
    // IoC injection and other magic based on the platform that you are in. 
    AdalInitializer.Initialize ();
}

public async Task AsyncInit(UIViewController controller, MySimpleStorage storage)
{
    _storage = storage;
    _controller = controller;

    _authContext = new AuthenticationContext (authority);
}

public async Task<string> RefreshTokens()
{
    var refreshToken = _storage.Get<string> (Constants.CacheKeys.RefreshToken);
    AuthenticationResult authResult = null;
    var result = "Acquired a new Token"; 

    if (string.IsNullOrEmpty (refreshToken)) 
    {
       authResult = await _authContext.AcquireTokenAsync (
                    resourceId, clientId, new Uri (redirectUrl), new AuthorizationParameters (_controller), UserIdentifier.AnyUser, null);

    } else {
       authResult = await _authContext.AcquireTokenByRefreshTokenAsync (refreshToken, clientId);
       result = "Refreshed an existing Token";
    }

    if (authResult.UserInfo != null)
       _storage.Save<string> (Constants.CacheKeys.Email, authResult.UserInfo.DisplayableId);

    _storage.Save<string> (Constants.CacheKeys.Token, authResult.AccessToken);
    _storage.Save<string> (Constants.CacheKeys.RefreshToken, authResult.RefreshToken);

    return result;
}

As you can see, it is very simple. You could keep a reference to your AuthenticationContext in your app. In fact, it is recommended that you do so, for later use as the aggressive GC on Monotouch might dispose of it quickly.

Note that I am storing the token and the refresh token as I mentioned above, but you do not need to do that if you only using the library to authenticate once. In the next blog post, I will show how you could manage these tokens for further interaction with another app that is also using AAD for authentication.

I hope you found this series of posts useful, and as usual, if there is something not clear or you need some help with similar projects that you are undertaking, then get in touch, and we will do our best to help. I have pushed the sample code from this posts series to GitHub, and can be found here

This blog post is the first in a series that cover Azure Active Directory Single Sign On (SSO) Authentication in native mobile applications.

  1. Authenticating iOS app users with Azure Active Directory (this post)
  2. How to Best handle AAD access tokens in native mobile apps
  3. Using Azure SSO access token for multiple AAD resources from native mobile apps
  4. Sharing Azure SSO access token across multiple native mobile apps.

Extending Yammer SSO to Support Users Without an Email Address

BY TONY DU, JOEL NEFF

Yammer Enterprise is offered through the Microsoft Office 365 Enterprise plan. Deployment of Yammer Single Sign-On (SSO) for Office 365 users with a valid primary email address is a relative simple and well documented process.

One of our customers had a requirement for Yammer as a social platform, however a large percentage of their workforce are not enabled for email services. In the ‘SSO Implementation FAQ‘ published by Microsoft, it suggests that it is possible to configure SSO support for user accounts that do not have an email address associated with them, however there isn’t any supporting documentation to go with it.

The process outlined here assumes that Yammer SSO has already been enabled for users with a valid primary email address and all user accounts have been configured with a publicly routable UserPrincipalName suffix (UPN) for logon. This blog post provides guidance for extending Yammer SSO to support users without an email address, requiring a custom claim configuration on ADFS and the Office 365 tenant to enable this scenario.

ADFS Configuration

As in the image below, you should have an existing ‘Relying Party Trust’ configuration on ADFS if Yammer SSO is enabled for ordinary email enabled users.

Note: The ‘E-Mail Address’ at right side column for ‘Outgoing Claim Type‘ should be replaced with ‘SAML_SUBJECT’.

In order to extend the support to users without primary email address the ‘samAccountName’ attribute will be used for the claim rule (you could also use the UserPrincipalName). Therefore the following four custom claim rules need to be created and configured on the ‘Issuance Transform Rules‘ tab under the ‘Relying Party Trusts‘ node of the ADFS management console.

1. Remove the existing rule for ‘E-Mail-Addresses‘ under ‘Issuances Transform Rules
2. Add following custom rules in the order specified below to ensure the logic flows

Rule 1: Check for Email Address
– Click on Add Rules and select custom rule
– Insert the following text and save

@RuleName = &quot;Check for Email&quot;
c:[Type == &quot;http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname&quot;, Issuer == &quot;AD AUTHORITY&quot;]
=&gt; add(store = &quot;Active Directory&quot;, types = (&quot;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress&quot;), query = &quot;;mail;{0}&quot;, param = c.Value);

Rule 2: Check for No Email Address
– Click on Add Rules and select custom rule
– Insert the following text and save

@RuleName = &quot;No email&quot;
NOT EXISTS([Type == &quot;http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress&quot;])
=&gt; add(Type = &quot;http://emailCheck&quot;, Value = &quot;NoEmail&quot;);

Rule 3: If No Email Address Exists Use samAccountName Attribute
– Click on Add Rules and select custom rule
– Insert the following text and save

@RuleName = &quot;Send samAccountName for users without email&quot;
c:[Type == &quot;http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname&quot;, Issuer == &quot;AD AUTHORITY&quot;]
&amp;&amp; [Type == &quot;http://emailCheck&quot;, Value == &quot;NoEmail&quot;]
=&gt; issue(store = &quot;Active Directory&quot;, types = (&quot;SAML_SUBJECT&quot;), query = &quot;;samAccountName;{0}&quot;, param = c.Value);

Rule 4: Use Primary Email Address if email address exists
– Click on Add Rules and select custom rule
– Insert the following text and save

@RuleTemplate = &quot;LdapClaims&quot;
@RuleName = &quot;Send email to Yammer&quot;
c:[Type == &quot;http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname&quot;, Issuer == &quot;AD AUTHORITY&quot;]
=&gt; issue(store = &quot;Active Directory&quot;, types = (&quot;SAML_SUBJECT&quot;), query = &quot;;mail;{0}&quot;, param = c.Value);

The custom rules will be listed in order that they were created in as shown below:

Office 365 Tenant Configuration

You will need to raise a support request with Microsoft to set the ‘Allow Fake Email‘ option on the email domain being used for Yammer SSO. For all user accounts without a valid email address the ‘Fake Email: true‘ flag will be set after its authentication by ADFS and the Microsoft Office 365 Support Engineer will be able validate this for you.

Yammer Directory Synchronization Tool

Yammer DirSync is typically used for synchronising user account information between your Active Directory and Office 365 Yammer. Yammer DirSync does not officially support user accounts without a valid primary email address as stated in the Yammer Directory Synchronization FAQ:

As such, the recommended way to do this would be to manually synchronise your user list to Yammer by using a CSV. To automate the synchronisation for user accounts without an email address, custom coding through the Yammer REST API would be required.

As is documented in the Yammer configuration guide, Yammer DirSync only requires the two attributes of GUID and mail set on the user accounts for it to work. As a workaround it would be possible to populate the mail attribute in Active Directory with the ‘fake’ email address for the user accounts you would like to synchronise, however this may not be a suitable approach for every environment.

Claims-Based Federation Service using Microsoft Azure

In this post I will discuss how you can setup Microsoft Azure to provide federation services with claims authentication in the same way that an Active Directory Federation Service (ADFS) farm would on-premises. This can be achieved with an Azure subscription, Access Control Services (ACS) and an Azure Active Directory (AAD) instance. The key benefit of using Azure SaaS is that Microsoft have taken care of all the high availability and load scaling configuration, therefor you have no need to manage multiple ADFS servers to gain the same desired functionality.

If you don’t have an Azure subscription then signup for a free trial.

To have this process work in Azure we are going to need 2 functions –

  1. A service supporting claims-based protocols and be our token issuer – ACS
  2. A synchronized directory with connectivity to our claims issuer service – DirSync/AAD.

Azure Access Control Services (ACS) is a cloud based federated identity provider which currently supports tokens issued from social identities such as Windows Live ID, Facebook, Google, Yahoo and also the over-looked feature of enterprise identities like Active Directory. ACS can do some great things with transitions between protocols and transformation of claims as it issues secure tokens from the identity provider to the relying party applications.

Azure Active Directory (AAD) will house the synchronized identities from the on-premises Active Directory and provide claims-based authentication as it sends secure tokens with embedded claims to ACS.

The Solution

This scenario will apply to the majority of organizations whom are wanting to map the identity attributes from a source Active Directory (LDAP) to the outgoing claims type for a single sign on (SSO) experience.

Step 1 – Get the Identity in the Cloud

We need to use either a new directory in Azure or use an existing Office 365 directory if you have a tenant syncing already (skip to step 2) –

  • Turn on Synchronization by selecting Directory Integration > ACTIVATE
  • Create a user account to authenticate from your directory synchronization tool to AAD
  • Download the directory sync tool
  • Install and configure the directory sync tool on a server that is joined to your local Active Directory domain, and then run an initial sync. More information go here
  • Remember to enable password copy in the configuration wizard

Step 2 – Create an ACS Namespace

  • Select > New > App Services > Access Control > Quick Create
  • Give it a useful name prefix example: ‘kloudfed’
  • Once finished creating, Select > Manage
  • Select > Application Integration and see the Endpoint References

Next we need to create the Azure Active Directory as the Identity Provider

Step 3 – Create AAD Endpoint Mapping

Currently we have no way of ACS connecting to the information in AAD. To do this we create an Application Endpoint –

  • Select Active Directory > Federated Identity Instance > Applications > ADD AN APPLICATION
  • Select Add an application my organization is developing
  • Give it a name example: ‘Access Control Services’

  • In APP Properties:
    • Sign-ON URL = < ACS Management Portal >
    • APP ID URI = < ACS Management Portal >

  • In Azure Management Portal > Open your newly created APP
  • Select > View Endpoints

  • Copy Federation Metadata document URL to add to ACS

Step 4 – Add AAD as an Identity Provider in ACS

With the Federation Metadata Endpoint configured this can be the Identity Provider defined in ACS –

  • In ACS Portal Under Trust Relationships Select > Identity Providers
  • Select Add
  • In the Add Identity Provider Page Select > WS-Federation identity provider (e.g. Microsoft AD FS 2.0) > Select Next
  • Give it a name and paste the Federation Metadata URL from the previous step

  • Click Save

Now we are ready to add a claims-aware application in ACS which is requiring federated identity authentication.

Step 5 – Create a Relying Party Application

I’m not a developer, but this is the quickest way I know to make a claims-aware application using my copy of Visual Studio Express –

  • Select File > New Project > Web > ASP .NET Web Application

  • Click OK
  • Click > Change Authentication

  • Select Organization Account > Select On-Premises
  • Enter the ACS WS-Federation Metadata URL and make up an Application Unique ID

Step 6 – Add Relying Party Application information to ACS

The ACS Namespace wont issue tokens till it trusts the application. In the ACS Management Portal –

  • Select Relying Party Applications > New
  • Important – Realm is your App ID URI entered in the above steps

  • Generate a default claim transformation rule

Step 7 – Run a claims aware application

Here is my web application which will redirect from default URL (localhost) which is requiring authentication from Azure Active Directory –

  • The Redirect takes me to Azure Active Directory login

  • Enter Username & Password
  • Then I’m taken to the trusted application redirect URL after successful authenticating and we can already see claims information highlighted in yellow. Success!

     

Fiddler2 Capture

Let’s look at the web requests in a Fiddler2 capture to see what’s happening behind the scenes of my browser. Here are some condensed capture snippets –

#6

302 Redirectlocalhost to kloudfed.accesscontrol.windows.net:


#17

302 Redirectkloudfed.accesscontrol.windows.net to login.windows.net service:


#21

302 Redirectlogin.windows.net to login.microsoftonline.com:

#40

200 Result – Token response with claims returned from kloudfed.accesscontrol.windows.net

Filtering through the above #40 decrypted capture we find claims information. This is where we can validate if the web application is receiving the expected information in the token(I’ve removed the double-encoded values from the capture for readability) –

We can see the token is SAML2.0:

TokenType=http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0

One example of a claim attribute:

Name=http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname><AttributeValue>Peterson</AttributeValue>

Conclusion

If you’re after a claims-based federation service for SSO and installing a bunch of new servers in your existing infrastructure is something you’re not keen on undertaking, then maybe Azure gets a look. In an industry where everything must be called by its acronym to be thought of as a serious entity, I hereby label Microsoft Azure Federation Services “MAFS”.

Through reading Kloud blog posts you have solutions for creating a claims-based federation service in the cloud (MAFS) or an on-premises ADFS farm with Server 2012 R2 (both of which should only take you about 10 minutes to install!).