Posted in : NetScaler By Xenit

3 years ago

In our deployments of XenMobile we always recommend that our customers use the Two Factor option for enrollment, requiring username, password as well as a PIN created in the administration GUI of the appliance, for the added security. In larger organizations this can put some toll on the administrators which is why there is a self-help portal for the users. This portal allows users to create their own PIN and also comes with the added benefit of allowing them to wipe or lock lost and stolen devices themselves, cutting down on the time between theft and action taken.
However, this comes with a drawback. There is no built-in way in XenMobile to enforce any kind of second factor for the login to this portal, which effectively renders the MFA for enroll useless. To prevent this, we can put NetScaler AAA ahead of the login to enforce a second factor for logon to the portal.
I’ll assume that you already have AAA set up, with an authentication profile we can use. In my examples, ours is called AAA-AUPL-EXT_OTP
Starting with some standard boilerplate:

add policy patset PATSET_HOSTHEADER_XM_SHP
bind policy patset PATSET_HOSTHEADER_XM_SHP enroll.example.com -index 1
add policy expression EXP_ADV_HOSTHEADER_XM_SHP "HTTP.REQ.HEADER(\"Host\").SET_TEXT_MODE(IGNORECASE).CONTAINS_ANY(\"PATSET_HOSTHEADER_XM_SHP\")"

Add the traffic actions, policies as well as the form-fill action:

add tm formSSOAction AAA-TFSSO-XM_SHP -actionURL "/zdm/cxf/login" -userField login -passwdField password -ssoSuccessRule true -nvtype STATIC -submitMethod POST
add tm trafficAction AAA-TPF-XM_SHP_LOGIN -appTimeout 1 -SSO ON -formSSOAction AAA-TFSSO-XM_SHP -persistentCookie OFF -InitiateLogout OFF -kcdAccount NONE
add tm trafficAction AAA-TPF-XM_SHP_LOGOUT -appTimeout 1 -persistentCookie OFF -InitiateLogout ON -kcdAccount NONE
add tm trafficPolicy AAA-TPL-XM_SHP_LOGIN "HTTP.REQ.URL.CONTAINS(\"login_xdm_uc.jsp\")" AAA-TPF-XM_SHP_LOGIN
add tm trafficPolicy AAA-TPL-XM_SHP_LOGOUT "HTTP.REQ.URL.CONTAINS(\"/zdm/logout\")" AAA-TPF-XM_SHP_LOGOUT

/zdm/cxf/login is the actual path to where the logon method from /zdm/login_xdm_uc.jsp is posted to. You can view the logon script at https://mdm.example.com/zdm/scripts/logon.js and see this for yourself.
Depending on how your AAA is set up, we might also need an authorization policy. Here I do it via a policy label:

add authorization policy AZP-EXT_ENROLL-NOOP EXP_ADV_HOSTHEADER_XM_SHP DENY
add authorization policy AZP-EXT_ENROLL EXP_ADV_HOSTHEADER_XM_SHP ALLOW
add authorization policylabel AZPL-EXT_ENROLL
bind authorization policylabel AZPL-EXT_ENROLL AZP-EXT_ENROLL 100

A few rewrites:

add rewrite action RWA-REQ-XM_SHP_REFERER replace "HTTP.REQ.HEADER(\"Referer\")" "\"https://\" + HTTP.REQ.HOSTNAME + \"/zdm/login_xdm_uc.jsp\""
add rewrite action RWA-RES-XM_SHP_STATUS_CODE replace HTTP.RES.STATUS 302
add rewrite action RWA-RES-XM_SHP_STATUS_MSG replace HTTP.RES.STATUS_MSG "\"Found : Moved Temporarily\""
add rewrite action RWA-RES-XM_SHP_LOCATION insert_http_header Location "\"https://\" + HTTP.REQ.HOSTNAME + \"/zdm/\""
add rewrite policy RWP-REQ-XM_SHP_REFERER "HTTP.REQ.URL.PATH_AND_QUERY.CONTAINS(\"login_xdm_uc.jsp\")" RWA-REQ-XM_SHP_REFERER
add rewrite policy RWP-RES-XM_SHP_STATUS_CODE "HTTP.RES.BODY(1000).CONTAINS(\"<status>OK</status>\")" RWA-RES-XM_SHP_STATUS_CODE
add rewrite policy RWP-RES-XM_SHP_STATUS_MSG "HTTP.RES.BODY(1000).CONTAINS(\"<status>OK</status>\")" RWA-RES-XM_SHP_STATUS_MSG
add rewrite policy RWP-RES-XM_SHP_LOCATION "HTTP.RES.BODY(1000).CONTAINS(\"<status>OK</status>\")" RWA-RES-XM_SHP_LOCATION

