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