Category Archives: Server Based Computing

SSO to SharePoint and XenApp with NetScaler, ADFS and Kerberos

Isn’t the holy grail of user experience not the possibility to only logon once and never to enter credentials again? We can do that today, and with the NetScaler 11 release this is even easier than ever.

In this post we’ll be chaining products like ADFS, SharePoint, Citrix XenApp and NetScaler with technologies like SAML and Kerberos. We’ll also be using the new Unified Gateway functionality to do everything with a single external IP. I’m also assuming some basic knowledge of ADFS, IIS and NetScaler Gateway. Indeed, this is not for the faint hearted.

So what is the use case? Well, one of my customers wanted a solution to provide their users with Single Sign On (SSO) access to all of their applications. This solution would be composed of a portal site containing links to all applications (web apps, or Windows apps hosted on XenApp), and an access point consolidating various authentication methods and providing federated access. The customer has internal users, but also has employees and associates working at universities spread all over the country, who would like to login with their university account instead of an AD account of the customer.

The solution should reduce the number of helpdesk calls to reset passwords – especially for users coming from a federated partner, but also calls for getting access to applications.

Design

design

This specfic solution requires an Active Directory account for each user in the resource domain to access XenApp applications. Federated users thus also have an AD account, which we’ll lookup using the email address of the user.

Do note that this reliance on Unified Gateway requires the NetScaler Enterprise Edition. But then again, when you’re using the NetScaler to authenticate your users to web applications you should already have the Enterprise Edition for AAA functionality.

Configuration

So without further ado, I present the solution:

  1. Configure ADFS
  2. Configure NetScaler for ADFS authentication via SAML
  3. Configure NetScaler for Kerberos Contrained Delegation
  4. Configure NetScaler Unified Gateway
  5. Configure StoreFront for Kerberos Contrained Delegation
  6. Configure the XML Broker to accept Kerberos tickets
  7. Configure web resources to accept Kerberos tickets

Configure ADFS

First we’ll add the NetScaler as a relying partner for ADFS. To do this, you can generally follow CTX133919 – How to Configure NetScaler SAML to Work with Microsoft AD FS 2.0 IDP.

Now we’re going to make sure that we get the User Principal Name for each account that’s logging in (for both users in the resource domain as Federated users). We assume that the identity provider for the Federated users delivers his/her email address as a claim.

For these Federated users we’re going to lookup the User Principal Name using the email address of the user. We do this by adding an Issuance Transform rule of the type “Send claims using a custom rule”:

ADFS - Relying partner claim rule - Get UPN

In this example the email address is of the claim type “http://contoso.com/partneremail”. We use the value of this claim to lookup the User Principal Name of the user.

Note that this rule only executes when the claim of this type is given, for users authenticating with their resource AD credentials, this rule is not hit.

Then we’re going to transfer the User Principal Name As the Name ID claim by adding another Issuance Transform rule of the type “Transform an Incoming Claim”:

ADFS - Relying partner claim rule - Transform UPN to Name ID

This rule is hit for all users. As you will see in the NetScaler configuration later on, we will use this Name ID claim.

Configure NetScaler for ADFS authentication via SAML

Before configuring ADFS authentication we must install at least one (but two recommended) certificate.

  1. we need the server certificate of the ADFS server
  2. we need a certificate to sign our SAML traffic (for this we need the private key). Because this certificate is only used in traffic between the NetScaler and ADFS server, this can be a self-signed certificate.

So if you haven’t installed these yet on the NetScaler, do so now.

NetScaler - Configure Authentication SAML ServerIn the NetScaler, head to your Authentication Polices and add a new SAML server.

For the IDP Certificate Name, use the server certificate of the ADFS server.

For the redirect URL use https://<ADFS FQDN>/adfs/ls/formssignin.aspx

For the User Field, enter “Name ID”

For the signing certificate, use the certificate that you prepared for SAML signing

