[java-identity-provider] branch master updated: Ldaptive v1.3 API changes.
Daniel Fisher
dfisher at vt.edu
Wed Dec 4 16:05:22 EST 2019
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=7503489fcfa746f63f311793c4a90f4dd8a1c7f8
The following commit(s) were added to refs/heads/master by this push:
new 7503489 Ldaptive v1.3 API changes.
7503489 is described below
commit 7503489fcfa746f63f311793c4a90f4dd8a1c7f8
Author: Daniel Fisher <dfisher at vt.edu>
AuthorDate: Wed Dec 4 15:54:12 2019 -0500
Ldaptive v1.3 API changes.
Removes DEFAULT connection strategy.
Removes blockWhenEmpty pool config.
Removes support for JNDI properties.
Fixes IDP-1440, IDP-1401, IDP-1357, IDP-1095.
---
.../AbstractExecutableSearchFilterBuilder.java | 6 +
idp-attribute-resolver-spring/pom.xml | 5 -
.../dc/ldap/impl/LDAPDataConnectorParser.java | 168 ++------
.../spring/impl/StringToDurationConverter.java | 33 ++
.../dc/ldap/LDAPDataConnectorParserTest.java | 177 ++------
.../ldap-attribute-resolver-spring-context.xml | 24 +-
...dap-attribute-resolver-spring-props-context.xml | 14 -
.../resolver/spring/dc/ldap/ldap-v2.properties | 3 -
.../resolver/spring/dc/ldap/ldap-v3.properties | 17 +-
.../resolver/ldap-attribute-resolver-v2-hybrid.xml | 2 -
.../resolver/ldap-attribute-resolver-v2-jndi.xml | 34 --
.../resolver/ldap-attribute-resolver-v2-multi.xml | 5 -
.../resolver/ldap-attribute-resolver-v2-nosec.xml | 4 -
.../resolver/ldap-attribute-resolver-v2-props.xml | 2 -
.../ldap/resolver/ldap-attribute-resolver-v2.xml | 4 -
.../idp/authn/PooledTemplateSearchDnResolver.java | 4 +-
.../idp/authn/TemplateSearchDnResolver.java | 4 +-
.../config/LDAPAuthenticationFactoryBean.java | 474 +++++++++++++++++++++
.../authn/impl/LDAPCredentialValidatorTest.java | 3 +-
idp-conf/pom.xml | 5 -
.../resources/conf/authn/ldap-authn-config.xml | 149 ++-----
.../main/resources/system/conf/global-system.xml | 1 -
.../net/shibboleth/idp/test/InMemoryDirectory.java | 15 +-
idp-distribution/pom.xml | 10 -
.../schema/shibboleth-attribute-resolver.xsd | 20 +-
idp-war-distribution/pom.xml | 11 -
26 files changed, 656 insertions(+), 538 deletions(-)
diff --git a/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/ldap/impl/AbstractExecutableSearchFilterBuilder.java b/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/ldap/impl/AbstractExecutableSearchFilterBuilder.java
index dffa7e0..cde77f2 100644
--- a/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/ldap/impl/AbstractExecutableSearchFilterBuilder.java
+++ b/idp-attribute-resolver-impl/src/main/java/net/shibboleth/idp/attribute/resolver/dc/ldap/impl/AbstractExecutableSearchFilterBuilder.java
@@ -23,6 +23,7 @@ import javax.annotation.Nullable;
import org.ldaptive.ConnectionFactory;
import org.ldaptive.LdapException;
import org.ldaptive.Response;
+import org.ldaptive.ResultCode;
import org.ldaptive.SearchExecutor;
import org.ldaptive.SearchFilter;
import org.ldaptive.SearchResult;
@@ -61,6 +62,11 @@ public abstract class AbstractExecutableSearchFilterBuilder extends AbstractInit
@Nonnull final ConnectionFactory factory) throws LdapException {
final Response<SearchResult> response = executor.search(factory, searchFilter);
log.trace("Search returned response {}", response);
+ if (response.getResultCode() != ResultCode.SUCCESS) {
+ // It's possible for the LDAP to return partial results and report either a size limit or
+ // time limit result code. Throw if we don't receive all results.
+ throw new LdapException("Search operation did not return success: " + response.getResultCode());
+ }
return response.getResult();
}
diff --git a/idp-attribute-resolver-spring/pom.xml b/idp-attribute-resolver-spring/pom.xml
index 0ff653d..8632475 100644
--- a/idp-attribute-resolver-spring/pom.xml
+++ b/idp-attribute-resolver-spring/pom.xml
@@ -181,11 +181,6 @@
<scope>test</scope>
</dependency>
<dependency>
- <groupId>org.ldaptive</groupId>
- <artifactId>ldaptive-unboundid</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
<groupId>com.unboundid</groupId>
<artifactId>unboundid-ldapsdk</artifactId>
<scope>test</scope>
diff --git a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/impl/LDAPDataConnectorParser.java b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/impl/LDAPDataConnectorParser.java
index 1d49f05..b278a80 100644
--- a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/impl/LDAPDataConnectorParser.java
+++ b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/impl/LDAPDataConnectorParser.java
@@ -25,10 +25,13 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.xml.namespace.QName;
+import org.ldaptive.ActivePassiveConnectionStrategy;
import org.ldaptive.BindConnectionInitializer;
import org.ldaptive.ConnectionConfig;
import org.ldaptive.Credential;
import org.ldaptive.DefaultConnectionFactory;
+import org.ldaptive.RandomConnectionStrategy;
+import org.ldaptive.RoundRobinConnectionStrategy;
import org.ldaptive.SearchExecutor;
import org.ldaptive.SearchFilter;
import org.ldaptive.SearchRequest;
@@ -42,8 +45,6 @@ import org.ldaptive.pool.IdlePruneStrategy;
import org.ldaptive.pool.PoolConfig;
import org.ldaptive.pool.PooledConnectionFactory;
import org.ldaptive.pool.SearchValidator;
-import org.ldaptive.pool.SoftLimitConnectionPool;
-import org.ldaptive.provider.ConnectionStrategy;
import org.ldaptive.sasl.Mechanism;
import org.ldaptive.sasl.SaslConfig;
import org.ldaptive.ssl.SslConfig;
@@ -95,7 +96,7 @@ public class LDAPDataConnectorParser extends AbstractDataConnectorParser {
* Parses a version 2 configuration. <br/>
* The following automatically created & injected beans acquire hard wired defaults:
* <ul>
- * <li>{@link SearchExecutor#setTimeLimit(long)} defaults to 3000, overridden by the "searchTimeLimit" attribute.
+ * <li>{@link SearchExecutor#setTimeLimit(Duration)} defaults to 3s, overridden by the "searchTimeLimit" attribute.
* </li>
* <li>{@link SearchExecutor#setSizeLimit(long)} defaults to 1, overridden by the "maxResultSize" attribute.</li>
* <li>{@link SearchRequest#setBaseDn(String)} default to "", overridden by the "validateDN" attribute.</li>
@@ -105,7 +106,7 @@ public class LDAPDataConnectorParser extends AbstractDataConnectorParser {
* attribute "minPoolSize" are set.</li>
* <li>{@link PoolConfig#setMaxPoolSize(int)} defaults to 3 if neither the attribute "poolMaxIdleSize" nor the
* attribute "maxPoolSize" are set.</li>
- * <li>{@link PoolConfig#setValidatePeriod(long)} defaults to 1800, overridden by the attribute
+ * <li>{@link PoolConfig#setValidatePeriod(Duration)} defaults to 30m, overridden by the attribute
* "validateTimerPeriod"</li>
* </ul>
*
@@ -123,46 +124,6 @@ public class LDAPDataConnectorParser extends AbstractDataConnectorParser {
BeanDefinitionBuilder.genericBeanDefinition(DefaultConnectionFactory.class);
connectionFactory.addConstructorArgValue(v2Parser.createConnectionConfig(parserContext));
- final BeanDefinitionBuilder provider =
- BeanDefinitionBuilder.genericBeanDefinition(DefaultConnectionFactory.getDefaultProvider().getClass());
- final BeanDefinitionBuilder providerConfig =
- BeanDefinitionBuilder.genericBeanDefinition(DefaultConnectionFactory.getDefaultProvider()
- .getProviderConfig().getClass());
- final String connectionStrategy = AttributeSupport.getAttributeValue(config, new QName("connectionStrategy"));
- if (connectionStrategy == null) {
- providerConfig.addPropertyValue("connectionStrategy", ConnectionStrategy.ACTIVE_PASSIVE);
- } else {
- switch (connectionStrategy) {
- case "DEFAULT":
- providerConfig.addPropertyValue("connectionStrategy", ConnectionStrategy.DEFAULT);
- break;
-
- case "ROUND_ROBIN":
- providerConfig.addPropertyValue("connectionStrategy", ConnectionStrategy.ROUND_ROBIN);
- break;
-
- case "RANDOM":
- providerConfig.addPropertyValue("connectionStrategy", ConnectionStrategy.RANDOM);
- break;
-
- default:
- providerConfig.addPropertyValue("connectionStrategy", ConnectionStrategy.ACTIVE_PASSIVE);
- break;
- }
- }
-
- final ManagedMap<String, String> props = new ManagedMap<>();
- final List<Element> propertyElements =
- ElementSupport.getChildElements(config,
- new QName(AttributeResolverNamespaceHandler.NAMESPACE, "LDAPProperty"));
- for (final Element e : propertyElements) {
- props.put(AttributeSupport.getAttributeValue(e, new QName("name")),
- AttributeSupport.getAttributeValue(e, new QName("value")));
- }
- providerConfig.addPropertyValue("properties", props);
- provider.addPropertyValue("providerConfig", providerConfig.getBeanDefinition());
- connectionFactory.addPropertyValue("provider", provider.getBeanDefinition());
-
final String searchBuilderID = v2Parser.getBeanSearchBuilderID();
if (searchBuilderID != null) {
builder.addPropertyReference("executableSearchBuilder", searchBuilderID);
@@ -183,7 +144,7 @@ public class LDAPDataConnectorParser extends AbstractDataConnectorParser {
builder.addPropertyValue("connectionFactory", connectionFactory.getBeanDefinition());
}
- final BeanDefinition searchExecutor = v2Parser.createSearchExecutor(props);
+ final BeanDefinition searchExecutor = v2Parser.createSearchExecutor();
builder.addPropertyValue("searchExecutor", searchExecutor);
final String mappingStrategyID = AttributeSupport.getAttributeValue(config, new QName("mappingStrategyRef"));
@@ -278,22 +239,14 @@ public class LDAPDataConnectorParser extends AbstractDataConnectorParser {
connectionConfig.addPropertyValue("useStartTLS", useStartTLS);
}
if (connectTimeout != null) {
- final BeanDefinitionBuilder timeout =
- BeanDefinitionBuilder.rootBeanDefinition(V2Parser.class, "buildDuration");
- timeout.addConstructorArgValue(connectTimeout);
- timeout.addConstructorArgValue(1);
- connectionConfig.addPropertyValue("connectTimeout", timeout.getBeanDefinition());
+ connectionConfig.addPropertyValue("connectTimeout", connectTimeout);
} else {
- connectionConfig.addPropertyValue("connectTimeout", 3000);
+ connectionConfig.addPropertyValue("connectTimeout", Duration.ofSeconds(3));
}
if (responseTimeout != null) {
- final BeanDefinitionBuilder timeout =
- BeanDefinitionBuilder.rootBeanDefinition(V2Parser.class, "buildDuration");
- timeout.addConstructorArgValue(responseTimeout);
- timeout.addConstructorArgValue(1);
- connectionConfig.addPropertyValue("responseTimeout", timeout.getBeanDefinition());
+ connectionConfig.addPropertyValue("responseTimeout", responseTimeout);
} else {
- connectionConfig.addPropertyValue("responseTimeout", 3000);
+ connectionConfig.addPropertyValue("responseTimeout", Duration.ofSeconds(3));
}
final BeanDefinitionBuilder sslConfig = BeanDefinitionBuilder.genericBeanDefinition(SslConfig.class);
sslConfig.addPropertyValue("credentialConfig", createCredentialConfig(parserContext));
@@ -319,6 +272,26 @@ public class LDAPDataConnectorParser extends AbstractDataConnectorParser {
if (principal != null || principalCredential != null || authenticationType != null) {
connectionConfig.addPropertyValue("connectionInitializer", connectionInitializer.getBeanDefinition());
}
+ final String connectionStrategy = AttributeSupport.getAttributeValue(
+ configElement, new QName("connectionStrategy"));
+ if (connectionStrategy == null) {
+ connectionConfig.addPropertyValue("connectionStrategy", new ActivePassiveConnectionStrategy());
+ } else {
+ switch (connectionStrategy) {
+ case "ROUND_ROBIN":
+ connectionConfig.addPropertyValue("connectionStrategy", new RoundRobinConnectionStrategy());
+ break;
+
+ case "RANDOM":
+ connectionConfig.addPropertyValue("connectionStrategy", new RandomConnectionStrategy());
+ break;
+
+ default:
+ connectionConfig.addPropertyValue("connectionStrategy", new ActivePassiveConnectionStrategy());
+ break;
+ }
+ }
+
return connectionConfig.getBeanDefinition();
}
// CheckStyle: CyclomaticComplexity ON
@@ -453,12 +426,10 @@ public class LDAPDataConnectorParser extends AbstractDataConnectorParser {
/**
* Creates a new search executor bean definition from a v2 XML configuration.
*
- * @param props ldap properties
- *
* @return search executor bean definition
*/
// CheckStyle: CyclomaticComplexity|MethodLength OFF
- @Nonnull public BeanDefinition createSearchExecutor(final ManagedMap<String, String> props) {
+ @Nonnull public BeanDefinition createSearchExecutor() {
final String baseDn = AttributeSupport.getAttributeValue(configElement, new QName("baseDN"));
final String searchScope = AttributeSupport.getAttributeValue(configElement, new QName("searchScope"));
final String derefAliases = AttributeSupport.getAttributeValue(configElement, new QName("derefAliases"));
@@ -478,18 +449,11 @@ public class LDAPDataConnectorParser extends AbstractDataConnectorParser {
}
if (derefAliases != null) {
searchExecutor.addPropertyValue("derefAliases", derefAliases);
- } else if (props.containsKey("java.naming.ldap.derefAliases")) {
- searchExecutor.addPropertyValue(
- "derefAliases", props.get("java.naming.ldap.derefAliases").toUpperCase());
}
if (searchTimeLimit != null) {
- final BeanDefinitionBuilder duration =
- BeanDefinitionBuilder.rootBeanDefinition(V2Parser.class, "buildDuration");
- duration.addConstructorArgValue(searchTimeLimit);
- duration.addConstructorArgValue(1);
- searchExecutor.addPropertyValue("timeLimit", duration.getBeanDefinition());
+ searchExecutor.addPropertyValue("timeLimit", searchTimeLimit);
} else {
- searchExecutor.addPropertyValue("timeLimit", 3000);
+ searchExecutor.addPropertyValue("timeLimit", Duration.ofSeconds(3));
}
if (maxResultSize != null) {
searchExecutor.addPropertyValue("sizeLimit", maxResultSize);
@@ -532,11 +496,6 @@ public class LDAPDataConnectorParser extends AbstractDataConnectorParser {
BeanDefinitionBuilder.rootBeanDefinition(V2Parser.class, "buildStringList");
binaryAttrs.addConstructorArgValue(ElementSupport.getElementContentAsString(binaryAttrsElement));
searchExecutor.addPropertyValue("binaryAttributes", binaryAttrs.getBeanDefinition());
- } else if (props.containsKey("java.naming.ldap.attributes.binary")) {
- final BeanDefinitionBuilder binaryAttrs =
- BeanDefinitionBuilder.rootBeanDefinition(V2Parser.class, "buildStringList");
- binaryAttrs.addConstructorArgValue(props.get("java.naming.ldap.attributes.binary"));
- searchExecutor.addPropertyValue("binaryAttributes", binaryAttrs.getBeanDefinition());
}
return searchExecutor.getBeanDefinition();
@@ -583,28 +542,15 @@ public class LDAPDataConnectorParser extends AbstractDataConnectorParser {
AttributeSupport.getAttributeValue(poolConfigElement, new QName("expirationTime"));
final BeanDefinitionBuilder pool =
- BeanDefinitionBuilder.rootBeanDefinition(V2Parser.class, "buildConnectionPool");
- pool.addConstructorArgValue(AttributeSupport.getAttributeValue(configElement, new QName("blockWhenEmpty")));
+ BeanDefinitionBuilder.genericBeanDefinition(BlockingConnectionPool.class);
+ pool.addPropertyValue("name", "resolver-pool");
if (blockWaitTime != null) {
- final BeanDefinitionBuilder duration =
- BeanDefinitionBuilder.rootBeanDefinition(V2Parser.class, "buildDuration");
- duration.addConstructorArgValue(blockWaitTime);
- duration.addConstructorArgValue(1);
- pool.addPropertyValue("blockWaitTime", duration.getBeanDefinition());
+ pool.addPropertyValue("blockWaitTime", blockWaitTime);
}
if (expirationTime != null) {
- final BeanDefinitionBuilder period =
- BeanDefinitionBuilder.rootBeanDefinition(V2Parser.class, "buildDuration");
- period.addConstructorArgValue(expirationTime);
- period.addConstructorArgValue(2000);
- final BeanDefinitionBuilder idle =
- BeanDefinitionBuilder.rootBeanDefinition(V2Parser.class, "buildDuration");
- idle.addConstructorArgValue(expirationTime);
- idle.addConstructorArgValue(1000);
final BeanDefinitionBuilder strategy =
BeanDefinitionBuilder.genericBeanDefinition(IdlePruneStrategy.class);
- strategy.addConstructorArgValue(period.getBeanDefinition());
- strategy.addConstructorArgValue(idle.getBeanDefinition());
+ strategy.addConstructorArgValue(expirationTime);
pool.addPropertyValue("pruneStrategy", strategy.getBeanDefinition());
}
pool.addPropertyValue("poolConfig", createPoolConfig());
@@ -667,14 +613,9 @@ public class LDAPDataConnectorParser extends AbstractDataConnectorParser {
poolConfig.addPropertyValue("validatePeriodically", validatePeriodically);
}
if (validateTimerPeriod != null) {
- final BeanDefinitionBuilder period =
- BeanDefinitionBuilder.rootBeanDefinition(V2Parser.class, "buildDuration");
- period.addConstructorArgValue(validateTimerPeriod);
- // Convert to seconds.
- period.addConstructorArgValue(1000);
- poolConfig.addPropertyValue("validatePeriod", period.getBeanDefinition());
+ poolConfig.addPropertyValue("validatePeriod", validateTimerPeriod);
} else {
- poolConfig.addPropertyValue("validatePeriod", 1800);
+ poolConfig.addPropertyValue("validatePeriod", Duration.ofMinutes(30));
}
return poolConfig.getBeanDefinition();
}
@@ -753,19 +694,6 @@ public class LDAPDataConnectorParser extends AbstractDataConnectorParser {
}
/**
- * Converts the supplied duration to milliseconds and divides it by the divisor. Useful for modifying durations
- * while resolving property replacement.
- *
- * @param duration the duration (which may have gone through spring translation from iso to long)
- * @param divisor to modify the duration with
- *
- * @return result of the division
- */
- public static long buildDuration(@Nonnull final Duration duration, final long divisor) {
- return duration.toMillis() / divisor;
- }
-
- /**
* Converts the supplied value to a list of strings delimited by {@link XMLConstants#LIST_DELIMITERS} and comma.
*
* @param value to convert to a list
@@ -777,24 +705,6 @@ public class LDAPDataConnectorParser extends AbstractDataConnectorParser {
}
/**
- * Returns a soft limit connection pool if blockWhenEmpty is false, otherwise return a blocking connection pool.
- *
- * @param blockWhenEmpty boolean string indicating the type of blocking connection pool
- *
- * @return soft limit or blocking connection pool
- */
- @Nonnull public static BlockingConnectionPool buildConnectionPool(@Nullable final String blockWhenEmpty) {
- BlockingConnectionPool pool = null;
- if (blockWhenEmpty == null || Boolean.valueOf(blockWhenEmpty)) {
- pool = new BlockingConnectionPool();
- } else {
- pool = new SoftLimitConnectionPool();
- }
- pool.setName("resolver-pool");
- return pool;
- }
-
- /**
* Returns a search validator or null if validatePeriodically is false.
*
* @param validatePeriodically whether to create a search validator
diff --git a/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/impl/StringToDurationConverter.java b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/impl/StringToDurationConverter.java
new file mode 100644
index 0000000..76701dd
--- /dev/null
+++ b/idp-attribute-resolver-spring/src/main/java/net/shibboleth/idp/attribute/resolver/spring/impl/StringToDurationConverter.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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
+ *
+ * http://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 net.shibboleth.idp.attribute.resolver.spring.impl;
+
+import java.time.Duration;
+import org.springframework.core.convert.converter.Converter;
+
+/**
+ * Spring converter that produces a {@link java.time.Duration} from it's ISO time format.
+ */
+public class StringToDurationConverter implements Converter<String, Duration> {
+
+ @Override
+ public Duration convert(final String s)
+ {
+ return Duration.parse(s);
+ }
+}
diff --git a/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/LDAPDataConnectorParserTest.java b/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/LDAPDataConnectorParserTest.java
index 083d431..dd96c28 100644
--- a/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/LDAPDataConnectorParserTest.java
+++ b/idp-attribute-resolver-spring/src/test/java/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/LDAPDataConnectorParserTest.java
@@ -30,22 +30,18 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import org.ldaptive.BindConnectionInitializer;
import org.ldaptive.ConnectionConfig;
import org.ldaptive.DefaultConnectionFactory;
-import org.ldaptive.DerefAliases;
import org.ldaptive.SearchExecutor;
-import org.ldaptive.SearchScope;
import org.ldaptive.pool.BlockingConnectionPool;
import org.ldaptive.pool.IdlePruneStrategy;
import org.ldaptive.pool.PoolConfig;
import org.ldaptive.pool.PooledConnectionFactory;
import org.ldaptive.pool.SearchValidator;
-import org.ldaptive.provider.ProviderConfig;
import org.ldaptive.ssl.CredentialConfig;
import org.ldaptive.ssl.SslConfig;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
@@ -188,35 +184,31 @@ public class LDAPDataConnectorParserTest {
getLdapDataConnector(new String[] {"net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-minimal.xml"});
assertNotNull(dataConnector);
assertTrue(dataConnector.isFailFastInitialize());
- assertEquals(Duration.ZERO, dataConnector.getNoRetryDelay());
+ assertEquals(dataConnector.getNoRetryDelay(), Duration.ZERO);
final DefaultConnectionFactory connFactory = (DefaultConnectionFactory) dataConnector.getConnectionFactory();
assertNotNull(connFactory);
final ConnectionConfig connConfig = connFactory.getConnectionConfig();
assertNotNull(connConfig);
- assertEquals("ldap://localhost:10389", connConfig.getLdapUrl());
- assertEquals(false, connConfig.getUseSSL());
- assertEquals(false, connConfig.getUseStartTLS());
+ assertEquals(connConfig.getLdapUrl(), "ldap://localhost:10389");
+ assertFalse(connConfig.getUseSSL());
+ assertFalse(connConfig.getUseStartTLS());
final BindConnectionInitializer connInitializer = (BindConnectionInitializer) connConfig.getConnectionInitializer();
- assertEquals("cn=Directory Manager", connInitializer.getBindDn());
- assertEquals("password", connInitializer.getBindCredential().getString());
- assertEquals(3000, connConfig.getConnectTimeout());
- assertEquals(3000, connConfig.getResponseTimeout());
+ assertEquals(connInitializer.getBindDn(), "cn=Directory Manager");
+ assertEquals(connInitializer.getBindCredential().getString(), "password");
+ assertEquals(connConfig.getConnectTimeout(), Duration.ofSeconds(3));
+ assertEquals(connConfig.getResponseTimeout(), Duration.ofSeconds(3));
final SslConfig sslConfig = connFactory.getConnectionConfig().getSslConfig();
assertNotNull(sslConfig);
final CredentialConfig credentialConfig = sslConfig.getCredentialConfig();
assertNotNull(credentialConfig);
- final ProviderConfig<?> providerConfig = connFactory.getProvider().getProviderConfig();
- assertNotNull(providerConfig);
- assertTrue(providerConfig.getProperties().isEmpty());
-
final SearchExecutor searchExecutor = dataConnector.getSearchExecutor();
assertNotNull(searchExecutor);
- assertEquals("", searchExecutor.getBaseDn());
+ assertEquals(searchExecutor.getBaseDn(), "");
assertNull(searchExecutor.getSearchFilter());
- assertEquals(3000, searchExecutor.getTimeLimit());
+ assertEquals(searchExecutor.getTimeLimit(), Duration.ofSeconds(3));
final ConnectionFactoryValidator validator = (ConnectionFactoryValidator) dataConnector.getValidator();
assertNotNull(validator);
@@ -252,47 +244,43 @@ public class LDAPDataConnectorParserTest {
assertNotNull(connFactory);
final BlockingConnectionPool connPool = (BlockingConnectionPool) connFactory.getConnectionPool();
assertNotNull(connPool);
- assertEquals(0, connPool.getBlockWaitTime());
+ assertNull(connPool.getBlockWaitTime());
assertEquals("resolver-pool", connPool.getName());
final PoolConfig poolConfig = connPool.getPoolConfig();
assertNotNull(poolConfig);
- assertEquals(0, poolConfig.getMinPoolSize());
- assertEquals(3, poolConfig.getMaxPoolSize());
+ assertEquals(poolConfig.getMinPoolSize(), 0);
+ assertEquals(poolConfig.getMaxPoolSize(), 3);
assertFalse(poolConfig.isValidatePeriodically());
- assertEquals(1800, poolConfig.getValidatePeriod());
+ assertEquals(poolConfig.getValidatePeriod(), Duration.ofMinutes(30));
assertTrue(connPool.getFailFastInitialize());
assertNull(connPool.getValidator());
final IdlePruneStrategy pruneStrategy = (IdlePruneStrategy) connPool.getPruneStrategy();
assertNotNull(pruneStrategy);
- assertEquals(300, pruneStrategy.getPrunePeriod());
- assertEquals(600, pruneStrategy.getIdleTime());
+ assertEquals(pruneStrategy.getPrunePeriod(), Duration.ofMinutes(5));
+ assertEquals(pruneStrategy.getIdleTime(), Duration.ofMinutes(10));
final ConnectionConfig connConfig = connPool.getConnectionFactory().getConnectionConfig();
assertNotNull(connConfig);
- assertEquals("ldap://localhost:10389", connConfig.getLdapUrl());
- assertEquals(false, connConfig.getUseSSL());
- assertEquals(false, connConfig.getUseStartTLS());
+ assertEquals(connConfig.getLdapUrl(), "ldap://localhost:10389");
+ assertFalse(connConfig.getUseSSL());
+ assertFalse(connConfig.getUseStartTLS());
final BindConnectionInitializer connInitializer = (BindConnectionInitializer) connConfig.getConnectionInitializer();
- assertEquals("cn=Directory Manager", connInitializer.getBindDn());
- assertEquals("password", connInitializer.getBindCredential().getString());
- assertEquals(3000, connConfig.getConnectTimeout());
- assertEquals(3000, connConfig.getResponseTimeout());
+ assertEquals(connInitializer.getBindDn(), "cn=Directory Manager");
+ assertEquals(connInitializer.getBindCredential().getString(), "password");
+ assertEquals(connConfig.getConnectTimeout(), Duration.ofSeconds(3));
+ assertEquals(connConfig.getResponseTimeout(), Duration.ofSeconds(3));
final SslConfig sslConfig = connPool.getConnectionFactory().getConnectionConfig().getSslConfig();
assertNotNull(sslConfig);
final CredentialConfig credentialConfig = sslConfig.getCredentialConfig();
assertNotNull(credentialConfig);
- final ProviderConfig<?> providerConfig = connPool.getConnectionFactory().getProvider().getProviderConfig();
- assertNotNull(providerConfig);
- assertTrue(providerConfig.getProperties().isEmpty());
-
final SearchExecutor searchExecutor = dataConnector.getSearchExecutor();
assertNotNull(searchExecutor);
- assertEquals("", searchExecutor.getBaseDn());
+ assertEquals(searchExecutor.getBaseDn(), "");
assertNull(searchExecutor.getSearchFilter());
- assertEquals(3000, searchExecutor.getTimeLimit());
+ assertEquals(searchExecutor.getTimeLimit(), Duration.ofSeconds(3));
final ConnectionFactoryValidator validator = (ConnectionFactoryValidator) dataConnector.getValidator();
assertNotNull(validator);
@@ -318,74 +306,6 @@ public class LDAPDataConnectorParserTest {
assertNotNull(attrs.get("entryDN"));
}
- @Test public void v2JndiConfig() throws Exception {
- final LDAPDataConnector dataConnector =
- getLdapDataConnector(new String[] {"net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-jndi.xml"});
- assertNotNull(dataConnector);
- assertEquals(Duration.ofMinutes(5), dataConnector.getNoRetryDelay());
- final DefaultConnectionFactory connFactory = (DefaultConnectionFactory) dataConnector.getConnectionFactory();
- assertNotNull(connFactory);
-
- final ConnectionConfig connConfig = connFactory.getConnectionConfig();
- assertNotNull(connConfig);
- assertEquals("ldap://localhost:10389", connConfig.getLdapUrl());
- assertEquals(false, connConfig.getUseSSL());
- assertEquals(true, connConfig.getUseStartTLS());
- final BindConnectionInitializer connInitializer = (BindConnectionInitializer) connConfig.getConnectionInitializer();
- assertEquals("cn=Directory Manager", connInitializer.getBindDn());
- assertEquals("password", connInitializer.getBindCredential().getString());
- assertEquals(2000, connConfig.getConnectTimeout());
- assertEquals(4000, connConfig.getResponseTimeout());
-
- final SslConfig sslConfig = connFactory.getConnectionConfig().getSslConfig();
- assertNotNull(sslConfig);
- final CredentialConfig credentialConfig = sslConfig.getCredentialConfig();
- assertNotNull(credentialConfig);
-
- final ProviderConfig<?> providerConfig = connFactory.getProvider().getProviderConfig();
- assertNotNull(providerConfig);
- assertEquals("value1", providerConfig.getProperties().get("name1"));
- assertEquals("finding", providerConfig.getProperties().get("java.naming.ldap.derefAliases"));
- assertEquals("jpegPhoto employeeNumber", providerConfig.getProperties().get("java.naming.ldap.attributes.binary"));
-
- final SearchExecutor searchExecutor = dataConnector.getSearchExecutor();
- assertNotNull(searchExecutor);
- assertEquals("ou=people,dc=shibboleth,dc=net", searchExecutor.getBaseDn());
- assertNull(searchExecutor.getSearchFilter());
- assertEquals(7000, searchExecutor.getTimeLimit());
- assertEquals(SearchScope.SUBTREE, searchExecutor.getSearchScope());
- assertEquals(DerefAliases.FINDING, searchExecutor.getDerefAliases());
- assertEquals(new String[] {"jpegPhoto", "employeeNumber"}, searchExecutor.getBinaryAttributes());
-
- final ConnectionFactoryValidator validator = (ConnectionFactoryValidator) dataConnector.getValidator();
- assertNotNull(validator);
- assertFalse(validator.isThrowValidateError());
- assertNotNull(validator.getConnectionFactory());
-
- final ExecutableSearchBuilder<?> searchBuilder = dataConnector.getExecutableSearchBuilder();
- assertNotNull(searchBuilder);
-
- final StringAttributeValueMappingStrategy mappingStrategy =(StringAttributeValueMappingStrategy) dataConnector.getMappingStrategy();
- assertNotNull(mappingStrategy);
- assertTrue(mappingStrategy.isNoResultAnError());
- assertTrue(mappingStrategy.isMultipleResultsAnError());
-
- assertNull(dataConnector.getResultsCache());
-
- dataConnector.initialize();
- final AttributeResolutionContext context =
- TestSources.createResolutionContext(TestSources.PRINCIPAL_ID, TestSources.IDP_ENTITY_ID,
- TestSources.SP_ENTITY_ID);
- final Map<String, IdPAttribute> attrs = dataConnector.resolve(context);
- assertNotNull(attrs);
- assertEquals(5, attrs.size());
- assertNotNull(attrs.get("cn"));
- assertNotNull(attrs.get("sn"));
- assertNotNull(attrs.get("jpegPhoto"));
- assertEquals(attrs.get("employeeNumber").getValues().get(0).getNativeValue(), "C2J20hMNp7NlUwQ+");
- assertNotNull(attrs.get("entryDN"));
- }
-
@Test public void v2PropsConfig() throws Exception {
final Resource props = new ClassPathResource("net/shibboleth/idp/attribute/resolver/spring/dc/ldap/ldap-v2.properties");
final LDAPDataConnector dataConnector =
@@ -525,61 +445,54 @@ public class LDAPDataConnectorParserTest {
protected void doTest(final LDAPDataConnector dataConnector) throws ResolutionException {
final String id = dataConnector.getId();
- assertEquals("myLDAP", id);
- assertEquals(Duration.ofMinutes(5), dataConnector.getNoRetryDelay());
+ assertEquals(id, "myLDAP");
+ assertEquals(dataConnector.getNoRetryDelay(), Duration.ofMinutes(5));
final PooledConnectionFactory connFactory = (PooledConnectionFactory) dataConnector.getConnectionFactory();
assertNotNull(connFactory);
final BlockingConnectionPool connPool = (BlockingConnectionPool) connFactory.getConnectionPool();
assertNotNull(connPool);
- assertEquals(5000, connPool.getBlockWaitTime());
- assertEquals("resolver-pool", connPool.getName());
+ assertEquals(connPool.getBlockWaitTime(), Duration.ofSeconds(5));
+ assertEquals(connPool.getName(), "resolver-pool");
final PoolConfig poolConfig = connPool.getPoolConfig();
assertNotNull(poolConfig);
- assertEquals(5, poolConfig.getMinPoolSize());
- assertEquals(10, poolConfig.getMaxPoolSize());
+ assertEquals(poolConfig.getMinPoolSize(), 5);
+ assertEquals(poolConfig.getMaxPoolSize(), 10);
assertTrue(poolConfig.isValidatePeriodically());
- assertEquals(900, poolConfig.getValidatePeriod());
+ assertEquals(poolConfig.getValidatePeriod(), Duration.ofMinutes(15));
assertFalse(connPool.getFailFastInitialize());
final SearchValidator searchValidator = (SearchValidator) connPool.getValidator();
assertNotNull(searchValidator);
- assertEquals("dc=shibboleth,dc=net", searchValidator.getSearchRequest().getBaseDn());
- assertEquals("(ou=people)", searchValidator.getSearchRequest().getSearchFilter().getFilter());
+ assertEquals(searchValidator.getSearchRequest().getBaseDn(), "dc=shibboleth,dc=net");
+ assertEquals(searchValidator.getSearchRequest().getSearchFilter().getFilter(), "(ou=people)");
final IdlePruneStrategy pruneStrategy = (IdlePruneStrategy) connPool.getPruneStrategy();
assertNotNull(pruneStrategy);
- assertEquals(300, pruneStrategy.getPrunePeriod());
- assertEquals(600, pruneStrategy.getIdleTime());
+ assertEquals(pruneStrategy.getPrunePeriod(), Duration.ofMinutes(5));
+ assertEquals(pruneStrategy.getIdleTime(), Duration.ofMinutes(10));
final ConnectionConfig connConfig = connPool.getConnectionFactory().getConnectionConfig();
assertNotNull(connConfig);
- assertEquals("ldap://localhost:10389", connConfig.getLdapUrl());
- assertEquals(false, connConfig.getUseSSL());
- assertEquals(true, connConfig.getUseStartTLS());
+ assertEquals(connConfig.getLdapUrl(), "ldap://localhost:10389");
+ assertFalse(connConfig.getUseSSL());
+ assertTrue(connConfig.getUseStartTLS());
final BindConnectionInitializer connInitializer = (BindConnectionInitializer) connConfig.getConnectionInitializer();
- assertEquals("cn=Directory Manager", connInitializer.getBindDn());
- assertEquals("password", connInitializer.getBindCredential().getString());
- assertEquals(2000, connConfig.getConnectTimeout());
- assertEquals(4000, connConfig.getResponseTimeout());
+ assertEquals(connInitializer.getBindDn(), "cn=Directory Manager");
+ assertEquals(connInitializer.getBindCredential().getString(), "password");
+ assertEquals(connConfig.getConnectTimeout(), Duration.ofSeconds(2));
+ assertEquals(connConfig.getResponseTimeout(), Duration.ofSeconds(4));
final SslConfig sslConfig = connPool.getConnectionFactory().getConnectionConfig().getSslConfig();
assertNotNull(sslConfig);
final CredentialConfig credentialConfig = sslConfig.getCredentialConfig();
assertNotNull(credentialConfig);
- final Map<String, Object> providerProps = new HashMap<>();
- providerProps.put("name1", "value1");
- providerProps.put("name2", "value2");
- final ProviderConfig<?> providerConfig = connPool.getConnectionFactory().getProvider().getProviderConfig();
- assertNotNull(providerConfig);
- assertEquals(providerProps, providerConfig.getProperties());
-
final SearchExecutor searchExecutor = dataConnector.getSearchExecutor();
assertNotNull(searchExecutor);
- assertEquals("ou=people,dc=shibboleth,dc=net", searchExecutor.getBaseDn());
+ assertEquals(searchExecutor.getBaseDn(), "ou=people,dc=shibboleth,dc=net");
assertNull(searchExecutor.getSearchFilter());
- assertEquals(7000, searchExecutor.getTimeLimit());
+ assertEquals(searchExecutor.getTimeLimit(), Duration.ofSeconds(7));
final ConnectionFactoryValidator validator = (ConnectionFactoryValidator) dataConnector.getValidator();
assertNotNull(validator);
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/ldap-attribute-resolver-spring-context.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/ldap-attribute-resolver-spring-context.xml
index e58fa3d..8086ca8 100644
--- a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/ldap-attribute-resolver-spring-context.xml
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/ldap-attribute-resolver-spring-context.xml
@@ -4,30 +4,16 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean id="connectionFactory" class="org.ldaptive.pool.PooledConnectionFactory">
<property name="connectionPool">
- <bean class="org.ldaptive.pool.BlockingConnectionPool" init-method="initialize" p:blockWaitTime="5000" p:failFastInitialize="false" p:name="resolver-pool">
+ <bean class="org.ldaptive.pool.BlockingConnectionPool" init-method="initialize" p:blockWaitTime="PT5S" p:failFastInitialize="false" p:name="resolver-pool">
<constructor-arg index="0">
<bean class="org.ldaptive.pool.PoolConfig" p:minPoolSize="5" p:maxPoolSize="10"
- p:validatePeriodically="true" p:validatePeriod="900" />
+ p:validatePeriodically="true" p:validatePeriod="PT15M" />
</constructor-arg>
<constructor-arg index="1">
<bean class="org.ldaptive.DefaultConnectionFactory">
- <property name="provider">
- <bean class="org.ldaptive.provider.jndi.JndiProvider">
- <property name="providerConfig">
- <bean class="org.ldaptive.provider.jndi.JndiProviderConfig">
- <property name="properties">
- <map>
- <entry key="name1" value="value1" />
- <entry key="name2" value="value2" />
- </map>
- </property>
- </bean>
- </property>
- </bean>
- </property>
<property name="connectionConfig">
<bean class="org.ldaptive.ConnectionConfig" p:ldapUrl="ldap://localhost:10389"
- p:useStartTLS="true" p:connectTimeout="2000" p:responseTimeout="4000">
+ p:useStartTLS="true" p:connectTimeout="PT2S" p:responseTimeout="PT4S">
<property name="connectionInitializer">
<bean class="org.ldaptive.BindConnectionInitializer" p:bindDn="cn=Directory Manager"
p:bindCredential="password" />
@@ -57,12 +43,12 @@
</bean>
</property>
<property name="pruneStrategy">
- <bean class="org.ldaptive.pool.IdlePruneStrategy" p:prunePeriod="300" p:idleTime="600" />
+ <bean class="org.ldaptive.pool.IdlePruneStrategy" p:prunePeriod="PT5M" p:idleTime="PT10M" />
</property>
</bean>
</property>
</bean>
- <bean class="org.ldaptive.SearchExecutor" p:baseDn="ou=people,dc=shibboleth,dc=net" p:returnAttributes="uid,homephone,mail" p:timeLimit="7000" />
+ <bean class="org.ldaptive.SearchExecutor" p:baseDn="ou=people,dc=shibboleth,dc=net" p:returnAttributes="uid,homephone,mail" p:timeLimit="PT7S" />
<bean id="cache" class="com.google.common.cache.Cache" factory-bean="cacheBuilderExternal" factory-method="build" />
<bean id="filter" class="net.shibboleth.idp.attribute.resolver.dc.ldap.impl.TemplatedExecutableSearchFilterBuilder"
p:templateText="(uid=${resolutionContext.principal})" p:velocityEngine-ref="shibboleth.VelocityEngine"
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/ldap-attribute-resolver-spring-props-context.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/ldap-attribute-resolver-spring-props-context.xml
index 23b4676..79d44a3 100644
--- a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/ldap-attribute-resolver-spring-props-context.xml
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/ldap-attribute-resolver-spring-props-context.xml
@@ -15,20 +15,6 @@
</constructor-arg>
<constructor-arg index="1">
<bean class="org.ldaptive.DefaultConnectionFactory">
- <property name="provider">
- <bean class="org.ldaptive.provider.jndi.JndiProvider">
- <property name="providerConfig">
- <bean class="org.ldaptive.provider.jndi.JndiProviderConfig">
- <property name="properties">
- <map>
- <entry key="name1" value="%{jndi.property1}" />
- <entry key="name2" value="%{jndi.property2}" />
- </map>
- </property>
- </bean>
- </property>
- </bean>
- </property>
<property name="connectionConfig">
<bean class="org.ldaptive.ConnectionConfig" p:ldapUrl="%{connectionConfig.ldapURL}"
p:useStartTLS="%{connectionConfig.useStartTLS}"
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/ldap-v2.properties b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/ldap-v2.properties
index c1a509c..8fb999d 100644
--- a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/ldap-v2.properties
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/ldap-v2.properties
@@ -14,9 +14,6 @@ search.filter=(uid=${resolutionContext.principal})
search.returnAttributes=uid,homephone,mail
search.timeLimit=PT7S
-jndi.property1=value1
-jndi.property2=value2
-
connectionPool.blockWaitTime=PT5S
connectionPool.expirationTime=PT10M
connectionPool.minPoolSize=5
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/ldap-v3.properties b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/ldap-v3.properties
index 69203de..8d90f8f 100644
--- a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/ldap-v3.properties
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/ldap-v3.properties
@@ -1,7 +1,7 @@
connectionConfig.ldapURL=ldap://localhost:10389
connectionConfig.useStartTLS=true
-connectionConfig.connectTimeout=2000
-connectionConfig.responseTimeout=4000
+connectionConfig.connectTimeout=PT2S
+connectionConfig.responseTimeout=PT4S
connectionConfig.bindDn=cn=Directory Manager
connectionConfig.bindCredential=password
@@ -12,20 +12,17 @@ noRetryDelay=PT5M
search.baseDn=ou=people,dc=shibboleth,dc=net
search.filter=(uid=${resolutionContext.principal})
search.returnAttributes=uid,homephone,mail
-search.timeLimit=7000
+search.timeLimit=PT7S
-jndi.property1=value1
-jndi.property2=value2
-
-connectionPool.blockWaitTime=5000
+connectionPool.blockWaitTime=PT5S
connectionPool.minPoolSize=5
connectionPool.maxPoolSize=10
connectionPool.validatePeriodically=true
-connectionPool.validatePeriod=900
+connectionPool.validatePeriod=PT15M
connectionPool.validator.baseDn=dc=shibboleth,dc=net
connectionPool.validator.filter=(ou=people)
-connectionPool.pruneStrategy.prunePeriod=300
-connectionPool.pruneStrategy.idleTime=600
+connectionPool.pruneStrategy.prunePeriod=PT5M
+connectionPool.pruneStrategy.idleTime=PT10M
connectionPool.failFastInitialize=false
cache.cacheBuilderSpec=expireAfterAccess=10s,maximumSize=25
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-hybrid.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-hybrid.xml
index 7ab6cff..67321e5 100644
--- a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-hybrid.xml
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-hybrid.xml
@@ -7,8 +7,6 @@
useStartTLS="true" searchTimeLimit="PT7S"
executableSearchBuilderRef="filter" mappingStrategyRef="mappings" validatorRef="validator" noRetryDelay="PT5M"
connectTimeout="PT2S" responseTimeout="PT4S">
- <LDAPProperty name="name1" value="value1" />
- <LDAPProperty name="name2" value="value2" />
<StartTLSTrustCredential xsi:type="security:X509Inline" xmlns:security="urn:mace:shibboleth:2.0:security"
id="LDAPtoIdPCredential">
<security:Certificate>
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-jndi.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-jndi.xml
deleted file mode 100644
index 0d0942c..0000000
--- a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-jndi.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<AttributeResolver xmlns="urn:mace:shibboleth:2.0:resolver" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sec="urn:mace:shibboleth:2.0:security"
- xsi:schemaLocation="urn:mace:shibboleth:2.0:resolver http://shibboleth.net/schema/idp/shibboleth-attribute-resolver.xsd
- urn:mace:shibboleth:2.0:security http://shibboleth.net/schema/idp/shibboleth-security.xsd">
-
- <DataConnector id="myLDAP" xsi:type="LDAPDirectory"
- ldapURL="ldap://localhost:10389"
- baseDN="ou=people,dc=shibboleth,dc=net"
- principal="cn=Directory Manager"
- principalCredential="password"
- useStartTLS="true"
- searchTimeLimit="PT7S"
- noResultIsError="true"
- multipleResultsIsError="true"
- noRetryDelay="PT5M"
- trustFile="net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap.crt"
- connectTimeout="PT2S"
- responseTimeout="PT4S">
-
- <LDAPProperty name="name1" value="value1"/>
- <LDAPProperty name="java.naming.ldap.attributes.binary" value="jpegPhoto employeeNumber"/>
- <LDAPProperty name="java.naming.ldap.derefAliases" value="finding"/>
-
- <ReturnAttributes>cn sn jpegPhoto employeeNumber</ReturnAttributes>
-
- <FilterTemplate>
- <![CDATA[
- (uid=${resolutionContext.principal})
- ]]>
- </FilterTemplate>
-
- </DataConnector>
-
-</AttributeResolver>
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-multi.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-multi.xml
index 960316c..c0ee482 100644
--- a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-multi.xml
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-multi.xml
@@ -54,11 +54,6 @@
<sec:Certificate>src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/client.crt</sec:Certificate>
</StartTLSTrustCredential>
-
- <LDAPProperty name="name2" value="value2"/>
-
- <LDAPProperty name="name1" value="value1"/>
-
<ResultCacheBean>cache</ResultCacheBean>
<ResultCacheBean>cache</ResultCacheBean>
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-nosec.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-nosec.xml
index 709a3e5..b0d1a51 100644
--- a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-nosec.xml
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-nosec.xml
@@ -42,12 +42,8 @@
<sec:Certificate>src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/client.crt</sec:Certificate>
</StartTLSAuthenticationCredential>
- <LDAPProperty name="name2" value="value2"/>
-
<ReturnAttributes>a b g t</ReturnAttributes>
- <LDAPProperty name="name1" value="value1"/>
-
<ReturnAttributes>a b g t</ReturnAttributes>
<FilterTemplate>
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-props.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-props.xml
index 7dc1bf6..cc87424 100644
--- a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-props.xml
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2-props.xml
@@ -21,8 +21,6 @@
]]>
</FilterTemplate>
<ReturnAttributes>%{search.returnAttributes}</ReturnAttributes>
- <LDAPProperty name="name1" value="%{jndi.property1}"/>
- <LDAPProperty name="name2" value="%{jndi.property2}"/>
<StartTLSTrustCredential xsi:type="security:X509Inline" xmlns:security="urn:mace:shibboleth:2.0:security" id="LDAPtoIdPCredential">
<security:Certificate>
MIICATCCAWoCCQCZy4ovDlQTvDANBgkqhkiG9w0BAQUFADBFMRMwEQYKCZImiZPy
diff --git a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2.xml b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2.xml
index 508ddfd..ff1c684 100644
--- a/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2.xml
+++ b/idp-attribute-resolver-spring/src/test/resources/net/shibboleth/idp/attribute/resolver/spring/dc/ldap/resolver/ldap-attribute-resolver-v2.xml
@@ -58,12 +58,8 @@
<InputAttributeDefinition ref="321"/>
- <LDAPProperty name="name2" value="value2"/>
-
<ReturnAttributes>a b g t employeeNumber</ReturnAttributes>
- <LDAPProperty name="name1" value="value1"/>
-
<ReturnAttributes>a b g t employeeNumber</ReturnAttributes>
<BinaryAttributes>g employeeNumber</BinaryAttributes>
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/PooledTemplateSearchDnResolver.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/PooledTemplateSearchDnResolver.java
index 76cc4b6..93324ac 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/PooledTemplateSearchDnResolver.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/PooledTemplateSearchDnResolver.java
@@ -76,9 +76,9 @@ public class PooledTemplateSearchDnResolver extends AbstractTemplateSearchDnReso
@Override public String toString() {
return String.format(
"[%s@%d::factory=%s, templateName=%s, baseDn=%s, userFilter=%s, userFilterParameters=%s, "
- + "allowMultipleDns=%s, subtreeSearch=%s, derefAliases=%s, followReferrals=%s]",
+ + "allowMultipleDns=%s, subtreeSearch=%s, derefAliases=%s]",
getClass().getName(), hashCode(), factory, getTemplate().getTemplateName(), getBaseDn(),
getUserFilter(), Arrays.toString(getUserFilterParameters()), getAllowMultipleDns(), getSubtreeSearch(),
- getDerefAliases(), getFollowReferrals());
+ getDerefAliases());
}
}
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/TemplateSearchDnResolver.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/TemplateSearchDnResolver.java
index f0d415d..b09c59a 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/TemplateSearchDnResolver.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/TemplateSearchDnResolver.java
@@ -77,9 +77,9 @@ public class TemplateSearchDnResolver extends AbstractTemplateSearchDnResolver i
@Override public String toString() {
return String.format(
"[%s@%d::factory=%s, templateName=%s, baseDn=%s, userFilter=%s, userFilterParameters=%s, "
- + "allowMultipleDns=%s, subtreeSearch=%s, derefAliases=%s, followReferrals=%s]",
+ + "allowMultipleDns=%s, subtreeSearch=%s, derefAliases=%s]",
getClass().getName(), hashCode(), factory, getTemplate().getTemplateName(), getBaseDn(),
getUserFilter(), Arrays.toString(getUserFilterParameters()), getAllowMultipleDns(), getSubtreeSearch(),
- getDerefAliases(), getFollowReferrals());
+ getDerefAliases());
}
}
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
new file mode 100644
index 0000000..2636d45
--- /dev/null
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/LDAPAuthenticationFactoryBean.java
@@ -0,0 +1,474 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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
+ *
+ * http://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 net.shibboleth.idp.authn.config;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import net.shibboleth.idp.authn.PooledTemplateSearchDnResolver;
+import org.apache.velocity.app.VelocityEngine;
+import org.ldaptive.BindConnectionInitializer;
+import org.ldaptive.ConnectionConfig;
+import org.ldaptive.ConnectionInitializer;
+import org.ldaptive.Credential;
+import org.ldaptive.DefaultConnectionFactory;
+import org.ldaptive.LdapURL;
+import org.ldaptive.auth.Authenticator;
+import org.ldaptive.auth.FormatDnResolver;
+import org.ldaptive.auth.PooledBindAuthenticationHandler;
+import org.ldaptive.auth.ext.ActiveDirectoryAuthenticationResponseHandler;
+import org.ldaptive.auth.ext.EDirectoryAuthenticationResponseHandler;
+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.BlockingConnectionPool;
+import org.ldaptive.pool.IdlePruneStrategy;
+import org.ldaptive.pool.PoolConfig;
+import org.ldaptive.pool.PooledConnectionFactory;
+import org.ldaptive.pool.SearchValidator;
+import org.ldaptive.ssl.CredentialConfig;
+import org.ldaptive.ssl.SslConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.config.AbstractFactoryBean;
+
+/** LDAP Authentication configuration. See ldap-authn-config.xml */
+public class LDAPAuthenticationFactoryBean extends AbstractFactoryBean<Authenticator> {
+
+ /** Class logger. */
+ @Nonnull
+ private final Logger log = LoggerFactory.getLogger(LDAPAuthenticationFactoryBean.class);
+
+ /** Enum that defines authenticator configuration. Labels maps to values in ldap.properties. */
+ public enum AuthenticatorType {
+ ANON_SEARCH("anonSearchAuthenticator"),
+ BIND_SEARCH("bindSearchAuthenticator"),
+ DIRECT("directAuthenticator"),
+ AD("adAuthenticator");
+
+ /** Label for this type. */
+ private final String label;
+
+ AuthenticatorType(final String s) {
+ label = s;
+ }
+
+ public String label() {
+ return label;
+ }
+
+ public static AuthenticatorType fromLabel(final String s) {
+ for (AuthenticatorType at : AuthenticatorType.values()) {
+ if (at.label().equals(s)) {
+ return at;
+ }
+ }
+ return null;
+ }
+ }
+
+ /** Enum that defines LDAP trust configuration. Labels maps to values in ldap.properties. */
+ public enum TrustType {
+ JVM("jvmTrust"),
+ CERTIFICATE("certificateTrust"),
+ KEYSTORE("keyStoreTrust");
+
+ /** Label for this type. */
+ private final String label;
+
+ TrustType(final String s) {
+ label = s;
+ }
+
+ public String label() {
+ return label;
+ }
+
+ public static TrustType fromLabel(final String s) {
+ for (TrustType tt : TrustType.values()) {
+ if (tt.label().equals(s)) {
+ return tt;
+ }
+ }
+ return null;
+ }
+ }
+
+ /** Type of authenticator to configure. */
+ private AuthenticatorType authenticatorType;
+
+ /** Type of trust model to configure. */
+ private TrustType trustType;
+
+ /** LDAP URL. */
+ private String ldapUrl;
+
+ /** Whether to use startTLS for connections. */
+ private boolean useStartTLS;
+
+ /** Whether to use LDAPS for connections. */
+ private boolean useSSL;
+
+ /** Wait time for connects. */
+ private Duration connectTimeout;
+
+ /** Wait time for operation responses. */
+ private Duration responseTimeout;
+
+ /** Trust configuration when using certificate based trust. */
+ private CredentialConfig trustCertificatesCredentialConfig;
+
+ /** Trust configuration when using truststore based trust. */
+ private CredentialConfig truststoreCredentialConfig;
+
+ /** Wait time for getting a connection from the pool. */
+ private Duration blockWaitTime;
+
+ /** Minimum pool size. */
+ private int minPoolSize;
+
+ /** Maximum pool size. */
+ private int maxPoolSize;
+
+ /** Whether to validate connections when checked out from the pool. */
+ private boolean validateOnCheckout;
+
+ /** Whether to validate connections periodically on a background thread. */
+ private boolean validatePeriodically;
+
+ /** Period at which to validate periodically. */
+ private Duration validatePeriod;
+
+ /** Period at which to check and enforce the idle time. */
+ private Duration prunePeriod;
+
+ /** Time at which a connection has been idle and should be removed from the pool. */
+ private Duration idleTime;
+
+ /** Java format string used to construct an LDAP DN. See {@link String#format(String, Object...)}. */
+ private String dnFormat;
+
+ /** Base DN used to search for users. */
+ private String baseDn;
+
+ /** LDAP filter used to search for users. */
+ private String userFilter;
+
+ /** Whether to use a SUBTREE search with the baseDn. */
+ private boolean subtreeSearch;
+
+ /** Whether to return the LDAP entry even if the user BIND fails. */
+ private boolean resolveEntryOnFailure;
+
+ /** Velocity engine used to materialize the LDAP filter. */
+ private VelocityEngine velocityEngine;
+
+ /** Privileged entry used to search for users. */
+ private String bindDn;
+
+ /** Credential for the privileged entry. */
+ private String bindDnCredential;
+
+ /** Whether to use the password policy control with the BIND operation. See draft-behera-ldap-password-policy. */
+ private boolean usePasswordPolicy;
+
+ /** Whether to use the password expiration control with the BIND operation. See draft-vchu-ldap-pwd-policy. */
+ private boolean usePasswordExpiration;
+
+ /** Whether to use account state data as defined by the FreeIPA directory schema. */
+ private boolean isFreeIPA;
+
+ /** Whether to use account state data as defined by the EDirectory schema. */
+ private boolean isEDirectory;
+
+ public void setAuthenticatorType(final String type) {
+ authenticatorType = AuthenticatorType.fromLabel(type);
+ }
+
+ public void setTrustType(final String type) {
+ trustType = TrustType.fromLabel(type);
+ }
+
+ public void setLdapUrl(final String url) {
+ ldapUrl = url;
+ }
+
+ public void setUseStartTLS(final boolean b) {
+ useStartTLS = b;
+ }
+
+ public void setUseSSL(final boolean b) {
+ useSSL = b;
+ }
+
+ public void setConnectTimeout(final Duration timeout) {
+ connectTimeout = timeout;
+ }
+
+ public void setResponseTimeout(final Duration timeout) {
+ responseTimeout = timeout;
+ }
+
+ public void setTrustCertificatesCredentialConfig(final CredentialConfig config) {
+ trustCertificatesCredentialConfig = config;
+ }
+
+ public void setTruststoreCredentialConfig(final CredentialConfig config) {
+ truststoreCredentialConfig = config;
+ }
+
+ public void setBlockWaitTime(final Duration time) {
+ blockWaitTime = time;
+ }
+
+ public void setMinPoolSize(final int size) {
+ minPoolSize = size;
+ }
+
+ public void setMaxPoolSize(final int size) {
+ maxPoolSize = size;
+ }
+
+ public void setValidateOnCheckout(final boolean b) {
+ validateOnCheckout = b;
+ }
+
+ public void setValidatePeriodically(final boolean b) {
+ validatePeriodically = b;
+ }
+
+ public void setValidatePeriod(final Duration period) {
+ validatePeriod = period;
+ }
+
+ public void setPrunePeriod(final Duration period) {
+ prunePeriod = period;
+ }
+
+ public void setIdleTime(final Duration time) {
+ idleTime = time;
+ }
+
+ public void setDnFormat(final String format) {
+ dnFormat = format;
+ }
+
+ public void setBaseDn(final String dn) {
+ baseDn = dn;
+ }
+
+ public void setUserFilter(final String filter) {
+ userFilter = filter;
+ }
+
+ public void setSubtreeSearch(final boolean b) {
+ subtreeSearch = b;
+ }
+
+ public void setResolveEntryOnFailure(final boolean b) {
+ resolveEntryOnFailure = b;
+ }
+
+ public void setVelocityEngine(final VelocityEngine engine) {
+ velocityEngine = engine;
+ }
+
+ public void setBindDn(final String dn) {
+ bindDn = dn;
+ }
+
+ public void setBindDnCredential(final String credential) {
+ bindDnCredential = credential;
+ }
+
+ public void setUsePasswordPolicy(final boolean b) {
+ usePasswordPolicy = b;
+ }
+
+ public void setUsePasswordExpiration(final boolean b) {
+ usePasswordExpiration = b;
+ }
+
+ public void setFreeIPA(final boolean b) {
+ isFreeIPA = b;
+ }
+
+ public void setEDirectory(final boolean b) {
+ isEDirectory = b;
+ }
+
+ /**
+ * Returns a new SslConfig object derived from the configured {@link #trustType}. Default uses JVM trust.
+ *
+ * @return new SslConfig
+ */
+ protected SslConfig createSslConfig() {
+ final SslConfig config = new SslConfig();
+ switch(trustType) {
+ case CERTIFICATE:
+ config.setCredentialConfig(trustCertificatesCredentialConfig);
+ break;
+ case KEYSTORE:
+ config.setCredentialConfig(truststoreCredentialConfig);
+ break;
+ case JVM:
+ default:
+ break;
+ }
+ return config;
+ }
+
+ /**
+ * Returns a new ConnectionConfig without a connection initializer.
+ *
+ * @return new ConnectionConfig
+ */
+ protected ConnectionConfig createConnectionConfig() {
+ return createConnectionConfig(null);
+ }
+
+ /**
+ * Returns a new ConnectionConfig with the supplied connection initializer.
+ *
+ * @param initializer to configure or null
+ *
+ * @return new ConnectionConfig
+ */
+ protected ConnectionConfig createConnectionConfig(@Nullable final ConnectionInitializer initializer) {
+ final ConnectionConfig config = new ConnectionConfig();
+ config.setLdapUrl(ldapUrl);
+ config.setUseStartTLS(useStartTLS);
+ config.setConnectTimeout(connectTimeout);
+ config.setResponseTimeout(responseTimeout);
+ config.setSslConfig(createSslConfig());
+ if (initializer != null) {
+ config.setConnectionInitializer(initializer);
+ }
+ return config;
+ }
+
+ /**
+ * Returns a new blocking connection pool. Wires a {@link SearchValidator} by default.
+ *
+ * @param name of the connection pool
+ * @param config to assign to the pool
+ *
+ * @return new blocking connection pool
+ */
+ protected BlockingConnectionPool createConnectionPool(final String name, final ConnectionConfig config)
+ {
+ final PoolConfig poolConfig = new PoolConfig();
+ poolConfig.setMinPoolSize(minPoolSize);
+ poolConfig.setMaxPoolSize(maxPoolSize);
+ poolConfig.setValidateOnCheckOut(validateOnCheckout);
+ poolConfig.setValidatePeriodically(validatePeriodically);
+ poolConfig.setValidatePeriod(validatePeriod);
+ final BlockingConnectionPool pool = new BlockingConnectionPool();
+ pool.setName(name);
+ pool.setBlockWaitTime(blockWaitTime);
+ pool.setPoolConfig(poolConfig);
+ pool.setPruneStrategy(new IdlePruneStrategy(prunePeriod, idleTime));
+ pool.setValidator(new SearchValidator());
+ pool.setFailFastInitialize(false);
+ pool.setConnectionFactory(new DefaultConnectionFactory(config));
+ pool.initialize();
+ return pool;
+ }
+
+ @Override
+ protected Authenticator createInstance() throws Exception {
+ // check for deprecated useSSL property
+ if (useSSL) {
+ log.warn("The useSSL property is deprecated, specify the use of LDAPS in your URL by using the ldaps:// scheme.");
+ final LdapURL url = new LdapURL(ldapUrl);
+ for (String s : url.getHostnamesWithSchemeAndPort()) {
+ if (!s.startsWith("ldaps://")) {
+ throw new IllegalArgumentException("useSSL property specified but URL scheme is not ldaps:// for " + s);
+ }
+ }
+ }
+ final Authenticator authenticator = new Authenticator();
+ authenticator.setAuthenticationHandler(
+ new PooledBindAuthenticationHandler(
+ new PooledConnectionFactory(createConnectionPool("bind-pool", createConnectionConfig()))));
+ switch(authenticatorType) {
+ case BIND_SEARCH:
+ final PooledTemplateSearchDnResolver bindSearchDnResolver =
+ new PooledTemplateSearchDnResolver(velocityEngine, userFilter);
+ bindSearchDnResolver.setBaseDn(baseDn);
+ bindSearchDnResolver.setSubtreeSearch(subtreeSearch);
+ bindSearchDnResolver.setConnectionFactory(
+ new PooledConnectionFactory(
+ createConnectionPool(
+ "search-pool",
+ createConnectionConfig(new BindConnectionInitializer(bindDn, new Credential(bindDnCredential))))));
+ authenticator.setDnResolver(bindSearchDnResolver);
+ authenticator.setResolveEntryOnFailure(resolveEntryOnFailure);
+ break;
+ case DIRECT:
+ authenticator.setDnResolver(new FormatDnResolver(dnFormat));
+ authenticator.setResolveEntryOnFailure(resolveEntryOnFailure);
+ break;
+ case AD:
+ authenticator.setDnResolver(new FormatDnResolver(dnFormat));
+ authenticator.setResolveEntryOnFailure(resolveEntryOnFailure);
+ authenticator.setAuthenticationResponseHandlers(new ActiveDirectoryAuthenticationResponseHandler());
+ break;
+ case ANON_SEARCH:
+ final PooledTemplateSearchDnResolver anonSearchDnResolver =
+ new PooledTemplateSearchDnResolver(velocityEngine, userFilter);
+ anonSearchDnResolver.setBaseDn(baseDn);
+ anonSearchDnResolver.setSubtreeSearch(subtreeSearch);
+ anonSearchDnResolver.setConnectionFactory(
+ new PooledConnectionFactory(
+ createConnectionPool(
+ "search-pool",
+ createConnectionConfig())));
+ authenticator.setDnResolver(anonSearchDnResolver);
+ authenticator.setResolveEntryOnFailure(resolveEntryOnFailure);
+ default:
+ break;
+ }
+ final List<String> retAttrs = new ArrayList<>();
+ if (usePasswordPolicy) {
+ authenticator.setAuthenticationRequestHandlers(new PasswordPolicyAuthenticationRequestHandler());
+ authenticator.setAuthenticationResponseHandlers(new PasswordPolicyAuthenticationResponseHandler());
+ } else if (usePasswordExpiration) {
+ authenticator.setAuthenticationResponseHandlers(new PasswordExpirationAuthenticationResponseHandler());
+ } else if (isEDirectory) {
+ retAttrs.addAll(Arrays.asList(EDirectoryAuthenticationResponseHandler.ATTRIBUTES));
+ authenticator.setAuthenticationResponseHandlers(new EDirectoryAuthenticationResponseHandler());
+ } else if (isFreeIPA) {
+ retAttrs.addAll(Arrays.asList(FreeIPAAuthenticationResponseHandler.ATTRIBUTES));
+ authenticator.setAuthenticationResponseHandlers(new FreeIPAAuthenticationResponseHandler());
+ }
+ if (!retAttrs.isEmpty()) {
+ authenticator.setReturnAttributes(retAttrs.toArray(new String[0]));
+ }
+ return authenticator;
+ }
+
+ @Override
+ public Class<?> getObjectType() {
+ return Authenticator.class;
+ }
+}
diff --git a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/LDAPCredentialValidatorTest.java b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/LDAPCredentialValidatorTest.java
index a88c1b0..1164162 100644
--- a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/LDAPCredentialValidatorTest.java
+++ b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/LDAPCredentialValidatorTest.java
@@ -17,6 +17,7 @@
package net.shibboleth.idp.authn.impl;
+import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -417,7 +418,7 @@ public class LDAPCredentialValidatorTest extends BaseAuthenticationContextTest {
warningAuthenticator.setAuthenticationResponseHandlers(new AuthenticationResponseHandler() {
public void handle(AuthenticationResponse response) throws LdapException {
response.setAccountState(
- new AccountState(new AccountState.DefaultWarning(java.util.Calendar.getInstance(), 10)));
+ new AccountState(new AccountState.DefaultWarning(ZonedDateTime.now(), 10)));
}
});
validator.setAuthenticator(warningAuthenticator);
diff --git a/idp-conf/pom.xml b/idp-conf/pom.xml
index 426ca71..605aa9b 100644
--- a/idp-conf/pom.xml
+++ b/idp-conf/pom.xml
@@ -99,11 +99,6 @@
<!-- Test Dependencies -->
<dependency>
- <groupId>org.ldaptive</groupId>
- <artifactId>ldaptive-unboundid</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
<groupId>com.unboundid</groupId>
<artifactId>unboundid-ldapsdk</artifactId>
<scope>test</scope>
diff --git a/idp-conf/src/main/resources/conf/authn/ldap-authn-config.xml b/idp-conf/src/main/resources/conf/authn/ldap-authn-config.xml
index 44e1b60..ebe0d76 100644
--- a/idp-conf/src/main/resources/conf/authn/ldap-authn-config.xml
+++ b/idp-conf/src/main/resources/conf/authn/ldap-authn-config.xml
@@ -5,129 +5,46 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
-
default-init-method="initialize"
default-destroy-method="destroy"
default-lazy-init="true">
- <alias name="%{idp.authn.LDAP.authenticator:anonSearchAuthenticator}" alias="shibboleth.authn.LDAP.authenticator" />
<bean id="shibboleth.authn.LDAP.returnAttributes" parent="shibboleth.CommaDelimStringArray">
<constructor-arg type="java.lang.String" value="%{idp.authn.LDAP.returnAttributes:1.1}" />
</bean>
- <!-- Connection Configuration -->
- <bean id="connectionConfig" class="org.ldaptive.ConnectionConfig" abstract="true" p:ldapUrl="%{idp.authn.LDAP.ldapURL}"
- p:useStartTLS="%{idp.authn.LDAP.useStartTLS:true}"
- p:useSSL="%{idp.authn.LDAP.useSSL:false}"
- p:connectTimeoutDuration="%{idp.authn.LDAP.connectTimeout:PT3S}"
- p:responseTimeoutDuration="%{idp.authn.LDAP.responseTimeout:PT3S}"
- p:sslConfig-ref="sslConfig" />
-
- <alias name="%{idp.authn.LDAP.sslConfig:certificateTrust}" alias="sslConfig" />
-
- <bean id="jvmTrust" class="org.ldaptive.ssl.SslConfig" />
- <bean id="certificateTrust" class="org.ldaptive.ssl.SslConfig">
- <property name="credentialConfig">
- <bean parent="shibboleth.X509ResourceCredentialConfig" p:trustCertificates="%{idp.authn.LDAP.trustCertificates:undefined}" />
- </property>
- </bean>
- <bean id="keyStoreTrust" class="org.ldaptive.ssl.SslConfig">
- <property name="credentialConfig">
- <bean parent="shibboleth.KeystoreResourceCredentialConfig" p:truststore="%{idp.authn.LDAP.trustStore:undefined}" />
- </property>
- </bean>
-
- <!-- Authentication handler -->
- <bean id="authHandler" class="org.ldaptive.auth.PooledBindAuthenticationHandler" p:connectionFactory-ref="bindPooledConnectionFactory" />
- <bean id="bindPooledConnectionFactory" class="org.ldaptive.pool.PooledConnectionFactory" p:connectionPool-ref="bindConnectionPool" />
- <bean id="bindConnectionPool" class="org.ldaptive.pool.BlockingConnectionPool" parent="connectionPool"
- p:connectionFactory-ref="bindConnectionFactory" p:name="bind-pool" />
- <bean id="bindConnectionFactory" class="org.ldaptive.DefaultConnectionFactory" p:connectionConfig-ref="bindConnectionConfig" />
- <bean id="bindConnectionConfig" parent="connectionConfig" />
-
- <!-- Format DN resolution -->
- <bean id="formatDnResolver" class="org.ldaptive.auth.FormatDnResolver" p:format="%{idp.authn.LDAP.dnFormat:undefined}" />
-
- <!-- Pool Configuration -->
- <bean id="connectionPool" class="org.ldaptive.pool.BlockingConnectionPool" abstract="true"
- p:blockWaitTimeDuration="%{idp.pool.LDAP.blockWaitTime:PT3S}"
- p:poolConfig-ref="poolConfig"
- p:pruneStrategy-ref="pruneStrategy"
- p:validator-ref="searchValidator"
- p:failFastInitialize="false" />
- <bean id="poolConfig" class="org.ldaptive.pool.PoolConfig"
- p:minPoolSize="%{idp.pool.LDAP.minSize:3}"
- p:maxPoolSize="%{idp.pool.LDAP.maxSize:10}"
- p:validateOnCheckOut="%{idp.pool.LDAP.validateOnCheckout:false}"
- p:validatePeriodically="%{idp.pool.LDAP.validatePeriodically:true}"
- p:validatePeriodDuration="%{idp.pool.LDAP.validatePeriod:PT5M}" />
- <bean id="pruneStrategy" class="org.ldaptive.pool.IdlePruneStrategy"
- p:prunePeriodDuration="%{idp.pool.LDAP.prunePeriod:PT5M}"
- p:idleTimeDuration="%{idp.pool.LDAP.idleTime:PT10M}" />
- <bean id="searchValidator" class="org.ldaptive.pool.SearchValidator" />
-
- <!-- Anonymous Search Configuration -->
- <bean name="anonSearchAuthenticator" class="org.ldaptive.auth.Authenticator" p:resolveEntryOnFailure="%{idp.authn.LDAP.resolveEntryOnFailure:false}">
- <constructor-arg index="0" ref="anonSearchDnResolver" />
- <constructor-arg index="1" ref="authHandler" />
- </bean>
- <bean id="anonSearchDnResolver" class="net.shibboleth.idp.authn.PooledTemplateSearchDnResolver"
- p:baseDn="#{'%{idp.authn.LDAP.baseDN:undefined}'.trim()}"
- p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}"
- p:connectionFactory-ref="anonSearchPooledConnectionFactory" >
- <constructor-arg index="0" ref="shibboleth.VelocityEngine" />
- <constructor-arg index="1" value="#{'%{idp.authn.LDAP.userFilter:undefined}'.trim()}" />
- </bean>
- <bean id="anonSearchPooledConnectionFactory" class="org.ldaptive.pool.PooledConnectionFactory"
- p:connectionPool-ref="anonSearchConnectionPool" />
- <bean id="anonSearchConnectionPool" class="org.ldaptive.pool.BlockingConnectionPool" parent="connectionPool"
- p:connectionFactory-ref="anonSearchConnectionFactory" p:name="search-pool" />
- <bean id="anonSearchConnectionFactory" class="org.ldaptive.DefaultConnectionFactory" p:connectionConfig-ref="anonSearchConnectionConfig" />
- <bean id="anonSearchConnectionConfig" parent="connectionConfig" />
-
- <!-- Bind Search Configuration -->
- <bean name="bindSearchAuthenticator" class="org.ldaptive.auth.Authenticator" p:resolveEntryOnFailure="%{idp.authn.LDAP.resolveEntryOnFailure:false}">
- <constructor-arg index="0" ref="bindSearchDnResolver" />
- <constructor-arg index="1" ref="authHandler" />
- </bean>
- <bean id="bindSearchDnResolver" class="net.shibboleth.idp.authn.PooledTemplateSearchDnResolver"
- p:baseDn="#{'%{idp.authn.LDAP.baseDN:undefined}'.trim()}"
- p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}"
- p:connectionFactory-ref="bindSearchPooledConnectionFactory" >
- <constructor-arg index="0" ref="shibboleth.VelocityEngine" />
- <constructor-arg index="1" value="#{'%{idp.authn.LDAP.userFilter:undefined}'.trim()}" />
- </bean>
- <bean id="bindSearchPooledConnectionFactory" class="org.ldaptive.pool.PooledConnectionFactory"
- p:connectionPool-ref="bindSearchConnectionPool" />
- <bean id="bindSearchConnectionPool" class="org.ldaptive.pool.BlockingConnectionPool" parent="connectionPool"
- p:connectionFactory-ref="bindSearchConnectionFactory" p:name="search-pool" />
- <bean id="bindSearchConnectionFactory" class="org.ldaptive.DefaultConnectionFactory" p:connectionConfig-ref="bindSearchConnectionConfig" />
- <bean id="bindSearchConnectionConfig" parent="connectionConfig" p:connectionInitializer-ref="bindConnectionInitializer" />
- <bean id="bindConnectionInitializer" class="org.ldaptive.BindConnectionInitializer"
- p:bindDn="#{'%{idp.authn.LDAP.bindDN:undefined}'.trim()}">
- <property name="bindCredential">
- <bean class="org.ldaptive.Credential">
- <constructor-arg value="%{idp.authn.LDAP.bindDNCredential:undefined}" />
- </bean>
- </property>
- </bean>
-
- <!-- Direct Search Configuration -->
- <bean name="directAuthenticator" class="org.ldaptive.auth.Authenticator" p:resolveEntryOnFailure="%{idp.authn.LDAP.resolveEntryOnFailure:false}">
- <constructor-arg index="0" ref="formatDnResolver" />
- <constructor-arg index="1" ref="authHandler" />
- </bean>
-
- <!-- Want to use ppolicy? Configure support by adding <bean id="authenticationResponseHandler" class="org.ldaptive.auth.ext.PasswordPolicyAuthenticationResponseHandler"
- /> add p:authenticationResponseHandlers-ref="authenticationResponseHandler" to the authenticator <bean id="authenticationControl"
- class="org.ldaptive.control.PasswordPolicyControl" /> add p:authenticationControls-ref="authenticationControl" to the authHandler -->
-
- <!-- Active Directory Configuration -->
- <bean id="adAuthenticator" class="org.ldaptive.auth.Authenticator" p:authenticationResponseHandlers-ref="authenticationResponseHandler"
- p:resolveEntryOnFailure="%{idp.authn.LDAP.resolveEntryOnFailure:false}">
- <constructor-arg index="0" ref="formatDnResolver" />
- <constructor-arg index="1" ref="authHandler" />
- </bean>
- <bean id="authenticationResponseHandler" class="org.ldaptive.auth.ext.ActiveDirectoryAuthenticationResponseHandler" />
+ <bean id="shibboleth.authn.LDAP.trustCertificates" parent="shibboleth.X509ResourceCredentialConfig" p:trustCertificates="%{idp.authn.LDAP.trustCertificates:undefined}" />
+ <bean id="shibboleth.authn.LDAP.truststore" parent="shibboleth.KeystoreResourceCredentialConfig" p:truststore="%{idp.authn.LDAP.trustStore:undefined}" />
+
+ <bean id="shibboleth.authn.LDAP.authenticator" class="net.shibboleth.idp.authn.config.LDAPAuthenticationFactoryBean"
+ p:authenticatorType="%{idp.authn.LDAP.authenticator:anonSearchAuthenticator}"
+ p:trustType="%{idp.authn.LDAP.sslConfig:certificateTrust}"
+ p:ldapUrl="%{idp.authn.LDAP.ldapURL}"
+ p:useStartTLS="%{idp.authn.LDAP.useStartTLS:true}"
+ p:connectTimeout="%{idp.authn.LDAP.connectTimeout:PT3S}"
+ p:responseTimeout="%{idp.authn.LDAP.responseTimeout:PT3S}"
+ p:trustCertificatesCredentialConfig-ref="shibboleth.authn.LDAP.trustCertificates"
+ p:truststoreCredentialConfig-ref="shibboleth.authn.LDAP.truststore"
+ p:blockWaitTime="%{idp.pool.LDAP.blockWaitTime:PT3S}"
+ p:minPoolSize="%{idp.pool.LDAP.minSize:3}"
+ p:maxPoolSize="%{idp.pool.LDAP.maxSize:10}"
+ p:validateOnCheckout="%{idp.pool.LDAP.validateOnCheckout:false}"
+ p:validatePeriodically="%{idp.pool.LDAP.validatePeriodically:true}"
+ p:validatePeriod="%{idp.pool.LDAP.validatePeriod:PT5M}"
+ p:prunePeriod="%{idp.pool.LDAP.prunePeriod:PT5M}"
+ p:idleTime="%{idp.pool.LDAP.idleTime:PT10M}"
+ p:dnFormat="%{idp.authn.LDAP.dnFormat:undefined}"
+ p:baseDn="#{'%{idp.authn.LDAP.baseDN:undefined}'.trim()}"
+ p:userFilter="#{'%{idp.authn.LDAP.userFilter:undefined}'.trim()}"
+ p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}"
+ p:resolveEntryOnFailure="%{idp.authn.LDAP.resolveEntryOnFailure:false}"
+ p:velocityEngine-ref="shibboleth.VelocityEngine"
+ p:bindDn="#{'%{idp.authn.LDAP.bindDN:undefined}'.trim()}"
+ p:bindDnCredential="%{idp.authn.LDAP.bindDNCredential:undefined}"
+ p:usePasswordPolicy="%{idp.authn.LDAP.usePasswordPolicy:false}"
+ p:usePasswordExpiration="%{idp.authn.LDAP.usePasswordExpiration:false}"
+ p:freeIPA="%{idp.authn.LDAP.freeIPADirectory:false}"
+ p:EDirectory="%{idp.authn.LDAP.eDirectory:false}"
+ />
</beans>
diff --git a/idp-conf/src/main/resources/system/conf/global-system.xml b/idp-conf/src/main/resources/system/conf/global-system.xml
index 084ff3d..f719000 100644
--- a/idp-conf/src/main/resources/system/conf/global-system.xml
+++ b/idp-conf/src/main/resources/system/conf/global-system.xml
@@ -58,7 +58,6 @@
<property name="arguments">
<props>
<prop key="org.apache.xml.security.ignoreLineBreaks">%{idp.apache.xml.security.ignoreLineBreaks:true}</prop>
- <prop key="org.ldaptive.provider">%{idp.ldaptive.provider:%{org.ldaptive.provider:org.ldaptive.provider.unboundid.UnboundIDProvider}}</prop>
</props>
</property>
</bean>
diff --git a/idp-conf/src/test/java/net/shibboleth/idp/test/InMemoryDirectory.java b/idp-conf/src/test/java/net/shibboleth/idp/test/InMemoryDirectory.java
index 19f7b7a..068a888 100644
--- a/idp-conf/src/test/java/net/shibboleth/idp/test/InMemoryDirectory.java
+++ b/idp-conf/src/test/java/net/shibboleth/idp/test/InMemoryDirectory.java
@@ -23,9 +23,9 @@ import java.security.KeyStore;
import javax.annotation.Nonnull;
+import com.unboundid.util.ssl.SSLUtil;
import org.ldaptive.ssl.CredentialConfigFactory;
-import org.ldaptive.ssl.SslConfig;
-import org.ldaptive.ssl.TLSSocketFactory;
+import org.ldaptive.ssl.SSLContextInitializer;
import org.springframework.core.io.Resource;
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
@@ -67,12 +67,11 @@ public class InMemoryDirectory {
final KeyStore ks = KeyStore.getInstance("JKS");
final String ksPass = "changeit";
ks.load(keystore.getInputStream(), ksPass.toCharArray());
- final TLSSocketFactory socketFactory = new TLSSocketFactory();
- socketFactory.setSslConfig(new SslConfig(CredentialConfigFactory.createKeyStoreCredentialConfig(ks, ksPass)));
- socketFactory.initialize();
-
- config.setListenerConfigs(InMemoryListenerConfig.createLDAPConfig("default", null, port,
- socketFactory));
+ final SSLContextInitializer sslInit =
+ CredentialConfigFactory.createKeyStoreCredentialConfig(ks, ksPass).createSSLContextInitializer();
+ final SSLUtil sslUtil = new SSLUtil(sslInit.getKeyManagers(), sslInit.getTrustManagers());
+ config.setListenerConfigs(
+ InMemoryListenerConfig.createLDAPConfig("default", null, port, sslUtil.createSSLSocketFactory()));
} catch (final GeneralSecurityException e) {
throw new IOException("Error reading keystore", e);
}
diff --git a/idp-distribution/pom.xml b/idp-distribution/pom.xml
index 7cd7f44..22e8c7e 100644
--- a/idp-distribution/pom.xml
+++ b/idp-distribution/pom.xml
@@ -77,16 +77,6 @@
<version>${metrics.version}</version>
<scope>runtime</scope>
</dependency>
- <dependency>
- <groupId>org.ldaptive</groupId>
- <artifactId>ldaptive-unboundid</artifactId>
- <scope>runtime</scope>
- </dependency>
- <dependency>
- <groupId>com.unboundid</groupId>
- <artifactId>unboundid-ldapsdk</artifactId>
- <scope>runtime</scope>
- </dependency>
<!-- Test Dependencies -->
diff --git a/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd b/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd
index 0512951..9308298 100644
--- a/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd
+++ b/idp-schema/src/main/resources/schema/shibboleth-attribute-resolver.xsd
@@ -775,13 +775,6 @@
</documentation>
</annotation>
</element>
- <element name="LDAPProperty" type="resolver:PropertyType">
- <annotation>
- <documentation>
- LDAP connection properties relevant to the underlying provider being used.
- </documentation>
- </annotation>
- </element>
<element name="StartTLSTrustCredential" type="sec:X509Credential">
<annotation>
<documentation>
@@ -816,7 +809,7 @@
<attribute name="connectionStrategy" type="resolver:ConnectionStrategyType">
<annotation>
<documentation>
- The LDAP connection strategy. Acceptable values are DEFAULT, ACTIVE_PASSIVE, ROUND_ROBIN, and RANDOM.
+ The LDAP connection strategy. Acceptable values are ACTIVE_PASSIVE, ROUND_ROBIN and RANDOM.
Default value is ACTIVE_PASSIVE.
</documentation>
</annotation>
@@ -1581,7 +1574,6 @@
<documentation>Supported connection strategies.</documentation>
</annotation>
<restriction base="string">
- <enumeration value="DEFAULT"/>
<enumeration value="ACTIVE_PASSIVE"/>
<enumeration value="ROUND_ROBIN"/>
<enumeration value="RANDOM"/>
@@ -1646,16 +1638,6 @@
</documentation>
</annotation>
</attribute>
- <attribute name="blockWhenEmpty" type="resolver:string">
- <annotation>
- <documentation>
- Whether the pool should block when maxPoolSize objects are in use.
- If false, pool will grow beyond the maxPoolSize value.
- Note that a properly configured blocking pool will yield better performance.
- Default value is true.
- </documentation>
- </annotation>
- </attribute>
<attribute name="blockWaitTime" type="resolver:string">
<annotation>
<documentation>
diff --git a/idp-war-distribution/pom.xml b/idp-war-distribution/pom.xml
index e8ce3e9..5bfe382 100644
--- a/idp-war-distribution/pom.xml
+++ b/idp-war-distribution/pom.xml
@@ -44,17 +44,6 @@
<version>${metrics.version}</version>
<scope>runtime</scope>
</dependency>
- <!-- IDP-1401 - UnboundID as default ldaptive LDAP provider -->
- <dependency>
- <groupId>org.ldaptive</groupId>
- <artifactId>ldaptive-unboundid</artifactId>
- <scope>runtime</scope>
- </dependency>
- <dependency>
- <groupId>com.unboundid</groupId>
- <artifactId>unboundid-ldapsdk</artifactId>
- <scope>runtime</scope>
- </dependency>
</dependencies>
<distributionManagement>
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list