Securing and restricting access to Office 365 with custom AD FS claimrules

We’ve been working hard with one of our clients to secure access to Office 365 workloads such as Exchange Online. In this specific article we will share our experience how to restrict access to Exchange Online to specific networks and for specific protocols.

This client was using MobileIron for securing mobile devices and wanted to integrate this MDM solution with Office 365.

The tricky part of securing access to Exchange Online with MobileIron is the fact that MobileIron Sentry servers require dedicated IP adresses to Exchange. As you can imagine, the always changing Office 365 Cloud – with all it’s IP Addresses – will make it hard to follow this requirement. Thus we had to use a different technology, outside of MobileIron for restricting access to Office 365.

We chose to implement custom claimrules in AD FS, the enviroment we built this solution for on was an AD FS 2016 farm. In this new version of AD FS there are several changes on how to create custom claim rule, by default AD FS 2016 uses Access Control Policies and with these policies it was not possible to create such custom claim rules. So before we begin, we will start with explaining how torevert back to making use of the old school way of creating claim rules

  1. Log on the one of your AD FS servers
  2. Fire up PowerShell and run these commands
    1. $ADFSRpt = Get-AdfsRelyingPartyTrust -Name “Microsoft Office 365 Identity Platform”
    2. Set-AdfsRelyingPartyTrust -TargetRelyingParty $ADFSRpt -AccessControlPolicyName $null
    3. Set-AdfsRelyingPartyTrust -TargetRelyingParty $ADFSRpt -IssuanceAuthorizationRules $null
    4. Set-AdfsRelyingPartyTrust -TargetRelyingParty $ADFSRpt -IssuanceAuthorizationRules ‘@RuleName = “TEMP RULE” exists([Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-proxy”%5D) => issue(Type = “http://schemas.microsoft.com/authorization/claims/deny”,Value = “true”);’
  3. Open the AD FS Management Console
  4. Navigate to “Relying Party Trusts” and select the Office 365 relying party trust.
  5. Click on “Edit Access Control Policy” in the right menu to find the old menu for configuring “Issuance Authorization Rules”
  6. Remove the “TEMP RULE’ but DO NOT close the window
    Issuance AuthorizationRules

Now here the cool part comes, which is actually restricting specific traffic and protocols to specific networks, for instance SMTP or EWS traffic.

Restricting ActiveSync Protocol

  1. Add new rule
  2. Insert the following custom claim
  3. This claim contains the dedicated IP Adress from the MobileIron Sentry server from which we do accept ActiveSync traffic to Office 365. All other IP adressess are denied.

exists([Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-proxy”%5D)
&& exists([Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-client-application”, Value == “Microsoft.Exchange.ActiveSync”])
&& NOT exists([Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-forwarded-client-ip”, Value =~ “\b82\.125\.45\.23\b”])
=> issue(Type = “http://schemas.microsoft.com/authorization/claims/deny”, Value = “true”);

Restricting IMAP Protocol

  1. Add new rule
  2. Insert the following custom claim
  3. This claim contains the dedicated IP Adress from the MobileIron Sentry server from which we do accept IMAP traffic to Office 365. All other IP adressess are denied.

exists([Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-proxy”%5D)
&& exists([Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-client-application”, Value == “Microsoft.Exchange.Imap”])
&& NOT exists([Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-forwarded-client-ip”, Value =~ “\b82\.125\.45\.23\b”])
=> issue(Type = “http://schemas.microsoft.com/authorization/claims/deny”, Value = “true”);

Restricting SMTP Protocol

  1. Add new rule
  2. Insert the following custom claim
  3. This claim contains the dedicated IP Adress from the MobileIron Sentry server from which we do accept SMTP traffic to Office 365. All other IP adressess are denied.

exists([Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-proxy”%5D)
&& exists([Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-client-application”, Value == “Microsoft.Exchange.SMTP”])
&& NOT exists([Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-forwarded-client-ip”, Value =~ “\b82\.125\.45\.23\b”])
=> issue(Type = “http://schemas.microsoft.com/authorization/claims/deny”, Value = “true”);

Restricting POP Protocol

  1. Add new rule
  2. Insert the following custom claim
  3. This claim contains the dedicated IP Adress from the MobileIron Sentry server from which we do accept POP traffic to Office 365. All other IP adressess are denied.

exists([Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-proxy”%5D)
&& exists([Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-client-application”, Value == “Microsoft.Exchange.Pop”])
&& NOT exists([Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-forwarded-client-ip”, Value =~ “\b82\.125\.45\.23\b”])
=> issue(Type = “http://schemas.microsoft.com/authorization/claims/deny”, Value = “true”);

Restricting EWS Protocol

  1. Add new rule
  2. Insert the following custom claim
  3. This claim contains the public IP Adress range from the on-premises network from which we do accept EWS traffic to Office 365. All other IP adressess are denied. For this claimrule we also require the hybrid Exchange servers to send EWS traffic to Office 365 for delivering rich-coexistence functionality to all users. This example allows traffic from the range of 82.125.45.1 – 82.125.45.14.

exists([Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-proxy”%5D
&& exists([Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-client-application”, Value == “Microsoft.Exchange.SMTP”])
&& NOT exists([Type == “http://schemas.microsoft.com/2012/01/requestcontext/claims/x-ms-forwarded-client-ip”, Value =~ “\b82\.125\.45\.([1-9]|1[0-4])\b”])
=> issue(Type = “http://schemas.microsoft.com/authorization/claims/deny”, Value = “true”);

Now the current rule configuration should look like this:

Issuance AuthorizationRules2

The last rule to be added is a standard rule “Permit Access to All Users” and be sure this rule is at the bottom of the list with the “Permit” action.

Now all desired Exchange protocols are restricted to anywhere besides the MobileIron Sentry server or either the on-premises network range for some EWS traffic to support free/busy and other hybrid traffic to Exchange on-premises. However the new Outlook for iOS and Android app doesn’t use these traditional Exchange protocols. This new nifty app uses the Graph API for fetching e-mail and other resources.

To restrict access from unknown clients to Exchang Online with the use of the Outlook for iOS or Android app we chose to make use of Conditional Access for Azure Active Directory. And restrict access from any other networks then the public IP address from the Sentry server. To make use of this feature an Azure Active Directory Premium P1 license is required though!

A last fun fact to end this blogpost with is the fact that the documentation provided by Microsoft on TechNet is incorrect. The technet documentation on Limiting Access to Office 365 Services Based on the Location of the Client lists an incorrect HTTP Header for Imap traffic Microsoft.Exchange.PopImap. After a lot of searching and troubleshooting with Microsoft our eye fell on a little detail in the ADFS trace logs which caused the initial claimrule for Imap to fail. We found out that HTTP Headers for Imap traffic use the value Microsoft.Exchange.Imap and not Microsoft.Exchange.PopImap as described in the article!! Below here you can find the event registered in the AD FS Trace Logs from a IMAP client:

Following request context headers present:

X-MS-Client-Application: Microsoft.Exchange.Imap
X-MS-Client-User-Agent: –
client-request-id: 6338b8c2-c283-4c93-2c00-0080000000c6
X-MS-Endpoint-Absolute-Path: /adfs/services/trust/2005/usernamemixed
X-MS-Forwarded-Client-IP: xxx.xxx.xxx.xxx, xxx.xxx.xxx.xxx
X-MS-Proxy: WAP
X-MS-ADFS-Proxy-Client-IP: xxx.xxx.xxx.xxx

Big shout-out to my fellow friend and teammember Kevin Raap for working together on the claimrules, and finding out the flaw in Microsoft Technet documentation.

Configuring a multi-tenant federation with AD FS in a multi forest scenario with PowerShell

For weeks we have been working with Microsoft Premier Support and several product teams within Microsoft on a multi-forest to multi-tenant federation solution for Office 365 at two Dutch municipalites. There was some unclarity concerning supportabilty for our desired architecture at Microsoft, but as Microsoft calls it… this architecture qualifies for supportabilty. The fun part is, this scenario doesn’t require the provisioning of AD objects by hand, and allows you to use AADConnect to do this for you!

Now as the topology shows, we have two accounting forests where the AADConnect servers and Active Directory users reside. Each municipality has its own forest (forest B and forest C) and a configured a two-way full trust (forest-wide) to the resource forest (forest A). The Active Directory Federation Services (AD FS) farm resides in the resource forest (forest A).

Now the business requirement is having a single but high available AD FS farm in a resource forest, delivering an easy way of administering Identity Management for the long term. While at the same time delivering single sign-on functionality to all users working with Office 365 for each respected municipality.

Now the hard part here is the second federation to Office 365. The first federation configurated between the Microsoft Federation Gateway and your on-premises AD FS farm is pretty straight forward. And here is how it’s done:

  1. Log in to one of the AD FS Servers with an Domain Administrator account.
  2. You need to install the modules that are required for Office 365,
    1. Microsoft Online Service Sign-in Assistant for IT Professionals RTW
    2. Windows Azure Active Directory Module for Windows PowerShell (64-bit version
  3. Setup a Remote PowerShell connection to your tenant with an account having Global Administrator rights with this script;
    1. Import-Module MSOnline
      $O365Cred = Get-Credential
      $O365Session = New-PSSession –ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell -Credential $O365Cred -Authentication Basic -AllowRedirection
      Import-PSSession $O365Session
      Connect-MsolService –Credential $O365Cred

Once connected to the first tenant in Office 365 on the AD FS server run this cmd-let, be sure to use the -SupportMultipleDomains $true parameter.

Convert-MsolDomainToFederated -DomainName contoso.com -SupportMultipleDomain $true

The –SupportMultipleDomain parameter is needed since this is required for the multi-tenant configuration to work. This paramater makes sure that the federation is built with the correct IssuerUri set to https://contoso.com/adfs/services/trust/ instead of the Federation Service namespace (generally sts.domain.com) when not using this parameter. This is a vital requirement later on. To double-check this you can check the Claim Rules in AD FS management, the third rule should containt this claim:

c:[Type == “http://schemas.xmlsoap.org/claims/UPN“] => issue(Type = “http://schemas.microsoft.com/ws/2008/06/identity/claims/issuerid“, Value = regexreplace(c.Value, “^((.*)([.|@]))?(?<domain>[^.]*[.].*)$”, “http://${domain}/adfs/services/trust/“));

Now this was the first municipality for which contoso.com is the federated domain. You can download the script at the bottom of this blog.

Wait for a minute -or five- untill the federation kicks in and let’s carry on implementing the second federation…the real fun part!

First of all we need to export the token-signing certificate from the AD FS farm by PowerShell:

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

Next we can establish a new Remote PowerShell session to the second tenant with the script shared in step one of this post. After that we configure the second federation with this PowerShell script.

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

Now the most beautiful part of this second implementation is that it only configures endpoints on the Microsoft Federation Gateway, and doesn’t touch our on-premises configuration. The magic third claim we talked about earlier is all we need for it to work!

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.

Download the PowerShell scripts right here!

 

 

 

Intune device enrollment AD FS sign-in error “An error occurred. Contact your administrator for more information.”

Recently a client of mine added Windows Intune to their existing Office 365 subscription. The enablement of Intune requires users to install the Company Portal App on their mobile device which enrolls their device to your Office 365 organization.

In the process of enrolling a device it asks to login to Office 365. When a user tries to login with a federated Identity useraccount the login session will be redirected to your local AD FS sign-in page. However, when this is done from a mobile device it throws an error.

“An error occurred. Contact your administrator for more information.”

4-2-2016 14-17-03

Now once you have a look on the AD FS Admin eventviewer logging which can be found under the Applications and Services tree in the eventviewer MMC snap-in.

There you will find the error listed below:

Encountered error during federation passive request.

Additional Data

Protocol Name:
wsfed

Relying Party:
urn:federation:MicrosoftOnline

Exception details:
Microsoft.IdentityServer.Service.Policy.PolicyServer.Engine.InvalidAuthenticationTypePolicyException: MSIS7102: Requested Authentication Method is not supported on the STS.
at Microsoft.IdentityServer.Web.Authentication.GlobalAuthenticationPolicyEvaluator.EvaluatePolicy(IList`1 mappedRequestedAuthMethods, AccessLocation location, ProtocolContext context, HashSet`1 authMethodsInToken, Boolean& validAuthMethodsInToken)
at Microsoft.IdentityServer.Web.Authentication.AuthenticationPolicyEvaluator.RetrieveFirstStageAuthenticationDomain(Boolean& validAuthMethodsInToken)
at Microsoft.IdentityServer.Web.Authentication.AuthenticationPolicyEvaluator.EvaluatePolicy(Boolean& isLastStage, AuthenticationStage& currentStage, Boolean& strongAuthRequried)
at Microsoft.IdentityServer.Web.PassiveProtocolListener.GetAuthMethodsFromAuthPolicyRules(PassiveProtocolHandler protocolHandler, ProtocolContext protocolContext)
at Microsoft.IdentityServer.Web.PassiveProtocolListener.GetAuthenticationMethods(PassiveProtocolHandler protocolHandler, ProtocolContext protocolContext)
at Microsoft.IdentityServer.Web.PassiveProtocolListener.OnGetContext(WrappedHttpListenerContext context)

Solution:

  1. Logon to AD FS server(s).
  2. Open the AD FS Management Console
  3. On the right hand side right click on the Authentication Policies folder
  4. Choose “Edit Global Primary Authentication…”
  5. In this menu you should check (enable) Forms Authentication on both Intranet and Extranet.

 

After enabling forms authentication on both sides the AD FS requests sent from mobile devices will be succesfully authenticated by the AD FS secure token service.

SharePoint Online performance issue caused by deleted term store admin user objects

After working with Microsoft for over a month on a daily basis we found the cause of a serious performance issue within SharePoint Online. This issue affected several enterprise customers of ours.

This issue only occurs on sites which use the “managed navigation” functionality. In SharePoint, you can choose between two navigation methods: structural navigation or managed navigation. Structural navigation is based on site structure. Managed navigation is based on term sets. For further information read this article.

Rootcause symptoms which identify the cause:
When clients initiate a webrequest to the SharePoint Online site it takes 5 to 30 seconds untill the server returns data to the GET method. See this screenshot from Internet Exporer “Profiler”. 

IE_Profiler

Rootcause analysis:
After intensively troubleshooting several tenants we noticed strange behaviour the way the system communicates with the Managed Metadata Service Application. Since the sites are using managed navigation the content will be represented using a managed metadata term set. Because of this configuration EVERY FIRST WEBREQUEST is relies on your defined term sets and its configuration.

Solution:
Allright. Now that we have some understanding how the system relies on the Managed Metadata Service Application when using a managed navigation let’s proceed to implementing the solution.

The reason why the system “waits” for over 15 seconds on this specific part of SharePoint is caused by corrupt or missing user permissions on the database of the Service Application. As we explained “Managed navigation is using term store for its items, every time a request made to the term store, it will try to look for these users which takes some time until the process gives up.  Therefore causes the delay.”

1. Check if there are “present” Term Store Administrators defined in the Office365 portal by going to the SharePoint Admin center.
2. Select “term store” on the left hand side menu.
3. Check if you see any current users defined or SID’s i.e. s-1-5-21-2522053391-2242016340-1337919630-744690. See the image listed below.

Term_store_permissions
4. If you have identified these unknown SID’s on your environment OR identified other non system service-accounts please feel free to remove the permissions to instantly improve performance. 

Now.. if you are using AD FS and DirSync for providing single sign-on access to Office365 services then stick with me. If for instance while developing and building SharePoint solutions several users (developers or admins) have been granted the “Term Set Administrator” permission. At some point the project finishes and their account will be disabled or deleted at the on-premises Active Directory Services. Standard behaviour is that this deletion synchronizes to the cloud with DirSync. This process succesfully deletes the userobject on all front-end systems of Office365 but NOT correctly on all back-end systems in regarding to the Managed Metadata Service Application. In our case the user’s SID was still present on the Managed Metadata SQL database and therefore first webrequests got stuck on this explicit permission.

The only solution for this is contacting Microsoft Support and request them to delete the SID’s and/or old user objects on the database. Once deleted you will instantly notice great performance improvement on your environment!