[java-shib-attribute] branch main updated: JSATTR-33 LDAP referrals use default config

Scott Cantor cantor.2 at osu.edu
Mon Jul 29 12:10:30 UTC 2024


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

scantor pushed a commit to branch main
in repository java-shib-attribute.

View the commit online:
http://git.shibboleth.net/view/?p=java-shib-attribute.git;a=commit;h=3ba14e7ad467a03ca4f229ea9819b14ec8569c57

The following commit(s) were added to refs/heads/main by this push:
     new 3ba14e7ad JSATTR-33 LDAP referrals use default config
3ba14e7ad is described below

commit 3ba14e7ad467a03ca4f229ea9819b14ec8569c57
Author: Daniel Fisher <dfisher at vt.edu>
AuthorDate: Sun Jul 28 21:43:36 2024 -0400

    JSATTR-33 LDAP referrals use default config
    
    Update AbstractExecutableSearchFilterBuilder to use the factory connection config when a FollowSearchReferralHandler is configured.
    Add referral unit tests.
    
    https://shibboleth.atlassian.net/browse/JSATTR-33
---
 .../AbstractExecutableSearchFilterBuilder.java     |  18 ++++
 .../dc/ldap/impl/LDAPDataConnectorTest.java        | 108 ++++++++++++++++-----
 2 files changed, 104 insertions(+), 22 deletions(-)

diff --git a/shib-attribute-resolver-api/src/main/java/net/shibboleth/idp/attribute/resolver/dc/ldap/AbstractExecutableSearchFilterBuilder.java b/shib-attribute-resolver-api/src/main/java/net/shibboleth/idp/attribute/resolver/dc/ldap/AbstractExecutableSearchFilterBuilder.java
index 48d189a66..dded12137 100644
--- a/shib-attribute-resolver-api/src/main/java/net/shibboleth/idp/attribute/resolver/dc/ldap/AbstractExecutableSearchFilterBuilder.java
+++ b/shib-attribute-resolver-api/src/main/java/net/shibboleth/idp/attribute/resolver/dc/ldap/AbstractExecutableSearchFilterBuilder.java
@@ -14,6 +14,8 @@
 
 package net.shibboleth.idp.attribute.resolver.dc.ldap;
 
+import java.util.Arrays;
+
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
@@ -23,6 +25,9 @@ import org.ldaptive.LdapException;
 import org.ldaptive.ResultCode;
 import org.ldaptive.SearchOperation;
 import org.ldaptive.SearchResponse;
+import org.ldaptive.handler.SearchResultHandler;
+import org.ldaptive.referral.DefaultReferralConnectionFactory;
+import org.ldaptive.referral.FollowSearchReferralHandler;
 import org.slf4j.Logger;
 
 import net.shibboleth.idp.attribute.resolver.dc.ExecutableSearchBuilder;
