Repository: knox Updated Branches: refs/heads/master 6eb64e525 -> 62a75e0e0
KNOX-644 - Limit/page results of LDAP group membership search (Kevin Risden via lmccay) Project: http://git-wip-us.apache.org/repos/asf/knox/repo Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/62a75e0e Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/62a75e0e Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/62a75e0e Branch: refs/heads/master Commit: 62a75e0e015ae35f27a08e156f792b6e5517fb6a Parents: 6eb64e5 Author: Larry McCay <lmc...@hortonworks.com> Authored: Sun Oct 2 13:01:34 2016 -0400 Committer: Larry McCay <lmc...@hortonworks.com> Committed: Sun Oct 2 13:01:34 2016 -0400 ---------------------------------------------------------------------- .../ldap/BaseDirectoryServiceFactory.java | 4 +- .../ldap/SimpleLdapDirectoryServer.java | 4 +- .../gateway/shirorealm/KnoxLdapRealm.java | 105 +++++++++++++------ .../apache/hadoop/gateway/GatewayMessages.java | 9 ++ pom.xml | 2 +- 5 files changed, 89 insertions(+), 35 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/knox/blob/62a75e0e/gateway-demo-ldap/src/main/java/org/apache/hadoop/gateway/security/ldap/BaseDirectoryServiceFactory.java ---------------------------------------------------------------------- diff --git a/gateway-demo-ldap/src/main/java/org/apache/hadoop/gateway/security/ldap/BaseDirectoryServiceFactory.java b/gateway-demo-ldap/src/main/java/org/apache/hadoop/gateway/security/ldap/BaseDirectoryServiceFactory.java index dc3468d..2d2bc1f 100644 --- a/gateway-demo-ldap/src/main/java/org/apache/hadoop/gateway/security/ldap/BaseDirectoryServiceFactory.java +++ b/gateway-demo-ldap/src/main/java/org/apache/hadoop/gateway/security/ldap/BaseDirectoryServiceFactory.java @@ -206,7 +206,7 @@ public class BaseDirectoryServiceFactory implements DirectoryServiceFactory directoryService.setSchemaManager( schemaManager ); // Init the LdifPartition - LdifPartition ldifPartition = new LdifPartition( schemaManager /*, directoryService.getDnFactory()*/ ); + LdifPartition ldifPartition = new LdifPartition( schemaManager, directoryService.getDnFactory() ); ldifPartition.setPartitionPath( new File( workingDirectory, "schema" ).toURI() ); SchemaPartition schemaPartition = new SchemaPartition( schemaManager ); schemaPartition.setWrappedPartition( ldifPartition ); @@ -235,7 +235,7 @@ public class BaseDirectoryServiceFactory implements DirectoryServiceFactory // Inject the System Partition Partition systemPartition = partitionFactory.createPartition( directoryService.getSchemaManager(), - //directoryService.getDnFactory(), + directoryService.getDnFactory(), "system", ServerDNConstants.SYSTEM_DN, 500, http://git-wip-us.apache.org/repos/asf/knox/blob/62a75e0e/gateway-demo-ldap/src/main/java/org/apache/hadoop/gateway/security/ldap/SimpleLdapDirectoryServer.java ---------------------------------------------------------------------- diff --git a/gateway-demo-ldap/src/main/java/org/apache/hadoop/gateway/security/ldap/SimpleLdapDirectoryServer.java b/gateway-demo-ldap/src/main/java/org/apache/hadoop/gateway/security/ldap/SimpleLdapDirectoryServer.java index efa8df8..12fe30d 100644 --- a/gateway-demo-ldap/src/main/java/org/apache/hadoop/gateway/security/ldap/SimpleLdapDirectoryServer.java +++ b/gateway-demo-ldap/src/main/java/org/apache/hadoop/gateway/security/ldap/SimpleLdapDirectoryServer.java @@ -57,7 +57,8 @@ public class SimpleLdapDirectoryServer { enabledPosixSchema( service ); Partition partition = factory.getPartitionFactory().createPartition( - service.getSchemaManager(), "users", rootDn, 500, service.getInstanceLayout().getInstanceDirectory() ); + service.getSchemaManager(), service.getDnFactory(), "users", rootDn, 500, + service.getInstanceLayout().getInstanceDirectory() ); service.addPartition( partition ); CoreSession session = service.getAdminSession(); @@ -67,7 +68,6 @@ public class SimpleLdapDirectoryServer { server = new LdapServer(); server.setTransports( transports ); server.setDirectoryService( service ); - } private static void enabledPosixSchema( DirectoryService service ) throws LdapException { http://git-wip-us.apache.org/repos/asf/knox/blob/62a75e0e/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java ---------------------------------------------------------------------- diff --git a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java b/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java index eb1e862..4cfc7e9 100644 --- a/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java +++ b/gateway-provider-security-shiro/src/main/java/org/apache/hadoop/gateway/shirorealm/KnoxLdapRealm.java @@ -19,6 +19,7 @@ package org.apache.hadoop.gateway.shirorealm; +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -33,13 +34,19 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.naming.AuthenticationException; +import javax.naming.Context; import javax.naming.NamingEnumeration; import javax.naming.NamingException; +import javax.naming.PartialResultException; +import javax.naming.SizeLimitExceededException; import javax.naming.directory.Attribute; import javax.naming.directory.SearchControls; import javax.naming.directory.SearchResult; +import javax.naming.ldap.Control; import javax.naming.ldap.LdapContext; import javax.naming.ldap.LdapName; +import javax.naming.ldap.PagedResultsControl; +import javax.naming.ldap.PagedResultsResponseControl; import org.apache.hadoop.gateway.GatewayMessages; import org.apache.hadoop.gateway.audit.api.Action; @@ -245,43 +252,81 @@ public class KnoxLdapRealm extends JndiLdapRealm { private Set<String> rolesFor(PrincipalCollection principals, final String userName, final LdapContext ldapCtx, final LdapContextFactory ldapContextFactory) throws NamingException { - final Set<String> roleNames = new HashSet(); - final Set<String> groupNames = new HashSet(); - NamingEnumeration<SearchResult> searchResultEnum = null; - try { + final Set<String> roleNames = new HashSet<>(); + final Set<String> groupNames = new HashSet<>(); + + String userDn; + if (userSearchAttributeName == null || userSearchAttributeName.isEmpty()) { + // memberAttributeValuePrefix and memberAttributeValueSuffix were computed from memberAttributeValueTemplate + userDn = memberAttributeValuePrefix + userName + memberAttributeValueSuffix; + } else { + userDn = getUserDn(userName); + } + + // Activate paged results + int pageSize = 100; + int numResults = 0; + byte[] cookie = null; + try { + ldapCtx.addToEnvironment(Context.REFERRAL, "ignore"); + + ldapCtx.setRequestControls(new Control[]{new PagedResultsControl(pageSize, Control.NONCRITICAL)}); + + do { // ldapsearch -h localhost -p 33389 -D uid=guest,ou=people,dc=hadoop,dc=apache,dc=org -w guest-password // -b dc=hadoop,dc=apache,dc=org -s sub '(objectclass=*)' - searchResultEnum = ldapCtx.search( - getGroupSearchBase(), - "objectClass=" + groupObjectClass, - SUBTREE_SCOPE); - - String userDn = null; - if (userSearchAttributeName == null || userSearchAttributeName.isEmpty()) { - // memberAttributeValuePrefix and memberAttributeValueSuffix were computed from memberAttributeValueTemplate - userDn = memberAttributeValuePrefix + userName + memberAttributeValueSuffix; - } else { - userDn = getUserDn(userName); - } - while (searchResultEnum.hasMore()) { // searchResults contains all the groups in search scope + + NamingEnumeration<SearchResult> searchResultEnum = null; + try { + searchResultEnum = ldapCtx.search( + getGroupSearchBase(), + "objectClass=" + groupObjectClass, + SUBTREE_SCOPE); + + while (searchResultEnum != null && searchResultEnum.hasMore()) { // searchResults contains all the groups in search scope + numResults++; final SearchResult group = searchResultEnum.next(); addRoleIfMember(userDn, group, roleNames, groupNames, ldapContextFactory); + } + } catch (PartialResultException e) { + LOG.ignoringPartialResultException(); + } finally { + if (searchResultEnum != null) { + searchResultEnum.close(); + } } - // save role names and group names in session so that they can be easily looked up outside of this object - SecurityUtils.getSubject().getSession().setAttribute(SUBJECT_USER_ROLES, roleNames); - SecurityUtils.getSubject().getSession().setAttribute(SUBJECT_USER_GROUPS, groupNames); - if (!groupNames.isEmpty() && (principals instanceof MutablePrincipalCollection)) { - ((MutablePrincipalCollection)principals).addAll(groupNames, getName()); - } - LOG.lookedUpUserRoles(roleNames, userName); - } - finally { - if (searchResultEnum != null) { - searchResultEnum.close(); + // Examine the paged results control response + Control[] controls = ldapCtx.getResponseControls(); + if (controls != null) { + for (Control control : controls) { + if (control instanceof PagedResultsResponseControl) { + PagedResultsResponseControl prrc = (PagedResultsResponseControl) control; + cookie = prrc.getCookie(); + } + } } - } - return roleNames; + + // Re-activate paged results + ldapCtx.setRequestControls(new Control[]{new PagedResultsControl(pageSize, cookie, Control.CRITICAL)}); + } while (cookie != null); + } catch (SizeLimitExceededException e) { + LOG.sizeLimitExceededOnlyRetrieved(numResults); +// System.out.println("Only retrieved first " + numResults + " groups due to SizeLimitExceededException."); + } catch(IOException e) { + LOG.unableToSetupPagedResults(); +// System.out.println("Unabled to setup paged results"); + } + + // save role names and group names in session so that they can be easily looked up outside of this object + SecurityUtils.getSubject().getSession().setAttribute(SUBJECT_USER_ROLES, roleNames); + SecurityUtils.getSubject().getSession().setAttribute(SUBJECT_USER_GROUPS, groupNames); + if (!groupNames.isEmpty() && (principals instanceof MutablePrincipalCollection)) { + ((MutablePrincipalCollection)principals).addAll(groupNames, getName()); + } + LOG.lookedUpUserRoles(roleNames, userName); + + return roleNames; } private void addRoleIfMember(final String userDn, final SearchResult group, http://git-wip-us.apache.org/repos/asf/knox/blob/62a75e0e/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java index c9dc3b2..c256a65 100644 --- a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java @@ -412,4 +412,13 @@ public interface GatewayMessages { @Message( level = MessageLevel.DEBUG, text = "Default topology forward from {0} to {1}" ) void defaultTopologyForward( String oldTarget, String newTarget ); + + @Message( level = MessageLevel.ERROR, text = "Unable to setup PagedResults" ) + void unableToSetupPagedResults(); + + @Message( level = MessageLevel.INFO, text = "Ignoring PartialResultException" ) + void ignoringPartialResultException(); + + @Message( level = MessageLevel.WARN, text = "Only retrieved first {0} groups due to SizeLimitExceededException." ) + void sizeLimitExceededOnlyRetrieved(int numResults); } http://git-wip-us.apache.org/repos/asf/knox/blob/62a75e0e/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 50371b1..6746163 100644 --- a/pom.xml +++ b/pom.xml @@ -1019,7 +1019,7 @@ <dependency> <groupId>org.apache.directory.server</groupId> <artifactId>apacheds-all</artifactId> - <version>2.0.0-M15</version> + <version>2.0.0-M16</version> <exclusions> <exclusion> <groupId>ldapsdk</groupId>