LDAP Authentication using spring-security
Hi network! Recently I have got a chance to work on implementing LDAP authentication using spring-security.
It was a wonderful learning experience, would like to share with you all briefly the concepts that I have learned.
Please feel free to add any extra information or correct me if required.
Introduction:
LDAP is a very common technology used across organization to store their employee's data. Windows' Active Directory, Oracle's OID or open source OpenLDAP are some examples. Authentication is also one of its most common use-case.
Lightweight Directory Access Protocol (LDAP) is a language to interact with directory databases/ servers. It uses TCP/IP under the hood to communicate.
Directory server stores the information related to users in a hierarchical format.
It stores their general attributes, groups, passwords and provides us operations like bind, unbind, add entry, delete entry, etc., and LDAP is the protocol to communicate with it.
How the information is stored on LDAP servers?
We store the information in the form of a inverted tree structure (root at the top).
Root here is know as Domain Component (dc), which can have branching as per the policy design, grouping the users into Organizational Units (ou).
These units will have the users with all its attributes. This is referred to as DIT (Directory Information Tree).
Eg. Lets consider an user "Pranav" who is a developer in an organization named "Example". Below is the sample DIT in which his information will be stored on the LDAP server.
dc=example,dc=com
- ou=marketing
- user: x
- ou=finance
- user: y
- ou=engineering
- ou=QA
- user: z
- ou=developer
- user: Pranav
Comman Name (cn): Pranav
Sur Name (sn): Joshi
UserID (uid): 143
Recommended by LinkedIn
UserName: pjoshi
email: gmail@pranav.com
Password: xxxxxxx
Distingueshed Name (dn): cn=Pranav,ou=developer,ou=engineering,dc=example,dc=com
What is a DN ?
Distingueshed Name (dn) is a attribute which is used to uniquely identify each entry in the DIT on the LDAP server. It can be considered as an absolute path of a entry/ node.
Starting from the 'cn' navigating back to the 'dc', we can form the 'dn' of each entry. Like in above example 'dn' of user Pranav is 'cn=Pranav,ou=developer,ou=engineering,dc=example,dc=com'.
Note: It is not compulsory to use 'cn', we can have any custom attribute (username, uid, etc.) to be part of 'dn', but 'cn' is most common.
LDAP Authentication:
Spring offers to authenticate LDAP user using two ways -
i. Password Comparison: LDAP server often provides us with password "compare" operation, where we can authenticate the user without actually retrieving the value of password attribute. Or we can locally check the password by retrieving the attribute value.
ii. Bind Authentication: This is the most common and secured way as the responsibility of authentication resides at LDAP server without exposing the password to the clients. We just submit the username and password to the LDAP server, which will be authenticated and return some set of user attributes as requested, if authentication is successful.
I have implemented authentication via LDAP Bind, and will here try to explain the spring-security flow for authentication.
1. UsernamePasswordAuthenticationFilter : HTTP request from the client is intercepted by this filter. Username and password is extracted to form a UsernamePasswordAuthenticationToken, which is further used by the authenticators. ProviderManager's autheticate() is called from here.
2. ProviderManager : It tries to authenticate using the supported AuthenticationProviders configured to it. If authentication fails, it tries using the next AuthenticationProviders and exception from last one is re-thrown if fails for all.
For LDAP we have configured LdapAuthenticationProvider.
3. LdapAuthenticationProvider : It mainly does two tasks i. doAuthentication() ii.loadUserAuthorities() to obtain UserDetails which is then used to create successful Authentication object.
4. BindAuthenticator : As mentioned earlier, I have implemented LDAP Authentication - the 'bind' way. BindAuthenticator will be called to 'doAuthentication'. LDAP bind operation will be attempted using the username and password. If authentication is successful, a Directory Context will be loaded with the fetched attributes, else exception is thrown. If DN patterns are configured, it authenticates with them directly, else uses the configured search object to find the user and authenticates with the returned DN.
5. LdapUserDetailsMapper : To create a UserDetails object from the DirectoryContext, i.e to map the LDAP attributes (dn, cn, sn, etc.) with the spring-security understandable UserDetails object (which stores user information) this class is used.
6. LdapAuthoritiesPopulator : Granted authorities (spring-security understandable form) for an Ldap user are obtained
7. AbstractLdapAuthenticationProvider :: createSuccessfulAuthentication() - finally a Authentication object is prepared using the UserDetails which is then set in the SecurityContextHolder indicating that this request is now authenticated.
Hope this gives you a high-level understanding of the flow. Spring security offers us to customize these implementations and configure many more things.