Citrix Gateway and Microsoft Azure Multi-Factor Authentication

Citrix Gateway presents all hosted, SaaS, web, enterprise, and mobile applications to users on any device and any browser. It uses nFactor Authentication to authenticate users against on-premises Microsoft AD and leverages Microsoft AD FS for Azure Multi-Factor Authentication (MFA).

Overview

Citrix Gateway

Citrix Gateway provides users with one access point and single sign-on (SSO) to business applications and data deployed in a data center and the cloud. It is delivered as SaaS across a range of devices—laptops, desktops, thin clients, tablets, and smart phones. Citrix Gateway provides consolidation, helps reduce the footprint of remote access infrastructure, reduces cost, and provides ease of management and a better end-user experience. Citrix Gateway helps transition IT to hybrid cloud and SaaS environments.

  • Federation and single sign-on

Citrix Gateway provides federated identity and supports SAML 2.0, OAuth, and OpenID to achieve single sign-on across all applications whether they are web, VDI, enterprise, or SaaS applications.

  • User directory on-premises

Citrix Gateway provides SSO to SaaS applications such as Office 365 and Salesforce, and it keeps the user directory on-premises. It can be implemented as an IdP or proxy for Microsoft Active Directory Federation Services (AD FS).

  • Multi-factor (nFactor) authentication

Citrix Gateway provides nFactor authentication mechanisms and allows granular control over who is accessing the network, what is being accessed, and how and when it is accessed. It supports all the authentication mechanisms such as RADIUS, TACACS, NTLM, Diameter, SAML 2.0, OAuth 2.0, and OpenID 2.0.

  • Contextual access control policies

Citrix Gateway allows granular access control to business applications based on the state of the end-user device, user, user location, and other data. An IT administrator can create, manage, and enforce the policies to access data securely in an application environment. These policies can be implemented for VDI, web, mobile, enterprise, and SaaS applications.

  • Visibility and Monitoring

Citrix Application Delivery Management includes Gateway Insight, which provides visibility of the end-to-end user experience for all applications accessed through Citrix Gateway. It provides information for application support teams to troubleshoot issues regarding authentication failures, including EPA check failures and single sign-on failures.

Applications

Supported apps

Microsoft Azure MFA

People are connecting to organizational resources in increasingly complicated scenarios. People connect from organization-owned, personal, and public devices on and off the corporate network using smart phones, tablets, PCs, and laptops, often on multiple platforms. In this always-connected, multi-device, and multi-platform world, the security of user accounts is more important than ever. Passwords, no matter their complexity, used across devices, networks, and platforms are no longer sufficient to ensure the security of the user account, especially when users tend to reuse passwords across accounts. Sophisticated phishing and other social engineering attacks can result in user names and passwords being posted and sold across the dark web.

The security of the two-step verification process lies in its layered approach. Compromising multiple authentication factors presents a significant challenge for attackers. Even if an attacker manages to learn the user’s password, it is useless without also having possession of the additional authentication method. It works by requiring two or more of the following authentication methods:

  • Something you know (typically a password)
  • Something you have (a trusted device that is not easily duplicated, like a phone)
  • Something you are (biometrics)

Azure Multi-Factor Authentication helps safeguard access to data and applications. It provides an extra layer of security using a second form of authentication. Organizations can use conditional access to make the solution fit their specific needs.

Microsoft Azure MFA deployment methods

There are different methods to leverage Azure MFA as a second factor of authentication. Such methods are briefly explained below with their pros and cons.

Azure MFA server

Microsoft Azure Multi-Factor Authentication server was the original method and it is going to be deprecated. It should not be considered for any new implementation as

  • There is no further investment from Microsoft going forward on this method.
  • There is no integration with SSPR and Azure MFA Cloud-based.
  • There is no seamless migration tool from MFA Server to MFA Cloud-based solution.

Azure MFA Network Policy Server extension

Network Policy Server (NPS) extension for Azure MFA is a supported solution which uses NPS Adapter to connect with Azure MFA Cloud-based. It can be used as the on-premises RADIUS server.

  • NPS Adapter (RADIUS) will provide a network location inside/outside MFA Rule or On/Off.
  • It is not compatible with Azure AD Conditional Access Policies similar to SAML integration method. Conditional Access policies have much richer and better user experiences.
  • Users must be registered in MFA prior to using NPS Adapter. Unlike Azure MFA Cloud-based and Conditional Access, if user is not registered, then NPS Extension fails to authenticate user, which generates more calls to the help desk.
  • When NPS Adapter invokes MFA, it hits users registered default option. There is no visual notification to the user that MFA is required and coming. There is no UI for the user to change MFA methods during a gated process. If the user doesn’t have their default device with them, it will fail. The user must go back to selfservice portal and reset default option, and then try to connect again.

Microsoft AD FS and Azure MFA

If your organization is federated with Azure AD, but Passwords Hash are not synchronized with Azure AD, then you can use on-premises AD for Lightweight Directory Access Protocol (LDAP) and enable Azure MFA as part of Access Policies on AD FS relay parties. Starting with Windows Server 2016, you can now configure Azure MFA for primary authentication.

  • Azure MFA adapter is built into Windows Server 2016, and there is no need for an additional installation.
  • Azure MFA adapter integrates directly with Azure AD and does not require an on-premises Azure MFA server.
  • If users are not registered for MFA, they are guided through the process on next sign-in. It ensures less calls to the help desk and a better process for users.
  • Users get a visual notification that MFA is required and coming. Users can change gateway option during a gated process in the UI.

Azure AD and Azure MFA

If your organization is synchronizing Passwords Hash into Azure AD, Azure MFA can be leveraged via Conditional Access policies to challenge users for a second factor authentication.

  • This method does not require any additional installations on-premises.
  • If users are not registered for MFA, they are guided through the process on the next sign-in. It ensures less calls to the help desk and a better process for users.
  • Users get a visual notification that MFA is required and coming. Users can change the gateway option during a gated process in the UI.

Azure AD pass-through authentication and Azure MFA

Azure AD pass-through authentication (PTA) allows users to sign in to both on-premises and cloud-based applications using the same passwords. When users sign in using Azure AD, this feature validates users’ passwords directly against on-premises Active Directory. Azure AD PTA is an alternative to Azure AD Password Hash Synchronization, which provides the same benefit of cloud authentication to organizations.

  • Azure AD PTA requires a lightweight agent to be installed on-premises.
  • Azure AD PTA protects the user accounts by working seamlessly with the Azure AD Conditional Access policies, including Azure MFA.
  • Users can complete self-service password management tasks in the cloud.
  • On-premises passwords are never stored in the cloud in any form.
  • The agent only makes outbound connections from within your network. Therefore, there is no requirement to install the agent in a perimeter network, also known as a DMZ.

Current situation

An environment with the following characteristics requires leveraging Azure MFA as a second factor of authentication:

  • On-premises AD with Azure AD Synchronization is configured.
  • Azure AD Password Hash Synchronization is disabled.
  • Access to O365 applications is required.
  • Access to Citrix Virtual Apps and Desktops on-premises is required.
  • Access to applications with modern authentication method (SAML, OAuth) is required.
  • Access to applications with legacy authentication method is required.

Design points

Here are the design points for the proposed solution:

  • Access hosted, SaaS, enterprise, and web applications in a single portal and securely is required.
  • Users must only be required to enter their credentials once during the authentication process.
  • Single sign-on must be provided for all hosted, SaaS, enterprise, and web applications.

Proposed solution

Overview

The proposed solution is based on the following components:

  • On-premises Citrix Gateway
  • On-premises Microsoft AD
  • On-premises Microsoft AD FS
  • On-premises Citrix ADC as AD FS Proxy
  • Microsoft Azure MFA

Citrix Gateway is leveraging authentication, authorization, and auditing feature (Citrix ADC AAA) and nFactor authentication mechanisms to authenticate user with LDAP policy and leverage Access Policy on AD FS Relay Party to trigger Azure MFA validation process. After Azure MFA validates the user, AD FS generates SAML Assertion (SAML response) and redirects the user back to Citrix Gateway. At that point, the user is authenticated and Citrix Gateway presents all applications that the user is authorized to use.

