in AppExpert, Security

Passwordreset portal with NetScaler as frontend


Users that forget their password usually adds unwanted queues to helpdesk. Wouldn’t it be nice, if the user’s themselves could reset their own password?

This article gives you a good solution to do exactly that with the power of NetScaler (Citrix ADC) n-Factor flexible authentication framework, internal variables and a mix of Content switching, Loadbalacing servers, Authentication(AAA) servers, and a fair amount of AppExpert (policies) 🙂



NetScaler Enterprise edition with a fairly new version, it was build with 12.1 48.xx, as long as there is support for nFactor and variables.

Windows2016 with support for .NET running C#

Server certificates.


Readers note:

All domains and ip’s have been replaced with dummy’s (or removed), it’s expected to have a certain level of NetScaler knowledge to implement this.

Lets start with how it looks from the user perspective:

Initial page (

User clicks on “Password reset link”

User enters username (which was the same as email in my case)

A message saying an email has been sent to the user:

User goes to their inbox, and clicks the link in the email.

After clicking the link, two password fields are displayed, when the input in both boxes are identical and password requirements are met, the “change password” button is enabled.

After clicking “Change password” the user should close down all browsers(to ensure new session cookies) and try and login with the new password.

Easy peasy, at least for the user.

Behind the scene:

(The following only describes the password reset functionality, which mean the “regular” login flow is not shown in this article)

Readers note: I will try and explain a little bit at the time, write some config, and refer back to that section. Also, if you have not quite understood how nFactor works, there are some articles around that would be ideal to read first.


There are 2 ContentSwitch Virtual Servers configured.

  1. Entry_portal, This in the intial entry point and where the “Password reset link” has been added.
  2. Passwordreset_portal, nFactor configuration, validation of the user, checking of token



Let’s take a closer look on the entry portal, what’s interesting here is the customization, the rest is just here for understanding.


A look inside that file(Entry_with_PW_reset_link.xml) shows the following custom code snippet:

And from here, there is nothing that helps besides knowledge. “passwordreset_link” refers to a piece of javascript code, that’s stored in:


The following has been added:

To give the link a bit of a markup, i’ve added a class “pwresetlink” so i can identify the link in a CSS file, which is located here:


The following has been added:

Passwordrest portal

Since its a password reset solution, there is a lot more config here, and the flow of reading is pretty similar to the entry portal, i will start from the entry point on netscaler (ContentSwitch) and break it down from there and explain the more exotic parts of the configuration.

This is the entrypoint.

Backend service:

Just a regular HTTP service, this should of course be changed to HTTPS when going into production.

Traffic steering policies:

The initial request is with URL “/entry” (since that is what the link from the entry_portal has configured) and not “/” as it is in normal cases. Let’s have a look at what happens on “/entry”

So if you have the right URL, and come from our entry_portal, the request is forwarded to LBVS_pwreset_noauth

And here there is a few responder policies.

Arh, variables(hello old friend,, the ability to store information about the transaction / user / flow on NetScaler.

Taking further look on NSAssign_add_ip_2:

The variable is a map (basically an array), which contain a list of entries. In my example i set the Key of the map to the source ip of the client connecting, and the value to “ok” (there might be a cleaner way of archiving what i am trying to, the documentation is a little bit thin, and examples sparesome on this topic)

If it would be visualized it would look something like: ok ok ok

After adding the source ip to the variable, another policy is hit

So the user is redirected to “/”, which re-actives the content switch policies. The next that’s active is:

If the client source ip is nowhere to be found in the variable map, then do action CSACT_pwreset_deny, which does:

Which is a text message returned to the user, that they are breaking the intended flow. This could be send it an external syslog server, and used for security purposes, because who would try and break the regular user flow? Maybe a h4x0r!!

Next CS pol hit:

Having a closer look at LBVS_pwreset, you will see there is a Authentication VS bound to that LB,  let’s follow the breadcrumbs:

The authentication policy on the AAAVS refers to an Authentication PolicyLabel(meaning nFactor)

The Label:

The policy on the Label:

Hoooold it Morten, you are only doing a NO_AUTHN action? Where is the authentication in that?

So true, this piece of the puzzle was not finalized, so basically i just accept whatever input that comes, and use it onwards in the traffic flow. Although before going to production i would add a verification of the user in Active Directory (make an LDAP ACTION with “no authentication” checked and “User Required” checked), to make sure it exists. Also, the input here is the value i use for the email address later, so a non-valid email address, would not achieve anything (in terms of resetting the password=


The important part in CheckBox_enter_user.xml is:

Now the request has been authenticated at the AAA VS level, and the remaining policies on the LBVS will be actived. The first one being:

Another variable map:

If the variable does not contain a value for “AAA.USER.NAME” (the input string that was entered earlier), NetScaler will add a entry in the map with the following data:

“(\”User:\” + AAA.USER.NAME + \”Timestamp:\” + SYS.TIME + \”Random:\” + SYS.RANDOM.MUL(65000)).ENCRYPT(\”ENCKEY_token_AES\”,BASE64URL)”

And the data is encrypted with the key called “ENCKEY_token_AES” and output from the encrypt() function is set to be BASE64URL(we need this, and not BASE64, since we will refer to this token in the email sent to the user)

Configuration for the encryption key is:

A visualization of the variable map would be: DrS6ak1Rr1VuWtqOVLDfQzTpLC568k_44EW9ejz0K_-SpbqtxMSiB70IpDawMaT1_itvT8LK3RG4TUxEP134YEKptKD2dkJLyd9fMuw3OHea- <another encrypted string3> <another encrypted string>

After adding the token to the user, a policy label is invoked.

Another token is added(last one, i promise!):

Okay okay okay, really slow here to make sure everybody is onboard.


That means the key of the variable is the value of the variable NSVAR_nstoken_map[AAA.USER.NAME] and the value is just “added” So for this is AAA.USER.NAME) the value is: DrS6ak1Rr1VuWtqOVLDfQzTpLC568k_44EW9ejz0K_-SpbqtxMSiB70IpDawMaT1_itvT8LK3RG4TUxEP134YEKptKD2dkJLyd9fMuw3OHea-

A visualization:

DrS6ak1Rr1VuWtqOVLDfQzTpLC568k_44EW9ejz0K_-SpbqtxMSiB70IpDawMaT1_itvT8LK3RG4TUxEP134YEKptKD2dkJLyd9fMuw3OHea- Added
<another encrypted string3> Added

Now a unique token has been created for that user, which we can verify later when the user is clicking on the link.

Next policy being hit for URL “/” is: (Notice that we changing from Responder to Rewrite)

Here there is a HTTPCallout that is being activated, a closer look on that:

A GET request will be sent to “LBVS_pwreset_httpcallout” (there is a separate LBVS entity for the Callout functionality, just to make sure that no policies are applied) looking like

If the app “sendmail.aspx” returns a string that contains “successfully” it’s considered to be successful execution of the app

So if conditions are met, RSACT_success is invoked.

The user’s request for URL “/” is behind the scene rewritten to “/sucess.aspx”

Now a message is displayed for the user saying “an email has been sent, check your inbox”

The link which is sent to user looks like:

When clicked the following CSPOL is activated:

PS_set_pass_urls is a pattern set containing the urls (/setpass.aspx, /jquery.js, /password.js, /password_style.css)

The request is redirected to LBVS_pwreset_noauth, and a responder policy is activated.

If the value of the token in the URL string, is not found in the NSVAR_nstoken_map, it gets denied, that means security is now held by the encryption of the token, and the match on NetScaler.


The server has 2 important apps to support the solution,

I’ll just paste the code, and add some comments on the interesting parts after eachfile.


A black page, that actives the c# code



Nothing special here, just fabricate a link with the token received from NetScaler sent to the mail/username that was entered earlier.



Present 2 password fields that the user can start typing in, when user starts typing, javascript kicks in, and displays information about password complexity.



The password for the service account, could properly be protected better, maybe on an external service somewhere which has some controls/reporting/usage tracking.

For the production setup i did, i ended having that information stored on NetScaler in an encrypted string i could send with the request.

An important note here, is that NetScaler is encrypting the token with BASE64URL as output, and the input expected is regular BASE64, thats why “-” is replaced with “+” and “_” with “/”



I am no javascript expert, but i made it work 🙂



I am for sure not a graphical expert, but its no too bad is it?



Phew, you made it so far! I think the solution is a good display of the cool features that has been added into NetScaler over the years, going from a Load Balancer, to a security device that lets you open up your infrastructure a little bit without compromising security. User’s does not have to call servicedesk for simple routine tasks, and security won’t have a nervous breakdown. I am sure the same functionality could be achieved with a different (and maybe more smooth) configuration, maybe only 1 CSVS, or the use of WEBAUTH authentication policies, better use of NO_AUTH policies matching on URLS – i’ll let that be up for the real experts out there to tidy up my example.

If there was one thing i could wish for Christmas, it would be to possibility to dump the current dataset of an variable, you really have no idea whats inside a variable at a given time.

Set all sails for the next n-Factor / variable endeavor, i believe that the possibilities on how to mix and match security flows are close to endless, i would love to hear about how you are using n-Factor / Variables

Q & A:

Q: But how can i click the link in the email that i don’t have access to?

A: You can’t, the solution was build for a “shadow” domain, which means that users were locked out of an system that has the same usernames as their regular enterprise domain(being their email).


Q: Would it be possible to alter the config to reset the password without sending an email which the user cannot enter?

A: Yes, although it raises a flag on how to identify and verify the user.


Q: What if username is not the same as the email?

A: That could be handled with searching the user object in AD for the email (if’ its there), or doing an HTTPCallout to retrieve the information from a 3rd party.


Q: What if i only want to do a unlock function?

A: That’s possible too!


Q: What is the “Enable enhanced logging” checkbox?

A: 2 PoC’s melted together, and the checkbox is not used in this solution.


Q: I dont have AAA.USER.NAME on my NetScaler

A: The expression is fairly new, and replaces HTTP.REQ.USER.NAME


Q: Is there an easy way of seeing what’s in a variable map?

A: No, not really, you have to create an Audit message function and enable “User Configurable Log Messages” in your syslog settings. And bind that to a policy(responder or rewrite). It would be a nice enhancement to have a tool that would dump the contents of variables in the CLI.


Q: I have a question that’s not listed here?

A: Reach out to me on social media somewhere 🙂


What do you think?


  1. Hi in ns the loginchema folder is moved add authentication loginSchema ALS_entry -authenticationSchema “/nsconfig/loginschema/LoginSchema/Entry_with_PW_reset_link.xml”

    Am i correct in assuming that you create the Entry_with_PW_reset_link.xml yourself and that the content in the xml is nothing more than:


    • Seth, Your correct that i create the loginschema myself, and the content of the file is similar to any other loginschema file, but has a referal to the javascript code in the xml.

      The location might have changed – pick one that works 😉