For the issuer name, you can use any arbitrary name, as long as you configure the same identifier name in ADFS. In this example I use the URL of the Unified Gateway.

Reject Unsigned Assertion you may leave on (should pose no problems if you’ve configured the certificates correctly).

For the SAML Binding, choose POST Binding.

 

After you’ve created the Server object, you can create a SAML auth policy. As the expression, you can use “ns_true”, as the action you select the Server object you’ve just created (srv_spadfs in this example).

We’ll use the SAML auth policy later when configuring the NS Gateway instance of the Universal Gateway.

Configure NetScaler for Kerberos Contrained Delegation

To authenticate to web servers, we’ll be using Kerberos. Because we’re only getting the UPN of the user (not the password), we’re going to depend on Kerberos Constrained Delegation. This allows the NetScaler to authenticate on behalf of the user to other servers which accept Kerberos tickets.

There are several ways to configure access to authenticate and request Kerberos tickets on NetScaler (using a keytab file, using certificates or with a user account). Here we’ll be using a user account.

First, create a user account in Active Directory to which we’ll delegate rights to access other services. Best is to create it as a service account (do not expire the password).

NetScaler - KCD AccountThen configure the KCD Account on the NetScaler. Under Security > AAA > KCD Accounts, add a new KCD account:

Give the account a new name (e.g. kcdaccount1). This name is only used on the NetScaler.

For the Realm, enter the Kerberos realm of the resource domain (e.g. CONTOSO.LOCAL).

For the User Realm, enter the Kerberos realm where the users reside. Because in our case all users have a user account in the resource domain, this is the same (e.g. CONTOSO.LOCAL).

For the Delegated User, enter the exact name of the AD service account you’ve previously created, and enter the password as well.

 

 

 

 

After that, we’ll create a Traffic policy which we’ll later attach to the LB vservers after which the web servers are located. Make sure SSO is turned on and you’ve selected the KCD account you’ve previously created (e.g. kcdaccount1).

NetScaler - Traffic Profile

There, all set for KCD on the NetScaler!

Configure NetScaler Unified Gateway

So, one of the cool new features is the Unified Gateway. Technically speaking the Unified Gateway allows us to put the NetScaler Gateway behind a Content Switch. The Content Switch is configured with a public-facing IP and accepts all client connections. The NS Gateway is then configured with a non-adressable ip (0.0.0.0). The CS redirects traffic to the NS Gateway based on a carefully constructed CS policy.NetScaler - Unified GatewayWe can even use the NS Gateway auth server for authentication (even to web applications), so no AAA vServer is necessary, which means we save a public IP!

And if you configure the Content Switch with a wildcard certificate (or a SAN certificate), you can put any host behind the CS (e.g. sharepoint.contoso.com, owa.contoso.com, …) using additional CS policies.

The easiest way to setup a Unified Gateway on NetScaler is to use the built-in wizard.

When creating the Unified Gateway, do note that the Unified Gateway IP you have to enter actually is the IP of the public facing Content Switch.

As for the certificate, best to use a wildcard certificate for your public domain, or a SAN certificate containing all external URLs (though less flexible if you want to add more URLs behind it). If you’re only going to use cVPN, then a standard SSL certificate may suffice – though since I only recommend cVPN for but the simplest use cases – I strongly advise not to go with that path.

Curiously you cannot select SAML for authentication via the Wizard, for now, add something like LDAP auth. That doesn’t have to work – we’ll disable authentication later on the NG vserver.

Portal theme and applications aren’t important (unless you’re going for the cVPN route).

Once you’ve created the Unified Gateway you’ll hopefully find a new CS and a new NG vserver on your NetScaler.

Let’s configure them for our solution:

First, make sure you add the SAML auth policy you’ve previously created to the NetScaler Gateway virtual server. You do this by editing this NS Gateway. Remove any other authentication policies which might have been added with the Wizard.

NetScaler - Gateway Authentication

