Single sign-on to Office 365 using NetScaler SAML and nFactor authentication with Azure MFA

The following post describes how to configure SAML authentication with NetScaler as the IdP (Identity Provider) and Microsoft Office 365 as the SP (Service Provider). Going above just using SAML, a mixture of Azure Multi-Factor Authentication, User Certificates, LDAP and Negotiate authentication policies are used for authentication from external and internal locations.

To follow this guide, you should have atleast a single NetScaler ADC running Enterprise licensing or above. You should also have an Active Directory domain and a subscription to Office 365 with a verified external domain in place. The domain you use with Office 365 should be added as a UPN to Active Directory if it is not already your domain name suffix. The domain you also use with Office 365 cannot be set as primary. Microsoft do not allow primary domains to be federated. It is normal to set your default onmicrosoft.com domain as the primary domain.

♣ The Authentication Scenarios
♣ Additional Reading
♣ What is SAML
♣ Create Office 365 Domain Federation
♣ Create required Authentication Policies, Policy Labels and Login Schemas
♣ Create external AAA vServer and bind policies
♣ Authentication Results – External Users
♣ Create internal AAA vServer and bind policies
♣ Authentication Results – Internal Users
♣ Traffic Trace for external Certificate + LDAP Authentication

The Authentication Scenarios

The authentication methods and scenarios described in this post are as follows:

  • Internal users that can make contact with a Domain Controller use Integrated Windows Authentication for access to Office 365 services. Any non-Windows device that cannot perform IWA is not discussed, however it would be easy enough to support such device types.
  • External users with a user based certificate authenticate to Office 365 services with certificate based authentication followed by LDAP.
  • External users without a user based certificate authenticate to Office 365 services with LDAP followed by Azure Multi-Factor Authentication.

Note: Whilst following the guide, you could keep things simple and only use LDAP authentication for external users. I just like to go a bit further to show the capabilities.

Additional Reading

This post talks about the use of Azure Multi-Factor Authentication but does not go into detail on how to setup or configure the required components and integrate the solution with NetScaler. To read how to setup and configure this technology see https://jgspiers.com/azure-multi-factor-authentication-netscaler-unified-gateway/

This post also talks about the use of nFactor Authentication for NetScaler. To read more on this feature see https://jgspiers.com/nfactor-authentication-with-netscaler-gateway/

What is SAML

SAML (Security Assertion Markup Language) provides a way for one federation (Identity Provider) to authenticate with another separate federation (Service Provider) typically to consume available services. As a SaaS provider, Office 365 (the Service Provider) directs users who want to authenticate to the service across to NetScaler (the Identity Provider). NetScaler is normally connected to Active Directory, however supports a number of different authentication protocols and as such can challenge the user for a range of authentication methods. If a user can successfully authenticate, the NetScaler sends a SAML assertion (token) to Office 365. Since Office 365 is configured to trust the NetScaler IdP, the token is accepted and users are granted access to the service.

Create Office 365 Domain Federation

To get started, you should have AD Connnect configured between your on-premise Active Directory and Office 365. This allows synchronisation of user accounts and attributes. I’ll not go into detail on how you set this up but within the Office 365 Admin Center go to Settings -> Services & add-ins -> Azure multi-factor authentication.

You can run the readiness check tool from here, then download and install AD Connect on your internal AD servers.

When you have AD Connect running, users from your Active Directory will be synchronised to Azure AD as part of your Office 365 package.

The next steps requires you to configure your instance of Azure AD for federation. You should have an external certificate ready matching the FQDN that Office 365 uses when redirecting users to NetScaler to complete authentication. The destination (redirect URL) will point to a NetScaler AAA vServer. In my case, the Redirect URL is https://aaa.jspiers.org. When providing this certificate to Office 365, you do not include the private key.

On your Domain Controller, run the Azure Active Directory PowerShell Module.

Enter command Connect-MsolService.

Enter credentials of an Office 365 Global Administrator. Click Sign in.

Run and following commands:

$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2(“yourcertlocation.crt“)

$certData = [system.convert]::tobase64string($cert.rawdata)

Run and following commands:

$domain = "yourdomain.com"

$fedBrandName = "yourfedname"

$IdPloginurl = "https://AAAURL/saml/login"

$IdPlogouturl = "https://AAAURL/cgi/tmlogout"

Run the following command which sets your domain name up with federated authentication:

Set-MsolDomainAuthentication -DomainName $domain -FederationBrandName $fedBrandName -Authentication Federated -PassiveLogOnUri $Idploginurl -SigningCertificate $certdata -IssuerUri $IdPloginurl -ActiveLogOnUri $IdPloginurl -LogOffUri $IdPlogouturl -PreferredAuthenticationProtocol SAMLP

