Browse Source

Add Flag to enable searching of LDAP groups on subtrees

Closes gh-8939
Roberto Paolillo 5 years ago
parent
commit
2cccf223df

+ 26 - 1
config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.java

@@ -42,7 +42,7 @@ import org.springframework.test.web.servlet.MockMvc;
 import java.io.IOException;
 import java.net.ServerSocket;
 import java.util.List;
-
+import javax.naming.directory.SearchControls;
 import static java.util.Collections.singleton;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
@@ -67,6 +67,8 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
 		assertThat(authoritiesPopulator).hasFieldOrPropertyWithValue("groupRoleAttribute", "cn");
 		assertThat(authoritiesPopulator).hasFieldOrPropertyWithValue("groupSearchBase", "");
 		assertThat(authoritiesPopulator).hasFieldOrPropertyWithValue("groupSearchFilter", "(uniqueMember={0})");
+		assertThat(authoritiesPopulator).extracting("searchControls").hasFieldOrPropertyWithValue("searchScope",
+				SearchControls.ONELEVEL_SCOPE);
 		assertThat(ReflectionTestUtils.getField(getAuthoritiesMapper(provider), "prefix")).isEqualTo("ROLE_");
 	}
 
@@ -124,6 +126,29 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
 		// @formatter:on
 	}
 
+	@Test
+	public void groupSubtreeSearchCustom() {
+		this.spring.register(GroupSubtreeSearchConfig.class).autowire();
+		LdapAuthenticationProvider provider = ldapProvider();
+
+		assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "searchControls"))
+				.extracting("searchScope").isEqualTo(SearchControls.SUBTREE_SCOPE);
+	}
+
+	@EnableWebSecurity
+	static class GroupSubtreeSearchConfig extends BaseLdapProviderConfig {
+		// @formatter:off
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			auth
+				.ldapAuthentication()
+					.contextSource(contextSource())
+					.userDnPatterns("uid={0},ou=people")
+					.groupSearchFilter("ou=groupName")
+					.groupSearchSubtree(true);
+		}
+		// @formatter:on
+	}
+
 	@Test
 	public void rolePrefixCustom() {
 		this.spring.register(RolePrefixConfig.class).autowire();

+ 25 - 0
config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderConfigurerTests.java

@@ -21,9 +21,11 @@ import org.junit.Test;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.authentication.ldap.LdapAuthenticationProviderBuilderSecurityBuilderTests.BaseLdapProviderConfig;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
 import org.springframework.security.config.test.SpringTestRule;
+import org.springframework.security.core.authority.AuthorityUtils;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.test.web.servlet.MockMvc;
 
@@ -70,6 +72,15 @@ public class LdapAuthenticationProviderConfigurerTests {
 				.andExpect(authenticated().withUsername("bob"));
 	}
 
+	@Test
+	public void authenticationManagerWhenSearchSubtreeThenNestedGroupFound() throws Exception {
+		this.spring.register(GroupSubtreeSearchConfig.class).autowire();
+
+		this.mockMvc.perform(formLogin().user("ben").password("benspassword"))
+				.andExpect(authenticated().withUsername("ben").withAuthorities(
+						AuthorityUtils.createAuthorityList("ROLE_SUBMANAGERS", "ROLE_MANAGERS", "ROLE_DEVELOPERS")));
+	}
+
 	@EnableWebSecurity
 	static class MultiLdapAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
 		// @formatter:off
@@ -121,4 +132,18 @@ public class LdapAuthenticationProviderConfigurerTests {
 						.port(0);
 		}
 	}
+
+	@EnableWebSecurity
+	static class GroupSubtreeSearchConfig extends BaseLdapProviderConfig {
+		// @formatter:off
+		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+			auth
+				.ldapAuthentication()
+					.groupSearchBase("ou=groups")
+					.groupSearchFilter("(member={0})")
+					.groupSearchSubtree(true)
+					.userDnPatterns("uid={0},ou=people");
+		}
+		// @formatter:on
+	}
 }

+ 15 - 0
config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java

@@ -61,6 +61,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
 		extends SecurityConfigurerAdapter<AuthenticationManager, B> {
 	private String groupRoleAttribute = "cn";
 	private String groupSearchBase = "";
+	private boolean groupSearchSubtree = false;
 	private String groupSearchFilter = "(uniqueMember={0})";
 	private String rolePrefix = "ROLE_";
 	private String userSearchBase = ""; // only for search
@@ -130,6 +131,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
 				contextSource, groupSearchBase);
 		defaultAuthoritiesPopulator.setGroupRoleAttribute(groupRoleAttribute);
 		defaultAuthoritiesPopulator.setGroupSearchFilter(groupSearchFilter);
+		defaultAuthoritiesPopulator.setSearchSubtree(groupSearchSubtree);
 		defaultAuthoritiesPopulator.setRolePrefix(this.rolePrefix);
 
 		this.ldapAuthoritiesPopulator = defaultAuthoritiesPopulator;
@@ -320,6 +322,19 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
 		return this;
 	}
 
+	/**
+	 * If set to true, a subtree scope search will be performed for group membership. If false a
+	 * single-level search is used.
+	 *
+	 * @param searchSubtree set to true to enable searching of the entire tree below the
+	 *                      <tt>groupSearchBase</tt>.
+	 * @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
+	 */
+	public LdapAuthenticationProviderConfigurer<B> groupSearchSubtree(boolean groupSearchSubtree) {
+		this.groupSearchSubtree = groupSearchSubtree;
+		return this;
+	}
+
 	/**
 	 * The LDAP filter to search for groups. Defaults to "(uniqueMember={0})". The
 	 * substituted parameter is the DN of the user.