NetScaler Native OTP – Prevent Enrollment of Additional Devices Externally

Download NetScaler Native OTP Device Limit Guide:
Full Version (GUI) | Short Version (CLI)

With the introduction of NetScaler 12.0 (build 51.24 to be exact), Citrix enhanced the value of NetScaler Unified Gateway even more by embedding the native support for one-time password (OTP). Initially, the OTP mobile apps were provided by third-parties, for example, Google and Microsoft Authenticators, but recently Citrix added this support to their own Citrix SSO mobile app.

I will not describe the details and benefits of NetScaler’s native OTP in this article. You are welcome to read about the solution in the Citrix Blog Post NetScaler Unified Gateway Provides One Time Password (OTP), Natively or watch the YouTube video here. There are several very detailed guides available to help you understand and configure the feature, such as Carl Stalhood and George Spiers guides as well as Citrix’s own NetScaler One Time Password (OTP) Guide. In this blog post I will share with you how we can limit the number of enrolled devices to one.

We first got this question from one of our clients, but after that we heard it many times from partners, fellow Citrix experts and other clients. At Citrix Synergy 2018 in Anaheim we shared the solution with Citrix NetScaler Engineering Team – the creators of nFactor and OTP support. Several Citrix customers and partners asked for this during Synergy sessions, so finally (sorry for the delay, guys) I am publishing it here.

