Smart Card Authentication to Citrix StoreFront Using F5 Access Policy Manager

Before I get started into discussing the solution in the title, I wanted to preface it with a little background. Prior to June 2020, I had never had any interaction or integration experience with Citrix StoreFront or any Citrix product for that matter. However, a few weeks ago my team was asked to help develop a solution providing smart card authentication and SSO. We approached this like any other web-based application that supported Windows Integrated Authentication. We would just simply provide the smart card auth portion and then use Kerberos Constrained Delegation as the SSO method. While we were right for the most part, there were definitely a few other Citrix requirements we missed.

Most of my experience in the past has been around VMware's Horizon View in which I have had an outstanding time working and collaborating with their engineering teams to provide and implement different solutions. With that, actually getting hands-on experience with StoreFront and the other Citrix services will help my team better understand and support these solutions in the future. Thanks to a few very bright engineers on the F5 side who have implemented this solution before, my team was finally able to get this working. This article is solely around smart card auth and SSO to StoreFront to display a set of applications a user is authorized to view. My goal is to follow this article with one on integrating FAS into the solution but we shall see. So with that, let's get started.

Configuring Storefront to Support Gateway Passthrough

  • Launch the Citrix StoreFront Management Console
  • Rightclick Stores and select Manage Citrix Gateways
  • Click Edit in order to modify an existing store or Add and use the following settings

General Settings

  • Display name: APM
  • Citrix Gateway URL: https://withsf.itc.demo/

The Citrix gateway URL is the external URL users will use to access the F5 BIG-IP virtual server.

  • Usage or role: Authentication and HDX routing

I am unsure of what HDX routing is for but by selecting this option, it provided the Secure Ticket Authority option in which I would match to my APM policy.

  • Select Security Ticket Authority and click Add
  • Type the host of the DDC hosting the STA service

  • Select Authentication Settings
  • Logon type: Domain
  • Callback URL: https://proxyauth.itc.demo

  • Click OK

Manage Beacons

  • Define a beacon address that is only accessible by internal users.
  • For External beacons, define 2 addresses that are only accessible to external users

Manage Authentication Methods

  • Select Pass-through from Citrix Gateway

  • Click the drop-down to the right and select Configure Delegated Authentication
  • Check the box to Fully delegate credential validation to Citrix Gateway

  • Click the drop-down to the right and select Configure Password Validation
  • From the drop-down select Validate Passwords via Delivery Controllers and select a delivery controller.

Manage Receiver for Web Sites

  • Select configure and Authentication Methods
  • Select Pass-through from Citrix Gateway

  • Select Advanced Settings and modify the Enable loopback communication to OnUsingHttp

Note: Modifying this setting from On to OnUsingHttp did not affect the outcome but based on Citrix documentation when terminating SSL at a proxy, this setting should be used. We will be performing Bridged mode SSL so still delivering encrypted content to StoreFront but changed this setting anyway as I was still not clear. This did change the way I had to troubleshoot though. When using Wireshark, I had to enable the loopback network adapter to capture this traffic.

Configure Remote Access Settings

  • Check the box to Enable Remote Access and allow users to access only resources delivered through StoreFront (No VPNN tunnel)
  • Select APM from the given options

Enabling Kerberos Constrained Delegation in AD and the F5 BIG-IP

I think it is important to note that Citrix StoreFront allowed authentication without KCD or any SSO profile assigned but for reference, please follow my article on DevCentral on how this is configured.

Otherwise, you can skip this step as we will be passing session variables obtained from APM to StoreFront for authorization purposes.

Creating an Active Directory AAA Object

  • Navigate to Access ›› Authentication and click Create
  • Name: ad-aaa
  • Domain Name: ITC.DEMO
  • Server Connection: You can use a pool or select direct to use a single AD source
  • IP: and click Add
  • Admin Name: define a user that has the ability to bind to AD
  • Admin Password: password
  • Click Finished

Creating a Smart Card Authentication Access Policy

  • Navigate to Access ›› Profiles / Policies : Access Profiles (Per-Session Policies) and click Create

General Properties

  • Name: SC
  • Profile Type: All
  • Customization Type: Modern
  • Configure your desired Language settings and click Finished