NetScaler - Gateway settingsSecond,

a) switch authentication off (how weird that might sound)

b) enable Login Once and

c) enable ICA Only (if you’re not going to use SSL VPN or SmartAccess policies) so you don’t consume Universal Licenses.

 

 

 

 

 

 

 

 

 

Add your StoreFront configuration as usual (STA servers & Session Policies).

That should be it for the NS Gateway.

Configure StoreFront for Kerberos Contrained Delegation

StoreFront will be a special case. In order to have SSO to XenApp, we’ll not be doing KCD from the NetScaler to StoreFront. Actually, we’re going to do Protocol Transition to Kerberos on the StoreFront server itself.

For that we’re going to (supposedly) use Smart Card authentication on the gateway. In StoreFront, add (or edit) a gateway and make sure the Logon Type is set to Smart Card. Like always, make sure that your StoreFront server can perform the callback (check that it can resolve the URL). In our environment we’re using the following settings:

StoreFront - NetScaler Gateway

 

Make sure you also enable Smart Card authentication on StoreFront.

StoreFront - Authentication Methods

Also, on the store we are going to enable Kerberos Delegation:

StoreFront - Store Configure Kerberos Delegation

Configure the XML Broker to accept Kerberos tickets

Now of course, this also requires our XML brokers to speak Kerberos. In XenApp 6.5 this is only  possible if you share the XML service with IIS. IIS will then handle the authentication part (and IIS understands Kerberos).

This means that we need at least one XenApp XML broker where the XML service shares it’s port with IIS. If you haven’t chosen this option during the installation of your server, you could follow CTX125107 – How to Configure XML Service to Share Port with IIS on Windows Server 2008 to reconfigure the XML broker to share the service with IIS.

However I strongly recommend against performing the above because I’ve encountered several issues with this (like no applications returned from time to time, config gets broken when installing Rollup Packs, etc), so I advise to install new XenApp servers with the XML broker integrated with IIS, and to use them as dedicated XML brokers.

Make sure that the “CtxAdminPool” and the “CtxScriptsPool” application pools run under the LocalSystem account as per CTX130480, otherwise you also might encounter connection problems. This is necessary because we’ll delegate rights to the StoreFront computer account to perform KCD to the XML broker. By running the app pools under the LocalSystem account, we can add delegation to the HTTP service on the computer account of the XML broker.

Talking about Kerberos delegation, we must configure delegation as follows to allow SSO to XenApp:

On the StoreFront computer account(s) add delegation for:

  • HTTP service of all XML brokers (also check if an HTTP SPN record exists for the service on those computers with SETSPN -L <hostname>)

On the XML Broker computer accounts add delegation for:

  • CIFS & LDAP services of all Domain Controllers
  • HOST service of all XenApp servers in the farm
  • HOST service of itself
  • HTTP service of itself

Active Directory - Delegation XML Broker - 2

On the XenApp computer accounts add delegation for:

  • CIFS & LDAP services of all Domain Controllers
  • HOST service of itself
  • HTTP service of all XML brokers

Note that when using KCD, you must delegate the whole chain. That means for example that if you are using roaming profiles on a remote file server, you must also add delegation to the CIFS service of that file server on the XenApp computer accounts.

Next to all this, your XML Broker must also be configured to trust XML requests. The easiest way to do this is with the XenApp policy “Trust XML Request Sent to this broker”, which you then apply to the XML brokers.

Configure web resources to accept Kerberos tickets

When accessing web resources we will be using KCD on the NetScaler. Very important to note that NetScaler will use the server name (which you define via Load Balancing > Servers) to perform Kerberos SSO. This means that you need to add the server with the exact name of the service (which has an SPN record) you’re accessing.

For example, you’re running a website which is running in an app pool with the LocalSystem account (like the XML brokers), then:

  • you need to add the server with the exact hostname of the server hosting the website
  • on the service account you’re using for KCD, you need to add delegation for either HOST/<hostname> or HTTP/<hostname> on that server

