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: 10.1.20.8 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: 10.1.20.6
- 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: 10.1.1.103
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: 10.1.20.101
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
when CLIENT_ACCEPTED { set citrix_logout 0 } when ACCESS_ACL_ALLOWED { 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!
- Joanthan_Frits1Nimbostratus
Where in the Citrix configuration does it point to the "Internal Call Back Virtual Server"?
- Steve_LyonsRet. Employee
You can find this under the manage citrix gateway information. In my example, I used Callback URL: https://proxyauth.itc.demo. Search for this in the article and you will see the screenshot of exactly where it is. Let me know if you are still having issues identifying it.
- Mattias_Jansso1Nimbostratus
Is it correct that the Callback-virtual server shouldn't have any default pool assigned?
- Steve_LyonsRet. Employee
That is correct. There will be no default pool assigned as the response will be sent back to storefront which is acting as the client in this request.
- Mattias_Jansso1Nimbostratus
Ok, im not 100% sure how that can work! But i believe you! :)
Another question: In the callback-virtual server:
The ssl client profile in your setup is requering certificate as it is using the same ssl profile as the storefront vs.
Is that ok too?
- Steve_LyonsRet. Employee
Haha, yeah believe me it took a lot of digging through Citrix documentation. Based on that, for non-password authentication the Storefront sever simply needs to resolve the same gateway (F5 BIG-IP) that the user authenticated against. If your internal storefront servers have connectivity to the external facing gateway VS on the BIG-IP, then I believe you should be able to use that. However, I believe in my testing of that scenario I had issues with client-less requests from the Storefront server because you cannot enable clientliess mode with On Demand Cert Auth.
In my scenario my customer does not allow that communication to occur so we simply created a new VS accessible internally and a basic access policy I don't believe it is a Citrix requirement to use the same certificate/key pair that you use for the client-ssl profile used on the F5 VS publishing the citrix gateway URL but rather ensuring that the callback server url has a valid certificate.
If you are supporting smart card auth on the BIG-IP and you use a separate callback virtual server, I did find it necessary to have a connectivity and VDI profile.
- Mattias_Jansso1Nimbostratus
Thank you. Impressive work and very kind of you to publish it!
Hopefully we get it to work here soon! :)
- Steve_LyonsRet. Employee
What my article does not include is the troubleshooting, network captures and more required to get this working. If you don't get this up and running right away and need to do packet captures with encrypted traffic, remember the two methods to do so. I personally find it easier to modify the SSL profile cipher string to support RSA only and use the private key in Wireshark but you can also use the RSA session secret using this solution article. https://support.f5.com/csp/article/K12783074
One other thing to note, under certain configuration circumstances Storefront will use its loopback IP to perform communication internally which I was not capturing because of my capture string was defining the BIG-P self IP and the routable Storefront IP.
In addition to this, if you are confused about the STA service, it was natively installed with the controller and required no configuration from me but I did have to define it in my access policy as a session variable.
If you are unsure who your F5 account team is, let me know and we can try to determine that so they can assist. If they are unable to do so, I still have my dev environment with this deployment functional so I may be able to provide more granular details if needed. Good luck and let me know how it goes.
- Mattias_Jansso1Nimbostratus
Hi again.
It doesn't work and from the client I see these requests after a successful smartcard logon:
Client request to storefront-vs
POST /Citrix/VDIWeb/Authentication/GetAuthMethods HTTP/1.1
Server response from storefront-vs
HTTP/1.1 200 OK
eXtensible Markup Language
<?xml
<authMethods
xmlns="http://citrix.com/delivery-services/webAPI/2-6/authMethods">
<method
name="Certificate"
url="SmartcardAuth/Login"/>
<method
name="CitrixAGBasic"
url="GatewayAuth/Login"/>
<method
name="CitrixAuth"
url="CitrixAuth/Login"/>
</authMethods>
Client request to storefront-vs
POST /Citrix/VDIWeb/GatewayAuth/Login HTTP/1.1\r\n
This request never gets a response
The client retries 5 times and then gives up.
Is /Citrix/VDIWeb/GatewayAuth/Login the correct authmethod?
- Mattias_Jansso1Nimbostratus
Sorry, I just sent this comment before reading your last edit