To check the settings you entered, run Get-MsolDomainFederationSettings -Domain domainname. 

To checked that the domain is now using federated authentication run command Get-MsolDomain. If you need to change the domain back to managed authentication run Set-MsolDomainAuthentication -DomainName domainname  -Authentication Federated

Create required Authentication Policies, Policy Labels and Login Schemas

A number of authentication policies are required to support the different scenarios when users are external or on the internal network. A mixture of LDAP, Certificate, Negotiate and Azure authentication policies will be created and used depending on where the user is located.

For more information on Azure Multi-Factor Authentication including setup and configuration see https://jgspiers.com/azure-multi-factor-authentication-netscaler-unified-gateway/

First, to create the Azure MFA policy navigate to Security -> AAA – Application Traffic -> Policies -> Authentication -> Advanced Policies -> Actions -> Servers -> Add.

Specify a name, insert the IP of the Azure MFA server. Specify a higher timeout than the default of 3 seconds. This gives users time to respond to the OTP, Phone Call or Authenticator application prompt. Enter bind credentials and then scroll down.

Under Server Logon Name Attribute enter UserPrincipalName. We use UPN because we want users to enter their email address to log on. Users are typically used to entering an email when accessing Office 365, Exchange OWA and any public email providers. Whilst there is no requirement for me, if you want to extract user groups during authentication then enter memberOf underneath Group Attribute. Expand More.

Enter mail under Attribute 1 and objectGUID under Attribute 2. These are additional attributes that Office 365 expects to receive within the SAML assertion. The objectGUID is an important attribute as this value is what Office 365 uses to direct users to the correct mailbox. Office 365 uses this value as your ImmutableID. This value is unique for every user. Finish creating the LDAP profile.

Navigate to Security – >AAA – Application Traffic -> Policies -> Authentication -> Advanced Policies -> Authentication Policies -> Add.

Enter a name for your Azure MFA policy, under Action Type select LDAP and under Action choose the new MFA policy you just created. Use true for the expression and click Create.

Next we create a SAML policy. Navigate to Security -> AAA – Application Traffic -> Policies -> Authentication -> Advanced Policies -> SAML IDP -> Profiles -> Add.

Enter a name. Under Assertion Consumer Service Url enter https://login.microsoftonline.com/login.srf. Under IDP Certificate Name choose the public certificate which matches your AAA vServer external URL users will be redirected to for authentication. Remember you also specified this same certificate when creating the Office 365 domain federation. Under Sign Assertion choose ASSERTION. Under Issuer Name specify your external AAA vServer URL in the format https://fqdn/saml/login. Scroll down.

Untick Reject Unsigned Requests. For Signature Algorithm choose RSA-SHA265. For Digest Method choose SHA256. For SAML Binding choose POST. Click More and scroll down.

Under Audience enter urn:federation:MicrosoftOnline. Under Skew Time the default value is 5 but can be lowered. This value specifies the amount of time difference that is allowed between the SP and IdP. Under Name ID Format choose Persistent and enter an expression of HTTP.REQ.USER.ATTRIBUTE(2).B64ENCODE. This specifies that the objectGUID attribute will be sent in the Assertion as Name ID. Under Attribute 1 enter Email and then enter expression HTTP.REQ.USER.ATTRIBUTE(1). Finish creating the SAML profile.

Click on the Policies tab -> Add.

Enter a name, choose the SAML profile you just created under Action and enter an expression of HTTP.REQ.HEADER(“Referer”).CONTAINS(“microsoftonline”).

Next a certificate policy will be created. Navigate to Security -> AAA – Application Traffic -> Policies -> Authentication -> Advanced Policies -> Actions -> CERT Actions -> Add.

Enter a name and under User Name Field select SubjectAltName:PrincipalName. Click Create.

Navigate to Security -> AAA – Application Traffic -> Policies -> Authentication -> Advanced Policies -> Authentication Policies -> Add.

Enter a name, choose CERT under Action Type and then select your certificate action. Enter true for expression and click Create.

The next policy created will be another LDAP policy. This policy is for users who have a certificate to be challenged for LDAP as next-factor. Navigate to Security -> AAA – Application Traffic -> Policies -> Authentication -> Advanced Policies -> Actions -> LDAP Actions -> Add.

Enter a name and specify the IP address of your preferably Load Balanced LDAP server. Enter bind credentials and scroll down.

Under Server Logon Name Attribute enter UserPrincipalName. Click More.