In another example, you’re running multiple websites on one host (each with their own hostname) and one of those websites you want to perform Kerberos SSO for is running under a specific user account. Then:

  • you must ensure that a SPN record exists for that hostname on the user account on which it is running (e.g. if the hostname is www.contoso.com, and it’s running under the CONTOSO\svc_website account, then check if the SPN is registered by running “setspn.exe -L CONTOSO\svc_website” – this will list all SPNs for that account – if not, add the SPN with “setspn.exe -a HTTP/www.contoso.com CONTOSO\svc_website”)
  • add the server on the NetScaler with the hostname of the website. This could pose a problem when you’re adding servers by IP on the NetScaler, because NS only allows one server with that same IP address. A workaround is to add the server by DNS name. (if the NS can’t resolve it then, add an A record on the NS DNS).
  • on the service account you’re using for KCD, you need to add delegation for HTTP/<hostname> on <user account> (e.g. HTTP/www.contoso.com on CONTOSO\svc_website)

Active Directory - Service Account - 2

Then, add the traffic policy you’ve previously created on the LB vserver, that will ensure Kerberos SSO will be performed.

Inspiration / References

Closing notes

I’m aware I didn’t include the configuration for the claims based auth to SharePoint scenario (and how we still get SSO), but this is because it’s rather straightfoward. SharePoint, while load balanced with NetScaler, is just configured for Claims based auth, and uses the ADFS server as IDP. The LB vserver on the NetScaler does not perform any authentication. When a user wants to access SharePoint for the first time, he/she authenticates at the ADFS, after which AFDS sets its own session cookie. So when the same user later wants to access XenApp, and gets redirected to ADFS by the NS, ADFS reads the session cookie and performs SSO.

That concludes it for now. While not really easy, it’s definately very awesome, showing the power of Citrix NetScaler once again. Any questions? Use the comments below 🙂

Troubleshooting “An error occurred while making the requested connection”

A dreadful error for users, but for admins too. Though, usually it’s easily fixed (in most cases there’s a problem with the load or licensing), but not in this particular case I encountered.

Well, one of the first things to do is to check out the event viewer of the Web Interface. I noticed I encountered a whole lot of 30102 errors coming from Citix Web Interface:

Error 30102

What’s this error about?

30102 Error Details

Now there can be a lot of things that can be causing this error. What’s of importance are the XML server which is queried and what function is reported to cause the error. The latter is [com.citrix.xml.NFuseProtocol.RequestLaunchRef].

The first thing I tried is restarting the XML service on the reported server (usually this is the top server you entered as server in the Citrix Farm (Web Interface > Server Farms), unless you use the list to load balance the XML request), but that didn’t help.

I tried various other things, but eventually I fired up WireShark, my tried and trusted networking tool, on the Web Interface server. I captured all traffic, but filtered out traffic coming from and going to the XML server (filter: ip.src == <ipaddress> || ip.dst == <ipaddress>), and looked at packets which were flowing when the 30102 errors occurred in the event viewer. I found the following issue:

POST /scripts/wpnbr.dll HTTP/1.1
Content-Type: text/xml
Host: xxxxxxx:9090
Content-Length: 561
Connection: Keep-Alive <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd"> <NFuseProtocol version="5.4">     <RequestLaunchRef>         <LaunchRefType>ICA</LaunchRefType>         <TicketTag>IMAHostId:15274</TicketTag>         <DeviceId>WI_QZBNv5ztEDpLu0THQ</DeviceId>         <SessionSharingKey>-peML5lFv4meHDULuC8Y14e</SessionSharingKey>         <Credentials>             <UserName>xxxxxxxx</UserName>             <Domain type="NT">xxxxxxxx</Domain>         </Credentials>         <TimetoLive>200</TimetoLive>     </RequestLaunchRef> </NFuseProtocol>
HTTP/1.1 100 Continue
Server: Citrix Web PN Server
Date: Fri, 25 May 2012 09:22:12 GMT
HTTP/1.1 200 OK
Server: Citrix Web PN Server
Date: Fri, 25 May 2012 09:22:12 GMT
Content-type: text/xml
Content-length: 217 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd"> <NFuseProtocol version="5.2">     <ResponseLaunchRef>       <ErrorId>unspecified</ErrorId>     </ResponseLaunchRef> </NFuseProtocol>

