I work as a system engineer in our sales department, where part of my work is to attend customer meetings, listening to all kinds of different request in a totally new context. The last question I hear is usually something like “Can NetScaler do this for us?” With NetScaler being the diverse Swiss army knife that it is, I tend to say “yes, I am 95% sure it will work, but I would like to see it my self” and “this is a PoC worthy.”

Recently this conversation happened around Microsoft Lync 2013. Mobile clients are regular clients and to sum up all the requirements it came down to “can the NetScaler implement a soft lockout function to prevent the users being locked out of Active directory?”

Having a Linux background, working with DevOps in a web environment, I had very little idea of the implications behind their request.

The situation

Active directory will lock a user account after 10 failed login attempts in a period of 1 hour. After that, it will require an administrator to go and unlock the account manually. The number of failed logins and the period of time are variables that can be configured in Active Directory group policy setting.

The resolution

Soft lockout means that you want to block the user from trying the maximum number of times before hitting the lockout threshold. In my example, I would block the users from trying to authenticate 8 times in 1 hour.

The importance

Why is this important? When you start to expose your active directory publicly, you should think about all the others that now will have the ability to access the crown jewels. An hacker could write a script that would lockout all users in your AD in a matter of seconds because of the number of failed retries on each user. Yes, he would have to know the username, but pretty much every company use a naming standard, so if you know 1 username, you have a pretty good idea of what the standard is.

The solutions

There are several ways to attack this. The easiest way was to utilize our AAA server, that actually can perform exactly what the customer wants by just filling in values in the right boxes. But this solution wouldn’t work since it had to support the native Microsoft Lync 2013 mobile app.

Another would be to inject a cookie in the communication stream which would keep track of the number of login attempts. I did try this, but again the Microsoft Lync 2013 mobile app didn’t understand “Set-Cookie” properly, so that solution was not feasible.

In NetScaler 10.5 (and 10.1.e) our engineering team has introduced something called variables, which has the ability to store information in request or response and then save it for later usage. This information could for example be the number of users that has requested the “login.php” and completed a successful login, allowing me to know precisely how many users were on my system. If my system weren’t able to handle any more than 1000 users, I could redirect user 1001 to a backup location.

The information could also be how many times a specific user had tried to login, which is exactly what I need to make the soft lockout function in NetScaler. Before I explain the configuration I made, you will need to understand the authentication flow of the Lync mobile client. I have taken out a lot of the non-relevant headers in the communication.

REQ1: POST /webticket/webticketservice.svc HTTP/1.1
RES1: HTTP/1.1 401 Unauthorized
RES1 header: WWW-Authenticate: NTLM
REQ2: POST /webticket/webticketservice.svc HTTP/1.1
REQ2 body: will contain sip:username@domain.com
RES2: HTTP/1.1 401 Unauthorized
REQ3: POST /webticket/webticketservice.svc HTTP/1.1
RES3: HTTP/1.1 200 OK
RES3 header: Persistent-Auth: true
REQ4: GET /ucwa/v1/applications HTTP/1.1
RES4: HTTP/1.1 401 Unauthorized
REQ5: POST /ucwa/v1/applications HTTP/1.1
RES5 : HTTP/1.1 201 Created
RES5 body : sip:username@domain.com

This is an example of an successful login attempt.

The configuration

I’ll try and explain each configuration line step by step.

#Define a variable
add ns variable lync_login_map3 -type "map(text(18),ulong,10000)" -expires 60

The variable name is “lync_login_map3” and it will be able to contain a key and a value on this key. The value can be a text string that is up to 18 characters long, and the value can be a number/integer. It will allow a maximum of 10.000 entries, and they are able to be there for 60 seconds at the time.

Variables configuration

#Define a function for the variable.
add ns assignment one_lync_login3 -variable "$lync_login_map3[HTTP.REQ.BODY(500000).AFTER_REGEX(re/sip:/).BEFORE_REGEX(re--)]" -add 1

The function name is one_lync_login_3, it will work on my variable lync_login_map3. It will increment the value of the key. They key will be extracted from the request that the client makes. The key is == username.

#clear a variable
add ns assignment clear_lync_login3 -variable "$lync_login_map3[HTTP.RES.BODY(500000).AFTER_REGEX(re/sip:/).BEFORE_REGEX(re--)]" –clear

The function name is clear_lync_login3, it will work on the variable lync_login_map3. It will clear the value of the key, the key will be extracted from the response that the server makes. The key is the username, else it wouldn’t work.

#Identifying a login request

add rewrite policy add_lync_login_pol "http.REQ.URL.EQ(\"/webticket/webticketservice.svc\") &&HTTP.REQ.HEADER(\"Authorization\").LENGTH.GE(200)" one_lync_login3

Policy that looks for the login url, with a specific header value over 200 charetars. Will invoke the one_lync_login3 function

#Reset value
add rewrite policy lync_reste_login_pol "http.REQ.URL.EQ(\"/ucwa/v1/applications\") && http.RES.STATUS.EQ(\"201\")" clear_lync_login3

Policy that will look for the second login url, and positive response. It will invoke the clear_lync_login3 function.

Denying access

#The response to the client
add responder action rsp_act_lync_Denied respondwith q{"HTTP/1.1 401 Denied\nConnection: close\nCache-Control: no-cache\nPragma: no-cache\n\n"}

The response that is given the the client when going over the threshold.

#Identifying when the threshold is exceeded.

add responder policy lync_rsp_denied "(http.REQ.URL.EQ(\"/webticket/webticketservice.svc\") && http.REQ.HEADER(\"Authorization\").LENGTH.GE(200)) && $lync_login_map3[ HTTP.REQ.BODY(500000).AFTER_REGEX(re/sip:/).BEFORE_REGEX(re--) ] > 3" rsp_act_lync_Denied

Looking at the specific login URL, and header, while fetching the value of the key in the variable called lync_login_map3. If the value is over 3, it will invoke the rsp_act_lync_Denied response.


#What should be logged

add audit messageaction lync_number_of_logins NOTICE "\"The user \" + HTTP.REQ.BODY(500000).AFTER_REGEX(re/sip:/).BEFORE_REGEX(re--) + \" has tried to login \" + $lync_login_map3[ HTTP.REQ.BODY(500000).AFTER_REGEX(re/sip:/).BEFORE_REGEX(re--) ]" -logtoNewnslog YES -bypassSafetyCheck YES

Extracting the key from the request, and the value for the key(username) in the variable lync_login_map3

#When should it log

add responder policy log_num_logins_lync "http.REQ.URL.EQ(\"/webticket/webticketservice.svc\") && http.REQ.HEADER(\"Authorization\").LENGTH.GE(200)" NOOP -logAction lync_number_of_logins

When a login request is identified, we don’t respond to it, the information is just extracted and logged.


That’s it folks, there you have variables in action, hopefully this blog can be an inspiration for what variables can do, and how to utilize them. I am looking forward to hear about other great usecases for variables!