The solution requires two public DNS records and two public IP addresses:

Description Value
Citrix Gateway FQDN access.ctxdemos.com
Citrix authentication, authorization, and auditing FQDN aaa.ctxdemos.com

The solution uses one public SSL certificate:

Description Value
Common Name access.ctxdemos.com
Subject Alternative Name sts.ctxdemos.com
Subject Alternative Name aaa.ctxdemos.com

The solution also uses a wildcard SSL certificate issued by internal Microsoft Certificate Authority Services:

Description Value
Common Name *.ctxdemos.com

Authentication flow

Sequence diagram

The following sequence diagram shows the authentication flow for the solution:

Sequence diagram

Authentication steps

The authentication steps are:

  1. User navigates to https://access.ctxdemos.com.
  2. Citrix Gateway redirects the user to the first Citrix ADC AAA VIP (Non-Addressable).
  3. First Citrix ADC AAA VIP uses a no-schema logon, which is configured with a single sign-on. Then it starts processing the advanced authentication policies.
  4. The first authentication policy is SAML SP to a non-addressable LB VIP to generate authentication cookies.
  5. The helper LB VIP is configured to use the second Citrix ADC AAA VIP (Addressable) for authentication. So, it redirects the user to the second authentication, authorization, and auditing VIP.
  6. Second Citrix ADC AAA VIP uses the Username Only logon schema, which prompts the user for the user name. Then it starts processing the advanced authentication policies.
  7. The first authentication policy is a Group Extraction, which queries the user name in an on-premises AD and validates if the user belongs to AzureMFACAUsers security group. Once the result of validation is successful, it starts to process the next authentication factor which is the LDAP policy.
  8. The LDAP policy uses the UsernameAndPassword login schema and a pre-filled user name field, and prompts the user for the AD password.
  9. When authentication on the second Citrix ADC AAA VIP is completed successfully, it goes back to helper LB VIP which generates a SAML response for the first authentication, authorization, and auditing VIP.
  10. The first Citrix ADC AAA VIP starts processing the next factor, which is a Group Extraction to ensure the user’s groups are extracted from AD and stored in the authentication, authorization, and auditing variable to be used later in the process.
  11. First Citrix ADC AAA VIP starts processing the next factor, which is a SAML SP to AD FS Proxy VIP on Citrix ADC.

    Note:

    Citrix ADC is federated with the AD FS farm. The detailed steps are explained in later sections.

  12. AD FS Proxy VIP validates that the authentication cookies (NSC_TMAA and NSC_TMAS) are set. Then it sends the SAML Request to a back end AD FS server (the back-end AD FS servers should be load balanced on internal Citrix ADC for high availability and resiliency of service).
  13. AD FS server processes the SAML request. Because the Access policy on the Relaying Party is set to “Permit all users and require MFA for authentication,” it triggers the Azure MFA authentication process.
  14. Azure MFA processes the user name. If it is already registered, it challenges the user with the configured method. If not, it prompts the user to register and set the primary and secondary authentication methods.
  15. Once Azure MFA authentication process is completed successfully, AD FS generates a SAML response for Citrix Gateway (First Citrix ADC AAA VIP).
  16. First Citrix ADC AAA VIP receives a SAML response and confirms that the authentication process for the user is completed.
  17. Citrix Gateway sends authentication information to Citrix StoreFront, which enumerates all applications and desktops that the user is authorized to use. Also, it processes the user’s group membership to present published bookmarks on Citrix Gateway.

Authentication screens

Most of the steps mentioned above are seamless to users as they are occurring internally between various VIPs on the Citrix ADC. The user experience is shown below:

Citrix Gateway logon page user name Citrix Gateway logon page user name and password Verification code

Implementation

Microsoft AD FS

Certificate requirements

Federation servers require the certificates in the following table:

Certificate Type Description What needs to be known before deploying
Secure Sockets Layer (SSL) certificate This is a standard Secure Sockets Layer (SSL) certificate that is used for securing communications between federation servers and clients. This certificate must be bound to the default website in the Internet Information Services (IIS) for a Federation Server or a Federation Server Proxy. For a Federation Server Proxy, the binding must be configured in IIS prior to running the Federation Server Proxy Configuration Wizard successfully. Recommendation: Because this certificate must be trusted by clients of AD FS, use a server authentication certificate that is issued by a public (third-party) certification authority (CA). For example, Verisign. Tip: The Subject name of this certificate is used to represent the Federation Service name for each instance of AD FS that you deploy. For this reason, you may want to consider choosing a Subject name on any new CA-issued certificates that best represents the name of your company or organization to partners.
Service communication certificate This certificate enables WCF message security for securing communications between federation servers. By default, the SSL certificate is used as the service communications certificate. This can be changed using the AD FS Management console.
Token-signing certificate This is a standard X509 certificate that is used for securely signing all tokens that the federation server issues. The token-signing certificate must contain a private key, and it should chain to a trusted root in the Federation Service. By default, AD FS creates a self-signed certificate. However, you can change this later to a CA-issued certificate by using the AD FS Management snap-in, depending on the needs of your organization.
Token-decryption certificate This is a standard SSL certificate that is used to decrypt any incoming tokens that are encrypted by a partner federation server. It is also published in the federation metadata. By default, AD FS creates a self-signed certificate. However, you can change this later to a CA-issued certificate by using the AD FS Management snap-in, depending on the needs of your organization.

Demo Environment Configuration

Certificate type Demo Environment Configuration
Secure Sockets Layer (SSL) certificate Internal certificate issued by internal issuing CA on AD FS server. Public trusted certificate on Citrix ADC.
Service communication certificate Internal certificate issued by AHS internal issuing certificate authority.
Token-signing certificate Auto generated by AD FS service.
Token-decryption certificate Auto generated by AD FS service.

In the demo environment, a wildcard certificate is enrolled and installed on the server.

Certificate authority

Service account requirements

You can either create a service account or leverage Group Managed Service Accounts (gMSA). To use gMSA, you need to create a Key Distribution Service Root Key. So, launch PowerShell and run the following command:

Add-KdsRootKey -EffectiveTime ((get-date).addhours(-10))

This command creates a Key Distribution Service Root Key, stored in Active Directory, and it allows you to create a group Managed Service Account (gMSA) as the AD FS service account you create later. Run this command with Domain Admin rights.

Root key

DNS record requirements

You need DNS A record for your AD FS Federation Service Name internally and externally. In the demo environment, Internal DNS record is pointing to the AD FS server IP and External DNS record is pointing to the Citrix Gateway public IP.

Record name Scope Type IP address
sts.ctxdemox.com Internal A 22.22.22.6
sts.ctxdemox.com External A 40.85.225.175

Add the AD FS role and configure the AD FS farm

Add the AD FS role

To add the AD FS role to Windows Server 2016 launch PowerShell and run the following command:

Install-WindowsFeature AD FS-Federation -IncludeManagementTools

PowerShell command

Configure the AD FS farm

Now you can begin your AD FS post-deployment configuration from Server Manager. Click Configure the federation service on this server.

Post deployment configuration

On the Welcome page, select Create the first federation server in a federation server farm, and then click Next.

Create the first federation server

On the Connect to Active Directory Domain Services page, ensure the Domain Administrator account is specified, and then click Next.

Connect to Active Directory domain services

On the Specify Service Properties page, complete the following steps, and then click Next:

  • Choose the certificate which was installed on the server in the previous steps.
  • The federation service name will automatically be populated based on the subject name of the certificate.
  • Put the display name for the federation service. For example, CTXDEMOS STS.

Specify service properties

On the Specify Service Account page, select Create a Group Managed Service Account, and enter a unique name for this account. Group Managed Service Accounts are supported in Windows Server 2012 onwards and come with strict, complex passwords which are changed automatically every 30 days. Click Next.

Create a group managed service account

On the Specify Configuration Database page, select specify the location of a SQL Server database. Click Next.

Specify configuration database

On the Review Options page, verify your configuration selections, and then click Next.

Review Options

On the Pre-requisite Checks page, verify that all prerequisite checks are successfully completed, and then click Configure.

Prerequisite checks

On the Results page, ensure that the installation is successful. Click Close to exit the wizard.

Post deployment configuration results

