One day I received a bizarre request from a customer, which we see a lot with Netscaler: they needed to compare a text string placed in a client certificate’s field that had to match with a value placed in a specified AD’s field.
The requirement was made because client certificates were enrolled by an external Certification Authority and the CN burned into the certificate was different from the one present in Active Directory user’s field. This meant another field had to be checked and matched in order to authorize users for login.
- User with certificate, if valid, logged on into Netscaler.
- User typed credentials which were checked by Active Directory and, at the same time, the certificate’s field was extracted and compared with that in Active Directory.
- If credentials were valid and strings comparison was successful, user was allowed to login.
Well, as a magic trick, it was possible with our Netscaler swiss army.
The customer requirement was to check the DESCRIPTION field in Active Directory and the CN field in the client certificate and to compare them.
The field in the certificate was something like that:
The part that had to be extracted was the string before the “/” character.
The configuration explained below made the magic.
The primary authentication policy made user authentication possible:
add authentication ldapAction AD -serverIP 22.214.171.124 -serverPort 636 -ldapBase “dc=example,dc=com” -ldapBindDn firstname.lastname@example.org -ldapBindDnPassword ce2e035360c83027a0c835 -encrypted -ldapLoginName samAccountName -groupAttrName memberOf -subAttributeName CN
The secondary authentication policy with authentication option disabled, was necessary to grab the description text from AD and to append it to the group string (i.e ABCDEFGH111000X,Grp_1,Grp_2):
add authentication ldapAction AD_noauth -serverIP 126.96.36.199 -serverPort 636 -ldapBase “dc=example,dc=com” -ldapBindDn email@example.com -ldapBindDnPassword ce2e035360c83027a0c835 -encrypted -ldapLoginName samAccountName -groupAttrName description -authentication DISABLED
A responder policy chain was used to make the comparison of the two fields after user has been typed his credentials.
The first policy was used to check if the user owned a certificate and was redirected to the Netscaler “cvpn” page which meant he have already passed the login process:
add responder policy AfterLogin “CLIENT.SSL.CLIENT_CERT.EXISTS && HTTP.REQ.URL.CONTAINS(\”cvpn\”)” NOOP
The second policy made the comparison of the two fields:
add responder policy CERTCheckBinding “(CLIENT.SSL.CLIENT_CERT.SUBJECT.NAME_VALUE(\”CN\”).AFTER_STR(\”CN=\”).TO_UPPER != (HTTP.REQ.USER.EXTERNAL_GROUPS.BEFORE_STR(\”,\”).TO_UPPER))” NotAllowed
If the values didn’t match the following action took place:
add responder action NotAllowed respondwith “\”You are not entitled to use this certificate because it doesn’t belong to you\”” -bypassSafetyCheck YES
<span style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif;font-size: 13px;line-height: 19px">The policy label was used to mesh up all the pieces:</span>
add responder policylabel CERTCheck
The last step was to bind policies in the proper way:
bind responder policylabel CERTCheck CERTCheckBinding 100 END
bind responder global AfterLogin 90 END -type REQ_OVERRIDE -invoke policylabel CERTCheck
In order to check what was happening and to troubleshoot, the following lines could be added to the configuration to see onscreen values from comparing.
add responder action Values respondwith “\”Cert. CN =\”+CLIENT.SSL.CLIENT_CERT.SUBJECT.NAME_VALUE(\”CN\”).AFTER_STR(\”CN=\”).TO_UPPER + \”#### LDAP USERGROUP=\” + HTTP.REQ.USER.EXTERNAL_GROUPS.BEFORE_STR(\”,\”).TO_UPPER + \”-\”” -bypassSafetyCheck YES
The responder policy “CERTCheckBinding” had to be bound to this “Values” action instead of the “NotAllowed” one.
Follow these steps and you’ll be able to successfully compare client certificate and Active Directory fields before a user logs into your Netscaler.
A special thank you to my colleague Daniele Vianini who helped on that.