Spring LDAP 的安全组角色属性

Spring Security groupRoleAttribute of LDAP

我的ldap树结构如下。我如何配置 groupRoleAttribute 以获得同级 records/tree (RolesList)?

ProfilesList
    Profile1
        UsersList
            uniqueMember=User1
            uniqueMember=User2
        RolesList
            uniqueMember=Role1
            uniqueMember=Role2
    Profile2
        UsersList
            uniqueMember=User3
            uniqueMember=User4
        RolesList
            uniqueMember=Role3
            uniqueMember=Role4

    <beans:bean class="org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator" id="ldapAuthoritiesPopulator">
        <beans:constructor-arg ref="contextSource" />
        <beans:constructor-arg value="ou=ProfilesList"/>
        <beans:property name="groupRoleAttribute" value="uniqueMember,cn=RolesList" />
        <beans:property name="groupSearchFilter" value="(&amp;(cn=UsersList)(uniqueMember={0}))"/>
    </beans:bean>

我最终编写了自己的 CustomLdapAuthoritiesPopulator 程序来支持此要求。希望对以后的人有所帮助。

    <beans:bean class="com.ldap.security.CustomLdapAuthoritiesPopulator" id="LdapAuthoritiesPopulator">
        <beans:constructor-arg ref="contextSource" />
        <beans:constructor-arg value="ou=Profile,ou=company"/>
    </beans:bean>

以下是我的 CustomLdapAuthoritiesPopulator。

import static org.springframework.ldap.query.LdapQueryBuilder.query;

import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.naming.Name;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.AbstractContextMapper;
import org.springframework.ldap.query.LdapQuery;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;

public class CustomLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator {
    private static final Logger logger = LoggerFactory.getLogger(CustomLdapAuthoritiesPopulator.class);

    private final LdapTemplate ldapTemplate;
    private String groupSearchBase;

    public CustomLdapAuthoritiesPopulator(ContextSource contextSource, String groupSearchBase) {
        this.ldapTemplate = new LdapTemplate(contextSource);
        this.groupSearchBase = groupSearchBase;
    }

    @Override
    public final Collection<GrantedAuthority> getGrantedAuthorities(DirContextOperations user, String username) {
        if (groupSearchBase == null) {
            return new HashSet<GrantedAuthority>();
        }

        logger.debug("Getting authorities for user " + user.getNameInNamespace());

        LdapQuery query = query().base(groupSearchBase)
                .where("cn").is("UsersList")
                .and("objectclass").is("groupOfUniqueNames")
                .and("uniqueMember").is(user.getNameInNamespace());

        logger.debug("query: " + query.toString());

        List<String> profileUsersList = ldapTemplate.search(query, new ProfileUsersListContextMapper());

        List<String[]> rolesList = new LinkedList<String[]>();
        for (String profile : profileUsersList) {
            query = query().base("ou="+profile+","+groupSearchBase)
                    .where("cn").is("RolesList");

            List<String[]> profileRolesList = ldapTemplate.search(query, new ProfileRolesListContextMapper());
            rolesList.addAll(profileRolesList);
        }

        Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
        for (String[] roles : rolesList) {
            for (String role : roles) {
                authorities.add(new SimpleGrantedAuthority(role));
            }
        }

        return authorities;
    }

    private static class ProfileUsersListContextMapper extends AbstractContextMapper<String> {
        public String doMapFromContext(DirContextOperations context) {
            String usersList = null;
            Name dn = context.getDn();
            if (!dn.isEmpty()) {
                if (dn.size() > 3) {
                    usersList = (dn.get(2).split("="))[1];
                }
            }
            return usersList;
        }
    }

    private static class ProfileRolesListContextMapper extends AbstractContextMapper<String[]> {
        public String[] doMapFromContext(DirContextOperations context) {
            String[] roleNames = null;

            String[] rolesList = context.getStringAttributes("uniqueMember");
            if (rolesList != null) {
                roleNames = new String[rolesList.length];
                for (int i = 0; i < rolesList.length; i++) {
                    String[] attributes = roleNames[i].split(",");
                    for (int j = 0; j < attributes.length; j++) {
                        String[] keyValue = attributes[j].split("=");
                        if ("cn".equalsIgnoreCase(keyValue[0])) {
                            roleNames[i] = keyValue[1];
                        }
                    }
                }
            }
            return roleNames;
        }
    }
}