Under Attribute 1 enter mail and under Attribute 2 enter objectGUID. Finish creating the LDAP action.

Navigate to Security -> AAA – Application Traffic -> Policies -> Authentication -> Advanced Policies -> Authentication Policies -> Add.

Enter a name, under Action Type choose LDAP. Under Action select the LDAP action you just created and enter an expression of true. Click Create.

The next policy is another LDAP one. This policy will not perform explicit LDAP authentication but will be used simply to obtain the required attributes that Office 365 expects to see in a SAML Assertion. This policy will be used for internal users only. Navigate to Security -> AAA – Application Traffic -> Policies -> Authentication -> Advanced Policies -> Actions -> LDAP Actions -> Add.

Enter a name, specify an IP address and enter bind credentials. Uncheck Authentication. Scroll down.

Under Server Logon Name Attribute enter userPrincipalName. Click More.

Under Attribute 1 enter mail and under Attribute 2 enter objectGUID. Finish creating the LDAP profile.

Navigate to Security -> AAA – Application Traffic -> Policies -> Authentication -> Advanced Policies -> Authentication Policies -> Add.

Enter a name, choose LDAP under Action Type and then select the LDAP profile you just created under Action. Enter an expression of true and click Create.

The next policy is of type NEGOTIATE. The Negotiate policy allows internal users to authenticate using Integrated Windows Authentication. Navigate to Security -> AAA – Application Traffic -> Policies -> Authentication -> Advanced Policies -> Actions -> NEGOTIATE Actions -> Add.

Enter a name, under Domain Name specify your domain name. The username and password fields are required however you can enter a dummy account that does not even exist. It is not used. Under NTLM Path enter the FQDN to a Load Balanced web server that will be contacted for NTLM authentication. The web server should support NTLM. IIS is a perfect candidate. Click Create.

Navigate to Security -> AAA – Application Traffic -> Policies -> Authentication -> Advanced Policies -> Authentication Policies -> Add.

Enter a name, specify NEGOTIATE under Action Type and choose the Negotiate action you just created. Enter an expression of true and click Create.

The next step involves creating a Login Schema. This schema is for external users who authenticate with a user certficate and are then asked for LDAP credentials. The schema extracts the username from the certificate so you don’t have to manually enter it. If you need more information on Login Schemas and Policy Labels see https://jgspiers.com/nfactor-authentication-with-netscaler-gateway/

Create a Login Schema that resides in /flash/nsconfig/loginschema. The Login Schema extracts your username from the user certificate and then asks for your LDAP password.

The XML file should contain the following:

<?xml version="1.0" encoding="UTF-8"?><AuthenticateResponse xmlns="http://citrix.com/authentication/response/1"><Status>success</Status><Result>more-info</Result><StateContext /><AuthenticationRequirements>
<PostBack>/nf/auth/doAuthentication.do</PostBack><CancelPostBack>/Citrix/Authentication/ExplicitForms/CancelAuthenticate</CancelPostBack><CancelButtonText>Cancel</CancelButtonText>
<Requirements><Requirement><Credential><ID>login</ID><SaveID>ExplicitForms-Username</SaveID><Type>username</Type></Credential><Label><Text>Username</Text><Type>plain</Type></Label><Input><AssistiveText>Please supply either domain\username or user@fully.qualified.domain</AssistiveText><Text><Secret>false</Secret><ReadOnly>true</ReadOnly><InitialValue>${HTTP.REQ.USER.NAME}</InitialValue><Constraint>.+</Constraint></Text></Input></Requirement><Requirement><Credential><ID>passwd</ID><SaveID>ExplicitForms-Password</SaveID><Type>password</Type></Credential><Label><Text>Password:</Text><Type>plain</Type></Label><Input><Text><Secret>true</Secret><ReadOnly>false</ReadOnly><InitialValue/><Constraint>.+</Constraint></Text></Input></Requirement>
<Requirement><Credential><Type>none</Type></Credential><Label><Text>Please enter your password</Text><Type>confirmation</Type></Label><Input /></Requirement>
<Requirement><Credential><ID>saveCredentials</ID><Type>savecredentials</Type></Credential><Label><Text>Remember my password</Text><Type>plain</Type></Label><Input><CheckBox>
<InitialValue>false</InitialValue></CheckBox></Input></Requirement><Requirement><Credential><ID>loginBtn</ID><Type>none</Type></Credential><Label><Type>none</Type></Label><Input><Button>Log On</Button></Input></Requirement></Requirements></AuthenticationRequirements>
</AuthenticateResponse>

Navigate to Security -> AAA – Application Traffic -> Login Schema -> Profiles -> Add.