Configure AD FS farm - automated

You can run the following PowerShell script:

#
# Windows PowerShell script for AD FS Deployment
#
Import-Module ADFS
Install-AdfsFarm `
-CertificateThumbprint:"BD02F30D90A96EEE4A5934F2EA979E7A052584AE" `
-FederationServiceDisplayName:"CTXDEMOS STS" `
-FederationServiceName:"adfs.ctxdemos.com" `
-GroupServiceAccountIdentifier:"C

Configure AD FS with Azure MFA

Configure AD FS servers

On each of your AD FS servers, launch PowerShell and run the following commands:

# Install Windows PowerShell MSOnline Module
Install-Module MSOnline

# Import Windows PowerShell MSOnline Module
Import-Module MSOnline

# Get the Azure Global Administrator credential
$credential = Get-Credential

# Sign in to your Azure Active Directory environment
Connect-MsolService -Credential $credential

# Set a variable for the Azure Tenant name
$azureTenantID = "ctxdemos.onmicrosoft.com"

# Set a variable for the Azure MFA Client GUID
$azureMFAClientGUID = "981f26a1-7f43-403b-a875-f8b09b8cd720"

# Generate a certificate for the Azure MFA on AD FS server
$azureMFACertificate = New-AdfsAzureMfaTenantCertificate -TenantId $azureTenantID

# Add the new credentials to the Azure MFA Client Service Principal
New-MsolServicePrincipalCredential -AppPrincipalId $azureMFAClientGUID -Type asymmetric -Usage verify -
Value $azureMFACertificate

Configure AD FS farm

Only on one of the AD FS servers, run the following command:

Set-AdfsAzureMfaTenant -TenantId $azureTenantID -ClientId $azureMFAClientGUID

Restart the AD FS service on each of your servers. Then you will see that Azure MFA is available as the primary and multifactor authentication method for the intranet and extranet use.

Primary authentication method

Multifactor authentication method

Configure AD FS with Citrix ADC

You need to create a federation trust between AD FS and Citrix ADC. In the AD FS Management Console, navigate to Relying Party Trust and select Add Relying Party Trust.

Add a relying party trust

Select Enter data about the relying party manually and click Next.

Enter data about the relying party

Enter a descriptive display name and optional notes. Click Next.

Optional notes

Click Next.

Configure a certificate

Select Enable support for the SAML 2.0 WebSSO protocol and enter https://CitrixGatewayFQDN/cgi/samlauth. In the demo environment, it is https://access.ctxdemos.com/cgi/samlauth. Click Next.

Configure a URL

Enter a unique identifier string for the Relying Party Trust. In the demo environment, it is https://access.ctxdemos.com. This identifier will be used as an Issuer URL in the Citrix ADC SAML profile. Click Next.

Configure an identifier

On the Choose Access Control Policy page, select Permit everyone and require MFA. Click Next.

Access Control Policy

Click Next.

Add trust

On the Finish page, select Configure claims issuance policy for this application. Click Close.

Finish

On the Issuance Transform Rules page, click Add Rule.

Add a rule

Click Next.

Select a template

Enter a descriptive name in Claim rule name field. Under Attribute store, select Active Directory. Then select the following: LDAP Attributes and Outgoing Claim Types.

Configure a rule

Create a new rule and use Send Claims Using a Custom Rule as Claim rule template. Enter a descriptive name for Claim rule name and enter the following string for Custom rule:

=> issue(Type = "logoutURL", Value = "https://adfs.yourdomain.com/adfs/ls/", Properties["http://schemas.xmlsoap.org/ws/2005/05/identity/claimproperties/attributename"] = "urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified");

Configure a rule

When the Claim Issuance Policies are created, click Ok.

Right-click Relying Party Trust > Citrix ADC, and select Properties. Select Endpoints and add an endpoint by clicking Add SAML for Logout. From the Endpoint type list, select SAML Logout. For Binding, select POST, and for Trusted URL, enter https://sts.ctxdemos.com/adfs/ls/?wa=wsignout1.0. This will act as a logout URL when logging out of Citrix ADC. Click OK.

SAML logout

Right-click Relying Party Trust > Citrix ADC, and select Properties. Select Encryption and add public SSL certificate that is installed on Citrix Gateway. This certificate will be used to decrypt an incoming SML Request from Citrix ADC. Repeat the same on Signature tab. This certificate will be used to check the signature of an incoming SAML Request. Click OK.

Enable IdP initiated sign-on page

You can enable the AD FS IdP initiated sign-on page. You will be using the IdP initiated sign-on to present a custom error page to unregistered MFA users. To enable, run the following command:

Set-AdfsProperties -EnableIdPInitiatedSignonPage $true

Test AD FS farm

Open a web browser and navigate to:

Citrix ADC and Citrix Gateway

Configure Citrix Gateway

You can configure Citrix Gateway through the wizard. Log on to Citrix ADC Management GUI, navigate to Unified Gateway, and click Create New Gateway. Then click Continue.

Single public access

Enter the name, IP, and FQDN for Unified Gateway and click Continue.

Citrix Gateway configuration

Select the public SSL certificate and click Continue.

Server certificate

Create a basic LDAP policy and bind it to Unified Gateway. Click Continue.

Authentication

Create a portal theme based on RfWebUI and bind it to Unified Gateway. Click Continue.

Portal theme

Select the plus sign (+) in front of the applications to integrate Citrix Gateway with StoreFront.

Integrate Gateway with StoreFront

Integrate Citrix StoreFront into Citrix Gateway

On the Application page, select XenApp & XenDesktop, and from the Choose Integration Point list, select StoreFront. Click Continue.

Select multiple settings

Enter a StoreFront URL and click Retrieve Stores. Then enter the Default Active Directory Domain and Secure Ticket Authority URL settings. Click Test STA Connectivity and then click Continue.

Test connectivity

Click Done and then click Continue.

Continue

Configure Citrix Gateway and integrate with StoreFront – CLI

# Create Session Policy and Action for Citrix Receiver
add vpn sessionAction AC_OS_22.22.44.50 -transparentInterception OFF -defaultAuthorizationAction ALLOW -SSO ON -icaProxy ON -wihome "https://access.ctxdemos.com/Citrix/ExternalWeb" -ClientChoices OFF -ntDomain CTXDEMOS -clientlessVpnMode OFF -storefronturl "https://access.ctxdemos.com"
add vpn sessionPolicy PL_OS_22.22.44.50 "HTTP.REQ.HEADER(\"User-Agent\").CONTAINS(\"CitrixReceiver\") && HTTP.REQ.HEADER(\"User-Agent\").CONTAINS(\"CitrixVPN\").NOT && HTTP.REQ.HEADER(\"User-Agent\").CONTAINS(\"NSGiOSplugin\").NOT" AC_OS_22.22.44.50

# Create Session Policy and Action for Citrix Web Client
add vpn sessionAction AC_WB_22.22.44.50 -transparentInterception ON -defaultAuthorizationAction ALLOW -forceCleanup cookie -SSO ON -ssoCredential PRIMARY -icaProxy OFF -wihome "https://storefront.ctxdemos.com/Citrix/ExternalWeb" -wiPortalMode COMPACT -ClientChoices OFF -ntDomain CTXDEMOS -clientlessVpnMode ON -clientlessPersistentCookie ALLOW
add vpn sessionPolicy PL_WB_22.22.44.50 "HTTP.REQ.HEADER(\"User-Agent\").CONTAINS(\"CitrixReceiver\").NOT" AC_WB_22.22.44.50

# Create Session Policy and Action for Citrix Gateway Client
add vpn sessionAction UG_VPN_SAct_22.22.44.50 -transparentInterception ON -defaultAuthorizationAction ALLOW -SSO ON -ClientChoices ON -clientlessVpnMode ON
add vpn sessionPolicy UG_VPN_SPol_22.22.44.50 true UG_VPN_SAct_22.22.44.50

# Create Session Policy and Action for RDP Proxy
add vpn sessionAction GATEWAY_SESSION_PRF_RDP -rdpClientProfileName RDP_CLIENT_PRF
add vpn sessionPolicy GATEWAY_SESSION_POL_RDP TRUE GATEWAY_SESSION_PRF_RDP