@@ -57,6 +62,19 @@ public abstract class AbstractExecutableSearchFilterBuilder extends AbstractInit
             @Nonnull public SearchResponse execute(@Nonnull final SearchOperation operation,
                     @Nonnull final ConnectionFactory factory) throws LdapException {
                 final SearchOperation op = SearchOperation.copy(operation);
+                // if a follow referral handler is configured, replace it with a handler that uses the factory
+                // connection config
+                if (op.getSearchResultHandlers() != null && op.getSearchResultHandlers().length > 0) {
+                    op.setSearchResultHandlers(Arrays.stream(op.getSearchResultHandlers())
+                        .map(h -> {
+                            if (h instanceof FollowSearchReferralHandler) {
+                                return new FollowSearchReferralHandler(
+                                    new DefaultReferralConnectionFactory(factory.getConnectionConfig()));
+                            } else {
+                                return h;
+                            }
+                        }).toArray(SearchResultHandler[]::new));
+                }
                 op.setConnectionFactory(factory);
                 final SearchResponse response = op.execute(searchFilter);
                 log.trace("Search returned response {}", response);
diff --git a/shib-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/ldap/impl/LDAPDataConnectorTest.java b/shib-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/ldap/impl/LDAPDataConnectorTest.java
index 827a0ba50..d1540e010 100644
--- a/shib-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/ldap/impl/LDAPDataConnectorTest.java
+++ b/shib-attribute-resolver-impl/src/test/java/net/shibboleth/idp/attribute/resolver/dc/ldap/impl/LDAPDataConnectorTest.java
@@ -25,10 +25,14 @@ import java.util.Properties;
 import javax.annotation.Nonnull;
 
 import org.apache.velocity.runtime.RuntimeConstants;
+import org.ldaptive.BindConnectionInitializer;
+import org.ldaptive.ConnectionConfig;
 import org.ldaptive.ConnectionFactory;
 import org.ldaptive.DefaultConnectionFactory;
 import org.ldaptive.SearchOperation;
 import org.ldaptive.SearchRequest;
+import org.ldaptive.handler.SearchResultHandler;
+import org.ldaptive.referral.FollowSearchReferralHandler;
 import org.springframework.core.io.ClassPathResource;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
@@ -68,12 +72,18 @@ public class LDAPDataConnectorTest {
     /** Base DN defined in LDIF. */
     private static final String TEST_BASE_DN = "ou=people,dc=shibboleth,dc=net";
 
+    /** Base DN defined for referrals. */
+    private static final String TEST_REFERRAL_BASE_DN = "ou=referral,dc=shibboleth,dc=net";
+
     /** Default search attributes for entry in LDIF. */
     private static final String[] TEST_RETURN_ATTRIBUTES = new String[] {"cn", "sn", "uid", "mail"};
 
     /** In-memory directory server. */
     private InMemoryDirectory directoryServer;
 
+    /** Port the directory server is listening on. */
+    private String ldapURL;
+
     /**
      * Creates an in-memory directory server. Leverages LDIF found in test resources.
      */
@@ -82,8 +92,19 @@ public class LDAPDataConnectorTest {
             new InMemoryDirectory(
                 new String[] {"dc=shibboleth,dc=net"},
                 new ClassPathResource("/net/shibboleth/idp/attribute/resolver/impl/dc/ldap/ldapDataConnectorTest.ldif"),
-                10389);
+                0,
+                true);
         directoryServer.start();
+        ldapURL = "ldap://localhost:" + directoryServer.getListenPort();
+
+        // add a referral entry to the server.
+        directoryServer.add(
+            "dn: ou=referral,dc=shibboleth,dc=net",
+            "objectClass: top",
+            "objectClass: referral",
+            "objectClass: extensibleObject",
+            "ou: referral",
+            "ref: " + "ldap://localhost:" + directoryServer.getListenPort() + "/ou=people,dc=shibboleth,dc=net");
     }
 
     /**
@@ -103,20 +124,32 @@ public class LDAPDataConnectorTest {
      * 
      * @param builder to build search requests
      * @param strategy to map search results
+     * @param searchResultHandlers to configure
+     * @param baseDN to search on
+     * @param returnAttrs attributes to return
      * 
      * @return ldap data connector
      * 
      * @throws ComponentInitializationException  ...
      */
-    protected LDAPDataConnector createLdapDataConnector(final ExecutableSearchBuilder<ExecutableSearchFilter> builder,
-            final SearchResultMappingStrategy strategy) throws ComponentInitializationException {
+    protected LDAPDataConnector createLdapDataConnector(
+        final ExecutableSearchBuilder<ExecutableSearchFilter> builder,
+        final SearchResultMappingStrategy strategy,
+        final SearchResultHandler[] searchResultHandlers,
+        final String baseDN,
+        final String... returnAttrs) throws ComponentInitializationException
+    {
         final LDAPDataConnector connector = new LDAPDataConnector();
         connector.setId(TEST_CONNECTOR_NAME);
-        final ConnectionFactory connectionFactory = new DefaultConnectionFactory("ldap://localhost:10389");
+        final ConnectionConfig connectionConfig = new ConnectionConfig();
+        connectionConfig.setLdapUrl(ldapURL);
+        connectionConfig.setConnectionInitializers(new BindConnectionInitializer("cn=Directory Manager", "password"));
+        final ConnectionFactory connectionFactory = new DefaultConnectionFactory(connectionConfig);
         connector.setConnectionFactory(connectionFactory);
         final SearchOperation searchOperation = new SearchOperation();
         searchOperation.setRequest(
-          SearchRequest.builder().dn(TEST_BASE_DN).returnAttributes(TEST_RETURN_ATTRIBUTES).build());
+          SearchRequest.builder().dn(baseDN).returnAttributes(returnAttrs).build());
+        searchOperation.setSearchResultHandlers(searchResultHandlers);
         connector.setSearchOperation(searchOperation);
         connector.setExecutableSearchBuilder(builder == null ? 
                                              newParameterizedExecutableSearchFilterBuilder("(uid={principalName})") : builder);
@@ -167,7 +200,7 @@ public class LDAPDataConnectorTest {
             // OK
         }
 
-        final ConnectionFactory connectionFactory = new DefaultConnectionFactory("ldap://localhost:10389");
+        final ConnectionFactory connectionFactory = new DefaultConnectionFactory(ldapURL);
         connector.setConnectionFactory(connectionFactory);
 
         final SearchResultMappingStrategy mappingStrategy = new StringAttributeValueMappingStrategy();
@@ -180,7 +213,7 @@ public class LDAPDataConnectorTest {
             // OK
         }
         assertEquals(connector.getConnectionFactory(), connectionFactory);
-        assertEquals(connector.getSearchOperation(), searchOperation);
+        assertEquals(connector.getSearchOperation().getRequest(), searchOperation.getRequest());
         assertEquals(connector.getExecutableSearchBuilder(), requestBuilder);
         assertEquals(connector.getMappingStrategy(), mappingStrategy);
     }
@@ -209,13 +242,25 @@ public class LDAPDataConnectorTest {
     @Test public void resolve() throws ComponentInitializationException, ResolutionException {
         final ParameterizedExecutableSearchFilterBuilder builder =
                 newParameterizedExecutableSearchFilterBuilder("(uid={principalName})");
-        resolve(builder);
+        resolve(builder, TEST_BASE_DN);
+    }
+
+    @Test public void resolveReferral() throws ComponentInitializationException, ResolutionException {
+        final ParameterizedExecutableSearchFilterBuilder builder =
+            newParameterizedExecutableSearchFilterBuilder("(uid={principalName})");
+        resolve(builder, TEST_REFERRAL_BASE_DN);
     }
 
     @Test public void resolveMulti() throws ComponentInitializationException, ResolutionException {
         final ParameterizedExecutableSearchFilterBuilder builder =
                 newParameterizedExecutableSearchFilterBuilder("(uid=P*)");
-        resolveMulti(builder);
+        resolveMulti(builder, TEST_BASE_DN);
+    }
+
+    @Test public void resolveMultiReferral() throws ComponentInitializationException, ResolutionException {
+        final ParameterizedExecutableSearchFilterBuilder builder =
+            newParameterizedExecutableSearchFilterBuilder("(uid=P*)");
+        resolveMulti(builder, TEST_REFERRAL_BASE_DN);
     }
 
     @Test public void resolveWithDepends() throws ComponentInitializationException, ResolutionException {
@@ -273,7 +318,7 @@ public class LDAPDataConnectorTest {
         builder.setTemplateText("(uid=${resolutionContext.principal})");
         builder.setVelocityEngine(VelocityEngine.newVelocityEngine());
         builder.initialize();
-        resolve(builder);
+        resolve(builder, TEST_BASE_DN);
     }
     
     @Test(expectedExceptions={ResolutionException.class}) public void resolveTemplateExcept() throws ComponentInitializationException, ResolutionException {
@@ -286,7 +331,7 @@ public class LDAPDataConnectorTest {
         props.setProperty(RuntimeConstants.RESOURCE_LOADERS, "classpath, string");
         builder.setVelocityEngine(VelocityEngine.newVelocityEngine(props));
         builder.initialize();
-        resolve(builder);
+        resolve(builder, TEST_BASE_DN);
     }
 
 
@@ -343,9 +388,15 @@ public class LDAPDataConnectorTest {
         assertEquals(filter.getResultCacheKey(), "(cn=domain\\5Cuser\\2A)");
     }
 
-    protected void resolve(final ExecutableSearchBuilder<ExecutableSearchFilter> builder) throws ComponentInitializationException,
-            ResolutionException {
-        final LDAPDataConnector connector = createLdapDataConnector(builder, new StringAttributeValueMappingStrategy());
+    protected void resolve(final ExecutableSearchBuilder<ExecutableSearchFilter> builder, final String baseDN)
+        throws ComponentInitializationException, ResolutionException
+    {
+        final LDAPDataConnector connector = createLdapDataConnector(
+            builder,
+            new StringAttributeValueMappingStrategy(),
+            new SearchResultHandler[] {new FollowSearchReferralHandler()},
+            baseDN,
+            TEST_RETURN_ATTRIBUTES);
         connector.initialize();
 
         final AttributeResolutionContext context =
@@ -373,9 +424,15 @@ public class LDAPDataConnectorTest {
         assertTrue(attrs.get("mail").getValues().contains(new StringAttributeValue("peterprincipal at shibboleth.net")));
     }
 
-    protected void resolveMulti(final ExecutableSearchBuilder<ExecutableSearchFilter> builder) throws ComponentInitializationException,
-            ResolutionException {
-        final LDAPDataConnector connector = createLdapDataConnector(builder, new StringAttributeValueMappingStrategy());
+    protected void resolveMulti(final ExecutableSearchBuilder<ExecutableSearchFilter> builder, final String baseDN)
+        throws ComponentInitializationException, ResolutionException
+    {
+        final LDAPDataConnector connector = createLdapDataConnector(
+            builder,
+            new StringAttributeValueMappingStrategy(),
+            new SearchResultHandler[] {new FollowSearchReferralHandler()},
+            baseDN,
+            TEST_RETURN_ATTRIBUTES);
         connector.initialize();
         
         final AttributeResolutionContext context =
@@ -417,7 +474,8 @@ public class LDAPDataConnectorTest {
             throws ComponentInitializationException, ResolutionException {
         final StringAttributeValueMappingStrategy mappingStrategy = new StringAttributeValueMappingStrategy();
         mappingStrategy.setNoResultAnError(true);
-        final LDAPDataConnector connector = createLdapDataConnector(null, mappingStrategy);
+        final LDAPDataConnector connector = createLdapDataConnector(
+            null, mappingStrategy, null, TEST_BASE_DN, TEST_RETURN_ATTRIBUTES);
         connector.initialize();
 
         AttributeResolutionContext context =
@@ -440,7 +498,12 @@ public class LDAPDataConnectorTest {
             throws ComponentInitializationException, ResolutionException {
         final StringAttributeValueMappingStrategy mappingStrategy = new StringAttributeValueMappingStrategy();
         mappingStrategy.setMultipleResultsAnError(true);
-        final LDAPDataConnector connector = createLdapDataConnector(newParameterizedExecutableSearchFilterBuilder("(sn={principalName})"), mappingStrategy);
+        final LDAPDataConnector connector = createLdapDataConnector(
+            newParameterizedExecutableSearchFilterBuilder("(sn={principalName})"),
+            mappingStrategy,
+            null,
+            TEST_BASE_DN,
+            TEST_RETURN_ATTRIBUTES);
         connector.initialize();
 
         AttributeResolutionContext context =
@@ -460,7 +523,7 @@ public class LDAPDataConnectorTest {
     }
 
     @Test public void resolveWithCache() throws ComponentInitializationException, ResolutionException {
-        final LDAPDataConnector connector = createLdapDataConnector(null, null);
+        final LDAPDataConnector connector = createLdapDataConnector(null, null, null, TEST_BASE_DN, TEST_RETURN_ATTRIBUTES);
         final TestCache cache = new TestCache();
         connector.setResultsCache(cache);
         connector.initialize();
@@ -481,7 +544,7 @@ public class LDAPDataConnectorTest {
      * @throws ResolutionException ...
      */
     @Test public void resolveWithCacheCollison() throws ComponentInitializationException, ResolutionException {
-        final LDAPDataConnector connector = createLdapDataConnector(null, null);
+        final LDAPDataConnector connector = createLdapDataConnector(null, null, null, TEST_BASE_DN, TEST_RETURN_ATTRIBUTES);
         final TestCache cache = new TestCache();
         connector.setResultsCache(cache);
         connector.initialize();
@@ -510,7 +573,8 @@ public class LDAPDataConnectorTest {
         final ParameterizedExecutableSearchFilterBuilder builder =
                 newParameterizedExecutableSearchFilterBuilder("(uid={principalName})");
 
-        final DataConnector connector = createLdapDataConnector(builder, new StringAttributeValueMappingStrategy());
+        final DataConnector connector = createLdapDataConnector(
+            builder, new StringAttributeValueMappingStrategy(), null, TEST_BASE_DN, TEST_RETURN_ATTRIBUTES);
         connector.initialize();
 
         final AttributeResolutionContext context =

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


More information about the commits mailing list