Eventually, I found out that every time this happened the same TicketTag (in this case IMAHostId:15274) was given. When the TicketTag was different the response gave a valid ticket:

HTTP/1.1 200 OK
Server: Citrix Web PN Server
Date: Fri, 25 May 2012 08:06:29 GMT
Content-type: text/xml
Content-length: 228
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE NFuseProtocol SYSTEM "NFuse.dtd"> <NFuseProtocol version="5.2">     <ResponseTicket>       <Ticket>11CE036B24379D427366DA81E873C0</Ticket>     </ResponseTicket> </NFuseProtocol>

So it must have something to do with this particular TicketTag. Now, this IMAHostId responds to a specific server. When you go look on a XenApp server at HKLM\SOFTWARE\Wow6432Node\Citrix\IMA\RUNTIME\HostId you find the specific IMAHostId of the server (in decimal).

So putting all this together, it seemd that getting the LaunchReference from a specific server was failing. When I found the server by the IMAHostId (I just made a quick & dirty script to echo the HostId’s of all the servers in the farm), I restarted its IMA service, et voila, LaunchRequests to the server worked again!

(Eventually I found out it was not one, but two servers which were showing this behaviour, so I had to restart both IMA services. Anyway, I’m glad that this issue was solved!)

Happy troubleshooting! 🙂

UPDATE: On a recent project I’ve encountered this issue again, though this time it wasn’t the IMA service which was in trouble, but the XML broker didn’t trust XML requests sent to it. Enabling “Trust XML requests” Citrix computer policy on the XML brokers was the fix for this.

Changing the server certificate on Citrix AppController

Not so long ago I set up the new Citrix AppController (part of the new Citrix Cloud Gateway Enterprise) in a test environment to get to know the product a little better. Setting up the server wasn’t too much of an hassle, albeit not much documentation is available. I successfully added some web applications, and SSO worked.

What did annoy me however that I still got the red address bar in my browser, indicating that the website is insecure. By default, the AppController uses a self-signed certificate – which is, ofcourse, untrusted. So there are two ways to solve this; the simplest one is just to trust the self-signed cert by importing it. The other is to create an official certificate to be used. The problem is that the documentation on edocs.citrix.com is flawed, and will not work. So I had to figure it out myself. That’s what this post is about.

I’m not going to elaborate on how certificates work, I assume you have some working knowledge on the matter. To create the certificate we follow three steps:

Create a certificate request for the FQDN you’ll be using for the AppController

  1. Log on to the console of the AppController (eg with Putty)
  2. Remove the current private key
    sudo keytool -delete
    -alias tomcat -storepass changeit -keystore /root/.keystore
  3. Create a new key
    sudo /usr/java/jdk1.6.0_21/bin/keytool -keysize 2048 -genkey -alias tomcat -keyalg RSA -storepass changeit -keystore /root/.keystore
    You’ll be asked to fill in the details for the cert request. Important: When asked for “What is your first and last name?” enter the FQDN of the AppController, not your real first and last name!

Request a certificate from your Certificate Authority

  1. Create a certificate request
    sudo /usr/java/jdk1.6.0_21/bin/keytool -certreq -keyalg RSA -alias tomcat -file /home/admin/certreq.csr -storepass changeit -keystore /root/.keystore
  2. Use a SCP client, like WinSCP, to download the certificate request (/home/admin/certreq.csr) from the AppController onto your PC.
  3. Use the certificate request (it’s formatted in Base64 BTW) to request a certificate from your CA (your enterprise CA or a public CA). Download the certificate in PEM/Base64 format.

