mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-05-30 16:52:13 +00:00
SEC-2690: Support static nested groups in LDAP
This refers to groups that have member: <another group DN> as an attribute - Add in a utility method in the SpringSecurityLdapTemplate to retrieve multiple attributes and their values from an LDAP record - Make the DefaultLdapAuthoritiesPopulator more extensible - Add an LdapAuthority object that holds the DN in addition to other group attributes - Add a NestedLdapAuthoritiesPopulator to search statically nested groups
This commit is contained in:
parent
8a2a1b7a5b
commit
93b863d2e5
@ -17,6 +17,7 @@ package org.springframework.security.ldap;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.naming.Context;
|
||||
@ -99,6 +100,69 @@ public class SpringSecurityLdapTemplateITests extends AbstractLdapIntegrationTes
|
||||
assertTrue(values.contains("submanager"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiAttributeRetrievalWithNullAttributeNames() {
|
||||
Set<Map<String, String[]>> values =
|
||||
template.searchForMultipleAttributeValues(
|
||||
"ou=people",
|
||||
"(uid={0})",
|
||||
new String[] {"bob"},
|
||||
null);
|
||||
assertEquals(1, values.size());
|
||||
Map<String, String[]> record = (Map<String, String[]>)values.toArray()[0];
|
||||
assertAttributeValue(record,"uid","bob");
|
||||
assertAttributeValue(record,"objectclass","top","person","organizationalPerson","inetOrgPerson");
|
||||
assertAttributeValue(record,"cn","Bob Hamilton");
|
||||
assertAttributeValue(record,"sn","Hamilton");
|
||||
assertFalse(record.containsKey("userPassword"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiAttributeRetrievalWithZeroLengthAttributeNames() {
|
||||
Set<Map<String, String[]>> values =
|
||||
template.searchForMultipleAttributeValues(
|
||||
"ou=people",
|
||||
"(uid={0})",
|
||||
new String[] {"bob"},
|
||||
new String[0]);
|
||||
assertEquals(1, values.size());
|
||||
Map<String, String[]> record = (Map<String, String[]>)values.toArray()[0];
|
||||
assertAttributeValue(record,"uid","bob");
|
||||
assertAttributeValue(record,"objectclass","top","person","organizationalPerson","inetOrgPerson");
|
||||
assertAttributeValue(record,"cn","Bob Hamilton");
|
||||
assertAttributeValue(record,"sn","Hamilton");
|
||||
assertFalse(record.containsKey("userPassword"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiAttributeRetrievalWithSpecifiedAttributeNames() {
|
||||
Set<Map<String, String[]>> values =
|
||||
template.searchForMultipleAttributeValues(
|
||||
"ou=people",
|
||||
"(uid={0})",
|
||||
new String[] {"bob"},
|
||||
new String[] {
|
||||
"uid",
|
||||
"cn",
|
||||
"sn"
|
||||
});
|
||||
assertEquals(1, values.size());
|
||||
Map<String, String[]> record = (Map<String, String[]>)values.toArray()[0];
|
||||
assertAttributeValue(record,"uid","bob");
|
||||
assertAttributeValue(record,"cn","Bob Hamilton");
|
||||
assertAttributeValue(record,"sn","Hamilton");
|
||||
assertFalse(record.containsKey("userPassword"));
|
||||
assertFalse(record.containsKey("objectclass"));
|
||||
}
|
||||
|
||||
protected void assertAttributeValue(Map<String, String[]> record, String attributeName, String... values) {
|
||||
assertTrue(record.containsKey(attributeName));
|
||||
assertEquals(values.length,record.get(attributeName).length);
|
||||
for (int i=0; i<values.length; i++) {
|
||||
assertEquals(values[i],record.get(attributeName)[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoleSearchForMissingAttributeFailsGracefully() {
|
||||
String param = "uid=ben,ou=people,dc=springframework,dc=org";
|
||||
|
@ -60,7 +60,7 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapIntegrationTests
|
||||
@Test
|
||||
public void extraFilterPartToExcludeBob() throws Exception {
|
||||
FilterBasedLdapUserSearch locator = new FilterBasedLdapUserSearch("ou=people",
|
||||
"(&(cn=*)(!(|(uid={0})(uid=rod)(uid=jerry)(uid=slashguy))))", getContextSource());
|
||||
"(&(cn=*)(!(|(uid={0})(uid=rod)(uid=jerry)(uid=slashguy)(uid=javadude)(uid=groovydude)(uid=closuredude)(uid=scaladude))))", getContextSource());
|
||||
|
||||
// Search for bob, get back ben...
|
||||
DirContextOperations ben = locator.searchForUser("bob");
|
||||
|
@ -0,0 +1,134 @@
|
||||
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
||||
*
|
||||
* Licensed 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 org.springframework.security.ldap.userdetails;
|
||||
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.ldap.AbstractLdapIntegrationTests;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Filip Hanik
|
||||
*/
|
||||
public class NestedLdapAuthoritiesPopulatorTests extends AbstractLdapIntegrationTests {
|
||||
|
||||
private NestedLdapAuthoritiesPopulator populator;
|
||||
private LdapAuthority javaDevelopers;
|
||||
private LdapAuthority groovyDevelopers;
|
||||
private LdapAuthority scalaDevelopers;
|
||||
private LdapAuthority closureDevelopers;
|
||||
private LdapAuthority jDevelopers;
|
||||
private LdapAuthority circularJavaDevelopers;
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
populator = new NestedLdapAuthoritiesPopulator(getContextSource(), "ou=jdeveloper");
|
||||
populator.setGroupSearchFilter("(member={0})");
|
||||
populator.setIgnorePartialResultException(false);
|
||||
populator.setRolePrefix("");
|
||||
populator.setSearchSubtree(true);
|
||||
populator.setConvertToUpperCase(false);
|
||||
jDevelopers = new LdapAuthority("j-developers","cn=j-developers,ou=jdeveloper,dc=springframework,dc=org");
|
||||
javaDevelopers = new LdapAuthority("java-developers","cn=java-developers,ou=jdeveloper,dc=springframework,dc=org");
|
||||
groovyDevelopers = new LdapAuthority("groovy-developers","cn=groovy-developers,ou=jdeveloper,dc=springframework,dc=org");
|
||||
scalaDevelopers = new LdapAuthority("scala-developers","cn=scala-developers,ou=jdeveloper,dc=springframework,dc=org");
|
||||
closureDevelopers = new LdapAuthority("closure-developers","cn=closure-developers,ou=jdeveloper,dc=springframework,dc=org");
|
||||
circularJavaDevelopers = new LdapAuthority("circular-java-developers","cn=circular-java-developers,ou=jdeveloper,dc=springframework,dc=org");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScalaDudeJDevelopersAuthorities() {
|
||||
DirContextAdapter ctx = new DirContextAdapter("uid=scaladude,ou=people,dc=springframework,dc=org");
|
||||
Collection<GrantedAuthority> authorities = populator.getGrantedAuthorities(ctx,"scaladude");
|
||||
assertEquals(5, authorities.size());
|
||||
assertEquals(Arrays.asList(javaDevelopers, scalaDevelopers, circularJavaDevelopers, jDevelopers, groovyDevelopers), authorities);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJavaDudeJDevelopersAuthorities() {
|
||||
DirContextAdapter ctx = new DirContextAdapter("uid=javadude,ou=people,dc=springframework,dc=org");
|
||||
Collection<GrantedAuthority> authorities = populator.getGrantedAuthorities(ctx,"javadude");
|
||||
assertEquals(3, authorities.size());
|
||||
assertEquals(Arrays.asList(javaDevelopers, circularJavaDevelopers, jDevelopers), authorities);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScalaDudeJDevelopersAuthoritiesWithSearchLimit() {
|
||||
populator.setMaxSearchDepth(1);
|
||||
DirContextAdapter ctx = new DirContextAdapter("uid=scaladude,ou=people,dc=springframework,dc=org");
|
||||
Collection<GrantedAuthority> authorities = populator.getGrantedAuthorities(ctx,"scaladude");
|
||||
assertEquals(1, authorities.size());
|
||||
assertEquals(Arrays.asList(scalaDevelopers), authorities);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGroovyDudeJDevelopersAuthorities() {
|
||||
DirContextAdapter ctx = new DirContextAdapter("uid=groovydude,ou=people,dc=springframework,dc=org");
|
||||
Collection<GrantedAuthority> authorities = populator.getGrantedAuthorities(ctx,"groovydude");
|
||||
assertEquals(4, authorities.size());
|
||||
assertEquals(Arrays.asList(javaDevelopers,circularJavaDevelopers,jDevelopers,groovyDevelopers), authorities);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClosureDudeJDevelopersWithMembershipAsAttributeValues() {
|
||||
populator.setAttributeNames(new HashSet(Arrays.asList("member")));
|
||||
|
||||
DirContextAdapter ctx = new DirContextAdapter("uid=closuredude,ou=people,dc=springframework,dc=org");
|
||||
Collection<GrantedAuthority> authorities = populator.getGrantedAuthorities(ctx,"closuredude");
|
||||
assertEquals(5, authorities.size());
|
||||
assertEquals(Arrays.asList(closureDevelopers,javaDevelopers,circularJavaDevelopers,jDevelopers,groovyDevelopers), authorities);
|
||||
|
||||
LdapAuthority[] ldapAuthorities = authorities.toArray(new LdapAuthority[0]);
|
||||
assertEquals(5, ldapAuthorities.length);
|
||||
//closure group
|
||||
assertTrue(ldapAuthorities[0].getAttributes().containsKey("member"));
|
||||
assertNotNull(ldapAuthorities[0].getAttributes().get("member"));
|
||||
assertEquals(1, ldapAuthorities[0].getAttributes().get("member").length);
|
||||
assertEquals("uid=closuredude,ou=people,dc=springframework,dc=org",ldapAuthorities[0].getFirstAttributeValue("member"));
|
||||
|
||||
//java group
|
||||
assertTrue(ldapAuthorities[1].getAttributes().containsKey("member"));
|
||||
assertNotNull(ldapAuthorities[1].getAttributes().get("member"));
|
||||
assertEquals(3,ldapAuthorities[1].getAttributes().get("member").length);
|
||||
assertEquals(groovyDevelopers.getDn(),ldapAuthorities[1].getFirstAttributeValue("member"));
|
||||
assertEquals(
|
||||
new String[] {
|
||||
groovyDevelopers.getDn(),
|
||||
scalaDevelopers.getDn(),
|
||||
"uid=javadude,ou=people,dc=springframework,dc=org"
|
||||
},
|
||||
ldapAuthorities[1].getAttributes().get("member")
|
||||
);
|
||||
|
||||
//test non existent attribute
|
||||
assertNull(ldapAuthorities[2].getFirstAttributeValue("test"));
|
||||
assertNotNull(ldapAuthorities[2].getAttributeValues("test"));
|
||||
assertEquals(0, ldapAuthorities[2].getAttributeValues("test").length);
|
||||
//test role name
|
||||
assertEquals(jDevelopers.getAuthority(), ldapAuthorities[3].getAuthority());
|
||||
}
|
||||
}
|
@ -122,3 +122,109 @@ objectclass: groupOfNames
|
||||
cn: submanagers
|
||||
ou: submanager
|
||||
member: uid=ben,ou=people,dc=springframework,dc=org
|
||||
|
||||
#Nested groups data
|
||||
###################
|
||||
|
||||
dn: ou=jdeveloper,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: organizationalUnit
|
||||
ou: jdeveloper
|
||||
|
||||
|
||||
# javadude is part of (in a nested search)
|
||||
# circular-java-developers, java-developers, j-developers
|
||||
dn: uid=javadude,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Java Dude
|
||||
sn: Dude
|
||||
uid: javadude
|
||||
userPassword: javadudespassword
|
||||
|
||||
# groovydude is part of (in a nested search)
|
||||
# groovy-developers, java-developers, circular-java-developers, j-developers
|
||||
dn: uid=groovydude,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Groovy Dude
|
||||
sn: Dude
|
||||
uid: groovydude
|
||||
userPassword: groovydudespassword
|
||||
|
||||
# closuredude is part of (in a nested search)
|
||||
# closure-developers, groovy-developers, java-developers, circular-java-developers, j-developers
|
||||
dn: uid=closuredude,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Closure Dude
|
||||
sn: Dude
|
||||
uid: closuredude
|
||||
userPassword: closuredudespassword
|
||||
|
||||
# scaladude is part of (in a nested search)
|
||||
# scala-developers, groovy-developers, java-developers, circular-java-developers, j-developers
|
||||
dn: uid=scaladude,ou=people,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: person
|
||||
objectclass: organizationalPerson
|
||||
objectclass: inetOrgPerson
|
||||
cn: Scala Dude
|
||||
sn: Dude
|
||||
uid: scaladude
|
||||
userPassword: scaladudespassword
|
||||
|
||||
dn: cn=j-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: j-developers
|
||||
ou: jdeveloper
|
||||
member: cn=java-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
|
||||
dn: cn=java-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: java-developers
|
||||
ou: jdeveloper
|
||||
member: cn=groovy-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
member: cn=scala-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
member: uid=javadude,ou=people,dc=springframework,dc=org
|
||||
|
||||
dn: cn=circular-java-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: circular-java-developers
|
||||
ou: jdeveloper
|
||||
member: cn=groovy-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
member: cn=scala-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
member: uid=javadude,ou=people,dc=springframework,dc=org
|
||||
|
||||
|
||||
dn: cn=groovy-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: groovy-developers
|
||||
ou: jdeveloper
|
||||
member: cn=closure-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
member: uid=groovydude,ou=people,dc=springframework,dc=org
|
||||
member: cn=circular-java-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
|
||||
dn: cn=closure-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: closure-developers
|
||||
ou: jdeveloper
|
||||
member: uid=closuredude,ou=people,dc=springframework,dc=org
|
||||
|
||||
dn: cn=scala-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
objectclass: top
|
||||
objectclass: groupOfNames
|
||||
cn: scala-developers
|
||||
ou: jdeveloper
|
||||
member: uid=scaladude,ou=people,dc=springframework,dc=org
|
||||
|
@ -30,13 +30,18 @@ import org.springframework.util.Assert;
|
||||
import javax.naming.NamingEnumeration;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.PartialResultException;
|
||||
import javax.naming.directory.Attribute;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.SearchControls;
|
||||
import javax.naming.directory.SearchResult;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
@ -45,6 +50,7 @@ import java.util.Set;
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
* @author Filip Hanik
|
||||
* @since 2.0
|
||||
*/
|
||||
public class SpringSecurityLdapTemplate extends LdapTemplate {
|
||||
@ -52,6 +58,13 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
|
||||
private static final Log logger = LogFactory.getLog(SpringSecurityLdapTemplate.class);
|
||||
|
||||
public static final String[] NO_ATTRS = new String[0];
|
||||
|
||||
/**
|
||||
* Every search results where a record is defined by a Map<String,String[]>
|
||||
* contains at least this key - the DN of the record itself.
|
||||
*/
|
||||
public static final String DN_KEY = "spring.security.ldap.dn";
|
||||
|
||||
private static final boolean RETURN_OBJECT = true;
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
@ -139,6 +152,34 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
|
||||
*/
|
||||
public Set<String> searchForSingleAttributeValues(final String base, final String filter, final Object[] params,
|
||||
final String attributeName) {
|
||||
String[] attributeNames = new String[] {attributeName};
|
||||
Set<Map<String,String[]>> multipleAttributeValues = searchForMultipleAttributeValues(base,filter,params,attributeNames);
|
||||
Set<String> result = new HashSet<String>();
|
||||
for (Map<String,String[]> map : multipleAttributeValues) {
|
||||
String[] values = map.get(attributeName);
|
||||
if (values!=null && values.length>0) {
|
||||
result.addAll(Arrays.asList(values));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a search using the supplied filter and returns the values of each named attribute
|
||||
* found in all entries matched by the search. Note that one directory entry may have several values for the
|
||||
* attribute. Intended for role searches and similar scenarios.
|
||||
*
|
||||
* @param base the DN to search in
|
||||
* @param filter search filter to use
|
||||
* @param params the parameters to substitute in the search filter
|
||||
* @param attributeNames the attributes' values that are to be retrieved.
|
||||
*
|
||||
* @return the set of String values for each attribute found in all the matching entries.
|
||||
* The attribute name is the key for each set of values. In addition each map contains the DN as a String
|
||||
* with the key predefined key {@link #DN_KEY}.
|
||||
*/
|
||||
public Set<Map<String, String[]>> searchForMultipleAttributeValues(final String base, final String filter, final Object[] params,
|
||||
final String[] attributeNames) {
|
||||
// Escape the params acording to RFC2254
|
||||
Object[] encodedParams = new String[params.length];
|
||||
|
||||
@ -149,30 +190,83 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
|
||||
String formattedFilter = MessageFormat.format(filter, encodedParams);
|
||||
logger.debug("Using filter: " + formattedFilter);
|
||||
|
||||
final HashSet<String> set = new HashSet<String>();
|
||||
final HashSet<Map<String, String[]>> set = new HashSet<Map<String, String[]>>();
|
||||
|
||||
ContextMapper roleMapper = new ContextMapper() {
|
||||
public Object mapFromContext(Object ctx) {
|
||||
DirContextAdapter adapter = (DirContextAdapter) ctx;
|
||||
String[] values = adapter.getStringAttributes(attributeName);
|
||||
if (values == null || values.length == 0) {
|
||||
logger.debug("No attribute value found for '" + attributeName + "'");
|
||||
Map<String, String[]> record = new HashMap<String, String[]>();
|
||||
if (attributeNames==null||attributeNames.length==0) {
|
||||
try {
|
||||
for (NamingEnumeration ae = adapter.getAttributes().getAll(); ae.hasMore(); ) {
|
||||
Attribute attr = (Attribute) ae.next();
|
||||
extractStringAttributeValues(adapter, record, attr.getID());
|
||||
}
|
||||
}catch (NamingException x) {
|
||||
org.springframework.ldap.support.LdapUtils.convertLdapException(x);
|
||||
}
|
||||
} else {
|
||||
set.addAll(Arrays.asList(values));
|
||||
for (String attributeName : attributeNames) {
|
||||
extractStringAttributeValues(adapter, record, attributeName);
|
||||
}
|
||||
}
|
||||
record.put(DN_KEY, new String[] {getAdapterDN(adapter)});
|
||||
set.add(record);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
SearchControls ctls = new SearchControls();
|
||||
ctls.setSearchScope(searchControls.getSearchScope());
|
||||
ctls.setReturningAttributes(new String[] {attributeName});
|
||||
ctls.setReturningAttributes(attributeNames!=null&&attributeNames.length>0?attributeNames:null);
|
||||
|
||||
search(base, formattedFilter, ctls, roleMapper);
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DN for the context representing this LDAP record.
|
||||
* By default this is using {@link javax.naming.Context#getNameInNamespace()}
|
||||
* instead of {@link org.springframework.ldap.core.DirContextAdapter#getDn()} since the
|
||||
* latter returns a partial DN if a base has been specified.
|
||||
* @param adapter - the Context to extract the DN from
|
||||
* @return - the String representing the full DN
|
||||
*/
|
||||
protected String getAdapterDN(DirContextAdapter adapter) {
|
||||
//returns the full DN rather than the sub DN if a base is specified
|
||||
return adapter.getNameInNamespace();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts String values for a specified attribute name and places them in the map representing the ldap record
|
||||
* If a value is not of type String, it will derive it's value from the {@link Object#toString()}
|
||||
* @param adapter - the adapter that contains the values
|
||||
* @param record - the map holding the attribute names and values
|
||||
* @param attributeName - the name for which to fetch the values from
|
||||
*/
|
||||
protected void extractStringAttributeValues(DirContextAdapter adapter, Map<String, String[]> record, String attributeName) {
|
||||
Object[] values = adapter.getObjectAttributes(attributeName);
|
||||
if (values == null || values.length == 0) {
|
||||
logger.debug("No attribute value found for '" + attributeName + "'");
|
||||
return;
|
||||
}
|
||||
List<String> svalues = new ArrayList<String>();
|
||||
for (Object o : values) {
|
||||
if (o!=null) {
|
||||
if (String.class.isAssignableFrom(o.getClass())) {
|
||||
svalues.add((String)o);
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Attribute:" + attributeName + " contains a non string value of type[" + o.getClass() + "]");
|
||||
}
|
||||
svalues.add(o.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
record.put(attributeName, svalues.toArray(new String[svalues.size()]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a search, with the requirement that the search shall return a single directory entry, and uses
|
||||
* the supplied mapper to create the object from that entry.
|
||||
|
@ -127,7 +127,8 @@ public class ApacheDSContainer implements InitializingBean, DisposableBean, Life
|
||||
|
||||
server = new LdapServer();
|
||||
server.setDirectoryService(service);
|
||||
server.setTransports(new TcpTransport(port));
|
||||
//AbstractLdapIntegrationTests assume IPv4, so we specify the same here
|
||||
server.setTransports(new TcpTransport("127.0.0.1", port));
|
||||
start();
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,7 @@ import java.util.Set;
|
||||
* a search of the entire subtree under <tt>groupSearchBase</tt>.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @author Filip Hanik
|
||||
*/
|
||||
public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator {
|
||||
//~ Static fields/initializers =====================================================================================
|
||||
@ -105,6 +106,9 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
||||
*/
|
||||
private GrantedAuthority defaultRole;
|
||||
|
||||
/**
|
||||
* Template that will be used for searching
|
||||
*/
|
||||
private final SpringSecurityLdapTemplate ldapTemplate;
|
||||
|
||||
/**
|
||||
@ -127,7 +131,13 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
||||
* The pattern to be used for the user search. {0} is the user's DN
|
||||
*/
|
||||
private String groupSearchFilter = "(member={0})";
|
||||
/**
|
||||
* The role prefix that will be prepended to each role name
|
||||
*/
|
||||
private String rolePrefix = "ROLE_";
|
||||
/**
|
||||
* Should we convert the role name to uppercase
|
||||
*/
|
||||
private boolean convertToUpperCase = true;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
@ -143,7 +153,7 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
||||
public DefaultLdapAuthoritiesPopulator(ContextSource contextSource, String groupSearchBase) {
|
||||
Assert.notNull(contextSource, "contextSource must not be null");
|
||||
ldapTemplate = new SpringSecurityLdapTemplate(contextSource);
|
||||
ldapTemplate.setSearchControls(searchControls);
|
||||
getLdapTemplate().setSearchControls(getSearchControls());
|
||||
this.groupSearchBase = groupSearchBase;
|
||||
|
||||
if (groupSearchBase == null) {
|
||||
@ -212,8 +222,8 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
||||
+ groupSearchFilter + " in search base '" + getGroupSearchBase() + "'");
|
||||
}
|
||||
|
||||
Set<String> userRoles = ldapTemplate.searchForSingleAttributeValues(getGroupSearchBase(), groupSearchFilter,
|
||||
new String[]{userDn, username}, groupRoleAttribute);
|
||||
Set<String> userRoles = getLdapTemplate().searchForSingleAttributeValues(getGroupSearchBase(), groupSearchFilter,
|
||||
new String[]{userDn, username}, groupRoleAttribute);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Roles from search: " + userRoles);
|
||||
@ -232,7 +242,7 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
||||
}
|
||||
|
||||
protected ContextSource getContextSource() {
|
||||
return ldapTemplate.getContextSource();
|
||||
return getLdapTemplate().getContextSource();
|
||||
}
|
||||
|
||||
protected String getGroupSearchBase() {
|
||||
@ -297,6 +307,77 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
|
||||
* @see LdapTemplate#setIgnoreNameNotFoundException(boolean)
|
||||
*/
|
||||
public void setIgnorePartialResultException(boolean ignore) {
|
||||
ldapTemplate.setIgnorePartialResultException(ignore);
|
||||
getLdapTemplate().setIgnorePartialResultException(ignore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current LDAP template.
|
||||
* Method available so that classes extending this can override the template used
|
||||
* @return the LDAP template
|
||||
* @see {@link org.springframework.security.ldap.SpringSecurityLdapTemplate}
|
||||
*/
|
||||
protected SpringSecurityLdapTemplate getLdapTemplate() {
|
||||
return ldapTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default role
|
||||
* Method available so that classes extending this can override
|
||||
* @return the default role used
|
||||
* @see {@link #setDefaultRole(String)}
|
||||
*/
|
||||
protected GrantedAuthority getDefaultRole() {
|
||||
return defaultRole;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the search controls
|
||||
* Method available so that classes extending this can override the search controls used
|
||||
* @return the search controls
|
||||
*/
|
||||
protected SearchControls getSearchControls() {
|
||||
return searchControls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the attribute name of the LDAP attribute that will be mapped to the role name
|
||||
* Method available so that classes extending this can override
|
||||
* @return the attribute name used for role mapping
|
||||
* @see {@link #setGroupRoleAttribute(String)}
|
||||
*/
|
||||
protected String getGroupRoleAttribute() {
|
||||
return groupRoleAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the search filter configured for this populator
|
||||
* Method available so that classes extending this can override
|
||||
* @return the search filter
|
||||
* @see {@link #setGroupSearchFilter(String)}
|
||||
*/
|
||||
protected String getGroupSearchFilter() {
|
||||
return groupSearchFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the role prefix used by this populator
|
||||
* Method available so that classes extending this can override
|
||||
* @return the role prefix
|
||||
* @see {@link #setRolePrefix(String)}
|
||||
*/
|
||||
protected String getRolePrefix() {
|
||||
return rolePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if role names are converted to uppercase
|
||||
* Method available so that classes extending this can override
|
||||
* @return true if role names are converted to uppercase.
|
||||
* @see {@link #setConvertToUpperCase(boolean)}
|
||||
*/
|
||||
protected boolean isConvertToUpperCase() {
|
||||
return convertToUpperCase;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.security.ldap.userdetails;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An authority that contains at least a DN and a role name for an LDAP entry
|
||||
* but can also contain other desired attributes to be fetched during an LDAP
|
||||
* authority search.
|
||||
* @author Filip Hanik
|
||||
*/
|
||||
public class LdapAuthority implements GrantedAuthority {
|
||||
|
||||
|
||||
private String dn;
|
||||
private String role;
|
||||
private Map<String, String[]> attributes;
|
||||
|
||||
/**
|
||||
* Constructs an LdapAuthority that has a role and a DN but no other attributes
|
||||
* @param role
|
||||
* @param dn
|
||||
*/
|
||||
public LdapAuthority(String role, String dn) {
|
||||
this(role,dn,null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an LdapAuthority with the given role, DN and other LDAP attributes
|
||||
* @param role
|
||||
* @param dn
|
||||
* @param attributes
|
||||
*/
|
||||
public LdapAuthority(String role, String dn, Map<String,String[]> attributes) {
|
||||
if (role==null) throw new NullPointerException("role can not be null");
|
||||
this.role = role;
|
||||
this.dn = dn;
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the LDAP attributes
|
||||
* @return the LDAP attributes, map can be null
|
||||
*/
|
||||
public Map<String, String[]> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DN for this LDAP authority
|
||||
* @return
|
||||
*/
|
||||
public String getDn() {
|
||||
return dn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the values for a specific attribute
|
||||
* @param name the attribute name
|
||||
* @return a String array, never null but may be zero length
|
||||
*/
|
||||
public String[] getAttributeValues(String name) {
|
||||
String[] result = null;
|
||||
if (attributes!=null) {
|
||||
result = attributes.get(name);
|
||||
}
|
||||
if (result==null) {
|
||||
result = new String[0];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first attribute value for a specified attribute
|
||||
* @param name
|
||||
* @return the first attribute value for a specified attribute, may be null
|
||||
*/
|
||||
public String getFirstAttributeValue(String name) {
|
||||
String[] result = getAttributeValues(name);
|
||||
if (result.length>0) {
|
||||
return result[0];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String getAuthority() {
|
||||
return role;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the LdapAuthority based on {@link #getAuthority()} and {@link #getDn()} values
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof LdapAuthority)) return false;
|
||||
|
||||
LdapAuthority that = (LdapAuthority) o;
|
||||
|
||||
if (!dn.equals(that.dn)) return false;
|
||||
if (role != null ? !role.equals(that.role) : that.role != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = dn.hashCode();
|
||||
result = 31 * result + (role != null ? role.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LdapAuthority{" +
|
||||
"dn='" + dn + '\'' +
|
||||
", role='" + role + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed 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 org.springframework.security.ldap.userdetails;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.ldap.core.ContextSource;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.ldap.SpringSecurityLdapTemplate;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A LDAP authority populator that can recursively search static nested groups.
|
||||
* <p>An example of nested groups can be
|
||||
* <pre>
|
||||
* #Nested groups data
|
||||
*
|
||||
* dn: uid=javadude,ou=people,dc=springframework,dc=org
|
||||
* objectclass: top
|
||||
* objectclass: person
|
||||
* objectclass: organizationalPerson
|
||||
* objectclass: inetOrgPerson
|
||||
* cn: Java Dude
|
||||
* sn: Dude
|
||||
* uid: javadude
|
||||
* userPassword: javadudespassword
|
||||
*
|
||||
* dn: uid=groovydude,ou=people,dc=springframework,dc=org
|
||||
* objectclass: top
|
||||
* objectclass: person
|
||||
* objectclass: organizationalPerson
|
||||
* objectclass: inetOrgPerson
|
||||
* cn: Groovy Dude
|
||||
* sn: Dude
|
||||
* uid: groovydude
|
||||
* userPassword: groovydudespassword
|
||||
*
|
||||
* dn: uid=closuredude,ou=people,dc=springframework,dc=org
|
||||
* objectclass: top
|
||||
* objectclass: person
|
||||
* objectclass: organizationalPerson
|
||||
* objectclass: inetOrgPerson
|
||||
* cn: Closure Dude
|
||||
* sn: Dude
|
||||
* uid: closuredude
|
||||
* userPassword: closuredudespassword
|
||||
*
|
||||
* dn: uid=scaladude,ou=people,dc=springframework,dc=org
|
||||
* objectclass: top
|
||||
* objectclass: person
|
||||
* objectclass: organizationalPerson
|
||||
* objectclass: inetOrgPerson
|
||||
* cn: Scala Dude
|
||||
* sn: Dude
|
||||
* uid: scaladude
|
||||
* userPassword: scaladudespassword
|
||||
*
|
||||
* dn: cn=j-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
* objectclass: top
|
||||
* objectclass: groupOfNames
|
||||
* cn: j-developers
|
||||
* ou: jdeveloper
|
||||
* member: cn=java-developers,ou=groups,dc=springframework,dc=org
|
||||
*
|
||||
* dn: cn=java-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
* objectclass: top
|
||||
* objectclass: groupOfNames
|
||||
* cn: java-developers
|
||||
* ou: jdeveloper
|
||||
* member: cn=groovy-developers,ou=groups,dc=springframework,dc=org
|
||||
* member: cn=scala-developers,ou=groups,dc=springframework,dc=org
|
||||
* member: uid=javadude,ou=people,dc=springframework,dc=org
|
||||
*
|
||||
* dn: cn=groovy-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
* objectclass: top
|
||||
* objectclass: groupOfNames
|
||||
* cn: java-developers
|
||||
* ou: jdeveloper
|
||||
* member: cn=closure-developers,ou=groups,dc=springframework,dc=org
|
||||
* member: uid=groovydude,ou=people,dc=springframework,dc=org
|
||||
*
|
||||
* dn: cn=closure-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
* objectclass: top
|
||||
* objectclass: groupOfNames
|
||||
* cn: java-developers
|
||||
* ou: jdeveloper
|
||||
* member: uid=closuredude,ou=people,dc=springframework,dc=org
|
||||
*
|
||||
* dn: cn=scala-developers,ou=jdeveloper,dc=springframework,dc=org
|
||||
* objectclass: top
|
||||
* objectclass: groupOfNames
|
||||
* cn: java-developers
|
||||
* ou: jdeveloper
|
||||
* member: uid=scaladude,ou=people,dc=springframework,dc=org * </pre>
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
* @author Filip Hanik
|
||||
*/
|
||||
|
||||
public class NestedLdapAuthoritiesPopulator extends DefaultLdapAuthoritiesPopulator {
|
||||
private static final Log logger = LogFactory.getLog(NestedLdapAuthoritiesPopulator.class);
|
||||
|
||||
/**
|
||||
* The attribute names to retrieve for each LDAP group
|
||||
*/
|
||||
private Set<String> attributeNames;
|
||||
|
||||
/**
|
||||
* Maximum search depth - represents the number of recursive searches performed
|
||||
*/
|
||||
private int maxSearchDepth = 10;
|
||||
/**
|
||||
* Constructor for group search scenarios. <tt>userRoleAttributes</tt> may still be
|
||||
* set as a property.
|
||||
*
|
||||
* @param contextSource supplies the contexts used to search for user roles.
|
||||
* @param groupSearchBase if this is an empty string the search will be performed from the root DN of the
|
||||
*/
|
||||
public NestedLdapAuthoritiesPopulator(ContextSource contextSource, String groupSearchBase) {
|
||||
super(contextSource, groupSearchBase);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Set<GrantedAuthority> getGroupMembershipRoles(String userDn, String username) {
|
||||
if (getGroupSearchBase() == null) {
|
||||
return new HashSet<GrantedAuthority>();
|
||||
}
|
||||
|
||||
Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
|
||||
|
||||
performNestedSearch(userDn, username, authorities, getMaxSearchDepth());
|
||||
|
||||
return authorities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the nested group search
|
||||
* @param userDn - the userDN to search for, will become the group DN for subsequent searches
|
||||
* @param username - the username of the user
|
||||
* @param authorities - the authorities set that will be populated, must not be null
|
||||
* @param depth - the depth remaining, when 0 recursion will end
|
||||
*/
|
||||
protected void performNestedSearch(String userDn, String username, Set<GrantedAuthority> authorities, int depth) {
|
||||
if (depth==0) {
|
||||
//back out of recursion
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Search aborted, max depth reached," +
|
||||
" for roles for user '" + username + "', DN = " + "'" + userDn + "', with filter "
|
||||
+ getGroupSearchFilter() + " in search base '" + getGroupSearchBase() + "'");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Searching for roles for user '" + username + "', DN = " + "'" + userDn + "', with filter "
|
||||
+ getGroupSearchFilter() + " in search base '" + getGroupSearchBase() + "'");
|
||||
}
|
||||
|
||||
if (getAttributeNames()==null) {
|
||||
setAttributeNames(new HashSet<String>());
|
||||
}
|
||||
if (StringUtils.hasText(getGroupRoleAttribute()) && !getAttributeNames().contains(getGroupRoleAttribute())) {
|
||||
getAttributeNames().add(getGroupRoleAttribute());
|
||||
}
|
||||
|
||||
Set<Map<String,String[]>> userRoles = getLdapTemplate().searchForMultipleAttributeValues(
|
||||
getGroupSearchBase(),
|
||||
getGroupSearchFilter(),
|
||||
new String[]{userDn, username},
|
||||
getAttributeNames().toArray(new String[getAttributeNames().size()]));
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Roles from search: " + userRoles);
|
||||
}
|
||||
|
||||
for (Map<String,String[]> record : userRoles) {
|
||||
boolean circular = false;
|
||||
String dn = record.get(SpringSecurityLdapTemplate.DN_KEY)[0];
|
||||
String[] roleValues = record.get(getGroupRoleAttribute());
|
||||
Set<String> roles = new HashSet<String>();
|
||||
roles.addAll(Arrays.asList(roleValues!=null?roleValues:new String[0]));
|
||||
for (String role : roles) {
|
||||
if (isConvertToUpperCase()) {
|
||||
role = role.toUpperCase();
|
||||
}
|
||||
role = getRolePrefix() + role;
|
||||
//if the group already exist, we will not search for it's parents again.
|
||||
//this prevents a forever loop for a misconfigured ldap directory
|
||||
circular = circular | (!authorities.add(new LdapAuthority(role,dn,record)));
|
||||
}
|
||||
String roleName = roles.size()>0 ? roles.iterator().next() : dn;
|
||||
if (!circular) {
|
||||
performNestedSearch(dn, roleName, authorities, (depth - 1));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the attribute names that this populator has been configured to retrieve
|
||||
* Value can be null, represents fetch all attributes
|
||||
* @return the attribute names or null for all
|
||||
*/
|
||||
public Set<String> getAttributeNames() {
|
||||
return attributeNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the attribute names to retrieve for each ldap groups. Null means retrieve all
|
||||
* @param attributeNames - the names of the LDAP attributes to retrieve
|
||||
*/
|
||||
public void setAttributeNames(Set<String> attributeNames) {
|
||||
this.attributeNames = attributeNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* How far should a nested search go. Depth is calculated in the number of levels we search up for
|
||||
* parent groups.
|
||||
* @return the max search depth, default is 10
|
||||
*/
|
||||
public int getMaxSearchDepth() {
|
||||
return maxSearchDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
* How far should a nested search go. Depth is calculated in the number of levels we search up for
|
||||
* parent groups.
|
||||
* @param maxSearchDepth the max search depth
|
||||
*/
|
||||
public void setMaxSearchDepth(int maxSearchDepth) {
|
||||
this.maxSearchDepth = maxSearchDepth;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package org.springframework.security.ldap.userdetails;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.ldap.SpringSecurityLdapTemplate;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author Filip Hanik
|
||||
*/
|
||||
public class LdapAuthorityTests {
|
||||
|
||||
public static final String DN = "cn=filip,ou=Users,dc=test,dc=com";
|
||||
LdapAuthority authority;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
Map<String,String[]> attributes = new HashMap<String,String[]>();
|
||||
attributes.put(SpringSecurityLdapTemplate.DN_KEY,new String[] {DN});
|
||||
attributes.put("mail",new String[] {"filip@ldap.test.org", "filip@ldap.test2.org"});
|
||||
authority = new LdapAuthority("testRole", DN, attributes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetDn() throws Exception {
|
||||
assertEquals(DN, authority.getDn());
|
||||
assertNotNull(authority.getAttributeValues(SpringSecurityLdapTemplate.DN_KEY));
|
||||
assertEquals(1, authority.getAttributeValues(SpringSecurityLdapTemplate.DN_KEY).length);
|
||||
assertEquals(DN, authority.getFirstAttributeValue(SpringSecurityLdapTemplate.DN_KEY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAttributes() throws Exception {
|
||||
assertNotNull(authority.getAttributes());
|
||||
assertNotNull(authority.getAttributeValues("mail"));
|
||||
assertEquals(2, authority.getAttributeValues("mail").length);
|
||||
assertEquals("filip@ldap.test.org", authority.getFirstAttributeValue("mail"));
|
||||
assertEquals("filip@ldap.test.org", authority.getAttributeValues("mail")[0]);
|
||||
assertEquals("filip@ldap.test2.org", authority.getAttributeValues("mail")[1]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAuthority() throws Exception {
|
||||
assertNotNull(authority.getAuthority());
|
||||
assertEquals("testRole",authority.getAuthority());
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user