Enter a name and then click the pencil icon.

Select the Login Schema XML file you just created and click Select.

Click Create.

Navigate to Security -> AAA – Application Traffic -> Policies -> Authentication -> Advanced Policies -> Authentication Policy Labels -> Add.

Enter a name, under Login Schema choose the schema policy you just created. Click Continue.

Click Click to select.

Choose the standard LDAP policy which will be asked when users complete certificate authentication. Click Select.

Choose END next to Goto Expression. Click Bind.

Click Done.

Navigate to Security -> AAA – Application Traffic -> Policies -> Authentication -> Advanced Policies -> Authentication Policy Labels -> Add.

Enter a name and select noschema as the Login Schema. Click Continue.

Click Click to select.

Select the internal no authentication LDAP policy. Click Select.

Choose END under Goto Expression and click Bind.

Click Done.

Create external AAA vServer and bind policies

Next we create an AAA Virtual Server. This Virtual Server is public facing only and will serve external users. This is a typical scenario where the NetScaler resides in the DMZ. Navigate to Security -> AAA – Application Traffic -> Virtual Servers -> Add.

Specify a name, an IP Address and click More.

Enter your domain name under Authentication Domain. Click OK.

Click No Server Certificate.

Click Click to select.

Choose your public AAA certificate. Click Select.

Click Bind.

Since we are also doing an element of certificate authentication we have to bind the root or intermediate issuing CA certificate to the AAA vServer. Click No CA Certificate.

Select your root or intermediate certificate and click Select. Click Bind -> Close.

You’ll end up as below with one server and one CA certificate. Click on No SAML IDP Policy.

Click Add Binding.

Click Click to select.

Select the SAML policy and click Select.

Click Bind.

Click Close.

Click No Authentication Policy.

Click Click to select.

Choose the certificate authentication policy. Click Select.

Click Click to select under Select Next Factor.

Choose your Policy Label which extracts the username from certificate and presents LDAP fields. Click Select.

Click Bind.

Click Add Binding.

Make sure the priority is higher than the certificate authentication policy. Click Click to select.

Select the Azure MFA policy. Click Select.

For Goto Expression select END. Click Bind.

Click Close.

Under SSL Parameters check Client Authentication and set it to Optional.

Click Done.

Save your configuration via GUI or via CLI using command save ns conf.

Authentication Results – External Users

Now it is time to test the authentication to Office 365 externally, using SAML Assertions from NetScaler.

The first test is a user with an issued user certificate. When you browse to https://login.microsoftonline.com and enter your email address, you are prompted to select a certificate (if you have one). You can configure Internet Explorer/Chrome to skip any prompts and automatically select the certificate. In this case, I click manually select the cetificate and click OK.

I am then directed to NetScaler triple A. The username from my certificate is extracted so now I only need to enter my LDAP password. After doing so, click Log On.

If you aren’t using certificates, the email address entered from Office 365 may not be passed to NetScaler which means having to retype the email address again. To pass this through follow Prepopulate username with NetScalers RfWebUI

If authentication is successful, an assertion is sent to Office 365 and I am granted access to my account.

The second test is with no user certificate. Upon entering my email address to https://login.microsoftonline.com I am directed to the NetScaler AAA vServer. This time since I do not have a user certificate I am explicitly prompted for a username and password. After clicking Log On you will receive an Azure MFA challenge. This could be a one-time password text message, phone call or Authenticator app prompt.

The Authenticator app prompt when used appears as below. Click Approve. 

I am then successfully directed to my Office 365 account.

Create internal AAA vServer and bind policies

Now that we have external users taken care off, we want to be able to authenticate internal users with a different set of policies. In theory, when users enter their email address to Office 365 they should be able to use Integrated Windows Authentication to log on so they do not even have to enter a password. The password they used to log on to their PC is simply sent to NetScaler automatically.

Create a new AAA vServer with an internal facing IP. Click More.

Enter your domain name and click OK.

Click No Server Certificate.

Click Click to select.

Select the same public certificate you attached to the external vServer. Click Select.

Click Bind.

Click No SAML IDP Policy.

Click Add Binding.

Click Click to select.

Select the SAML policy and click Select.

Click Bind.

Click Close.

Click No Authentication Policy.

Click Click to select.

Select the Negotiate policy and click Select.

Click Click to select under Select Next Factor.

Select the NoSchema Policy Label. Click Select.

Click Bind.

Click Close.

To support passthrough, we also need to create and bind a Session Policy to this vServer. Under Policies click +.

Choose Session and click Continue.

Click Click to select.