# Create Responder Policy and Action for Gateway Logout
add responder action RESACT_GATEWAY_LOGOFF_REDIRECT redirect "\"https://\" + HTTP.REQ.HOSTNAME.HTTP_URL_SAFE" -responseStatusCode 302
add responder policy RESPOL_GATEWAY_LOGOFF_REDIRECT "HTTP.REQ.URL.CONTAINS(\"/cgi/logout\")" RESACT_GATEWAY_LOGOFF_REDIRECT

# Create Citrix Gateway vServer
add vpn vserver UGVS_VPN_UGCTXDEMOS SSL 0.0.0.0 -loginOnce ON -Listenpolicy NONE -authnProfile AAA_AUTH_PRF_VPN -vserverFqdn access.ctxdemos.com
set ssl vserver UGVS_VPN_UGCTXDEMOS -ssl3 DISABLED -tls1 DISABLED -tls11 DISABLED -tls13 ENABLED -ocspStapling ENABLED -HSTS ENABLED -maxage 157680000 -IncludeSubdomains YES
bind ssl vserver UGVS_VPN_UGCTXDEMOS -certkeyName CTXDEMOS_PUBLIC_CERT
bind ssl vserver UGVS_VPN_UGCTXDEMOS -cipherName CTXDEMOS_FRONTEND_APLUS
bind vpn vserver UGVS_VPN_UGCTXDEMOS -portaltheme CTXDEMOS_PORTAL
bind vpn vserver UGVS_VPN_UGCTXDEMOS -staServer "https://wsctxdc01.ctxdemos.com"
bind vpn vserver UGVS_VPN_UGCTXDEMOS -policy POL-LDAPS-1
bind vpn vserver UGVS_VPN_UGCTXDEMOS -policy RESPOL_GATEWAY_LOGOFF_REDIRECT -priority 100 -gotoPriorityExpression END -type REQUEST
bind vpn vserver UGVS_VPN_UGCTXDEMOS -policy _cacheTCVPNStaticObjects -priority 10 -gotoPriorityExpression END -type REQUEST
bind vpn vserver UGVS_VPN_UGCTXDEMOS -policy _cacheOCVPNStaticObjects -priority 20 -gotoPriorityExpression END -type REQUEST
bind vpn vserver UGVS_VPN_UGCTXDEMOS -policy _cacheVPNStaticObjects -priority 30 -gotoPriorityExpression END -type REQUEST
bind vpn vserver UGVS_VPN_UGCTXDEMOS -policy _mayNoCacheReq -priority 40 -gotoPriorityExpression END -type REQUEST
bind vpn vserver UGVS_VPN_UGCTXDEMOS -policy _cacheWFStaticObjects -priority 10 -gotoPriorityExpression END -type RESPONSE
bind vpn vserver UGVS_VPN_UGCTXDEMOS -policy _noCacheRest -priority 20 -gotoPriorityExpression END -type RESPONSE
bind vpn vserver UGVS_VPN_UGCTXDEMOS -policy PL_OS_22.22.44.50 -priority 100 -gotoPriorityExpression NEXT -type REQUEST
bind vpn vserver UGVS_VPN_UGCTXDEMOS -policy PL_WB_22.22.44.50 -priority 110 -gotoPriorityExpression NEXT -type REQUEST
bind vpn vserver UGVS_VPN_UGCTXDEMOS -policy GATEWAY_SESSION_POL_RDP -priority 120 -gotoPriorityExpression NEXT -type REQUEST
bind vpn vserver UGVS_VPN_UGCTXDEMOS -policy UG_VPN_SPol_22.22.44.50 -priority 58000 -gotoPriorityExpression NEXT -type REQUEST

# Create Content Switching Policy and Action for Citrix Gateway
add cs action CSACT_UGCTXDEMOS -targetVserver UGVS_VPN_UGCTXDEMOS
add cs policy CSPOL_UGCTXDEMOS -rule "is_vpn_url  ||  HTTP.REQ.URL.PATH.SET_TEXT_MODE(IGNORECASE).STARTSWITH(\"/Citrix/External\")" -action CSACT_UGCTXDEMOS

# Create Content Switching vServer for Citrix Gateway
add cs vserver CSVS_UGCTXDEMOS SSL 22.22.44.50 443 -cltTimeout 180
set ssl vserver CSVS_UGCTXDEMOS -ssl3 DISABLED -tls1 DISABLED -tls11 DISABLED -tls13 ENABLED -ocspStapling ENABLED -HSTS ENABLED -maxage 157680000 -IncludeSubdomains YES
bind ssl vserver CSVS_UGCTXDEMOS -certkeyName CTXDEMOS_PUBLIC_CERT
bind ssl vserver CSVS_UGCTXDEMOS -cipherName CTXDEMOS_FRONTEND_APLUS
bind cs vserver CSVS_UGCTXDEMOS -policyName CSPOL_UGCTXDEMOS -priority 63000

# Create Responder Policy and Action for HTTP to HTTPS Redirection
add responder action RESACT_HTTP_TO_HTTPS redirect "\"https://\" + HTTP.REQ.HOSTNAME.HTTP_URL_SAFE + HTTP.REQ.URL.PATH_AND_QUERY.HTTP_URL_SAFE" -responseStatusCode 301
add responder policy RESPOL_HTTP_TO_HTTPS HTTP.REQ.IS_VALID RESACT_HTTP_TO_HTTPS

# Create Always On Server and Service
add server LBSRV_ALWAYS_UP 127.0.0.1
add service LBSVC_ALWAYS_UP LBSRV_ALWAYS_UP HTTP 80 -gslb NONE -maxClient 0 -maxReq 0 -cip ENABLED cip-header -usip YES -useproxyport YES -sp OFF -cltTimeout 180 -svrTimeout 360 -CKA NO -TCPB NO -CMP NO

# Create Always On vServer for Citrix Gateway
add lb vserver CSVS_UGCTXDEMOS_REDIRECT_HTTP_TO_HTTPS HTTP 22.22.44.50 80 -persistenceType NONE -cltTimeout 180
bind lb vserver CSVS_UGCTXDEMOS_REDIRECT_HTTP_TO_HTTPS LBSVC_ALWAYS_UP
bind lb vserver CSVS_UGCTXDEMOS_REDIRECT_HTTP_TO_HTTPS -policyName RESPOL_HTTP_TO_HTTPS -priority 100 -gotoPriorityExpression END -type REQUEST

Configure the first authentication server

# Create Initialization SAML SP Policy and Action and Bind it to Citrix ADC AAA Authentication vServer
add authentication samlAction AUTH_ACT_SAML_SP_VPN_TO_LB -samlIdPCertName CTXDEMOS_PUBLIC_CERT -samlSigningCertName CTXDEMOS_PUBLIC_CERT -samlRedirectUrl "https://access.ctxdemos.com/samltolb" -signatureAlg RSA-SHA256 -digestMethod SHA256 -samlBinding REDIRECT -groupNameField Groups
add authentication Policy AUTH_POL_SAMP_SP_VPN_TO_LB -rule TRUE -action AUTH_ACT_SAML_SP_VPN_TO_LB

# Create Authentication Policy and Action for SAML SP to ADFS
add authentication samlAction AUTH_ACT_SAML_SP_ADFS -samlIdPCertName CTXDEMOS_ADFS_TOKEN_SIGNING -samlSigningCertName CTXDEMOS_PUBLIC_CERT -samlRedirectUrl "https://sts.ctxdemos.com/adfs/ls/" -samlUserField "Name ID" -samlRejectUnsignedAssertion OFF -samlIssuerName "https://access.ctxdemos.com" -Attribute1 "E-Mail Address" -signatureAlg RSA-SHA256 -digestMethod SHA256 -logoutURL "https://sts.ctxdemos.com/adfs/ls/wa=wsignout1.0" -forceAuthn ON
add authentication Policy AUTH_POL_SAML_SP_ADFS -rule TRUE -action AUTH_ACT_SAML_SP_ADFS

# Create Authentication Policy Label for for SAML SP to ADFS
add authentication policylabel AUTH_POLLBL_ADFS_AZUREMFA -loginSchema LSCHEMA_INT
bind authentication policylabel AUTH_POLLBL_ADFS_AZUREMFA -policyName AUTH_POL_SAML_SP_ADFS -priority 100 -gotoPriorityExpression NEXT

