Category: NetScaler

Using NetScaler as OpenID Connect SP with ADFS as IDP

How do you configure Citrix NetScaler OpenID Connect Service Provider with Microsoft ADFS as OpenID Connect Identity Provider? I’ve tried making it easy to understand and how you do it using CLI (NetScaler CLI and powershell).

Read this post for doing this with SAML.



Using NetScaler as SAML SP with ADFS as IDP

How do you configure Citrix NetScaler SAML Service Provider with Microsoft ADFS as SAML Identity Provider? I’ve tried making it easy to understand and how you do it using CLI (NetScaler CLI and powershell).

Before we begin, let us look at what we need to establish the federation:

  • NetScaler (with at least Enterprise license)
  • Active Directory domain and ADFS (read this post if you want to load balance and use NetScaler as ADFS Proxy)
  • Website (lb vserver) we want to protect with AAA (will be referred to as the service provider)
  • AAA vserver to bind SAML Service Provider policy

In my case, the following FQDNs are used:

  • LB vserver: webapp-test.domain.com / LB-WEBAPP-TEST
  • AAA vserver: sp.domain.com / AAA-SP-DOMAIN.COM (note: it will actually not be access by the web browser)
  • ADFS: adfs.domain.com

When installing ADFS two self signed certificates are issued for Token-signing and Token-decryption. When it comes to the NetScaler, we could always use whatever certificate for the signing and decryption – but I recommend using a certificate that isn’t used for web site communication. That’s why I create a self signed certificate that I use: (note: I do this on my computer, modify the variables to match your environment – and even though this certificate and key is self signed – keep them secure)

The certificate (not the key) needs to be copied to the ADFS server for when we create the Relying Party Trust, and we also need to copy the ADFS Token-signing certificate to the NetScaler (below called adfs.domain.com-signing).

Copy the newly created certificate and key to the NetScaler, as well as the ADFS Token-signing certificate:

Now we need to create the SAML Service Provider action and profile, as well as bind it to the AAA vserver:

(Note: As I stated before, this policy is bound to the AAA vserver but the expression is matching the hostname of the LB vserver – since the web browser actually never is redirected to the AAA vserver in this scenario)

As a last step, create (if it isn’t already) an authentication profile and bind it to the LB vserver:

Now configure ADFS (modify the variables to match your need):

 



NetScaler HA heartbeats in Azure

When using NetScaler with multiple NICs in Azure, heartbeats will not be seen on other interfaces other than the one NSIP is configured on.

To resolve this, disable heartbeats on the other interfaces (in my case, NSIP is on 0/1 and disabling on 1/1 and 1/2):

 



Updated: NetScaler Active/Passive HA in Azure with multiple NICs/IPs (DSR/Floating IP)

I wrote a blog post for NetScaler active/passive HA in Azure with multiple NICs two days ago, and I’ve been trying to figure out if this was the best way to do it. In the other post, I was using IPPattern in NetScaler to set the vServers to a /31 – which does work but that’s just because of how the underlying Azure infrastrucuture works (where machines outside of the VM – for example Azure LB – can only access the IP that has been assigned to the VM).

There is another way of doing this, which doesn’t require you to use a /31. The key is in configuring DSR (Direct Server Return) in Azure LB (also known as Floating IP). This will make it possible to use the same VIP on the NetScalers as the Frontend IP of the Azure LB – which saves IP-addresses and is easier to configure. This is the way Citrix has documented it and this is how their HA template does it.



NetScaler Active/Passive HA in Azure with multiple NICs/IPs

Update:

I’ve found out that there’s a much easier way of doing the below in Azure – take a look at the updated blog post:

Updated: NetScaler Active/Passive HA in Azure with multiple NICs/IPs (DSR/Floating IP)

——

There are a lot of information out there about setting up NetScaler HA in Azure. One way is using a single NIC and a single IP for all traffic – which allows for active/passive but causes other limitations. Another way is to use multiple NICs/IPs and use active/active. Both cases uses Azure LB to provide high availability.



Citrix changing default ICA Protocol from TCP to UDP Q4 2017

For XenApp/XenDesktop versions released in Q4 2017 or later (version 7.16 or newer), the default protocol for ICA traffic will be changed from ICA TCP to Enlightened Data Transport (EDT). EDT is a recently-developed protocol from Citrix and is UDP based, unlike traditional ICA which is is TCP based. One of the reasons Citrix developed EDT is because TCP protocols have some drawbacks related to Congestion Control, leading to sub par performance in certain scenarios.

Citrix realizes however that UDP traffic is not always allowed, or configured, in Citrix environments, so they added a new feature called ‘Adaptive Transport’ which will try EDT protocol (UDP) first, and if that does not work it will fallback to using regular ICA over TCP.



RfWebUI idle timeout

There seems to be an issue with the idle timeout in RfWebUI (verified in NetScaler version 12.0) and I’ve created a workaround until it is solved.

It is all based on a JavaScript that checks if the user is logged on, if logged on it starts a timer and when the timer is reached logs the user out.

Change the parameter at the top ”var timeout = xyz” where xyz is the time out in seconds. Because I wasn’t able to only insert this script when the user is logged in (always had to refresh) I chose to create a check that checks every five seconds for the cookie NSC_AAAC which is created upon logon and removed during logout. In this case, we reset the timer if the mouse is moved, a page is loaded or a key is pressed. This can be changed based on your requirements (for example removing document.onclick = resetTimer; if you don’t want a click to reset the idle timer).

