Tag: ADFS

Netscaler: ADFS protected by AAA – How to handle SAML POST requests

A limitation with Netscaler AAA is that it cannot handle FormData sent in a POST request to a Netscaler LB vServer that is protected by a AAA vServer. What happens is that the Form data in the POST will not be included when the user is redirected back to the LB vServer after AAA authentication. This becomes relevant in scenarios where you have a SAML ServiceProvider (SP) that is configured to do a login POST to an SAML IdentityProvider (IDP) and that IDP is protected by Netscaler AAA.

Below is the process flow:
1. User browses to the SAML SP address https://app1.somedomain.com/saml/login, which in this scenario is the URL that initiates the SAML logon process
2. The SP gives the user a SAML request and the user’s browser performs a POST against the IDP URL https://adfs.mycompany.com/adfs/ls/ with this SAML Request as the Form data.
3. The address https://adfs.mycompany.com points to a Netscaler LB vServer which is protected by AAA, so when Netscaler sees the incoming GET request above it will redirect the user to https://aaa.mycompany.com for AAA authentication (we assume the user has not authenticated against this AAA vServer this web session).
4. User performs AAA authentication, and is afterwards redirected back to the original URL https://adfs.mycompany.com/adfs/ls. HOWEVER, the SAML Request Form data is now missing.
5. User will land on https://adfs.mycompany.com/adfs/ls and receive an error message, because the ADFS server doesn’t know how to handle a request that doesn’t have any SAML form data.

 

Important notes:

  • Form Data passed along with a POST to a LB vServer, such as ADFS, that is protected by AAA will be ‘dropped’ when the user is redirected back to the LB vServer after successful AAA authentication. This only applies if the user has not authenticated against the AAA in the current web session (ie the user does not have a NSC_TMAS cookie). We will make use of this later on.
  • Query values included in a POST are not ‘dropped’, so this flaw is limited to Form data only.

 

Solution/work-around:
The easiest solution is to simply ask the SAML SP to use Redirect instead of POST for the SAML authentication process, but if that is not an option (the SAML SP’s backend code or configuration doesn’t support SAML Redirect) then below is a work-around I’ve been using. Basically what you do is that you store the original SP URL, https://app1.somedomain.com/saml/login, in a cookie in the user’s browser and in step 5 the user will be redirected back to this URL again.

Below is the process flow with a work-around implemented for POST:
1. User browses to https://app1.somedomain.com/saml/login, which in this scenario is the url that initiates the SAML logon process
2. The SP gives the user a SAML request and the user’s browser performs a POST against the IDP URL https://adfs.mycompany.com/adfs/ls/ with this SAML Request as the Form data.
3. The address adfs.mycompany.com points to a Netscaler LB vServer which is protected by AAA, so when Netscaler sees the incoming GET request above it will redirect the user to https://aaa.mycompany.com for AAA authentication.
3b. NEW: When the user is redirected to https://aaa.mycompany.com now, a Rewrite policy will trigger that will create a cookie ”ADFSPostCookieURL” for the user, and this cookie will contain the value ”https://app1.somedomain.com/saml/login”.
4. User performs AAA authentication, and is afterwards redirected back to the original URL https://adfs.mycompany.com/adfs/ls.
5. NEW: We have a Responder policy on our ADFS LB vServer that checks if the path is ”/adfs/ls” and if the cookie ”ADFSPostCookieURL” exists, and if both are true then we read the value in cookie ”ADFSPostCookieURL” and Redirects the user to that URL.
6. User is redirected back to https://app1.somedomain.com/saml/login, which will restart the SAML logon process
7. The SP gives the user a new SAML request and the user’s browser again performs a POST against the IDP URL https://adfs.mycompany.com/adfs/ls/ with this SAML Request as the Form data.
8. A key difference now is that the user already has done AAA authentication this web session and thus has a valid AAA cookie, and won’t be redirected to https://aaa.mycompany.com for authentication. The POST against https://adfs.mycompany.com/adfs/ls/ will therefore happen successfully and the ADFS backend server will see the SAML Form data since that has not been dropped by AAA redirect.
9. Assuming the SAML Request ticket is valid, the ADFS server will give the user a SAML Response ticket and redirect the user to https://app1.somedomain.com/myApp and the user is now logged on to this 3rd party site successfully.

 

