spring security NestedLdapAuthoritiesPopulator 源码

  • 2022-08-13
  • 浏览 (381)

spring security NestedLdapAuthoritiesPopulator 代码

文件路径:/ldap/src/main/java/org/springframework/security/ldap/userdetails/NestedLdapAuthoritiesPopulator.java

/*
 * Copyright 2002-2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.security.ldap.userdetails;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.core.log.LogMessage;
import org.springframework.ldap.core.ContextSource;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.ldap.SpringSecurityLdapTemplate;
import org.springframework.util.StringUtils;

/**
 * A LDAP authority populator that can recursively search static nested groups.
 * <p>
 * An example of nested groups can be
 *
 * <pre>
 *  #Nested groups data
 *
 *  dn: uid=javadude,ou=people,dc=springframework,dc=org
 *  objectclass: top
 *  objectclass: person
 *  objectclass: organizationalPerson
 *  objectclass: inetOrgPerson
 *  cn: Java Dude
 *  sn: Dude
 *  uid: javadude
 *  userPassword: javadudespassword
 *
 *  dn: uid=groovydude,ou=people,dc=springframework,dc=org
 *  objectclass: top
 *  objectclass: person
 *  objectclass: organizationalPerson
 *  objectclass: inetOrgPerson
 *  cn: Groovy Dude
 *  sn: Dude
 *  uid: groovydude
 *  userPassword: groovydudespassword
 *
 *  dn: uid=closuredude,ou=people,dc=springframework,dc=org
 *  objectclass: top
 *  objectclass: person
 *  objectclass: organizationalPerson
 *  objectclass: inetOrgPerson
 *  cn: Closure Dude
 *  sn: Dude
 *  uid: closuredude
 *  userPassword: closuredudespassword
 *
 *  dn: uid=scaladude,ou=people,dc=springframework,dc=org
 *  objectclass: top
 *  objectclass: person
 *  objectclass: organizationalPerson
 *  objectclass: inetOrgPerson
 *  cn: Scala Dude
 *  sn: Dude
 *  uid: scaladude
 *  userPassword: scaladudespassword
 *
 *  dn: cn=j-developers,ou=jdeveloper,dc=springframework,dc=org
 *  objectclass: top
 *  objectclass: groupOfNames
 *  cn: j-developers
 *  ou: jdeveloper
 *  member: cn=java-developers,ou=groups,dc=springframework,dc=org
 *
 *  dn: cn=java-developers,ou=jdeveloper,dc=springframework,dc=org
 *  objectclass: top
 *  objectclass: groupOfNames
 *  cn: java-developers
 *  ou: jdeveloper
 *  member: cn=groovy-developers,ou=groups,dc=springframework,dc=org
 *  member: cn=scala-developers,ou=groups,dc=springframework,dc=org
 *  member: uid=javadude,ou=people,dc=springframework,dc=org
 *
 *  dn: cn=groovy-developers,ou=jdeveloper,dc=springframework,dc=org
 *  objectclass: top
 *  objectclass: groupOfNames
 *  cn: java-developers
 *  ou: jdeveloper
 *  member: cn=closure-developers,ou=groups,dc=springframework,dc=org
 *  member: uid=groovydude,ou=people,dc=springframework,dc=org
 *
 *  dn: cn=closure-developers,ou=jdeveloper,dc=springframework,dc=org
 *  objectclass: top
 *  objectclass: groupOfNames
 *  cn: java-developers
 *  ou: jdeveloper
 *  member: uid=closuredude,ou=people,dc=springframework,dc=org
 *
 *  dn: cn=scala-developers,ou=jdeveloper,dc=springframework,dc=org
 *  objectclass: top
 *  objectclass: groupOfNames
 *  cn: java-developers
 *  ou: jdeveloper
 *  member: uid=scaladude,ou=people,dc=springframework,dc=org *
 * </pre>
 *
 * @author Filip Hanik
 */

public class NestedLdapAuthoritiesPopulator extends DefaultLdapAuthoritiesPopulator {

	private static final Log logger = LogFactory.getLog(NestedLdapAuthoritiesPopulator.class);

	/**
	 * The attribute names to retrieve for each LDAP group
	 */
	private Set<String> attributeNames;

	/**
	 * Maximum search depth - represents the number of recursive searches performed
	 */
	private int maxSearchDepth = 10;

	/**
	 * Constructor for group search scenarios. <tt>userRoleAttributes</tt> may still be
	 * set as a property.
	 * @param contextSource supplies the contexts used to search for user roles.
	 * @param groupSearchBase if this is an empty string the search will be performed from
	 * the root DN of the
	 */
	public NestedLdapAuthoritiesPopulator(ContextSource contextSource, String groupSearchBase) {
		super(contextSource, groupSearchBase);
	}

