Earlier this year, I had to integrate the spring-security with Active Directory, for authentication and authorization. Eventhough there were some documentation available, I had to struggle a bit to get this working. So it will be a good idea to share my findings here. I have been looking for the minimal configuration that accomplishes the goal.
Notes:
- The sAMAccountName attribute in AD stores the user login.
- The persion tag will populate the the details of the user in org.springframework.security.ldap.userdetails.Person class. This is handy if one needs to get more than the username like first name, last name etc.
- A number of ldap related tags are not documented well. Refer to the package org.springframework.security.config.ldap for details of the possible tags that can be used in the spring context.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:s="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> <s:http> <s:intercept-url access="IS_AUTHENTICATED_REMEMBERED" pattern="/secure/**"> <s:form-login login-page="login.html" default-target-url="/secure/homepage.do" always-use-default-target="true"/> <s:logout/> </s:intercept-url> </s:http> <s:ldap-server id="ldap-server" url="ldap://host:389/" root="" manager-dn="cn=xxx,ou=xxx,DC=corp,dc=xxx,dc=com" manager-password="xxx"/> <s:authentication-manager alias="authenticationManager"> <s:ldap-authentication-provider user-search-filter="(&(objectclass=user)(sAMAccountName={0}))" user-search-base="dc=corp,dc=xxx,dc=com" group-search-filter="(&(objectclass=group)(member={0}))" group-search-base="ou=xxx,dc=corp,dc=xxx,dc=com" user-details-class="person" role-prefix="none" /> </s:authentication-manager> </beans>For example, if one wants to extract the full name of the user:
import org.springframework.security.ldap.userdetails.Person; public String getFullName() { Person person = (Person) getAuthentication().getPrincipal(); String[] cn = person.getCn(); StringBuilder sbuf = new StringBuilder(""); if (cn != null && cn.length > 0) { for (String s : cn) { sbuf.append(s).append(" "); } } return sbuf.toString().trim(); }
Unit Testing
import org.junit.Test; import org.junit.runner.RunWith; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations={"classpath:spring-security-context.xml"}) public class AuthenticationTest { @Test public void testAuth() { // Authentication auth = mock(Authentication.class); // when(auth.getPrincipal()).thenReturn("rod"); // when(auth.getCredentials()).thenReturn("koala"); // Cannot mock authenticator as the ProviderManager checks for // an instance of UsrenamePasswordAuthenticationToken. So create // a concrete instance. Authentication auth = new UsernamePasswordAuthenticationToken("rod", "koala"); auth = authenticationManager.authenticate(auth); assertTrue(auth.isAuthenticated()); } @Autowired private AuthenticationManager authenticationManager; }
Using embedded ldap server
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:s="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> <s:http> <s:intercept-url pattern="/secure/**" access="IS_AUTHENTICATED_REMEMBERED" /> <s:form-login login-page="/login.html" default-target-url="/secure/homepage.do" always-use-default-target="true"/> <s:logout /> </s:http> <s:ldap-server ldif="classpath:users.ldif" port="33389"/> <s:authentication-manager alias="authenticationManager"> <s:ldap-authentication-provider group-search-filter="member={0}" group-search-base="ou=groups" user-search-base="ou=people" user-search-filter="uid={0}" user-details-class="person" role-prefix="none"/> </s:authentication-manager> </beans>
Very helpful, thanks!
ReplyDelete