0
votes

I using ldap spring security to authenticate user. No problem with the authentication. Because of complex authorities we have created a CustomLdapAuthoritiesPopulator, see below program. Everything working fine but the connection is not closing. Every user login it create a new connection when execute the following line

List<String> appGroupUsersList = ldapTemplate.search(query, new AppGroupUsersListContextMapper());

How can i close the connection after i get the authorities from ldap?

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

    private final LdapTemplate ldapTemplate;
    private String groupSearchBase;

    public AblLdapAuthoritiesPopulator(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> appGroupUsersList = ldapTemplate.search(query, new AppGroupUsersListContextMapper());
        logger.debug("appGroupUsersList: " + appGroupUsersList.toString());
        if(appGroupUsersList.size() == 0) {
            throw new BadCredentialsException("Unauthorized Access");
        }

        List<String[]> functionsList = new LinkedList<String[]>();
        for (String appGroup : appGroupUsersList) {
            query = query().base("ou="+appGroup+","+groupSearchBase)
                    .where("cn").is("FunctionsList");

            List<String[]> appGroupFunctionsList = ldapTemplate.search(query, new AppGroupFunctionsListContextMapper());
            functionsList.addAll(appGroupFunctionsList);
        }

        Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
        for (String[] roles : functionsList) {
            for (String role : roles) {
                authorities.add(new SimpleGrantedAuthority(role));
            }
        }
        logger.debug("authorities: " + authorities.size());

        return authorities;
    }

    private static class AppGroupUsersListContextMapper 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 AppGroupFunctionsListContextMapper extends AbstractContextMapper<String[]> {
        public String[] doMapFromContext(DirContextOperations context) {
            String[] functionNames = null;
            String[] functionsList = context.getStringAttributes("uniqueMember");
            if (functionsList != null) {
                functionNames = new String[functionsList.length];
                for (int i = 0; i < functionsList.length; i++) {
                    String[] attributes = functionsList[i].split(",");
                    for (int j = 0; j < attributes.length; j++) {
                        String[] keyValue = attributes[j].split("=");
                        if ("cn".equalsIgnoreCase(keyValue[0])) {
                            functionNames[i] = keyValue[1];
                        }
                    }
                }
            }
            return functionNames;
        }
    }
}
1

1 Answers

0
votes

After i added the pooled=false in the DefaultSpringSecurityContextSource the issue resolved. the following is my configuration in xml.

<bean class="org.springframework.security.ldap.DefaultSpringSecurityContextSource" id="contextSource">
        <constructor-arg value="${ldap.url}"/>
        <property name="pooled" value="false" />
        <property name="userDn" value="${ldap.managerUser}"/>
        <property name="password" value="${ldap.managerPassword}"/>
    </bean>

<ldap:ldap-template id="ldapTemplate" ignore-name-not-found="true" context-source-ref="contextSource"/>

<authentication-manager alias="authenticationManager">
        <authentication-provider ref="customLdapAuthProvider"/>
    </authentication-manager>

    <beans:bean class="com.xxx.web.security.CustomLdapAuthenticationProvider" id="customLdapAuthProvider"/>

    <beans:bean class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider" id="ldapAuthProvider">
        <beans:constructor-arg ref="ldapBindAuthenticator"/>
        <beans:constructor-arg ref="LdapAuthoritiesPopulator"/>
        <beans:property name="userDetailsContextMapper" ref="ldapUserDetailsContextMapper"/>
    </beans:bean>

    <beans:bean class="com.xxx.web.security.CustomBindAuthenticator" id="ldapBindAuthenticator">
        <beans:constructor-arg ref="contextSource"/>
        <beans:property name="userSearch" ref="ldapSearchBean"/>
    </beans:bean>

    <beans:bean class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch" id="ldapSearchBean">
        <beans:constructor-arg value="${ldap.userSearchBase}"/>
        <beans:constructor-arg value="${ldap.userAttribute}"/>
        <beans:constructor-arg ref="contextSource"/>
    </beans:bean>

    <beans:bean class="com.xxx.web.security.CustomLdapAuthoritiesPopulator" id="LdapAuthoritiesPopulator">
        <beans:constructor-arg ref="contextSource" />
        <beans:constructor-arg value="${ldap.groupSearchBase}"/>
    </beans:bean>