When returned to the previous page displaying all access profiles, select Edit from the newly created policy

  • Between Start and Deny, select the + and then the Authentication tab
  • From the authentication list, select On-Demand Cert Auth and click Add Item

  • From the Auth Mode menu, select require from the drop-down and Save
  • Following the Successful branch, click the + and then the Assignment tab
  • From the assignment list, select Variable Assign and Add Item

  • Select Add new entry
  • In the 1st assignment field, select change
  • In the Custom Variable field type session.logon.last.upn
  • In the Custom Expression box add the following expression
set x509e_fields [split [mcget {session.ssl.cert.x509extension}] "\n"];
# For each element in the list:
foreach field $x509e_fields {
# If the element contains UPN:
if { $field contains "othername:UPN" } {
## set start of UPN variable
set start [expr {[string first "othername:UPN<" $field] +14}]
# UPN format is <user@domain>
# Return the UPN, by finding the index of opening and closing brackets, then use string range to get everything between.
return [string range $field $start [expr { [string first ">" $field $start] - 1 } ] ]; } }
# Otherwise return UPN Not Found:
return "UPN-NOT-FOUND";
  • Click Finished
  • Select Add new entry and change
  • In the Custom Variable field type session.logon.last.domain
  • In the Custom Expression field type expr {"ITC.DEMO"}
  • Click Finished