These are necessary since we need the correct referrer to be allowed to login. We also need to tell the client to move from enroll.example.com/zdm/login_xdm_uc.jsp to enroll.example.com/zdm/ once we have performed the login.
Create a service group for your nodes:

add serviceGroup SG-XM_SHP SSL -maxClient 0 -maxReq 0 -usip NO -useproxyport YES -cltTimeout 180 -svrTimeout 2005 -CKA NO -TCPB NO -CMP NO -appflowLog DISABLED -CIP ENABLED X-Forwarded-For
bind serviceGroup SG-XM_SHP YOUR_XMS_NODE1 443
bind serviceGroup SG-XM_SHP YOUR_XMS_NODE2 443

Finally, create a vServer and bind the policies:

add lb vserver LB-EXT-XM_SHP SSL 0.0.0.0 0 -persistenceType SOURCEIP -timeout 30 -cltTimeout 180 -authentication ON -authnProfile AAA-AUPL-EXT_OTP
bind ssl vserver LB-EXT-XM_SHP -certkeyName star.example.com
set ssl vserver LB-EXT-XM_SHP -SSL3 DISABLED
bind lb vserver LB-EXT-XM_SHP SG-XM_SHP
bind lb vserver LB-EXT-XM_SHP -policyName RWP-REQ-XM_SHP_REFERER -priority 100 -gotoPriorityExpression END -type REQUEST
bind lb vserver LB-EXT-XM_SHP -policyName RWP-RES-XM_SHP_STATUS -priority 100 -gotoPriorityExpression NEXT -type RESPONSE
bind lb vserver LB-EXT-XM_SHP -policyName RWP-RES-XM_SHP_STATUSMSG -priority 110 -gotoPriorityExpression NEXT -type RESPONSE
bind lb vserver LB-EXT-XM_SHP -policyName RWP-RES-XM_SHP_LOCATION -priority 120 -gotoPriorityExpression END -type RESPONSE
bind lb vserver LB-EXT-XM_SHP -policyName AAA-TPL-XM_SHP_LOGIN -priority 100 -gotoPriorityExpression END -type REQUEST
bind lb vserver LB-EXT-XM_SHP -policyName AAA-TPL-XM_SHP_LOGOUT -priority 110 -gotoPriorityExpression END -type REQUEST
bind lb vserver LB-EXT-XM_SHP -policyName AZP-EXT_ENROLL-NOOP -invoke policylabel AZPL-EXT_ENROLL -priority 100

Please note that this still leaves logon through mdm.example.com unprotected, since you still can browse directly there, so you should take care not to expose these pages to the outside. One way, if using SSL offload, is to block it with a responder policy:

add policy patset PATSET_PATH_XMS
bind policy patset PATSET_PATH_XMS "/zdm/console" -index 1
bind policy patset PATSET_PATH_XMS "/zdm/login.jsp" -index 2
bind policy patset PATSET_PATH_XMS "/zdm/log.jsp" -index 3
bind policy patset PATSET_PATH_XMS "/zdm/helper.jsp" -index 4
bind policy patset PATSET_PATH_XMS "/zdm/login_xdm_uc.jsp" -index 5
bind policy patset PATSET_PATH_XMS "/zdm/shp/console" -index 6
add responder policy REP-EXT_XM_ADMIN_DROP "CLIENT.IP.SRC.IN_SUBNET(10.0.0.0/8).NOT && CLIENT.IP.SRC.IN_SUBNET(192.168.0.0/16).NOT && CLIENT.IP.SRC.IN_SUBNET(172.16.0.0/12).NOT && HTTP.REQ.URL.STARTSWITH_ANY(\"PATSET_PATH_XMS\")" DROP
bind lb vserver XMS_LB_443 -policyName REP-EXT_XM_ADMIN_DROP -priority 100 -gotoPriorityExpression END -type REQUEST

Do note that this needs to be bound to your LB for MDM, not the vServer we set up above.

Tags :

Comments

frank vandebergh says

Great post!
Btw, you can use http.req.hostname.server instead of http.req.header(“host”). It is automatically case insensitive..

Add comment

Your comment will be revised by the site if needed.