[java-identity-provider] 02/02: IDP-1441 bind pool passivator

Daniel Fisher dfisher at vt.edu
Wed May 27 05:31:59 UTC 2020


This is an automated email from the git hooks/post-receive script.

dfisher pushed a commit to branch master
in repository java-identity-provider.

View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=469fd89aef52adbff5aef8ffaac81ecf53341717

commit 469fd89aef52adbff5aef8ffaac81ecf53341717
Author: Daniel Fisher <dfisher at vt.edu>
AuthorDate: Wed May 27 01:15:02 2020 -0400

    IDP-1441 bind pool passivator
    
    Update LDAPAuthenticationFactoryBean with an enum to describe bind pool passivation.
    Add pool validation properties to provide parity with the resolver.
---
 .../config/LDAPAuthenticationFactoryBean.java      | 135 ++++++++++++++++++++-
 .../resources/conf/attribute-resolver-ldap.xml     |   4 +-
 idp-conf/src/main/resources/conf/ldap.properties   |   5 +
 .../system/flows/authn/password-authn-beans.xml    |   3 +
 4 files changed, 141 insertions(+), 6 deletions(-)

diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/LDAPAuthenticationFactoryBean.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/LDAPAuthenticationFactoryBean.java
index 8eb9a8074..a300f1089 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/LDAPAuthenticationFactoryBean.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/LDAPAuthenticationFactoryBean.java
@@ -28,11 +28,15 @@ import net.shibboleth.utilities.java.support.primitive.DeprecationSupport.Object
 
 import org.apache.velocity.app.VelocityEngine;
 import org.ldaptive.BindConnectionInitializer;
+import org.ldaptive.BindRequest;
 import org.ldaptive.ConnectionConfig;
 import org.ldaptive.ConnectionInitializer;
 import org.ldaptive.Credential;
 import org.ldaptive.DefaultConnectionFactory;
 import org.ldaptive.LdapURL;
+import org.ldaptive.SearchFilter;
+import org.ldaptive.SearchRequest;
+import org.ldaptive.SearchScope;
 import org.ldaptive.auth.Authenticator;
 import org.ldaptive.auth.BindAuthenticationHandler;
 import org.ldaptive.auth.FormatDnResolver;
@@ -45,8 +49,10 @@ import org.ldaptive.auth.ext.FreeIPAAuthenticationResponseHandler;
 import org.ldaptive.auth.ext.PasswordExpirationAuthenticationResponseHandler;
 import org.ldaptive.auth.ext.PasswordPolicyAuthenticationRequestHandler;
 import org.ldaptive.auth.ext.PasswordPolicyAuthenticationResponseHandler;
+import org.ldaptive.pool.BindPassivator;
 import org.ldaptive.pool.BlockingConnectionPool;
 import org.ldaptive.pool.IdlePruneStrategy;
+import org.ldaptive.pool.Passivator;
 import org.ldaptive.pool.PoolConfig;
 import org.ldaptive.pool.PooledConnectionFactory;
 import org.ldaptive.pool.SearchValidator;
@@ -119,6 +125,33 @@ public class LDAPAuthenticationFactoryBean extends AbstractFactoryBean<Authentic
     }
   }
 
+  /** Enum that defines an LDAP pool passivator. Labels maps to values in ldap.properties. */
+  public enum PassivatorType {
+    NONE("none"),
+    BIND("bind"),
+    ANONYMOUS_BIND("anonymousBind");
+
+    /** Label for this type. */
+    private final String label;
+
+    PassivatorType(final String s) {
+      label = s;
+    }
+
+    public String label() {
+      return label;
+    }
+
+    public static PassivatorType fromLabel(final String s) {
+      for (PassivatorType pt : PassivatorType.values()) {
+        if (pt.label().equals(s)) {
+          return pt;
+        }
+      }
+      return null;
+    }
+  }
+
   /** Type of authenticator to configure. */
   private AuthenticatorType authenticatorType;
 
@@ -170,6 +203,15 @@ public class LDAPAuthenticationFactoryBean extends AbstractFactoryBean<Authentic
   /** Period at which to validate periodically. */
   private Duration validatePeriod;
 
+  /** DN to perform connection pool validation against. */
+  private String validateDn;
+
+  /** Filter to execute against {@link #validateDn}. */
+  private String validateFilter;
+
+  /** Type of passivator to configure for the bind pool. */
+  private PassivatorType bindPoolPassivatorType;
+
   /** Period at which to check and enforce the idle time. */
   private Duration prunePeriod;
 
@@ -286,6 +328,18 @@ public class LDAPAuthenticationFactoryBean extends AbstractFactoryBean<Authentic
     validatePeriod = period;
   }
 
+  public void setValidateDn(final String dn) {
+    validateDn = dn;
+  }
+
+  public void setValidateFilter(final String filter) {
+    validateFilter = filter;
+  }
+
+  public void setBindPoolPassivatorType(@Nonnull @NotEmpty final String type) {
+    bindPoolPassivatorType = PassivatorType.fromLabel(type);
+  }
+
   public void setPrunePeriod(@Nullable final Duration period) {
     prunePeriod = period;
   }