# Create Authentication Policy and Action for Group Extraction
add authentication ldapAction AUTH_ACT_LDAP_GROUP_EXTRACTION_AZUREMFACA -serverIP 22.22.22.61 -serverPort 636 -ldapBase "DC=ctxdemos,DC=com" -ldapBindDn "CN=svc_ctxadc01,OU=Services,OU=Accounts,DC=ctxdemos,DC=com" -ldapBindDnPassword 0c4fe86d56a865ef514a15affd1429f3e079ce1089731d4a407772d21036f3c8 -encrypted -encryptmethod ENCMTHD_3 -ldapLoginName sAMAccountName -searchFilter "memberOf:1.2.840.113556.1.4.1941:=CN=AzureMFACAUsers,OU=Groups,OU=Authorizations,DC=ctxdemos,DC=com" -groupAttrName memberOf -subAttributeName cn -secType SSL -authentication DISABLED -nestedGroupExtraction ON -maxNestingLevel 5 -groupNameIdentifier sAMAccountName -groupSearchAttribute memberOf -groupSearchSubAttribute CN -Attribute1 mail -Attribute2 objectGUID
add authentication Policy AUTH_POL_LDAP_GROUP_EXTRACTION_AZURAMFACA -rule TRUE -action AUTH_ACT_LDAP_GROUP_EXTRACTION_AZUREMFACA

# Create Authentication Policy Label for Group Extraction
add authentication policylabel AUTH_POLLBL_LDAP_GROUP_EXTRACTION_AZURAMFACA -loginSchema LSCHEMA_INT
bind authentication policylabel AUTH_POLLBL_LDAP_GROUP_EXTRACTION_AZURAMFACA -policyName AUTH_POL_LDAP_GROUP_EXTRACTION_AZURAMFACA -priority 100 -gotoPriorityExpression NEXT -nextFactor AUTH_POLLBL_ADFS_AZUREMFA


# Create Login Schema Policy and Profile for First Citrix ADC AAA Authentication vServer
add authentication loginSchema LSCHEMA_PRF_NOSCHEMA -authenticationSchema noschema -SSOCredentials YES
add authentication loginSchemaPolicy LSCHEMA_POL_NOSCHEMA -rule TRUE -action LSCHEMA_PRF_NOSCHEMA

# Create First Citrix ADC AAA Authentication vServer
add authentication vserver AAAVS_CTXDEMOS_COM_FOR_VPN SSL 0.0.0.0
set ssl vserver AAAVS_CTXDEMOS_COM_FOR_VPN -ssl3 DISABLED -tls1 DISABLED -tls11 DISABLED -tls13 ENABLED -ocspStapling ENABLED -HSTS ENABLED -maxage 157680000 -IncludeSubdomains YES
bind ssl vserver AAAVS_CTXDEMOS_COM_FOR_VPN -certkeyName CTXDEMOS_PUBLIC_CERT
bind ssl vserver AAAVS_CTXDEMOS_COM_FOR_VPN -cipherName CTXDEMOS_FRONTEND_APLUS
bind authentication vserver AAAVS_CTXDEMOS_COM_FOR_VPN -policy LSCHEMA_POL_NOSCHEMA -priority 100 -gotoPriorityExpression END
bind authentication vserver AAAVS_CTXDEMOS_COM_FOR_VPN -policy AUTH_POL_SAMP_SP_VPN_TO_LB -priority 100 -nextFactor AUTH_POLLBL_LDAP_GROUP_EXTRACTION_AZURAMFACA -gotoPriorityExpression NEXT

# Create First Citrix ADC AAA Authentication Profile
add authentication authnProfile AAA_AUTH_PRF_VPN -authnVsName AAAVS_CTXDEMOS_COM_FOR_VPN -AuthenticationHost aaa.ctxdemos.com -AuthenticationDomain ctxdemos.com

Configure a second authentication server

# Create Authentication Policy and Action for LDAP
add authentication ldapAction AUTH_ACT_LDAP -serverIP 22.22.22.61 -serverPort 636 -authTimeout 60 -ldapBase "DC=ctxdemos,DC=com" -ldapBindDn "CN=svc_ctxadc01,OU=Services,OU=Accounts,DC=ctxdemos,DC=com" -ldapBindDnPassword 273881819af883e70c33d83c0546eac84e81d6eeba904f2d65bbebf2819c025a -encrypted -encryptmethod ENCMTHD_3 -ldapLoginName sAMAccountName -groupAttrName memberOf -subAttributeName cn -secType SSL -passwdChange ENABLED -nestedGroupExtraction ON -maxNestingLevel 5 -groupNameIdentifier sAMAccountName -groupSearchAttribute memberOf -groupSearchSubAttribute CN -Attribute1 userprincipalname -Attribute2 mail -Attribute3 userParameters
add authentication Policy AUTH_POL_LDAP_USER_NAME_PASSWORD -rule TRUE -action AUTH_ACT_LDAP

# Create Login Schema Policy and Profile for Second Citrix ADC AAA Authentication vServer - Username (Pre-filled ) and Password
add authentication loginSchema LSCHEMA_USER_NAME_PASSWORD -authenticationSchema "/nsconfig/loginschema/CTXDEMOS_USER_NAME_PASS.xml" -SSOCredentials YES
add authentication loginSchemaPolicy LSCHEMA_POL_USER_NAME_PASSWORD -rule TRUE -action LSCHEMA_USER_NAME_PASSWORD

# Create Authentication Policy Label for LDAP Username and Password
add authentication policylabel AUTH_POLLBL_LDAP_USER_NAME_PASSWORD -loginSchema LSCHEMA_USER_NAME_PASSWORD
bind authentication policylabel AUTH_POLLBL_LDAP_USER_NAME_PASSWORD -policyName AUTH_POL_LDAP_USER_NAME_PASSWORD -priority 110 -gotoPriorityExpression NEXT

# Create Login Schema Policy and Profile for Second Citrix ADC AAA Authentication vServer - Username Only
add authentication loginSchema LSCHEMA_USER_NAME_ONLY -authenticationSchema "/nsconfig/loginschema/CTXDEMOS_USER_NAME_ONLY.xml"
add authentication loginSchemaPolicy LSCHEMA_POL_NOPASSWORD -rule TRUE -action LSCHEMA_USER_NAME_ONLY

# Create Citrix ADC AAA Session Policy and Profile
add tm sessionAction AAA_SESSION_PRF_CTXDEMOS -SSO ON -ssoDomain CTXDEMOS -persistentCookie ON -persistentCookieValidity 30
add tm sessionPolicy AAA_SESSION_POL_CTXDEMOS TRUE AAA_SESSION_PRF_CTXDEMOS

# Create Second Citrix ADC AAA Authentication vServer
add authentication vserver AAAVS_CTXDEMOS_COM SSL 22.22.44.51 443
set ssl vserver AAAVS_CTXDEMOS_COM -ssl3 DISABLED -tls1 DISABLED -tls11 DISABLED -tls13 ENABLED -ocspStapling ENABLED -HSTS ENABLED -maxage 157680000 -IncludeSubdomains YES
bind ssl vserver AAAVS_CTXDEMOS_COM -certkeyName CTXDEMOS_PUBLIC_CERT
bind ssl vserver AAAVS_CTXDEMOS_COM -cipherName CTXDEMOS_FRONTEND_APLUS
bind authentication vserver AAAVS_CTXDEMOS_COM -portaltheme CTXDEMOS_PORTAL
bind authentication vserver AAAVS_CTXDEMOS_COM -policy AAA_SESSION_POL_CTXDEMOS -priority 100 -gotoPriorityExpression NEXT
bind authentication vserver AAAVS_CTXDEMOS_COM -policy LSCHEMA_POL_NOPASSWORD -priority 110 -gotoPriorityExpression END
bind authentication vserver AAAVS_CTXDEMOS_COM -policy AUTH_POL_LDAP_GROUP_EXTRACTION_AZURAMFACA -priority 140 -nextFactor AUTH_POLLBL_LDAP_USER_NAME_PASSWORD -gotoPriorityExpression NEXT

