Posted in : NetScaler By Simon Gottschlag

2 years ago

I’ve previously written about how to use OpenID Connect in NetScaler and a way to use callouts to validate tokens. You can also use the function JWT_VERIFY_CERTKEY() but that requires that you (for now) keep the issuing certificate updated locally.
Another way is to setup an OpenID Connect client (OAuth Action) on Citrix ADC and enable 401 authentication in the load balancing vserver. Below is an example where the NetScaler will validate that the token sent is valid and issued by the correct provider. (I’ve used Azure AD in my example)
The only thing you have to do is send traffic with tokens (HTTP.REQ.HEADER(”Authorization”).SET_TEXT_MODE(IGNORECASE).CONTAINS(”Bearer ”)) to this LB and a session will be created in NetScaler. In my case, I’m also verifying that the user exists using a second factor to LDAP.

add policy patset PATSET_HOSTHEADER_WEBAPP
bind policy patset PATSET_HOSTHEADER_WEBAPP webapp.domain.com -index 1
add policy expression EXP_ADV_HOSTHEADER_WEBAPP "HTTP.REQ.HEADER(\"Host\").SET_TEXT_MODE(IGNORECASE).CONTAINS_ANY(\"PATSET_HOSTHEADER_WEBAPP\")"
add authentication ldapAction AAA-AS-LDAP_UPN_NOAUTH -serverIP <LDAP IP> -ldapBase "DC=DOMAIN,DC=COM" -ldapBindDn service@DOMAIN.COM -ldapBindDnPassword Secret -ldapLoginName userPrincipalName -groupAttrName memberOf -subAttributeName CN -secType TLS -ssoNameAttribute samAccountName -authentication DISABLED -nestedGroupExtraction ON -maxNestingLevel 8 -groupNameIdentifier samAccountName -groupSearchAttribute memberOf -groupSearchSubAttribute CN -Attribute1 samAccountName -Attribute2 userPrincipalName
add authentication OAuthAction AAA-AS-OAUTH_WEBAPP -authorizationEndpoint "https://login.microsoftonline.com/TenantID/oauth2/v2.0/authorize\?response_type=code&scope=openid%20profile&client_id=ClientID" -tokenEndpoint "https://login.microsoftonline.com/TenantID/oauth2/v2.0/token" -clientID ClientID -clientSecret Secret -GraphEndpoint "https://graph.windows.net/" -CertEndpoint "https://login.microsoftonline.com/TenantID/discovery/v2.0/keys" -userNameField preferred_username -issuer "https://login.microsoftonline.com/TenantID/v2.0"
add authentication Policy AAA-AP-LDAP_UPN_NOAUTH -rule true -action AAA-AS-LDAP_UPN_NOAUTH
add authentication Policy AAA-AP-OAUTH_WEBAPP -rule EXP_ADV_HOSTHEADER_WEBAPP -action AAA-AS-OAUTH_WEBAPP
add authentication policylabel AUPL-ADV_LDAP-NOAUTH -loginSchema LSCHEMA_INT
bind authentication policylabel AUPL-ADV_LDAP-NOAUTH -policyName AAA-AP-LDAP_UPN_NOAUTH -priority 100 -gotoPriorityExpression NEXT
add authentication vserver AAA-VS-OIDC_RP SSL 0.0.0.0
bind authentication vserver AAA-VS-OIDC_RP -policy AAA-AP-OAUTH_WEBAPP -priority 100 -nextFactor AUPL-ADV_LDAP-NOAUTH -gotoPriorityExpression NEXT
bind ssl vserver AAA-VS-OIDC_RP -certkeyName certName
add lb vserver LB-WEBAPP_TOKEN SSL 0.0.0.0 0 -persistenceType COOKIEINSERT -timeout 0 -persistenceBackup SOURCEIP -backupPersistenceTimeout 30 -persistMask 255.255.255.255 -cltTimeout 180 -authn401 ON -authnVsName AAA-VS-OIDC_RP
bind ssl vserver LB-WEBAPP_TOKEN -certkeyName certName

Try it out and all feedback is welcome!

Tags : Azure AD, Citrix ADC, Citrix NetScaler, NetScaler, OIDC, OpenID Connect

Comments

Frank Vandebergh says

Hi Simon,
The inline token validation is requested a lot by our customers. But the 401 OAUTH approach on Netscaler is removing the Authorization header when forwarding to the backend. Only if the next request is sending the AAA cookies, the header is forwarded. Do you have any idea for a workaround ? We are now trying to have the applications use a different header on the API side (e.g. X-Authorization) and then copying the authorization header to the custom one.

Simon Gottschlag says

Hi Frank,
I've seen it where the Authorization header is removed to backend (using form based authentication), but it was solved by adding a traffic action disabling SSO. In that case, before I understood that disabling SSO would solve it - I was able to solve it by adding a rewrite to just add the header in the request to the backend.
Have you tried adding a rewrite to add the Authorization header? Or is it still the same issue after that?
For your information, we should be able to extract the id_token in rewrites in the upcoming release (but I've only tested it with form based authentication):
add rewrite action rwa_add_idtoken insert_http_header Authorization ""Bearer " + AAA.USER.ATTRIBUTE("idtoken")"
add rewrite policy rwp_add_idtoken "HTTP.REQ.HEADER("Authorization").CONTAINS("Bearer").NOT" rwa_add_idtoken
If none of these work, send me an email and I'll take a closer look!

Frank Vandebergh says

Hi Simon,
Thanks for the feedback.
In my testing all rewrites including global would be too late and not able to capture the authorization header as my first idea was to copy it to another header using a global rewrite.
However I found a workaround, by using N-Factor, after OAuth I am using a no_authn factor that is using a login schema to extract the token as the user password expression.
As there is a limit on password length, I am using 16 sequential factors ;) Each factor extracts the user password as a substring of the token, and then sets it in the specified index.
Then on LB level I can use a rewrite to insert the header back as aaa.user.attribute(1) + 2,3,.. etc
Dirty but it does the job.
I've also heard now of the upcoming 12.1 release so that should help a lot, waiting to get my hands on it..
Thanks,
Regards

Add comment

Your comment will be revised by the site if needed.