Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use a custom authorities populator with Spring Security and the ActiveDirectoryLdapAuthenticationProvider?

I've successfully connected to Active Directory through LDAP to authenticate, and with the following in my ldap.xml I've called my custom authorities populator:

    <bean id="ldapAuthenticationProvider"
        class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
    <constructor-arg ref="ldapBindAuthenticator"/>
    <constructor-arg ref="ldapAuthoritiesPopulator"/>
</bean>

<bean id="ldapBindAuthenticator"
        class="org.springframework.security.ldap.authentication.BindAuthenticator">
    <constructor-arg ref="ldapServer"/>
    <property name="userSearch" ref="ldapSearch"/>
</bean>

<bean id="ldapSearch"
        class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
    <constructor-arg value="CN=Users"/>
    <constructor-arg value="(sAMAccountName={0})"/>
    <constructor-arg ref="ldapServer"/>
</bean>

<bean id="ldapAuthoritiesPopulator"
        class="my.project.package.ActiveDirectoryLdapAuthoritiesPopulator"/>

<bean id="ldapServer"
        class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
    <constructor-arg value="ldap://192.168.0.2/dc=test,dc=server"/>

    <property name="userDn" value="[email protected]"/>
    <property name="password" value="ldap"/>
    <property name="baseEnvironmentProperties">
        <map>
            <entry key="java.naming.referral">
                <value>follow</value>
            </entry>
        </map>
    </property>
</bean>

This works fine, and I can ascertain the user's authorization based on her group membership, but I would rather do this through the built-in Active Directory LDAP Authentication Provider:

<bean id="ldapAuthenticationProvider"
        class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">

        <constructor-arg value="test.server"/>
        <constructor-arg value="ldap://192.168.0.2:389"/>
        <property name="convertSubErrorCodesToExceptions" value="true"/>
</bean>

The problem with the above is that my custom authorities populator is (obviously) not called, so while I can authenticate my users (which works with the above), I am left without the groups (which I need to determine authorization).

I feel like this is a simple question, but for the life of me I cannot find an answer here or anywhere else. Do I have to extend the ActiveDirectoryLdapAuthenticationProvider class, and call my authorities populator from there?

(Thanks for all the help this site has given me for several years running; the effectiveness of this site can be gauged by the fact that I've only recently bothered to create an account, and this is my first question. Thanks in advance for your help.)

like image 415
cabbagery Avatar asked Apr 19 '13 20:04

cabbagery


1 Answers

Spring's ActiveDirectoryLdapAuthenticationProvider class is final, so my only real option (I'll entertain better ones if there are any takers) was to fork the class. I copied and pasted its contents, refactored slightly, and removed the final designation. Then, I created a separate subclass of the forked class, overriding the loadUserAuthorities() method, and added my own code for building a permissions mask.

I was then able to edit my ldap.xml file as follows:

    <bean id="ldapAuthenticationProvider"
            class="my.project.package.OverrideActiveDirectoryLdapAuthenticationProvider">   
        <constructor-arg value="test.server"/>
        <constructor-arg value="ldap://192.168.0.2:389"/>
        <property name="convertSubErrorCodesToExceptions" value="true"/>
</bean>

For any other n00bs like me, the subclass looks like this:

public class OverrideActiveDirectoryLdapAuthenticationProvider extends TestActiveDirectoryLdapAuthenticationProvider {

//my assignments

public OverrideActiveDirectoryLdapAuthenticationProvider(String domain,
        String url) {
    super(domain, url);
}

@Override
protected Collection<? extends GrantedAuthority> loadUserAuthorities(DirContextOperations userData, String username, String password) {
//original code with my own additions
//in my case, I injected code into the for(group : groups) loop
}

Worked like a charm.

Much thanks to zagyi for the assistance.

like image 52
cabbagery Avatar answered Sep 19 '22 06:09

cabbagery