Click Add.

Enter a name and then click the plus symbol next to Request Profile.

Enter a name. For Default Authorization Action specify ALLOW. For Single Sign-on to Web Applications specify ON. Click Create.

Enter an expression of true and click Create.

Now choose the newly created Session Policy and click Select.

Click Bind.

Click Done.

Save the running configuration. The NetScaler configuration is now complete.

On your internal DNS servers, create an A record for your Redirect URL which points at the internally addressable AAA vServer. This will prevent internal users from trying to route to the external AAA vServer.

For passthrough to work, you also need to make sure the AAA FQDN is added to your Local Intranet zone in Internet Explorer. Sites in Local Intranet have the required setting enabled by default “Automatic logon only in Intranet zone”.

Authentication Results – Internal Users

Now when internal users log on to https://login.microsoftonline.com watch how their logon happens automatically.

Note: If you have non-Windows devices they obviously cannot do Integrated Windows Authentication on the internal network. For such devices you will have to create additional authentication policies and use expressions to appropriately target those policies to the right devices.

Traffic Trace for external Certificate + LDAP Authentication

Below is an example of some of the steps that occur when certificate and LDAP authentication takes place against the NetScaler AAA vServer and a SAML assertion is posted to Office 365.

The initial SAML request is sent from Office 365 to NetScaler AAA.

The end-client connecting does an intial GET request for AAA page tmindex.html.

Notice the referer for the content is https://login.microsoftonline.com.

NetScaler returns an HTTP 200 OK. A series of GET requests then occur for content that make up the page.

The end-client does a POST to get available authentication methods.

Another POST is sent to get the nFactor authentication methods.

End-client intially performs certificate authentication as requested by NetScaler.

NetScaler starts an nFactor session for the user authenticating and the flow for authentication is determined.

End-client sends the second factor LDAP credentials to AAA.

NetScaler makes a bind request to LDAP and authentication is attempted.

If LDAP authentication is successful, AAA creates a session cookie and the user is successfully logged on. At this stage authentication is complete.

The end-client sends a POST requesting the SAML assertion.

NetScaler sends the assertion to the user, which is then forwarded to Office 365 to complete the process.


8 Comments

  • Kari Ruissalo

    December 15, 2017

    A great article. This was really insightful and helpful when setting up a federation (although I was doing a different setup than O365).

    Reply
  • Kari Ruissalo

    December 21, 2017

    Now I got this working for the most part but I seem to end up with NTLM fallback for the internal vServer constantly. I need to check your article once more 🙂

    … I do have an actual challenge also. In our case we have couple of ADFS 2.0 as SP. This seems to bring up an issue, as the ADFS 2.0 SP doesn’t send the referrer info in the http request header. So, if I need to bind multiple IdP Policies to one AAA vServer to have the SP data properly for each use case there’s really nothing that I could use to regocnize which SP I’m dealing with.

    I thought of using some sort of Content Switching per customer (each with their own URL, like idp.corp.com/cust1, idp.corp.com/cust2, and so forth…) but if I try to use LBs for rewriting a cookie or sth similar based on the requested URL I don’t understand how to redirect the traffic to the AAA vServer after. Also, the SaaS services are not accessed trough the NetScaler but via internet so that gives an extra twist to this one.

    Reply
    • George Spiers

      December 21, 2017

      There must be some header in the traffic sent from SP’s that allows you to identify what SP is sending the redirect? Also, the SP as you know will redirect users to the NetScaler URL. Depending on what URL the SP is sending the user too, you should be able to use an expression on your SAML policies to only evaluate against these URLs.
      That should mean that SP1.domain.com which resolves to NetScaler AAA VIP should be evaluated by SAML policy 1 and SP2.domain.com which resolves to same NetScaler AAA VIP should be evaluated by SAML policy 2.

      Reply
  • Chris

    October 22, 2018

    Could one set this up and then include ICA proxy for published app \ vdi?

    Reply
    • George Spiers

      October 22, 2018

      Of course 🙂

      Reply
  • J Birks

    July 15, 2019

    Thanks for sharing your solution

    Reply
  • Anonymous

    January 29, 2020

    Do you have any documentation on how to set up the internal negotiation? I am very confused about NTML and Kerberos and would be great if you have any guide for the setting up from the AD . Thanks! this is my email. jbernal62@gmail.com

    Reply
  • Anders

    August 28, 2020

    Would it be possible to do a similar solution but with oAuth and Citrix Cloud, to allow internal users SSO to Citrix Gateway (which only acts as IDP) and then to Citrix Cloud?

    Reply

Leave a Reply