@@ -414,6 +468,36 @@ public class LDAPAuthenticationFactoryBean extends AbstractFactoryBean<Authentic
    * @return new blocking connection pool
    */
   protected BlockingConnectionPool createConnectionPool(final String name, final ConnectionConfig config) {
+    return createConnectionPool(name, config, new SearchValidator());
+  }
+
+  /**
+   * Returns a new blocking connection pool using the supplied search validator.
+   *
+   * @param name of the connection pool
+   * @param config to assign to the pool
+   * @param validator pool validator
+   *
+   * @return new blocking connection pool
+   */
+  protected BlockingConnectionPool createConnectionPool(final String name, final ConnectionConfig config,
+                                                        final SearchValidator validator) {
+    return createConnectionPool(name, config, validator, null);
+  }
+
+  /**
+   * Returns a new blocking connection pool using the supplied search validator and passivator type. Note that a {@link
+   * PassivatorType#BIND} uses the configured {@link #bindDn} and {@link #bindDnCredential}.
+   *
+   * @param name of the connection pool
+   * @param config to assign to the pool
+   * @param validator pool validator
+   * @param passivator pool passivator
+   *
+   * @return new blocking connection pool
+   */
+  protected BlockingConnectionPool createConnectionPool(final String name, final ConnectionConfig config,
+                                                        final SearchValidator validator, final Passivator passivator) {
     final PoolConfig poolConfig = new PoolConfig();
     poolConfig.setMinPoolSize(minPoolSize);
     poolConfig.setMaxPoolSize(maxPoolSize);
@@ -425,13 +509,46 @@ public class LDAPAuthenticationFactoryBean extends AbstractFactoryBean<Authentic
     pool.setBlockWaitTime(blockWaitTime);
     pool.setPoolConfig(poolConfig);
     pool.setPruneStrategy(new IdlePruneStrategy(prunePeriod, idleTime));
-    pool.setValidator(new SearchValidator());
+    pool.setValidator(validator);
+    pool.setPassivator(passivator);
     pool.setFailFastInitialize(false);
     pool.setConnectionFactory(new DefaultConnectionFactory(config));
     pool.initialize();
     return pool;
   }
 
+  protected SearchValidator createSearchValidator(final String baseDn, final String filter) {
+    final SearchRequest searchRequest = new SearchRequest();
+    searchRequest.setReturnAttributes("1.1");
+    searchRequest.setSearchScope(SearchScope.OBJECT);
+    searchRequest.setSizeLimit(1);
+    if (baseDn != null) {
+      searchRequest.setBaseDn(baseDn);
+    } else {
+      searchRequest.setBaseDn("");
+    }
+    final SearchFilter searchFilter = new SearchFilter();
+    if (filter != null) {
+      searchFilter.setFilter(filter);
+    } else {
+      searchFilter.setFilter("(objectClass=*)");
+    }
+    searchRequest.setSearchFilter(searchFilter);
+    return new SearchValidator(searchRequest);
+  }
+
+  protected Passivator createPoolPassivator(final PassivatorType type) {
+    switch(type) {
+      case BIND:
+        return new BindPassivator(new BindRequest(bindDn, new Credential(bindDnCredential)));
+      case ANONYMOUS_BIND:
+        return new BindPassivator();
+      case NONE:
+      default:
+        return null;
+    }
+  }
+
 // Checkstyle: CyclomaticComplexity|MethodLength OFF
   @Override
   protected Authenticator createInstance() throws Exception {
@@ -453,7 +570,12 @@ public class LDAPAuthenticationFactoryBean extends AbstractFactoryBean<Authentic
     } else {
       authenticator.setAuthenticationHandler(
         new PooledBindAuthenticationHandler(
-          new PooledConnectionFactory(createConnectionPool("bind-pool", createConnectionConfig()))));
+          new PooledConnectionFactory(
+            createConnectionPool(
+              "bind-pool",
+              createConnectionConfig(),
+              createSearchValidator(validateDn, validateFilter),
+              createPoolPassivator(bindPoolPassivatorType)))));
     }
     switch(authenticatorType) {
     case BIND_SEARCH:
@@ -475,7 +597,8 @@ public class LDAPAuthenticationFactoryBean extends AbstractFactoryBean<Authentic
           new PooledConnectionFactory(
             createConnectionPool(
               "dn-search-pool",
-              createConnectionConfig(new BindConnectionInitializer(bindDn, new Credential(bindDnCredential))))));
+              createConnectionConfig(new BindConnectionInitializer(bindDn, new Credential(bindDnCredential))),
+              createSearchValidator(validateDn, validateFilter))));
         authenticator.setDnResolver(bindSearchDnResolver);
       }
       authenticator.setResolveEntryOnFailure(resolveEntryOnFailure);