# Create Second Citrix ADC AAA Authentication Profile
add authentication authnProfile AAA_AUTH_PRF -authnVsName AAAVS_CTXDEMOS_COM -AuthenticationHost aaa.ctxdemos.com -AuthenticationDomain ctxdemos.com

Configure Citrix ADC as AD FS WAP

Run the following commands in Citrix ADC CLI to configure Citrix ADC as AD FS Web Application Proxy (WAP):

# Pattern Set - ADFS Proxy Hostname
add policy patset PATSET_ADFS_HOSTNAME
bind policy patset PATSET_ADFS_HOSTNAME sts.ctxdemos.com -index 1 -charset ASCII
# Policy Expression - ADFS Proxy Hostname
add policy expression is_ADFS_HOSTNAME "HTTP.REQ.HEADER(\"Host\").TO_LOWER.CONTAINS_ANY(\"PATSET_ADFS_HOSTNAME\")"

# Pattern Set - ADFS Proxy Path for NoAuth
add policy patset PATSET_ADFS_PATH_NOAUTH
bind policy patset PATSET_ADFS_PATH_NOAUTH "/adfs/services/trust" -index 1 -charset ASCII
bind policy patset PATSET_ADFS_PATH_NOAUTH "/federationmetadata/2007-06/federationmetadata.xml" -index 2 -charset ASCII
bind policy patset PATSET_ADFS_PATH_NOAUTH "/adfs/fs/federationserverservice.asmx" -index 3 -charset ASCII
bind policy patset PATSET_ADFS_PATH_NOAUTH "/adfs/ls/FormsSignIn.aspx" -index 4 -charset ASCII
bind policy patset PATSET_ADFS_PATH_NOAUTH "/adfs/services/trust/2005/usernamemixed" -index 5 -charset ASCII
bind policy patset PATSET_ADFS_PATH_NOAUTH "/adfs/services/trust/mex" -index 6 -charset ASCII

# Policy Expression - ADFS Proxy Path for NoAuth
add policy expression is_ADFS_PROXY_NOAUTH "HTTP.REQ.URL.PATH.TO_LOWER.CONTAINS_ANY(\"PATSET_ADFS_PATH_NOAUTH\")"

# Pattern Set - ADFS Proxy Path for Passive Client
add policy patset PATSET_ADFS_PATH_ACTIVE_PASSIVE
bind policy patset PATSET_ADFS_PATH_ACTIVE_PASSIVE "/adfs" -index 1 -charset ASCII
bind policy patset PATSET_ADFS_PATH_ACTIVE_PASSIVE "/cgi/selfauth" -index 2 -charset ASCII

# Policy Expression - ADFS Proxy Path for Passive Client
add policy expression is_ADFS_PROXY_ACTIVE_PASSIVE "(HTTP.REQ.HEADER(\"Host\").TO_LOWER.CONTAINS_ANY(\"PATSET_ADFS_HOSTNAME\") && HTTP.REQ.URL.PATH.TO_LOWER.STARTSWITH_ANY(\"PATSET_ADFS_PATH_ACTIVE_PASSIVE\"))"

# Rewrite Policies for ADFS PIP
add rewrite action RWACT_X_MS_Proxy insert_http_header X-MS-Proxy "\"NETSCALER\""
add rewrite policy RWPOL_X_MS_Proxy true RWACT_X_MS_Proxy

add rewrite action RWACT_X_MS_Forwarded_Client_IP insert_http_header X-MS-Forwarded-Client-IP CLIENT.IP.SRC
add rewrite policy RWPOL_X_MS_Forwarded_Client_IP true RWACT_X_MS_Forwarded_Client_IP

add rewrite action RWACT_X_MS_Endpoint_Absolute_Path insert_http_header X-MS-Endpoint-Absolute-Path HTTP.REQ.URL
add rewrite policy RWPOL_X_MS_Endpoint_Absolute_Path true RWACT_X_MS_Endpoint_Absolute_Path

add rewrite action RWACT_X_MS_Target_Role insert_http_header X-MS-Target-Role "\"PrimaryComputer\""
add rewrite policy RWPOL_X_MS_Target_Role true RWACT_X_MS_Target_Role

add rewrite action RWACT_X_MS_ADFS_Proxy_Client_IP insert_http_header X-MS-ADFS-Proxy-Client-IP CLIENT.IP.SRC
add rewrite policy RWPOL_X_MS_ADFS_Proxy_Client_IP true RWACT_X_MS_ADFS_Proxy_Client_IP

add rewrite action RWACT_X_MS_Client_User_Agent insert_http_header X-MS-Client-User-Agent "HTTP.REQ.HEADER(\"User-Agent\")"
add rewrite policy RWPOL_X_MS_Client_User_Agent true RWACT_X_MS_Client_User_Agent

add rewrite action RWACT_ADFS_PROXYMEX replace HTTP.REQ.URL.PATH_AND_QUERY "\"/adfs/services/trust/proxymex\" + HTTP.REQ.URL.SET_TEXT_MODE(IGNORECASE).PATH_AND_QUERY.STRIP_START_CHARS(\"/adfs/services/trust/mex\").HTTP_URL_SAFE"
add rewrite policy RWPOL_ADFS_PROXYMEX "is_ADFS_HOSTNAME && HTTP.REQ.URL.TO_LOWER.STARTSWITH(\"/adfs/services/trust/mex\")" RWACT_ADFS_PROXYMEX

add rewrite policy RWPOL_ADFS_PROXY_HEADERS-NOACT TRUE NOREWRITE

add rewrite policylabel RWPOLLBL_ADFS_PROXY_HEADERS http_req
bind rewrite policylabel RWPOLLBL_ADFS_PROXY_HEADERS RWPOL_X_MS_Proxy 100 NEXT
bind rewrite policylabel RWPOLLBL_ADFS_PROXY_HEADERS RWPOL_X_MS_Forwarded_Client_IP 110 NEXT
bind rewrite policylabel RWPOLLBL_ADFS_PROXY_HEADERS RWPOL_X_MS_Endpoint_Absolute_Path 120 NEXT
bind rewrite policylabel RWPOLLBL_ADFS_PROXY_HEADERS RWPOL_X_MS_Target_Role 130 NEXT
bind rewrite policylabel RWPOLLBL_ADFS_PROXY_HEADERS RWPOL_X_MS_ADFS_Proxy_Client_IP 140 NEXT
bind rewrite policylabel RWPOLLBL_ADFS_PROXY_HEADERS RWPOL_X_MS_Client_User_Agent 150 NEXT
bind rewrite policylabel RWPOLLBL_ADFS_PROXY_HEADERS RWPOL_ADFS_PROXYMEX 160 NEXT

# Create ADFS Server and Service Group
add server LBSRV_ADFS wsadfs01.ctxdemos.com
add serviceGroup LBSVCGRP_ADFS_443 SSL -maxClient 0 -maxReq 0 -cip ENABLED X-MS-Forwarded-Client-IP -usip NO -useproxyport YES -sp ON -cltTimeout 180 -svrTimeout 360 -CKA NO -TCPB NO -CMP YES
bind ssl vserver LBSVCGRP_ADFS_443 -certkeyName CTXDEMOS-PUBLIC
bind ssl serviceGroup LBSVCGRP_ADFS_443 -cipherName CTXDEMO-BACKEND
set ssl serviceGroup LBSVCGRP_ADFS_443 -ssl3 DISABLED -tls1 DISABLED -tls11 DISABLED
bind serviceGroup LBSVCGRP_ADFS_443 LBSRV_ADFS 443

# Create ADFS Proxy NoAuth Load Balancing vServer
add lb vserver LBVS_ADFS_PROXY_NOAUTH SSL 0.0.0.0 0 -persistenceType NONE -cltTimeout 180
set ssl vserver LBVS_ADFS_PROXY_NOAUTH -ssl3 DISABLED -tls1 DISABLED -tls11 DISABLED -tls13 ENABLED -ocspStapling ENABLED -HSTS ENABLED -maxage 157680000 -IncludeSubdomains YES
bind ssl vserver LBVS_ADFS_PROXY_NOAUTH -certkeyName CTXDEMOS-PUBLIC
bind ssl vserver LBVS_ADFS_PROXY_NOAUTH -cipherName CTXDEMO-BACKEND
bind lb vserver LBVS_ADFS_PROXY_NOAUTH LBSVCGRP_ADFS_443
bind lb vserver LBVS_ADFS_PROXY_NOAUTH -policyName RWPOL_ADFS_PROXY_HEADERS-NOACT -priority 100 -gotoPriorityExpression NEXT -type REQUEST -invoke policylabel RWPOLLBL_ADFS_PROXY_HEADERS