Takeaways:

  • Our workaround revolves around storing the original url (https://app1.somedomain.com/saml/login) in some way so we can access it later, and requesting a SAML Request ticket twice from our SAML SP because in the second round we will not be bothered by AAA authentication.
  • Above solution is a bit hacky and involves requesting double SAML tickets from the SP, and there are a lot of Redirects involved, but it works well from an end-user perspective and it enables us to support SAML Post in conjunction with AAA.

 

If you have any questions regarding above solution, or ideas on how to handle above scenario in a better way, please contact me at rasmus.kindberg@xenit.se.

 

 

Below is the Netscaler configuration:



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):

 



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!



Manually configuring Unified Gateway

I’m writing this post in English to make it easier for our non-Swedish readers.

I’m going to try and explain how to configure Unified Gateway, without the wizard! I’ll try to let the commands speak for themselves, but feel free to comment if you need me to add some additional information about what I’m doing or why. I’ll be configuring Unified Gateway enabling ICA Proxy, RDP Proxy and AAA protected applications – we would also be able to add SSL VPN using a specific group, but we’ll leave that for another time.

I’ve tried to remove parameters that don’t ”matter”, but if there’s something that doesn’t work, it’s most likely because of that – just comment and I’ll update.

My first step of configuring Unified Gateway is also the easiest part, creating a redirect to https (in my own special way) for traffic coming in on http.

Now we’re able to redirect everything hitting HTTP to HTTPS with a 301 (Moved Permanently), while still keeping the Host-header, URL and query. I’ve also added the HSTS header, just to be sure.

 

Next step is configuring some basic AAA settings, and I always try to limit what is allowed by default and then use groups from the AD to allow access to different resources.

The above authentication profile is using ugw.example.com which is my URL to the Unified Gateway, which will be added later.

 

Now, let’s create an AAA portected web application with form fill, and require users to be members of a specific group. In my case, I’ll use ADFS for the form fill application:

You will find some more information about what needs to be configured on ADFS 3.0 to get this working in another blog post I’ve written (in Swedish, but you’ll find the commands).

 

Now let’s create another web application (which is using either 401 / WIA authentication or perhaps ADFS / SAML).

 

Now we need to create the  NetScaler Gateway and some groups.

 

As last step, let’s add all these vServers into one content switch:

 

Now we’ve got one content switch with NetScaler Gateway (ICA Proxy & RDP Proxy) as well as AAA protected applications, and single sign-on between everything. Configured manually!

When it comes to publishing the same URL internally (if you don’t want to use NetScaler Gateway internally as well), you can move the creating of the bookmark from NetScaler Gateway to XenApp/XenDesktop (described here by Jason Samuel, possible with version 7.11) and use StoreFront on the Content Switch instead of NetScaler Gateway.

Good luck and feel free to leave a comment!



ADFS – Test av autentisering

Efter en installation och konfiguration av ADFS vill man säkerställa att autentisering fungerar, ett enkelt sätt att testa detta är att besöka:

https://fqdn.contoso.com/adfs/ls/idpinitiatedsignon

Sitter man internt, får man möjligheten att klicka på Sign In och därefter är man inloggad:
adfs-test-page-sign-out

 
Sitter man externt får man istället möjligheten att ange användarnamn och lösenord:
adfs-test-page-external-sign-in

 



ADFS Single Sign-on med Google Chrome

Många använder Google Chrome istället för Internet Explorer i arbetet. Har man en domänjoinad dator och fungerande Single Sign-on med Internet Explorer finns det ett enkelt sätt att aktivera det för Google Chrome i ADFS, det enda som behöver göras är att lägga till en ytterligare UserAgent i paramtern för Windows Integrated Authentication (WIA) på ADFS.

Enkelt gjort via powershell:

För att det ska fungera är det ett krav att ExtendedProtectionTokenCheck är satt till ”None”:

 



Lastdelning av ADFS med NetScaler

Tänkte bara skriva ner några korta steg för hur jag användare Citrix NetScaler för lastdelning (och ersättare för ADFS Proxy / WAP). Nedan är hur jag gjort i tidigare version (innan 11.1) då SNI inte var supporterat.

Konfiguration på NetScaler:

Värt att tänka på kring detta är att klientcertifikat inte kommer fungera ihop med konfigurationen som den ser ut ovan. Min rekommendation om det behövs skulle vara att köra SSL_BRIDGE, men då behövs även WAP för den externa åtkomsten. Jag har inte tittat på att exemeplvis köra certifikatsbaserad autentisering i NetScaler för att sedan köra KCD mot ADFS, vilket kanske skulle fungera.

För att ovan konfiguration skall fungera behöver några saker göras på ADFS-servrarna.

Steg 1: Inaktivera SNI

Steg 2: Inaktivera Extended Protection Token Check (annars fungerar inte WIA / SSO internt)