Installing the certificate

  1. Upload the certificate chain (make sure they’re all in PEM/Base64) to the AppController. Do this again with your SCP client. Upload the certificates to /home/admin/
  2. Import the root and intermediate certificates with
    sudo /usr/java/jdk1.6.0_21/bin/keytool -import -trustcacerts -alias root -file /home/admin/<root certificate> -storepass changeit -keystore /root/.keystore
  3. Finally, import the server certificate:
    sudo /usr/java/jdk1.6.0_21/bin/keytool -import -trustcacerts -alias tomcat -file /home/admin/<certificate> -storepass changeit -keystore /root/.keystore
  4. Reboot

There, now you have that nice white or green address bar 🙂

Editing Farm Policies using the XenDesktop 5 SDK

Editing the XenDesktop Farm policies with PowerShell is not that hard, if you know how. I couldn’t find much, if any, documentation about the subject (only some for XenApp 6), so here’s a quick how to:

First, you start with adding the necessary Citrix PowerShell modules with (you perform this on a XD Controller on another machine with the XenDesktop SDK installed):

Add-PSSnapin Citrix.*

For convenience, we’re going to map the XDFarm policies to a drive, so we can browse it easily:

New-PSDrive XDFarm -root \ -PSProvider CitrixGroupPolicy -Controller <FQDN of a XD Controller>

From there you can browse the XD Farm policies easily:

Set-Location XDFarm:\
PS XDFarm:\> Get-ChildItem
User
Computer

If, for example, you would like to add multiple session printers to the Unfiltered User policy you would perform the following:

Set-ItemProperty XDFarm:\User\Unfiltered\Settings\ICA\printing\SessionPrinters
-name Values
-value @("<pathA>,model=<modelA>,location=<locationA>","<pathB>,model=<modelB>,location=<locationB>")

So, there you have it 🙂

Do note that you’re working with an in-memory version of the CitrixGroupPolicy object. That means that if you change settings in the Citrix Desktop Studio, this won’t be reflected in the current instance. Changes that you make however will be automatically written back to the XenDesktop database.

Client Drive Mapping failing

A collegue of mine had troubles getting Client Drive Mapping (CDM) to work with his new Citrix XenApp 6.5 environment. So I checked the regular stuff;

  • Is CDM policy configured? Correctly applied? (Yep)
  • Are no group policies configured which might be blocking CDM? (Nope)
  • Is CDM blocked on the ICA-tcp protocol? (Nope)
  • Is CDM working over RDP? (Yep)

Well, all seemed to be configured correctly. Since XenApp 6.5 is (at this time of writing) a Technical Preview, I almost filed it as a bug.

For a last attempt I turned to CTX238200 – Troubleshooting Client Drive Mapping. I verified all points meticulously until I got to point 7:

7. Ensure that Client Network is visible under Network Neighborhood. If it is not, follow the steps listed below:
a. Start Registry Editor (Regedt32.exe) and go to the following key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order
The
value for ProviderOrder contained only LanmanWorkstation.
Add CdmService, so
that the Value now reads “CdmService,LanmanWorkstation.”

b. For Presentation Server 4.5, ensure the path defined under the
CommonFilesDir value from
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion is
correct.

c. Restart the server

So I checked HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\Order, and found no CdmService, only LanManWorkstation. Hey, that could be it! So I put CdmService in there, but unfortunately, after a reboot, the drives still weren’t mapped. I turned to another environment I’ve setup at another customer with XenApp 6, where I knew that CDM was working fine. So I checked the Order value there:

Order key

Hmm, PICAClientNetwork looks interesting. And lo and behold, with PICAClientNetwork in the Order key (and rebooting), CDM worked!

So next time, you have troubles with CDM on XenApp 6(.5) and all seems to be configured well, don’t forget this one 😉