# Create ADFS Proxy NoAuth Content Switching Policy and Action
add cs action CSACT_ADFS_PROXY_NOAUTH -targetLBVserver LBVS_ADFS_PROXY_NOAUTH
add cs policy CSPOL_ADFS_PROXY_NOAUTH -rule is_ADFS_PROXY_NOAUTH -action CSACT_ADFS_PROXY_NOAUTH

# Create ADFS Proxy Active-Passive Load Balancing vServer
add lb vserver LBVS_ADFS_PROXY_ACTIVE_PASSIVE SSL 0.0.0.0 0 -persistenceType NONE -cltTimeout 180 -Authentication ON -authnProfile AAA_AUTH_PRF
set ssl vserver LBVS_ADFS_PROXY_ACTIVE_PASSIVE -ssl3 DISABLED -tls1 DISABLED -tls11 DISABLED -tls13 ENABLED -ocspStapling ENABLED -HSTS ENABLED -maxage 157680000 -IncludeSubdomains YES
bind lb vserver LBVS_ADFS_PROXY_ACTIVE_PASSIVE LBSVCGRP_ADFS_443
bind ssl vserver LBVS_ADFS_PROXY_ACTIVE_PASSIVE -certkeyName CTXDEMOS-PUBLIC
bind ssl vserver LBVS_ADFS_PROXY_ACTIVE_PASSIVE -cipherName CTXDEMO-FRONTEND
bind lb vserver LBVS_ADFS_PROXY_ACTIVE_PASSIVE -policyName RWPOL_ADFS_PROXY_HEADERS-NOACT -priority 100 -gotoPriorityExpression NEXT -type REQUEST -invoke policylabel RWPOLLBL_ADFS_PROXY_HEADERS

# Create ADFS Proxy Active-Passive Content Switching Policy and Action
add cs action CSACT_ADFS_PROXY_ACTIVE_PASSIVE -targetLBVserver LBVS_ADFS_PROXY_ACTIVE_PASSIVE
add cs policy CSPOL_ADFS_PROXY_ACTIVE_PASSIVE -rule is_ADFS_PROXY_ACTIVE_PASSIVE -action CSACT_ADFS_PROXY_ACTIVE_PASSIVE

# Bind Content Switching Policies to Citrix Gateway Content Switching vServer
bind cs vserver CSVS_UGCTXDEMOS -policyName CSPOL_ADFS_PROXY_NOAUTH -priority 100
bind cs vserver CSVS_UGCTXDEMOS -policyName CSPOL_ADFS_PROXY_ACTIVE_PASSIVE -priority 300

# Create Citrix ADC AAA Traffic Policies and Bind them to ADFS Proxy Active-Passive Load Balancing vServer
add tm formSSOAction AAATM_SSOPRF_ADFS_LOGIN -actionURL "/adfs/ls" -userField UserName -passwdField Password -ssoSuccessRule true -nameValuePair AuthMethod=FormsAuthentication -responsesize 15000 -submitMethod POST
add tm trafficAction AAATM_PRF_ADFS_LOGIN -appTimeout 1 -SSO ON -formSSOAction AAATM_SSOPRF_ADFS_LOGIN -persistentCookie OFF -InitiateLogout OFF -kcdAccount NONE -userExpression "HTTP.REQ.USER.ATTRIBUTE(3)" -passwdExpression "HTTP.REQ.USER.ATTRIBUTE(2)"
add tm trafficPolicy AAATM_POL_ADFS_LOGIN "HTTP.REQ.URL.TO_LOWER.STARTSWITH(\"/adfs/ls\")" AAATM_PRF_ADFS_LOGIN
add tm trafficAction AAATM_PRF_ADFS_LOGOUT -appTimeout 1 -persistentCookie OFF -InitiateLogout ON -kcdAccount NONE
add tm trafficPolicy AAATM_POL_ADFS_LOGOUT "HTTP.REQ.URL.TO_LOWER.STARTSWITH(\"/adfs/ls\") && HTTP.REQ.URL.QUERY.VALUE(\"wa\").EQ(\"wsignout1.0\")" AAATM_PRF_ADFS_LOGOUT
bind lb vserver LBVS_ADFS_PROXY_ACTIVE_PASSIVE -policyName AAATM_POL_ADFS_LOGIN -priority 100 -gotoPriorityExpression END -type REQUEST
bind lb vserver LBVS_ADFS_PROXY_ACTIVE_PASSIVE -policyName AAATM_POL_ADFS_LOGOUT -priority 110 -gotoPriorityExpression END -type REQUEST

Configure an initial authentication flow

# Create Initialization Load Balancing vServer
add lb vserver LBVS_SAML_SP_INITIALIZATION SSL 0.0.0.0 0 -persistenceType NONE -cltTimeout 180 -Authentication ON -authnProfile AAA_AUTH_PRF
set ssl vserver LBVS_SAML_SP_INITIALIZATION -ssl3 DISABLED -tls1 DISABLED -tls11 DISABLED -tls13 ENABLED -ocspStapling ENABLED -HSTS ENABLED -maxage 157680000 -IncludeSubdomains YES
bind lb vserver LBVS_SAML_SP_INITIALIZATION LBSVC-ALWAYS-UP
bind ssl vserver LBVS_SAML_SP_INITIALIZATION -certkeyName CTXDEMOS_PUBLIC_CERT
bind ssl vserver LBVS_SAML_SP_INITIALIZATION -cipherName CTXDEMOS_FRONTEND_APLUS

# Create Initialization Content Switching Policy and Action
add cs action CSACT_SAML_SP_INITIALIZATION -targetLBVserver LBVS_SAML_SP_INITIALIZATION
add cs policy CSPOL_SAML_SP_INITIALIZATION -rule "is_UGDEMO_HOSTNAME && HTTP.REQ.URL.PATH.TO_LOWER.STARTSWITH(\"/samltolb\")" -action CSACT_SAML_SP_INITIALIZATION

# Bind Content Switching Policies to Citrix Gateway Content Switching vServer
bind cs vserver CSVS_UGCTXDEMOS -policyName CSPOL_SAML_SP_INITIALIZATION -priority 500

# Create Initialization Citrix ADC AAA Traffic Policy and Action and Bind it to Load Balancing vServer
add tm samlSSOProfile AAATM_SAMLSSOPRF_VPN_TO_LB -samlSigningCertName CTXDEMOS_PUBLIC_CERT -assertionConsumerServiceURL "https://access.ctxdemos.com/cgi/samlauth" -relaystateRule "HTTP.REQ.URL.QUERY.VALUE(\"RelayState\")" -signatureAlg RSA-SHA256 -digestMethod SHA256 -Attribute1 Password -Attribute1Expr AAA.USER.PASSWD -Attribute2 Groups -Attribute2Expr AAA.USER.GROUPS -encryptAssertion ON -samlSPCertName CTXDEMOS_PUBLIC_CERT
add tm trafficAction AAATM_PRF_VPN_TO_LB -SSO ON -persistentCookie OFF -InitiateLogout OFF -kcdAccount NONE -samlSSOProfile AAATM_SAMLSSOPRF_VPN_TO_LB
add tm trafficPolicy AAATM_POL_VPN_TO_LB "HTTP.REQ.URL.STARTSWITH(\"/samltolb\")" AAATM_PRF_VPN_TO_LB
bind lb vserver LBVS_SAML_SP_INITIALIZATION -policyName AAATM_POL_VPN_TO_LB -priority 100 -gotoPriorityExpression END -type REQUEST

Cipher groups

