diff --git a/core/src/main/java/org/acegisecurity/ldap/LdapTemplate.java b/core/src/main/java/org/acegisecurity/ldap/LdapTemplate.java index cd4c202d6b..17af4bc990 100644 --- a/core/src/main/java/org/acegisecurity/ldap/LdapTemplate.java +++ b/core/src/main/java/org/acegisecurity/ldap/LdapTemplate.java @@ -19,12 +19,22 @@ import javax.naming.NamingException; import javax.naming.NamingEnumeration; import javax.naming.directory.DirContext; import javax.naming.directory.SearchControls; +import javax.naming.directory.SearchResult; +import javax.naming.directory.Attributes; +import javax.naming.directory.Attribute; import org.springframework.dao.DataAccessException; import org.springframework.util.Assert; +import java.util.Set; +import java.util.HashSet; + /** * LDAP equivalent of the Spring JdbcTemplate class. + *

+ * This is mainly intended to simplify Ldap access within Acegi Security's + * LDAP-related services. + *

* * @author Ben Alex * @author Luke Taylor @@ -36,6 +46,8 @@ public class LdapTemplate { private InitialDirContextFactory dirContextFactory; private String userDn = null; private String password = null; + /** Default search scope */ + private int searchScope = SearchControls.SUBTREE_SCOPE; public LdapTemplate(InitialDirContextFactory dirContextFactory) { Assert.notNull(dirContextFactory, "An InitialDirContextFactory is required"); @@ -52,6 +64,10 @@ public class LdapTemplate { this.password = password; } + public void setSearchScope(int searchScope) { + this.searchScope = searchScope; + } + public Object execute(LdapCallback callback) throws DataAccessException { DirContext ctx = null; @@ -93,4 +109,57 @@ public class LdapTemplate { return matches.booleanValue(); } + + /** + * Performs a search using the supplied filter and returns the union of the values of the named + * attribute found in all entries matched by the search. Note that one directory entry may have several + * values for the attribute. + * + * @param base the DN to search in + * @param filter search filter to use + * @param params the parameters to substitute in the search filter + * @param attributeName the attribute who's values are to be retrieved. + * @return the set of values for the attribute as a union of the values found in all the matching entries. + */ + public Set searchForSingleAttributeValues(final String base, final String filter, final Object[] params, final String attributeName) { + + + class LdapSearchCallback implements LdapCallback { + + public Object execute(DirContext ctx) throws NamingException { + Set unionOfValues = new HashSet(); + + SearchControls ctls = new SearchControls(); + + ctls.setSearchScope(searchScope); + ctls.setReturningAttributes(new String[] {attributeName}); + + NamingEnumeration matchingEntries = + ctx.search(base, filter, params, ctls); + + while (matchingEntries.hasMore()) { + SearchResult result = (SearchResult) matchingEntries.next(); + Attributes attrs = result.getAttributes(); + + // There should only be one attribute in each matching entry. + NamingEnumeration returnedAttributes = attrs.getAll(); + + while(returnedAttributes.hasMore()) { + Attribute returnedAttribute = (Attribute) returnedAttributes.next(); + NamingEnumeration attributeValues = returnedAttribute.getAll(); + + while(attributeValues.hasMore()) { + Object value = attributeValues.next(); + unionOfValues.add(value); + } + + } + } + + return unionOfValues; + } + } + + return (Set)execute(new LdapSearchCallback()); + } } diff --git a/core/src/test/java/org/acegisecurity/ldap/LdapTemplateTests.java b/core/src/test/java/org/acegisecurity/ldap/LdapTemplateTests.java index 9234fb1308..c3479a0a53 100644 --- a/core/src/test/java/org/acegisecurity/ldap/LdapTemplateTests.java +++ b/core/src/test/java/org/acegisecurity/ldap/LdapTemplateTests.java @@ -15,7 +15,10 @@ package org.acegisecurity.ldap; +import java.util.Set; + /** + * * @author Luke Taylor * @version $Id$ */ @@ -41,5 +44,15 @@ public class LdapTemplateTests extends AbstractLdapServerTestCase { // assertFalse(template.compare("uid=bob,ou=people", "userPassword", LdapUtils.getUtf8Bytes("wrongvalue"))); } + public void testSearchForSingleAttributeValues() { + LdapTemplate template = new LdapTemplate(getInitialCtxFactory()); + String param = "uid=ben,ou=people," + getInitialCtxFactory().getRootDn(); + + Set values = template.searchForSingleAttributeValues("ou=groups", "(member={0})", new String[] {param}, "ou"); + + assertEquals("Expected 2 results from search", 2, values.size()); + assertTrue(values.contains("developer")); + assertTrue(values.contains("manager")); + } }