BigBastis Blog

Java

Spring Security with custom AuthoritiesPopulator over LDAP

Posted on .

Spring Security with custom AuthoritiesPopulator over LDAP

Introduction

Java

Spring Security with custom AuthoritiesPopulator over LDAP

Posted on .

Spring offers you a lot of possibilities when it comes to configuration. But sometimes this billions of possibilities can be a real pita! Reacently i had to connect a Spring MVC application to a LDAP authentication server and since the webapp allready run on spring security i decided to keep it that way an use the LdapAuthenticationProvider offered by spring.

When your project is simple enough so you can use the default configurations offered by spring the complete working LDAP configuration can be as simple as this:

<security:authentication-manager>
	<security:ldap-authentication-provider 
		user-search-filter="(uid={0})"
		user-search-base="ou=users"
		group-search-filter="(uniqueMember={0})"
		group-search-base="ou=groups"
		group-role-attribute="cn"
		role-prefix="ROLE_">
	</security:ldap-authentication-provider>
 </security:authentication-manager>
 
 <security:ldap-server url="ldap://localhost:10389/o=mojo" 
	 manager-dn="uid=admin,ou=system" 
	 manager-password="secret" />

It’s as simple as that. Unfortunately our webapp doesn’t get the roles from the LDAP, it’s only used to authenticate the user, the roles are stored in a seperate database. So now we have to configure a seperate custom AuthoritiesPopulator for our users to get roles.

After a few minutes on google and stackoverflow a still haven’t found a suitable solution for my little problem, which is very strange since google AND stackoverflow combine all the human knowledge, right? 😉

I tried several combinations of different configurations and after a few hours i still haven’t found a good and complete example of a configuration i needed. I even started to think that my solution was to unusual to find some good examples.

But eventually after A LOT trial and error i managed to get it working. Looking back it’s not even complicated in any way, which makes me wonder why i haven’t found a complete example on the internet.

So just to document my solution for the next somebody who’s searching fo a similar way to implement LDAP in spring security, here’s my configuration:

spring-configuration:

<?xml version="1.0" encoding="windows-1252"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/security 
        http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <http use-expressions="true">
	    [...]
    </http>

	<authentication-manager>
		<authentication-provider ref='ldapAuthProvider'/>
	</authentication-manager>
	
	<beans:bean id="contextSource" 
		class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">

	    <beans:constructor-arg value="${ldap.url}" />
	    <beans:property name="userDn" value="${ldap.username}" />
	    <beans:property name="password" value="${ldap.password}" />
	</beans:bean>
	
	<beans:bean id="userSearch" 
		class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">

		<beans:constructor-arg index="0" value="" />
		<beans:constructor-arg index="1" value="(uid={0})" />
		<beans:constructor-arg index="2" ref="contextSource" />
		<beans:property name="searchSubtree" value="true" />
	</beans:bean>
	
   <beans:bean id="ldapAuthProvider" 
   		class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
     <beans:constructor-arg>
       <beans:bean 
       		class="org.springframework.security.ldap.authentication.BindAuthenticator">
			<beans:constructor-arg ref="contextSource" />
			<beans:property name="userDnPatterns">
				<beans:list>
					<beans:value>uid={0}</beans:value>
				</beans:list>
			</beans:property>
			<beans:property name="userSearch" ref="userSearch"/>
       </beans:bean>
     </beans:constructor-arg>
     <beans:constructor-arg>
       <beans:bean class="my.company.ldap.DatabaseAuthoritiesPopulator">
           <beans:constructor-arg ref="contextSource"/>
           <beans:constructor-arg value=""/>
           <beans:property name="groupRoleAttribute" value="cn"/>
       </beans:bean>
     </beans:constructor-arg>
   </beans:bean>
</beans:beans> 

DatabaseAuthoritiesPopulator.java

import java.util.HashSet;
import java.util.Set;

import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;

public class DatabaseAuthoritiesPopulator extends DefaultLdapAuthoritiesPopulator{

	public DatabaseAuthoritiesPopulator(ContextSource contextSource,String groupSearchBase) {
		super(contextSource, groupSearchBase);
	}
	
    public Set<GrantedAuthority> getAdditionalRoles(DirContextOperations user, String username) { 
    	//Get roles from a datasource of your choice
    	Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
        authorities.add((new SimpleGrantedAuthority("ROLE_USER")));
        return authorities;
    }
}

The tricky part is to set the „userSearch“ property on line 50. This property is optional and it’s easy to overlook. If this property is missing no LDAP search is performed and the LdapAuthenticationProvider tries to bind the user directly based on the given base(„“ in this case).

If you are having trouble testing the LDAP connection try activating DEBUG output for LdapAuthenticationProvider. Just put this logback.xml somewhere on your classpath:

<configuration>
	<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
		<!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder 
			by default -->
		<encoder>
			<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
			</pattern>
		</encoder>
	</appender>

	<logger level="DEBUG" additivity="false" name="org.springframework.security">
		<appender-ref ref="STDOUT" />
	</logger>
</configuration>

Now you have all the important information on your STDOUT.

profile

Sebastian Gross

http://www.bigbasti.com

Sebastian Gross arbeitet in Bielefeld als Softwareentwickler für .NET und Java im Bereich Web.Als Fan der .NET-Plattform lässt er sich kein Userguppen Treffen und Community Event im Raum OWL entgehen.Dabei hat er eine besondere Vorliebe für das ASP.NET MVC Framework und für das Test Driven Development (TDD) entwickelt.

There are no comments.

Kommentar verfassen

View Comments (0) ...
Navigation