When using it in Netscaler, add it like this:

If you are using the NetScaler Web UI to create the rewrite, the action expression will look like this:

 



Remove ”Password 2” from RfWebUI

Update:

Seems like the first method actually removes a password field when changing password. This shouldn’t do that:


Original post:

Have you had an issue with RfWebUI where you need to remove the ”Password 2”-field when for example using RADIUS as primary authentication source (challenge based) and LDAP as secondary?

As always, the great Sam Jacobs has the answer on Citrix Discussions.

If you don’t want to edit any files yourself or not create a a new theme you can use a rewrite to do this for you: (I’m editing style.css and not theme.css)

It should now look as expected:



Publishing XenMobile Self-Help Portal via NetScaler AAA

In our deployments of XenMobile we always recommend that our customers use the Two Factor option for enrollment, requiring username, password as well as a PIN created in the administration GUI of the appliance, for the added security. In larger organizations this can put some toll on the administrators which is why there is a self-help portal for the users. This portal allows users to create their own PIN and also comes with the added benefit of allowing them to wipe or lock lost and stolen devices themselves, cutting down on the time between theft and action taken.

However, this comes with a drawback. There is no built-in way in XenMobile to enforce any kind of second factor for the login to this portal, which effectively renders the MFA for enroll useless. To prevent this, we can put NetScaler AAA ahead of the login to enforce a second factor for logon to the portal.

I’ll assume that you already have AAA set up, with an authentication profile we can use. In my examples, ours is called AAA-AUPL-EXT_OTP

Starting with some standard boilerplate:

Add the traffic actions, policies as well as the form-fill action:

/zdm/cxf/login is the actual path to where the logon method from /zdm/login_xdm_uc.jsp is posted to. You can view the logon script at https://mdm.example.com/zdm/scripts/logon.js and see this for yourself.

Depending on how your AAA is set up, we might also need an authorization policy. Here I do it via a policy label:

A few rewrites:

These are necessary since we need the correct referrer to be allowed to login. We also need to tell the client to move from enroll.example.com/zdm/login_xdm_uc.jsp to enroll.example.com/zdm/ once we have performed the login.

Create a service group for your nodes:

Finally, create a vServer and bind the policies:

Please note that this still leaves logon through mdm.example.com unprotected, since you still can browse directly there, so you should take care not to expose these pages to the outside. One way, if using SSL offload, is to block it with a responder policy:

Do note that this needs to be bound to your LB for MDM, not the vServer we set up above.



Prepopulate username with NetScalers RfWebUI

We’ve been seeing an issue with AAA in front of ADFS where credentials entered at the service provider (Office 365 for example) doesn’t populate the username in the NetScaler login, which works with ADFS. This isn’t the biggest issue, but something that makes it annoying to use AAA instead of pure ADFS. We were able to do this just fine with the cookie NSC_NAME (or even query based) before when not using RfWebUI. Because RfWebUI is the latest and greatest as well as responsive, most want to use it.

I’ve been looking into how to solve this using RfWebUI and may not have found the best solution in the world, but it works reliably and is easy to implement. A big thanks to Sam Jacobs who helped me out with the javascript parts, I haven’t been working with it before so was crucial to tying the knot on the issue.

The first thing I had to figure out was how to extract the username that Office 365 sends to ADFS. We can see the username in the query to ADFS as follows:

Note: It is URL Encoded which means the @ will be presented as %40.

The thing is that when using AAA, a new redirect will be made directly inside NetScaler to the AAA vserver for authentication. I was thinking of either trying to add ”Set-Cookie: UserNameCookie=<email>” somewhere here but I was thinking that this may not work since rewrites doesn’t always work on internal redirects and I may have to add another redirect to an already long chain of redirects – which may cause issues for some browser. What I did find was a cookie named NSC_TASS that contains a long string of random letters, numbers and symbols. After trying some things I was able do decode it by first converting it from URL Encoded format and then from Base64. When doing this, I was able to see the original ADFS URL containing the query with the username. To do this, I had to run the following to get the email/username in the correct format for the NetScaler login:

In other words we do the following: Grab the value of NSC_TASS and decode the URL Encoding. After that, decode it using Base64. Then typecast it to a HTTP URL and grab the value of the query username, and decode the URL Encoding (converting %40 to @ in my case).

Now to the part where I had to get some help to actually insert the username into the form. The solutions works fine, but if you have a better way of doing it please share! We had to put a small loop and wait to make sure the input field is created before the username can be inserted. The result looks like this:

We’re waiting for the window to load, but for some reason that doesn’t mean that the input field ”login” exists (yet) and that’s where the setInterval-loop comes in. Without the loop, I did see it work most of the times on computers but rarely on phones. To make sure that this only happens when being redirected, we’ll be verifying that the cookie NSC_TASS exists and that the referrer length is greater or equal 1. After that we verifies that the element ”login” is created and inserts the username / email and changes focus to the password input.

Now it’s just a matter of using a rewirte to insert this:

If you are using the GUI, the rewrite part looks like this:

I hope this can help some people out there making their end users happier! If you find a way of doing this easier, please share!