	@Override
	public Set<GrantedAuthority> getGroupMembershipRoles(String userDn, String username) {
		if (getGroupSearchBase() == null) {
			return new HashSet<>();
		}
		Set<GrantedAuthority> authorities = new HashSet<>();
		performNestedSearch(userDn, username, authorities, getMaxSearchDepth());
		return authorities;
	}

	/**
	 * Performs the nested group search
	 * @param userDn - the userDN to search for, will become the group DN for subsequent
	 * searches
	 * @param username - the username of the user
	 * @param authorities - the authorities set that will be populated, must not be null
	 * @param depth - the depth remaining, when 0 recursion will end
	 */
	private void performNestedSearch(String userDn, String username, Set<GrantedAuthority> authorities, int depth) {
		if (depth == 0) {
			// back out of recursion
			logger.debug(LogMessage.of(() -> "Aborted search since max depth reached," + " for roles for user '"
					+ username + " with DN = " + userDn + " and filter " + getGroupSearchFilter() + " in search base '"
					+ getGroupSearchBase() + "'"));
			return;
		}
		logger.trace(LogMessage.of(() -> "Searching for roles for user " + username + " with DN " + userDn
				+ " and filter " + getGroupSearchFilter() + " in search base " + getGroupSearchBase()));
		if (getAttributeNames() == null) {
			setAttributeNames(new HashSet<>());
		}
		if (StringUtils.hasText(getGroupRoleAttribute()) && !getAttributeNames().contains(getGroupRoleAttribute())) {
			getAttributeNames().add(getGroupRoleAttribute());
		}
		Set<Map<String, List<String>>> userRoles = getLdapTemplate().searchForMultipleAttributeValues(
				getGroupSearchBase(), getGroupSearchFilter(), new String[] { userDn, username },
				getAttributeNames().toArray(new String[0]));
		logger.debug(LogMessage.format("Found roles from search %s", userRoles));
		for (Map<String, List<String>> record : userRoles) {
			boolean circular = false;
			String dn = record.get(SpringSecurityLdapTemplate.DN_KEY).get(0);
			List<String> roleValues = record.get(getGroupRoleAttribute());
			Set<String> roles = new HashSet<>();
			if (roleValues != null) {
				roles.addAll(roleValues);
			}
			for (String role : roles) {
				if (isConvertToUpperCase()) {
					role = role.toUpperCase();
				}
				role = getRolePrefix() + role;
				// if the group already exist, we will not search for it's parents again.
				// this prevents a forever loop for a misconfigured ldap directory
				circular = circular | (!authorities.add(new LdapAuthority(role, dn, record)));
			}
			String roleName = (roles.size() > 0) ? roles.iterator().next() : dn;
			if (!circular) {
				performNestedSearch(dn, roleName, authorities, (depth - 1));
			}
		}
	}

	/**
	 * Returns the attribute names that this populator has been configured to retrieve
	 * Value can be null, represents fetch all attributes
	 * @return the attribute names or null for all
	 */
	private Set<String> getAttributeNames() {
		return this.attributeNames;
	}

	/**
	 * Sets the attribute names to retrieve for each ldap groups. Null means retrieve all
	 * @param attributeNames - the names of the LDAP attributes to retrieve
	 */
	public void setAttributeNames(Set<String> attributeNames) {
		this.attributeNames = attributeNames;
	}

	/**
	 * How far should a nested search go. Depth is calculated in the number of levels we
	 * search up for parent groups.
	 * @return the max search depth, default is 10
	 */
	private int getMaxSearchDepth() {
		return this.maxSearchDepth;
	}

	/**
	 * How far should a nested search go. Depth is calculated in the number of levels we
	 * search up for parent groups.
	 * @param maxSearchDepth the max search depth
	 */
	public void setMaxSearchDepth(int maxSearchDepth) {
		this.maxSearchDepth = maxSearchDepth;
	}

}

相关信息

spring security 源码目录

相关文章

spring security DefaultLdapAuthoritiesPopulator 源码

spring security InetOrgPerson 源码

spring security InetOrgPersonContextMapper 源码

spring security LdapAuthoritiesPopulator 源码

spring security LdapAuthority 源码

spring security LdapUserDetails 源码

spring security LdapUserDetailsImpl 源码

spring security LdapUserDetailsManager 源码

spring security LdapUserDetailsMapper 源码

spring security LdapUserDetailsService 源码

0  赞