Initially, the number of devices that can be enrolled for OTP was not limited. This, to some extent, defeated the purpose of the Multi Factor Authentication with OTP, as any user could register an OTP device as long as the user’s credentials were known. Citrix will limit this in the next builds of 12.0 and 12.1 to five devices, but even this may be unacceptable to most clients. In their guides Carl and George recommend limiting the access to OTP Management to internal networks only by configuring the Login Schema Policy with CLIENT.IP.SRC.IN_SUBNET(subnet/mask) expression:
http.req.cookie.value(“NSC_TASS”).eq(“manageotp“) && client.IP.SRC.IN_SUBNET(

We decided to take this further:

  • Prevent enrollment of any additional devices externally. This means the user can enroll OTP device(s) if he has not enrolled any devices yet. However, we will prevent device enrollment from external networks if the user has previously enrolled an OTP device.
  • Do not limit the number of devices that can be enrolled from internal networks.

OTP stores device enrollment secrets in an Active Directory attribute that accepts Strings. Citrix’s documentation uses the userParameters Active Directory attribute. This guide assumes that you are using the standard (recommended) userParameters AD attribute.

Once an OTP device is enrolled/registered, NetScaler will write a string into the userParameters attribute of the user in the following format:


The trick is to take the userParameters attribute and write it to NetScaler’s internal User Attribute (I will use Attribute #7 in this guide), so it can later be used in the Login Schema and Authentication Policy expressions to evaluate if the user had already enrolled a device.

Since we have to know whether or not NetScaler should display the second (OTP) password field after the LDAP authentication happens, we will modify the way we present the credential prompts to users. To sum it up, instead of this:

We will do this:

Step 2

As a bonus this method gives us more flexibility to check other conditions before deciding to prompt the user for the second authentication factor. For example, check the AD Group membership. Here is an example scenario where the company security policy requirements are as follows:

  • Regular users should not be prompted for 2FA to access the Unified Gateway
  • Privileged (SSL VPN or say RDP Proxy) users must be prompted for 2FA to get access

In this case, we can check the user’s AD Group membership before displaying the Authenticator Passcode prompt.


We are going to build an authentication flow that includes the native OTP functionality. Here is the list of requirements:

  • The solution will support both single and multi-factor authentication
  • Only members of CTX-NetScaler-OTP AD Group will have the ability to use multi-factor authentication and enroll their devices
  • Users that are not members of CTX-NetScaler-OTP AD Group will be able to login with single-factor (LDAP) and have limited access to the Unified Gateway resources (managed by Session Policies, filtered by the AD Group)
  • Users will be limited to enroll a single device if accessing the Unified Gateway externally

Authentication Logical Flow and nFactor Policies

You can download the Short (CLI) Version of the guide or Full (GUI) Version that also includes some other considerations, such as Active Directory and Service Accounts.

Additional tip:
Check out How Do I Citrix NetScaler CLI series and grab a NetScaler CLI Troubleshooting cheat sheet to help you with your configurations.  It’s a handy cheat sheet that contains important commands, paths, and shortcuts, that are available on the net, but it usually takes way too much time to find them.

Please feel free to leave your comments and suggestions here, contact me via LinkedIn, email or follow me on Twitter.

By Stan Demburg

Explore how iRangers are changing the game by designing Virtualization technology solutions adjusted to real business needs.

43 thoughts on “NetScaler Native OTP – Prevent Enrollment of Additional Devices Externally

  1. My goal on this was to have 2Fa only enabled for users that were a member of an AD group. If they weren’t you would log in the first page with username and password, then get in to your citrix desktops. If you were a member of the group, the next page after login would be to enter your 2Factor key. I followed these instructions to a T, but they seem to get fuzzy towards the end of dealing with the group memberships and creating the session policies for them. After creating the two session policies, I went to bind the RDP.. one to the NS-Internal… AAA group, but I get an error:

    “Advanced VPN Session Policy cannot be bound if Classic VPN Session Policy is already bound to any entity (i.e. aaa user, aaa group, vpn vserver, vpn global)”

    Don’t understand that, as these are new policies that are just created and are not bound to anything. But even beyond that, I don’t see anywhere where you would map an AD account to this netscaler group, which is what I thought was part of this article. What I did instead, was in the authentication policy put my AD group in for AAA.USER.IS_MEMBER_OF() (and I used AAA.Users because netscaler said that HTTP.REQ.USERS was deprecated).

    When I go to the site, I get the login, but when I log in it goes to the next page where I get “No Active Policy During Authentication” error. I guess I’m stuck on where to go next. Any help would be great. Thanks

    1. Hi Ryan,
      The reason you’re getting the “Advanced VPN Session Policy cannot be bound if Classic VPN Session Policy is already bound…” error is because you have a Classic Session Policy bound somewhere else (ex. directly to your Gateway vServer, globally or AAA Group).

      In general, my advice is to create Advanced Session Policies, then unbind all your Classic Session Policies from everywhere and bind the new Advanced policies. Chances are you using simple “NS_TRUE” classic expressions which translate to “TRUE” advanced expression. The only valid reason to keep the Classic Policies is if you are using EPA checks as part of your Session Policies. In this case, you can migrate EPA to nFactor and get rid of Classic Policies (this still has some limitations) or keep the Classic Policies. If you want to keep Classic Policies, then use “NS_TRUE” classic expression instead of the “TRUE” advanced one.

      The AD Group membership check actually happens during the Authentication (which is before any Session Policy gets applied), after the LDAP Factor and before any of the OTP factors. It is done in the “UG-noauth-OTP-Verify_authpol” authentication policy:

      add authentication Policy UG-noauth-OTP-Verify_authpol -rule “AAA.USER.IS_MEMBER_OF(\”CTX-NetScaler-OTP\“) && HTTP.REQ.USER.ATTRIBUTE(7).CONTAINS(\”#@\”)” -action NO_AUTHN

      Replaced HTTP.REQ.USER. by AAA.USER – as you mentioned, the first one is deprecated.

      Stan Demburg

  2. This is excellent design. I probably would spent weeks getting to that point on my own if ever.
    I have implemented it in my lab and it works as describe with few issues. I will work on them later.
    But maybe you can advise me how to do small change. For me all users are external, so I can’t block /manageotp once user added a device. What I want to do is next.
    1) if user does not have OTP registered just let him into /manageotp to add device (as you did)
    2) if user registered let him into /manageotp but ask OTP password before as well.
    I did next. In UG-noauth-OTP-Mgmt_authpol I just left: HTTP.REQ.COOKIE.VALUE(“NSC_TASS”).EQ(“manageotp”)
    Now any user can get in. Now I just need to add UG-noauth-OTP-Verify_authpol which has next condition AAA.USER.ATTRIBUTE(7).CONTAINS(“#@”) into the flow and enable Verification propmt.
    May be you can help me with advise how to add this into the flow.
    Now if user want to add new devise he/she will need to have old one. If old one not available they can call support and support will clear OTP filed in AD.

  3. I got a bit further but now completely stack.
    1) I have kept everything like you describe
    2) I have added another Policy UG-noauth-OTP-Mgmt-Verify_authpol and put condition /manageotp && AAA.USER.ATTRIBUTE(7).CONTAINS(“#@”), set to NO_AUTHN and set second factor to new policy label UG-OTP-Mgmt-Passcode-Verify_pollabel
    3) This label has own Schema (same as OTP-Passcode-Only.xml but with different text so I know I landed on right policy)
    It has new policy UG-LDAP-OTP-Mgmt-Verify-NoAuth_auth with true and your action LDAP-OTP-Verify-NoAuth_authsrv
    4) I have added this new policy to main Policy Label with weight 150 (before regular OTP)
    Now I have 2 issues:
    1) check HTTP.REQ.COOKIE.VALUE(“NSC_TASS”).EQ(“manageotp”) looks like not working all the time. Sometimes it completely ignores that I put [Link deleted]and follows main policy (piority 300) sometimes it hit policy even when I don’t put /manageotp in URL. Anyone has this issue?
    2) issue two even when I hit this new policy label. I see my custom Login Schema (and in logs). I put OPT but instead of /manageotp page I am redirected to StoreFront application page. What is going on?
    How reliably end up on OTP Managment page?
    I will try open case with Support, but I am afraid they might not be able to support advance configuration.
    I would appreciate if you have any ideas.

    1. I think problem is in this extra LoginSchema profile. If it has custom UI to ask OTP it redirects to Store Front, if I put LSCHEMA_INT it redirect to manageOTP without OTP verification.
      Do I need something special into this custom .xml file to redirect it to manageOTP to make it work?
      It looks like as soon as OTP verification done Netscaler ignores NSC_TASS and goes to ICA StoreFront.
      Or I am missing something here.

  4. Hi Leanid,
    The issue may not be in the Login Schema. The OTP-Verify custom Login Schema does not have any redirects.
    From what I see the issue is with NetScaler native OTP module. Once the OTP module is triggered, you can no longer get back to it. So, when OTP is verified (module triggered), you cannot go back to OTP device registration. The only way I could think this may work is if you chain another Policy Label (with LSCHEMA_INT) as a next factor for the OTP verification (LDAP) policy. So, it will look like this:

    Start-LDAPs_authpol -> (next factor) -> Single-or-2FA_pollabel -> UG-noauth-OTP-Verify_authpol -> (next factor) -> UG-OTP-2FA-Vefrify_pollabel -> (new) UG-LDAP-OTP-Verify-then-Manage-NoAuth_authpol (AAA.USER.ATTRIBUTE(7).CONTAINS(“#@”).NOT) -> (next factor – new) -> UG-OTP-Mgmt-NoSchema_pollabel (with LSCHEMA_INT) -> UG-LDAP-OTP-Mgmt-NoAuth_authpol -> END

    Let me know if this works for you. Sorry, I have no ability to test this right now.

    1. Wow. Your idea worked. Thanks a lot Stan.
      I have created Policy Label with my OTP verification for manageotp and bind auth policy with second factor to another Policy label without LoginShema (LSCHEMA_INT) with same authentication action and no second factor.
      It worked great. User sent to manageotp site!!! And I have protected manageotp site. .

      Now the only issue is NSC_TASS cookie. If user first logged in to StoreFront then logout and does not close browser click to https://mysite/manageotp it goes back to StoreFront. It does not properly set NSC_TASS cookie so ManageOTP policies do not get triggered and it follows regular nFactor path. If user closes browser and tries again everything works. I think this issue should affect everyone, since it has nothing to do with my policies. Is there some trick to clear cookies on logout or maybe at some other moment to make stable NSC_TASS detection?

      On a side note, I think I started to figure out this nFactor authentication. This is bloody complicated. Once you get it , it does not look that scary, but good luck someone from outside trying to figure it out.

      1. Stan,
        Just want to say Thank you for this article.
        With it’s help I was able to configure nFactor with native OTP protecting main site as well as ManageOtp, Forgot Password (password reset) and KBA subscription. That allows me to use it for external users.
        I have seen a lot of examples with GUI and CLI and it was really hard to understand all object connections, especially if you want to modify and extend it. Your diagram on top of this article was most useful peace of information that allowed me to understand nFactor. It still took me 3 days to extend OTP to KBA and ManageOTP, but at least now, I think, I know how it works.
        I still need to sort out reset of NSC_TASS cookie in some cases, but I will probably do it with some kind of custom java scripting.

        1. You’re welcome, Leanid!

          In regards to the NSC_TASS cookie issue you’re having, for one of my clients I configured a separate AAA Virtual Server for OTP device enrollment (AAA works exactly the same as Gateway). So, it this case users have to go to instead of The request is then redirected (with a Responder action) to As part of the Responder action, you can wipe the existing NSC_TASS cookie, so your Responder expression will be similar to this:

          “”+”\r\n”+”Set-Cookie: NSC_TASS=xyz;Path=/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure\r\n\r\n”

          This will trigger NetScaler to generate a new NSC_TASS.

          1. Stan,
            Interesting approach. I will try it. I will send KBA registration there as well and keep “Password Reset” on Gateway site. From what I see “Password reset” is not using NSC_TASS cookie.
            Thanks a lot.

          2. Stan,
            This did not worked very well. It worked in principal, bit not the best user experience. User get redirected to different site and it does work for manageotp but there is no nice way back. Adding extra link “Go back” looks ugly. Also same approach does not work for KBA registration, since it want to redirect to main site (storefront) after it completed.
            I managed to catch NSC_TASS cookie when it come back from StoreFront logout (check referrer in header) and reset NSC_TASS. That helped a bit. Now the only user trap I have is inside manageotp and KBA registration. Once user in their flow there is no way back but finish it or restart browser. It desperately needed Cancel button. I can add button, but need to link it with some java script. I made it to call CTXS.Environment.logOff(); but it is not enough. I guess this is something I need to talk to Citrix support.

          3. Hi Leanid,

            For the Cancel button, you can try adding a redirect to “/cgi/tmlogout”. This is a standard NetScaler logout URL.

          4. I finally added Cancel button to forms. It was a pain.
            1) Had to register custom class with input type “submit” to prevent default submit action. Also had to add custom javascript first to set my own NSC_TASS_CLEAR cookie. I could not just clear NSC_TASS cookie since it has HttpOnly and not available for javascript, plus /cgi/tmlogout does not reset this cookie as well probably for the same reason.
            1) This is extension in script.js
            getCredentialTypeName: function () { return “nsg_cancel”; },
            getCredentialTypeMarkup: function (requirements) {
            var div = $(“”);

            $(document).on(‘ctxsformsauthenticationdisplayform’, function (e, data) {
            $(‘#nsg_cancel’).click(function() {
            document.cookie = “NSC_TASS_CLEAR=yes;path=/;Secure”;
            window.location.href = “/cgi/tmlogout”;
            return false;
            2) In style.css added css to make button flat:
            .CredentialTypensg_cancel input[type=”submit”] {
            display: inline-block;
            color: white;
            box-sizing: border-box;
            background-color: #999999;
            border: none;
            border-radius: 2px;
            transition:background-color 0.5s ease;
            cursor: pointer;
            .CredentialTypensg_cancel input[type=”submit”]:hover {
            background-color: #777777;
            3. Now in my custom Loginschima.xml added
            4. At Netscaler added NSC_TASS cookie cleanup if I detect my NSC_TASS_CLEAN cookie. Because of HttpOnly flag I had to do it with Netscaler policy and not javascript:
            “Set-Cookie: NSC_TASS=xyz;Path=/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure\r\n”+”Set-Cookie: NSC_TASS_CLEAR=no;Path=/;expires=Wednesday, 09-Nov-1999 23:12:40 GMT;Secure\r\n\r\n”
            For policy condition:
            HTTP.REQ.HOSTNAME.contains(“”) && HTTP.REQ.COOKIE.VALUE(“NSC_TASS_CLEAR”).EQ(“yes”)

            I will do more QA, but so far looks good. Again thanks a lot for your initial article it was good start point.

      2. Hi Leanid,
        Can you please share some CLI commands how you’ve fixed it?
        I’m trying to accomplish the same but i’m realy stock at the moment. My goal is to forward all the users to the manageOTP site if they don’t have any device configured.
        This is what you’ve done as well correct?
        Thank you very much!

        1. Jeor2011,
          Actually this is not what I do. And for your case my CLI will only confuse you. It already has KBA regitration and Password Reset with added OTP.
          What I do is what this Stan’s article does. Not enforcing OTP for users without registered device. At least at the beginning to allow soft rollout of this feature. So users without OTP device can login without issue. And I have added link to /manageotp to add device.
          Once they added device to OTP Stan’s example block access to /manageotp for external users. In my case I have added OTP verification to /manageotp if user already have a device registered. That was main deviation from this example and an issue that Stan help me to resolve.
          Users will need their old device to add a new one. If they don’t have it they will have to talk to support and support will zero out device registration in AD.

          1. Hey Leanid
            we are in a similar situation you was. we cannot stop access externally to MANAGEOTP as we have multiple clients coming in externally. what we are trying to do, is allow then to register a device on first imte accessing the new OTP platfrom but after that device is registered is either get them to have to use OTP so 2FA to get to manageOTP. can you help how I get this to work?

            Much appreciated.


  5. Hello Stan,
    a great guide thank you! Today I’ve updated the Netscaler to the new version 13. Unfortunately, I can no longer register devices
    via /manageotp after the update. it looks as if you will be forwarded to the storefront after login via the URL /manageotp. it
    looks as if you will be forwarded to the storefront after login via the URL /manageotp.
    Do you have an idea?

    thx Philipp

    1. Hi Philipp,

      In Citrix ADC 13.0 Citrix slightly changed the OTP support. For example, native Push is now supported and you can set the max number of devices users can register.

      Your issue may be related to the max number of devices, which is 4 by default. You can adjust this in GUI:
      – Navigate to Security > AAA – Application Traffic, click Change authentication AAA OTP Parameter under Authentication Settings section.
      – On the Configure AAA OTP Parameter page, enter the values for Max OTP device Configured.

      Here is Citrix’s original documentation for the Native OTP on 13.0:

      Let me know if adjusting the max # of devices helped.

      1. Hi Stan,
        many thanks for your response. I tried your trick with the maximum devices today, unfortunately without success. In addition, I have customized the “UG-noauth-OTP-Mgmt_authpol“ policy. But even with the change was not possible to add devices via the /manageotp URL. Do you have another idea? It almost looks like they have changed a lot under the hood with Version 13.


        1. Hi Philipp,

          Yes, it looks like lots of things have changed. However, /manageotp should still work.

          1. Hi Stan,
            First of all, thank you very much for this solution. But since we updated to 12.1 54.13 /manageotp does not work anymore. This version supports also max. Devices and have Push Service Option in LDAP Server Action. When we use default implementation with only one step login /manageotp is working. Any ideas how to fix it?

          2. Hi Chris,

            This may happen if ADC 12.1 build 54.13 dropped support for HTTP.REQ.USER in favor of AAA.USER

            Can you please try changing the UG-noauth-OTP-Verify_authpol (this is how I refer to the policy in the guide, you may have a different name) policy from:
            add authentication Policy UG-noauth-OTP-Verify_authpol -rule “HTTP.REQ.USER.IS_MEMBER_OF(\”CTX-NetScaler-OTP\”) && HTTP.REQ.USER.ATTRIBUTE(7).CONTAINS(\”#@\”)” -action NO_AUTHN

            add authentication Policy UG-noauth-OTP-Verify_authpol -rule “AAA.USER.IS_MEMBER_OF(\”CTX-NetScaler-OTP\”) && AAA.USER.ATTRIBUTE(7).CONTAINS(\”#@\”)” -action NO_AUTHN

            In GUI, change the HTTP.REQ.USER. to AAA.USER. (I would do that for all of your policies).

            Please let me know if this works for you.

    2. Hello Phillp,
      I found a solution to the problem.
      You have to exchange the SingleAuth-Pre-OTP.xml file (from Iranges) with the Netscaler 13.x original file SingleAuthManageOTP.xml, then the registration works and the devices can be registered again.
      I hope I could help them.

  6. Hello Stan,
    Good Day!!
    Recently, I have upgraded my NS appliance to version12.1 build 51.19. I have the below requirements. Kindly suggest how can I achieve it:
    1) Can we restrict users to add 1 device in NS version12.1 build 51.19.
    2) I want to restrict users to add 1 device only whether they connected internally or external network
    3) Can I remove the option of Delete device from the OTP registration page.

    Kindly suggest the same.
    Awaiting your reply.

    1. Hi Harsh,
      For #1 and 2 you can use the above instructions. This is exactly what they do – limit to a single device. For #2 to work just remove the internal IP range condition.

      In regards to #3, not sure how can this be achieved.

      1. Hi Stan,
        Thanks for the reply.
        I will try the same & will share the results.
        Harsh Kumar

        1. Hi Stan,
          I have configured the same settings as described in the Article. However, when I try to login to ManageOTP site, it gives error “No Active policy during authentication”.
          Can you please suggest, where I am making mistake?


        2. Hi Stan
          I have followed the same instructions as mentioned in the article. However, I made 1 mistake in between that while creating Authentication policylabel (UG-OTP-2FA-Verify_pollabel). I have assigned LSCHEMA_INT instead of “OTP-Passcode-Only_lschema”. Now when I am trying to delete that, it is saying “Resource in Use.” I am unable to delete that. I have also unbind the Policy but still the same.

          Can you please suggest how to fix it as when I am creating new policylabel for the same with other name, it does not take effect.


  7. Hi Stan,
    I reconfigured the entire NetScaler again. Unfortunately with the same result. Have you been able to test anything in the lab environment?

  8. Hi Stan,
    While configuring the Authentication PolicyLabel, I have created the PolicyLabel “UG-OTP-2FA-Verify_Pollabel” as LSCHEMA_INT. But now when I am trying to edit it or delete it, it says “Resource in use”
    Kindly suggest, how can I fix this.

  9. Hi Stan,
    Thanks for the great article!!!
    Finally, I restored my NS to last restore & revert all the settings back to old one. Then, I followed the above instruction to T & able to achieve the same & keeping the device registration to single device. But its all done in Test environment.
    Now when am I try to integrate my storefront with new NS configuration, getting error : Cannot complete the request.
    Can you please provide some suggestions on the same?


    1. Hi Harsh,

      There are quite a few reasons that could cause the “Cannot complete your request” error. Typically, this is caused by misconfiguration of the Storefront:
      – First, check if you can access and login to Storefront directly (no LB, no Gateway)
      – Check that your Gateway URL is configured right
      – If you configured the Callback URL, check that it is resolving to the NetScaler hosting your Gateway
      – Check out this Citrix KB:


      1. Hi Stan,
        Thanks for the suggestion!!
        I created a new session policy & bind it with the NS VServer & I am in the business now.
        Thanks once again!!!

  10. Hello Stan.
    This may sound like a silly question, but can you turn on the manageotp function without yet enabling OTP on the Gateway itself? In other words, I want to be able to get people to register their devices for prior to actually turning on OTP.

    1. Hi Shane,
      Yes, you can configure a separate AAA vServer to handle the device registration and even remove the /manageotp from your main Gateway. So, instead of configuring the Gateway AAA vServer, you apply the same login to another AAA vServer that will be dedicated to OTP device registration only.
      See the example below. I do not give the users the exact complex URL and path (, instead, I direct the users to go to to register their OTP device. NetScaler performs the redirection.
      There are a couple of custom Policy Labels involved – one is in the documentation in this post, another one NS-OTP-Mgmt-Unauth-ExtAccess_lschema just displays a warning message.

      add authentication authnProfile NS-OTP-Management_authprof -authnVsName NS-OTP-Management_authsrv -AuthenticationHost -AuthenticationDomain -AuthenticationLevel 200
      add authentication loginSchema OTP-Register-Only_lschema -authenticationSchema “/nsconfig/loginschema/OTP-RegistrationOnly.xml” -passwordCredentialIndex 1
      add authentication loginSchema NS-OTP-Mgmt-Unauth-ExtAccess_lschema -authenticationSchema “/nsconfig/loginschema/NS-OTP-Mgmt-Unauthorized-ExtAccess.xml”

      add lb vserver NS-OTP-Management_lbvs SSL 0 -persistenceType NONE -cltTimeout 180 -Authentication ON -authnProfile NS-OTP-Management_authprof

      add authentication vserver NS-OTP-Management_authsrv SSL

      add cs action NS-OTP-Mgmt-LBVS_csact -targetLBVserver NS-OTP-Management_lbvs
      add cs action NS-OTP-Mgmt-AAA_csact -targetVserver NS-OTP-Management_authsrv

      add cs policy NS-OTP-Mgmt-LBVS_cspol -rule “HTTP.REQ.HOSTNAME.SET_TEXT_MODE(IGNORECASE).EQ(\”\”) && HTTP.REQ.URL.PATH.STARTSWITH(\”/manageotp\”)” -action NS-OTP-Mgmt-LBVS_csact
      add cs policy NS-OTP-Mgmt-AAA_cspol -rule “HTTP.REQ.HOSTNAME.SET_TEXT_MODE(IGNORECASE).EQ(\”\”)” -action NS-OTP-Mgmt-AAA_csact

      add responder action OTP-Management-Redirect_respact redirect “\”\”” -responseStatusCode 302 -reasonPhrase “\”Redirect to OTP management\””

      add responder policy OTP-Management-Redirect_respol “HTTP.REQ.HOSTNAME.SET_TEXT_MODE(IGNORECASE).EQ(\”\”)” OTP-Management-Redirect_respact

      bind lb vserver NS-OTP-Management_lbvs Always-UP_svc

      add authentication Policy WPG-LDAPs_authpol -rule true -action WPG-LDAPs_authsrv
      add authentication Policy noauth_authpol -rule true -action NO_AUTHN
      add authentication Policy AAA-LDAP-OTP-Mgmt_authpol -rule “AAA.USER.IS_MEMBER_OF(\”CTX-NetScaler-OTP\”) && (AAA.USER.ATTRIBUTE(7).CONTAINS(\”#@\”).NOT || CLIENT.IP.SRC.IN_SUBNET(” -action LDAP-OTP-Combined_authsrv
      add authentication Policy AAA-noauth-OTP-Mgmt_authpol -rule “AAA.USER.IS_MEMBER_OF(\”CTX-NetScaler-OTP\”) && (AAA.USER.ATTRIBUTE(7).CONTAINS(\”#@\”).NOT || CLIENT.IP.SRC.IN_SUBNET(” -action NO_AUTHN

      add authentication policylabel UG-OTP-Mgmt-NoSchema_pollabel -loginSchema noschema_lschema
      add authentication policylabel AAA-OTP-Unauth-ExtAccess_pollabel -loginSchema NS-OTP-Mgmt-Unauth-ExtAccess_lschema

      bind authentication policylabel AAA-OTP-Register-Only_pollabel -policyName AAA-LDAP-OTP-Mgmt_authpol -priority 100 -gotoPriorityExpression NEXT
      bind authentication policylabel AAA-OTP-Mgmt-Access_pollabel -policyName AAA-noauth-OTP-Mgmt_authpol -priority 100 -gotoPriorityExpression NEXT -nextFactor AAA-OTP-Register-Only_pollabel
      bind authentication policylabel AAA-OTP-Mgmt-Access_pollabel -policyName noauth_authpol -priority 200 -gotoPriorityExpression NEXT -nextFactor AAA-OTP-Unauth-ExtAccess_pollabel
      bind authentication policylabel AAA-OTP-Unauth-ExtAccess_pollabel -policyName WPG-LDAPs_authpol -priority 100 -gotoPriorityExpression NEXT

      bind authentication vserver NS-OTP-Management_authsrv -policy SingleAuth-OTP-Management_lschemapol -priority 100 -gotoPriorityExpression END
      bind authentication vserver NS-OTP-Management_authsrv -policy WPG-LDAPs_authpol -priority 100 -nextFactor AAA-OTP-Mgmt-Access_pollabel -gotoPriorityExpression NEXT

  11. After update to to firmware above the /manageotp site no longer comes up. It actually give an error during login. Has anyone else experienced this issue using this configuration?

  12. Hi Stan,
    Good Day!!
    I have configured the Netscaler settings & everything is working fine using OTP feature.
    Netscaler version # NS12.1
    I observed that few users does not register themselves on ManageOTP url.
    Can you please suggest, how can I force users to register the device first & then login to Storefront page.
    Awaiting your reply.

    Harsh Kumar

  13. Hi Stan,
    I read your post on October 15, 2019 at 10:48 AM.
    A colleague had the / manageotp problem with NS version 13.0
    I have the same problem, the user can no longer register the cell phone.
    I implemented your suggestion, it does not work, the log file says:
    /home/build/rs_130_47_10_RTM/usr.src/netscaler/aaad/ldap_common.c[648]: extract_ldap_attribute 0-312: retrieved pwdLastSet value 132179561070547076 for testuser001, length is 18
    Fri Jan 31 13:21:07 2020
    /home/build/rs_130_47_10_RTM/usr.src/netscaler/aaad/ldap_drv.c[2420]: get_otp_attribute 0-312: OTP Secret Attribute name: , length 15
    Fri Jan 31 13:21:07 2020
    /home/build/rs_130_47_10_RTM/usr.src/netscaler/aaad/ldap_common.c[584]: extract_ldap_attribute 0-312: While retrieving ldap attributes userParameters attribute not found for testuser001
    Fri Jan 31 13:21:07 2020
    /home/build/rs_130_47_10_RTM/usr.src/netscaler/aaad/ldap_drv.c[2420]: get_otp_attribute 0-312: OTP Secret Attribute name: , length 15
    Fri Jan 31 13:21:07 2020
    /home/build/rs_130_47_10_RTM/usr.src/netscaler/aaad/ldap_drv.c[706]: receive_ldap_user_search_event 0-312: Failed to extract attribute, name: userParameters,
    Fri Jan 31 13:21:07 2020
    /home/build/rs_130_47_10_RTM/usr.src/netscaler/aaad/ldap_drv.c[2420]: get_otp_attribute 0-312: OTP Secret Attribute name: , length 15
    Can you give me a hint how I can solve the problem.
    UserParameters can no longer be found, the current version NS12.1 is working

    Thank you.

    1. Hey Darek
      Did you find a solution to the problem “Failed to extract attribute, name: userParameters”? I have the same issue but can’t find the solution. Thanks!

  14. Hi!
    I have configured OTP exactly as you have instructed. If I try to access /manageotp I get the following error “Try again or contact your help desk”. If I enter e.g. #@12345 to users userParameters AD-attribute and try to login it takes me to UG-OTP-2FA-Verify_pollabel and shows me the OTP-Passcode-Only_lschema login schema. So that works as it should. And if I try to login with that attribute empty (not trying to enroll a device first) it allows limited access as it should. So LDAP authentication works. But I cannot access /manageotp

    In var/log/ns.log I have the following error:
    Feb 13 08:15:52 02/13/2020:06:15:52 GMT netscaler 0-PPE-0 : default AAATM Message 14734 0 : “Failed to extract OTP secret from aaad, current factor: UG-OTP_Mgmt-NoSchema_pollabel, for user: user123 ”
    Feb 13 08:15:52 02/13/2020:06:15:52 GMT netscaler 0-PPE-0 : default AAA LOGIN_FAILED 14735 0 : User user123 – Client_ip – Failure_reason “External authentication server denied access”
    Feb 13 08:15:52 02/13/2020:06:15:52 GMT netscaler 0-PPE-0 : default AAA Message 14736 0 : “Authentication is rejected for user123 (client ip :, vserver ip: ), extended error, if any : ”

    Last lines of cat /tmp/aaad.debug:
    Thu Feb 13 11:50:59 2020 /home/build/rs_121_55_4_RTM/usr.src/netscaler/aaad/ldap_drv.c[905]: receive_ldap_user_search_event 0-224: Authentication is disabled for user user123, finishing ldap authentication
    Thu Feb 13 11:50:59 2020 /home/build/rs_121_55_4_RTM/usr.src/netscaler/aaad/naaad.c[3923]: send_accept 0-224: sending accept to kernel for : user123
    Thu Feb 13 11:50:59 2020 /home/build/rs_121_55_4_RTM/usr.src/netscaler/aaad/naaad.c[3840]: aaad_alloc_serialize_keyValue_attrs 0-224: Total attribute values to PE : 61,

    In the LDAP Action I am using the domain Administrator account as bind-account and the “Test LDAP Reachability” passes just fine. I have checked the LDAP actions several times and also tried using another bind account, but no luck.

    I am using a custom there based on RfWebUI, and also tried with the default RfWebUI theme. HSTS is disabled. Any ideas what could be causing this?

  15. Hello Stan,
    While following your guide I have created two XML files to upload to the netscaler. When I select either of these two xml files in Netscaler to create the login schema, I receive the following error message: l.getElementsByTagName is not a function and the creation of the login schema profile is not possible. It must have something to do with the format of the XML file but I just can’t find what’s wrong. Do you know how I can solve this? Thanks a lot for your guide!

  16. Hello, I just found why the XML was not working. I had to put as header and I had to remove all spaces and put everything on one line.

  17. Hi there

    Thanks for this very nice guide. As we would like to publish the manageotp page to external, we are thinking about to use our existing Radius infrastructure with SMSPasscode in Background (SMS will be sent to mobile of the user).
    Is there a way to protect the manageotp page with a RADIUS Rule? So the user would be requested to put in their AD-User Credentials and then will be forced to put in their SMS Passcode to authenticate, which would then unlock the manageotp site.
    This is because some of our users connect only from outside and would otherwise not be able to register their device for otp.

Leave a Reply

Your email address will not be published. Required fields are marked *