# Create Cipher Group for Backend vServers
add ssl cipher CTXDEMOS_BACKEND
bind ssl cipher CTXDEMOS_BACKEND -cipherName TLS1.3-AES256-GCM-SHA384 -cipherPriority 1
bind ssl cipher CTXDEMOS_BACKEND -cipherName TLS1.3-CHACHA20-POLY1305-SHA256 -cipherPriority 2
bind ssl cipher CTXDEMOS_BACKEND -cipherName TLS1.3-AES128-GCM-SHA256 -cipherPriority 3
bind ssl cipher CTXDEMOS_BACKEND -cipherName TLS1.2-ECDHE-RSA-AES256-GCM-SHA384 -cipherPriority 4
bind ssl cipher CTXDEMOS_BACKEND -cipherName TLS1.2-ECDHE-RSA-AES128-GCM-SHA256 -cipherPriority 5
bind ssl cipher CTXDEMOS_BACKEND -cipherName TLS1.2-ECDHE-ECDSA-AES256-GCM-SHA384 -cipherPriority 6
bind ssl cipher CTXDEMOS_BACKEND -cipherName TLS1.2-ECDHE-ECDSA-AES128-GCM-SHA256 -cipherPriority 7

# Create Cipher Group for Frondend vServers
add ssl cipher CTXDEMOS_FRONTEND
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1.3-AES256-GCM-SHA384 -cipherPriority 1
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1.3-CHACHA20-POLY1305-SHA256 -cipherPriority 2
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1.3-AES128-GCM-SHA256 -cipherPriority 3
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1.2-ECDHE-ECDSA-AES128-GCM-SHA256 -cipherPriority 4
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1.2-ECDHE-ECDSA-AES256-GCM-SHA384 -cipherPriority 5
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1.2-ECDHE-ECDSA-AES128-SHA256 -cipherPriority 6
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1.2-ECDHE-ECDSA-AES256-SHA384 -cipherPriority 7
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1-ECDHE-ECDSA-AES128-SHA -cipherPriority 8
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1-ECDHE-ECDSA-AES256-SHA -cipherPriority 9
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1.2-ECDHE-RSA-AES128-GCM-SHA256 -cipherPriority 10
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1.2-ECDHE-RSA-AES256-GCM-SHA384 -cipherPriority 11
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1.2-ECDHE-RSA-AES-128-SHA256 -cipherPriority 12
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1.2-ECDHE-RSA-AES-256-SHA384 -cipherPriority 13
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1-ECDHE-RSA-AES128-SHA -cipherPriority 15
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1-ECDHE-RSA-AES256-SHA -cipherPriority 16
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1.2-DHE-RSA-AES128-GCM-SHA256 -cipherPriority 17
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1.2-DHE-RSA-AES256-GCM-SHA384 -cipherPriority 18
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1-DHE-RSA-AES-128-CBC-SHA -cipherPriority 19
bind ssl cipher CTXDEMOS_FRONTEND -cipherName TLS1-DHE-RSA-AES-256-CBC-SHA -cipherPriority 20

# Create Cipher Group for Frondend vServers - A+
add ssl cipher CTXDEMOS_FRONTEND_APLUS
bind ssl cipher CTXDEMOS_FRONTEND_APLUS -cipherName TLS1.3-AES256-GCM-SHA384 -cipherPriority 1
bind ssl cipher CTXDEMOS_FRONTEND_APLUS -cipherName TLS1.3-CHACHA20-POLY1305-SHA256 -cipherPriority 2
bind ssl cipher CTXDEMOS_FRONTEND_APLUS -cipherName TLS1.3-AES128-GCM-SHA256 -cipherPriority 3
bind ssl cipher CTXDEMOS_FRONTEND_APLUS -cipherName TLS1.2-ECDHE-ECDSA-AES256-GCM-SHA384 -cipherPriority 4
bind ssl cipher CTXDEMOS_FRONTEND_APLUS -cipherName TLS1.2-ECDHE-ECDSA-AES128-GCM-SHA256 -cipherPriority 5
bind ssl cipher CTXDEMOS_FRONTEND_APLUS -cipherName TLS1.2-ECDHE-ECDSA-CHACHA20-POLY1305 -cipherPriority 6
bind ssl cipher CTXDEMOS_FRONTEND_APLUS -cipherName TLS1.2-ECDHE-ECDSA-AES256-SHA384 -cipherPriority 7
bind ssl cipher CTXDEMOS_FRONTEND_APLUS -cipherName TLS1.2-ECDHE-ECDSA-AES128-SHA256 -cipherPriority 8
bind ssl cipher CTXDEMOS_FRONTEND_APLUS -cipherName TLS1.2-ECDHE-RSA-AES256-GCM-SHA384 -cipherPriority 9
bind ssl cipher CTXDEMOS_FRONTEND_APLUS -cipherName TLS1.2-ECDHE-RSA-AES128-GCM-SHA256 -cipherPriority 13
bind ssl cipher CTXDEMOS_FRONTEND_APLUS -cipherName TLS1.2-ECDHE-RSA-CHACHA20-POLY1305 -cipherPriority 14
bind ssl cipher CTXDEMOS_FRONTEND_APLUS -cipherName TLS1.2-ECDHE-RSA-AES-256-SHA384 -cipherPriority 15
bind ssl cipher CTXDEMOS_FRONTEND_APLUS -cipherName TLS1.2-ECDHE-RSA-AES-128-SHA256 -cipherPriority 16

Login schema XML file

CTXDEMOS_USER_NAME_PASS.XML

<?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>User name</Text>
                    <Type>plain</Type>
                </Label>
                <Input>
                    <AssistiveText>Please supply username</AssistiveText>
                    <Text>
                        <Secret>false</Secret>
                        <ReadOnly>false</ReadOnly>
                        <InitialValue>${AAA.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>
                    <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>

CTXDEMOS_USER_NAME_ONLY.XML

<?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>User name</Text>
                    <Type>plain</Type>
                </Label>
                <Input>
                    <AssistiveText>Please supply username</AssistiveText>
                    <Text>
                        <Secret>false</Secret>
                        <ReadOnly>false</ReadOnly>
                        <InitialValue/>
                        <Constraint>.+</Constraint>
                    </Text>
                </Input>
            </Requirement>
            <Requirement>
                <Credential>
                    <Type>none</Type>
                </Credential>
                <Label>
                    <Text> Please submit credentials to continue Login ...</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>

References

Authentication to NetScaler using AD FS 4.0 on Server 2016, Citrix FAS, and Azure MFA in Azure Cloud. (2018). Retrieved from https://www.jgspiers.com/authentication-to-netscaler-using-ad-fs-4-0-server-2016-citrix-fas-azure-mfa-azure-cloud/

Configure Azure MFA as authentication provider with AD FS. (2019). Retrieved from https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/operations/configure-ad-fs-and-azure-mfa

Deploying a Federation Server Farm. (2017). Retrieved from https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/deployment/deploying-a-federation-server-farm

Federated Authentication Service ADFS deployment. (2018). Retrieved from https://docs.citrix.com/en-us/citrix-virtual-apps-desktops/secure/federated-authentication-service/fas-architectures/fas-adfs.html

Guide to deploying NetScaler as an Active Directory Federation Services Proxy. (n.d.). Retrieved from https://www.citrix.com/content/dam/citrix/en_us/documents/products-solutions/guide-to-deploying-netscaler-as-an-active-directory-federation-services-proxy.pdf

How it works: Azure Multi-Factor Authentication. (2018). Retrieved from https://docs.microsoft.com/en-us/azure/active-directory/authentication/concept-mfa-howitworks

Planning a cloud-based Azure Multi-Factor Authentication deployment. (2019). Retrieved from https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-getstarted

Tijl Van den Broeck. (Dec 7, 2017). ADFS v3 on Windows Server 2012 R2 with NetScaler. Retrieved from https://www.citrix.com/blogs/2015/05/29/adfs-v3-on-windows-server-2012-r2-with-netscaler/

Transition to hybrid cloud and SaaS with Citrix Gateway. (n.d.). Retrieved from https://www.citrix.com/products/citrix-gateway/resources/netscaler-unified-gateway.html

User sign-in with Azure Active Directory Pass-through Authentication. (2018). Retrieved from https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-pta

Written by Saman Salehian, Lead Networking Sales Engineer.