Note: If you decide to use KCD, this will need to be the fully qualified domain name and not the NetBIOS name. If not using KCD, expr {"ITC"} can be used.

  • Select Add new entry and change
  • In the Custom Variable field type session.citrix.sta_servers
  • In the Custom Expression field, type expr{http://xenapp1.itc.demo/scripts/ctxsta.dll"}
  • Click Finished

Note: The sta server should be the same server defined in Citrix StoreFront earlier in this article

  • You should now see three variable assignments, click Save

  • Following the fallback branch, select the + and select the Authentication tab

  • From the authentication list, select AD Query and Add Item

  • From the Server drop-down, select the AD AAA object created earlier in this article
  • SearchFilter: userPrincipalName=%{session.logon.last.upn}

  • Select the Branch Rules tab and click change
  • Remove the AD User's Primary Group ID is and click Add Expression
  • Context: AD Query
  • Condition AD Query Passed
  • Active Directory Query has Passed
  • Click Add Expression and Finished
  • Change the branch name to AD Query Passed and click Save

  • Following the AD Query Passed branch, select the + and click the Assignment tab
  • From the assignment list, select Variable Assign and Add Item

  • Click Add new entry
  • In the Custom Variable field type session.logon.last.username
  • In the Custom Expression field, select AAA Atribute from the drop down
  • Agent Type: AD
  • Attribute Type: Use user's attribute
  • AD attribute name: sAMAccountName
  • Click Finished and Save

  • Following the fallback branch, select the Deny ending and change to Allow

Once complete select Apply Access Policy and your VPE should look like the screenshot below

Creating an Access Policy for the Citrix Call Back Function

  • Navigate to Access ›› Profiles / Policies : Access Profiles (Per-Session Policies) and click Create
  • Name: citrix-callback
  • Profile Type: All
  • Select the supported languages and click Finish.
  • When returned to the list of access policies, select the Edit option as you did in the previous steps
  • Change the fallback action to Allow and Apply the Access Policy

Configuring a Storefront Pool

  • Navigate to Local Traffic ›› Pools : Pool List
  • Health Monitors: https
  • Load Balancing Method: Least Connections (member)
  • Address:
  • Service Port 443
  • Click Add and Finished

Configuring an HTTP Profile

  • Navigate to Local Traffic ›› Profiles : Services : HTTP and click Create
  • Name: smart-card-http
  • Parent Profile: http
  • Request Header Erase: Accept-Encoding
  • Request Header Insert: X-Citrix-Via:withsf.itc.demo

Note: X-Citrix-Via is the header name and withsf.itc.demo is the value. The value must match the external fqdn.

  • Redirect Rewrite: All
  • Insert X-Forwarded-For: Enabled
  • Click Finished

Create a Client SSL Profile to Support Smart Card Logon

  • Navigate to Local Traffic ›› Profiles : SSL : Client and click Create
  • Name:smartcard
  • Parent Profile: clientssl
  • Certificate Key Chain: Select the External Cert and Key that will be used for this website

  • Trusted Certificate Authorities: Select the CA certificate or bundle that was used to issue the client certificates
  • Advertised Certificate Authorities: Select the CA certificate or bundle that was used to issue the client certificates

  • Click Finished

Creating a Virtual Server for Smart Card Authentication

  • Navigate to Local Traffic ›› Virtual Servers : Virtual Server List and click Create
  • Name: smart-card-WSF
  • Type: Standard
  • Destination Address/Mask:

Note: This will be the IP address available to external users attempting to access Citrix resources

  • Service Port: 443
  • Protocol Profile: f5-tcp-wan
  • HTTP Profile (Client): smart-card-http
  • SSL Profile (Client): smartcard
  • SSL Profile (Server): serverssl

  • Source Address Translation: Auto Map

  • Access Profile: SC
  • Click the + next to Connectivity Profile to create a new profile.
  • Profile Name: WithStoreFront_Connectivity
  • Parent Profile: Connectivity
  • Click Ok

  • VDI Profile: vdi

  • Default Pool: storefront
  • Default Persistence Profile: cookie
  • Fallback Persistence Profile: source_addr

  • Click Finished

Create an Internal Call Back Virtual Server

  • Navigate to Local Traffic ›› Virtual Servers : Virtual Server List and click Create
  • Name: internal_callback
  • Destination Address/Mask:

Note: This is an internally accessible only IP address that will be accessed by StoreFront

  • Service Port: 443

  • Protocol Profile (Client): f5-tcp-lan
  • HTTP Profile (Client): http

  • SSL Profile (Client): smartcard

Note: You do not need to use the same client SSL profile but the certificates must match. In this example, I am using the same SSL profile.

  • SSL Profile (Server): serverssl

  • Access Profile: citrix-callback
  • Connectivity Profile: WithStoreFront_connect
  • VDI Profile: vdi

  • Click Finished

Configure Log Out iRule for StoreFront

  • Navigate to Local Traffic ›› iRules : iRule List and click Create
  • Name: sf-loggedout
  • Deffinition: Use the tcl content below and modify the storeWebName to reflect your environment
  set citrix_logout 0
  set type [ACCESS::session data get session.client.type]
  if { !($type starts_with "citrix") } {
    set storeWebName "/Citrix/UDF_storeWeb/"
    set http_uri [HTTP::uri]
    if { $http_uri == "/" || ($citrix_logout eq 0 && $http_uri ends_with "login.aspx") } {
     # log local0. "For [HTTP::uri] Redirecting to $storeWebName"
      ACCESS::respond 302 Location "https://[HTTP::host]$storeWebName"
    } elseif { $http_uri contains "Logoff" } {
      set citrix_logout 1
    } elseif { $citrix_logout eq 1 && $http_uri ends_with "login.aspx" } {
      set citrix_logout 0
      ACCESS::respond 200 content "Logged out\r\n" Connection close
      ACCESS::session remove
  • Click Finished

Assign Log Out iRule to External Virtual Server

  • Navigate to Local Traffic ›› Virtual Servers : Virtual Server List and select the external virtual server created in the previous steps (Not the callback)
  • Select the resources tab Manage next to iRules and move sf-loggedout from Available to Enabled

  • Cick Finished

Validate Access to StoreFront Access

  • From your external client, browse to your external URL where you should be prompted for a certificate

  • After clicking OK, if you are using Chrome or Firefox, you will be prompted to Detect Receiver, click Detect Receiver

  • Click Open Citrix Receiver Launcher
  • If you are not automatically redirected, select Already Installed
  • If all configuration steps were followed, you should then be presented with your apps and desktops

Now that you have hopefully authenticated to StoreFront, I wanted to say I am by no means a Citrix expert. If there are settings that should be changed per best practice, please shoot me a note and I would be more than happy to discuss. After the struggles I had deploying this over the past few weeks, I really hope this helps someone out there. Until next time!

Published Jul 13, 2020
Version 1.0

Was this article helpful?