16

I'm trying to use a authenticate with an Active directory using Spring Security 3.1. I get authenticated and all is well.

<sec:ldap-server id="ldapServer" url="ldap://ldap/dc=sub,dc=domain,dc=com" port="389" />

<sec:authentication-manager erase-credentials="true"  >
    <sec:authentication-provider ref="ldapActiveDirectoryAuthProvider" />
</sec:authentication-manager>

<bean id="ldapActiveDirectoryAuthProvider" 
        class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
    <constructor-arg value="domain" />
    <constructor-arg value="ldap://server:389/"/> 
</bean>

Now to the question. How do I handle roles for the user so that I can setup my filters?

eg.

<sec:intercept-url pattern="/**" access="ROLE_USER"/>

Solution

I found out how to do this by using the UserDetailContextMapper and map my AD groups to ROLE_USER,ROLE_ADMIN etc.

    <bean id="ldapActiveDirectoryAuthProvider" 
        class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
    <constructor-arg value="domain" />
    <constructor-arg value="ldap://host:389/"/> 
    <property name="userDetailsContextMapper" ref="tdrUserDetailsContextMapper"/>
    <property name="useAuthenticationRequestCredentials" value="true"/>
</bean>

<bean id="tdrUserDetailsContextMapper" class="com.bla.bla.UserDetailsContextMapperImpl"/>

Mapper class:

public class UserDetailsContextMapperImpl implements UserDetailsContextMapper, Serializable{
    private static final long serialVersionUID = 3962976258168853954L;

    @Override
    public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authority) {

        List<GrantedAuthority> mappedAuthorities = new ArrayList<GrantedAuthority>();


        for (GrantedAuthority granted : authority) {

            if (granted.getAuthority().equalsIgnoreCase("MY USER GROUP")) {
                mappedAuthorities.add(new GrantedAuthority(){
                    private static final long serialVersionUID = 4356967414267942910L;

                    @Override
                    public String getAuthority() {
                        return "ROLE_USER";
                    } 

                });
            } else if(granted.getAuthority().equalsIgnoreCase("MY ADMIN GROUP")) {
                mappedAuthorities.add(new GrantedAuthority() {
                    private static final long serialVersionUID = -5167156646226168080L;

                    @Override
                    public String getAuthority() {
                        return "ROLE_ADMIN";
                    }
                });
            }
        }
        return new User(username, "", true, true, true, true, mappedAuthorities);
    }

    @Override
    public void mapUserToContext(UserDetails arg0, DirContextAdapter arg1) {
    }
}
heldt
  • 4,166
  • 7
  • 39
  • 67
  • Hey, can you point me to guide to get started with ldap. I find their documentation spotty. IE talks about config files, but I have no idea where to put them – Cripto Oct 02 '14 at 04:35

2 Answers2

15

You can also inject a GrantedAuthoritiesMapper which was introduced in 3.1 as a general strategy for modifying the authorites. Plus you might want to use SimpleGrantedAuthority for the GrantedAuthority implementation. Alternatively, you could use an enum since you have a fixed set of values:

enum MyAuthority implements GrantedAuthority {
    ROLE_ADMIN,
    ROLE_USER;

    public String getAuthority() {
        return name();
    }
}


class MyAuthoritiesMapper implements GrantedAuthoritiesMapper {

    public Collection<? extends GrantedAuthority> mapAuthorities(Collection<? extends GrantedAuthority> authorities) {
        Set<MyAuthority> roles = EnumSet.noneOf(MyAuthority.class);

        for (GrantedAuthority a: authorities) {
            if ("MY ADMIN GROUP".equals(a.getAuthority())) {
                roles.add(MyAuthority.ROLE_ADMIN);
            } else if ("MY USER GROUP".equals(a.getAuthority())) {
                roles.add(MyAuthority.ROLE_USER);
            }
        }

        return roles;
    }
}
Shaun the Sheep
  • 22,353
  • 1
  • 72
  • 100
  • Thanks for this great answer. Did I overlook it in the spring documenation? With the `ldap-authentication-provider` and `user-context-mapper-ref` it is possible to set up ldap configuration in just a few lines, it took me a while to find this out though. – dr jerry Apr 18 '14 at 08:52
  • Can you link or write a complete example? I used it but look like my User still have Active Directory Group as authorities – sintetico82 Jul 25 '17 at 16:05
1

The roles in the beans.xml must be an exact match of the CN (common name) of the memberOf value attribute. You should read a tutorial about directory basics.

Say have this user: CN=Michael-O,OU=Users,OU=department,DC=sub,DC=company,DC=net In his context exists this memberOf value CN=Group Name,OU=Permissions,OU=Groups,OU=department,DC=sub,DC=company,DC=net

The Bean will locate this memberOf value and extract Group Name. You beans.xml has to have exactly this value.

Michael-O
  • 18,123
  • 6
  • 55
  • 121
  • My question might be some what unclear. I added my solution to my post. Your post was correct. – heldt Jan 13 '12 at 14:30