@@ -506,7 +629,8 @@ public class LDAPAuthenticationFactoryBean extends AbstractFactoryBean<Authentic
           new PooledConnectionFactory(
             createConnectionPool(
               "dn-search-pool",
-              createConnectionConfig())));
+              createConnectionConfig(),
+              createSearchValidator(validateDn, validateFilter))));
         authenticator.setDnResolver(anonSearchDnResolver);
       }
       authenticator.setResolveEntryOnFailure(resolveEntryOnFailure);
@@ -528,7 +652,8 @@ public class LDAPAuthenticationFactoryBean extends AbstractFactoryBean<Authentic
           new PooledConnectionFactory(
             createConnectionPool(
               "entry-search-pool",
-              createConnectionConfig(new BindConnectionInitializer(bindDn, new Credential(bindDnCredential))))));
+              createConnectionConfig(new BindConnectionInitializer(bindDn, new Credential(bindDnCredential))),
+              createSearchValidator(validateDn, validateFilter))));
         authenticator.setEntryResolver(searchEntryResolver);
       }
     }
diff --git a/idp-conf/src/main/resources/conf/attribute-resolver-ldap.xml b/idp-conf/src/main/resources/conf/attribute-resolver-ldap.xml
index 19b68d647..ca46e5d66 100644
--- a/idp-conf/src/main/resources/conf/attribute-resolver-ldap.xml
+++ b/idp-conf/src/main/resources/conf/attribute-resolver-ldap.xml
@@ -74,10 +74,12 @@
             blockWaitTime="%{idp.pool.LDAP.blockWaitTime:PT3S}"
             validatePeriodically="%{idp.pool.LDAP.validatePeriodically:true}"
             validateTimerPeriod="%{idp.pool.LDAP.validatePeriod:PT5M}"
+            validateDN="%{idp.pool.LDAP.validateDN:}"
+            validateFilter="%{idp.pool.LDAP.validateFilter:(objectClass=*)}"
             expirationTime="%{idp.pool.LDAP.idleTime:PT10M}"/>
     </DataConnector>
 
-    <!-- DataConector for pairwise-id (example depends on saml-nameid.properties). -->
+    <!-- DataConnector for pairwise-id (example depends on saml-nameid.properties). -->
 
 <!-- 
     <DataConnector id="computed" xsi:type="ComputedId"
diff --git a/idp-conf/src/main/resources/conf/ldap.properties b/idp-conf/src/main/resources/conf/ldap.properties
index dd72d8e24..1e0c51b5f 100644
--- a/idp-conf/src/main/resources/conf/ldap.properties
+++ b/idp-conf/src/main/resources/conf/ldap.properties
@@ -37,6 +37,9 @@ idp.authn.LDAP.bindDN                           = uid=myservice,ou=system
 # for AD use idp.authn.LDAP.dnFormat=%s at domain.com
 idp.authn.LDAP.dnFormat                         = uid=%s,ou=people,dc=example,dc=org
 
+# pool passivator, either none, bind or anonymousBind
+#idp.authn.LDAP.bindPoolPassivator                  = none
+
 # LDAP attribute configuration, see attribute-resolver.xml
 # Note, this likely won't apply to the use of legacy V2 resolver configurations
 idp.attribute.resolver.LDAP.ldapURL             = %{idp.authn.LDAP.ldapURL}
@@ -54,6 +57,8 @@ idp.attribute.resolver.LDAP.searchFilter        = (uid=$resolutionContext.princi
 #idp.pool.LDAP.validateOnCheckout               = false
 #idp.pool.LDAP.validatePeriodically             = true
 #idp.pool.LDAP.validatePeriod                   = PT5M
+#idp.pool.LDAP.validateDN                       =
+#idp.pool.LDAP.validateFilter                   = (objectClass=*)
 #idp.pool.LDAP.prunePeriod                      = PT5M
 #idp.pool.LDAP.idleTime                         = PT10M
 #idp.pool.LDAP.blockWaitTime                    = PT3S
diff --git a/idp-conf/src/main/resources/system/flows/authn/password-authn-beans.xml b/idp-conf/src/main/resources/system/flows/authn/password-authn-beans.xml
index 35c575c3b..4a8b1786c 100644
--- a/idp-conf/src/main/resources/system/flows/authn/password-authn-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/authn/password-authn-beans.xml
@@ -129,6 +129,9 @@
         p:validateOnCheckout="%{idp.pool.LDAP.validateOnCheckout:false}"
         p:validatePeriodically="%{idp.pool.LDAP.validatePeriodically:true}"
         p:validatePeriod="%{idp.pool.LDAP.validatePeriod:PT5M}"
+        p:validateDn="#{'%{idp.authn.LDAP.validateDN:}'.trim()}"
+        p:validateFilter="#{'%{idp.pool.LDAP.validateFilter:(objectClass=*)}'.trim()}"
+        p:bindPoolPassivatorType="%{idp.authn.LDAP.bindPoolPassivator:none}"
         p:prunePeriod="%{idp.pool.LDAP.prunePeriod:PT5M}"
         p:idleTime="%{idp.pool.LDAP.idleTime:PT10M}"
         p:dnFormat="%{idp.authn.LDAP.dnFormat:undefined}"

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list