1
0
mirror of synced 2026-08-04 09:17:02 +00:00

Initial LDAP provider checkin.

This commit is contained in:
Luke Taylor
2005-12-15 00:18:13 +00:00
parent 6e3a192a32
commit ce3d6f2129
27 changed files with 2585 additions and 0 deletions
@@ -0,0 +1,25 @@
package org.acegisecurity.providers.ldap;
import junit.framework.TestCase;
/**
* @author Luke Taylor
* @version $Id$
*/
public abstract class AbstractLdapServerTestCase extends TestCase {
protected static final String ROOT_DN = "dc=acegisecurity,dc=org";
protected static final String PROVIDER_URL = "ldap://monkeymachine:389/"+ROOT_DN;
//protected static final String PROVIDER_URL = "ldap://localhost:10389/" + ROOT_DN;
protected static final String MANAGER_USER = "cn=manager," + ROOT_DN;
protected static final String MANAGER_PASSWORD = "acegisecurity";
// protected static final LdapTestServer server = new LdapTestServer();
protected AbstractLdapServerTestCase() {
}
protected AbstractLdapServerTestCase(String string) {
super(string);
}
}
@@ -0,0 +1,140 @@
package org.acegisecurity.providers.ldap;
import javax.naming.Context;
import javax.naming.directory.DirContext;
import java.util.Hashtable;
import org.springframework.dao.DataAccessResourceFailureException;
import org.acegisecurity.BadCredentialsException;
/**
* Tests {@link InitialDirContextFactory}.
*
* @author Luke Taylor
* @version $Id$
*/
public class InitialDirContextFactoryTests extends AbstractLdapServerTestCase {
public void testNonLdapUrlIsRejected() throws Exception {
DefaultInitialDirContextFactory idf = new DefaultInitialDirContextFactory();
idf.setUrl("http://acegisecurity.org/dc=acegisecurity,dc=org");
try {
idf.afterPropertiesSet();
fail("Expected exception for non 'ldap://' URL");
} catch(IllegalArgumentException expected) {
}
}
public void testConnectionFailure() throws Exception {
DefaultInitialDirContextFactory idf = new DefaultInitialDirContextFactory();
// Use the wrong port
idf.setUrl("ldap://localhost:60389");
Hashtable env = new Hashtable();
env.put("com.sun.jndi.ldap.connect.timeout", "200");
idf.setExtraEnvVars(env);
idf.afterPropertiesSet();
try {
idf.newInitialDirContext();
fail("Connection succeeded unexpectedly");
} catch(DataAccessResourceFailureException expected) {
}
}
public void testAnonymousBindSucceeds() throws Exception {
DefaultInitialDirContextFactory idf = new DefaultInitialDirContextFactory();
idf.setUrl(PROVIDER_URL);
idf.afterPropertiesSet();
DirContext ctx = idf.newInitialDirContext();
// Connection pooling should be set by default for anon users.
assertEquals("true",ctx.getEnvironment().get("com.sun.jndi.ldap.connect.pool"));
ctx.close();
}
public void testBindAsManagerSucceeds() throws Exception {
DefaultInitialDirContextFactory idf = new DefaultInitialDirContextFactory();
idf.setUrl(PROVIDER_URL);
idf.setManagerPassword(MANAGER_PASSWORD);
idf.setManagerDn(MANAGER_USER);
idf.afterPropertiesSet();
DirContext ctx = idf.newInitialDirContext();
assertEquals("true",ctx.getEnvironment().get("com.sun.jndi.ldap.connect.pool"));
ctx.close();
}
public void testInvalidPasswordCausesBadCredentialsException() throws Exception {
DefaultInitialDirContextFactory idf = new DefaultInitialDirContextFactory();
idf.setUrl(PROVIDER_URL);
idf.setManagerDn(MANAGER_USER);
idf.setManagerPassword("wrongpassword");
idf.afterPropertiesSet();
try {
DirContext ctx = idf.newInitialDirContext();
fail("Authentication with wrong credentials should fail.");
} catch(BadCredentialsException expected) {
}
}
public void testConnectionAsSpecificUserSucceeds() throws Exception {
DefaultInitialDirContextFactory idf = new DefaultInitialDirContextFactory();
idf.setUrl(PROVIDER_URL);
idf.afterPropertiesSet();
DirContext ctx = idf.newInitialDirContext("uid=Bob,ou=people,dc=acegisecurity,dc=org",
"bobspassword");
// We don't want pooling for specific users.
assertNull(ctx.getEnvironment().get("com.sun.jndi.ldap.connect.pool"));
ctx.close();
}
public void testEnvironment() {
DefaultInitialDirContextFactory idf = new DefaultInitialDirContextFactory();
idf.setUrl("ldap://acegisecurity.org/");
// check basic env
Hashtable env = idf.getEnvironment();
assertEquals("com.sun.jndi.ldap.LdapCtxFactory", env.get(Context.INITIAL_CONTEXT_FACTORY));
assertEquals("ldap://acegisecurity.org/", env.get(Context.PROVIDER_URL));
assertEquals("simple",env.get(Context.SECURITY_AUTHENTICATION));
assertNull(env.get(Context.SECURITY_PRINCIPAL));
assertNull(env.get(Context.SECURITY_CREDENTIALS));
// Ctx factory.
idf.setInitialContextFactory("org.acegisecurity.NonExistentCtxFactory");
env = idf.getEnvironment();
assertEquals("org.acegisecurity.NonExistentCtxFactory", env.get(Context.INITIAL_CONTEXT_FACTORY));
// Auth type
idf.setAuthenticationType("myauthtype");
env = idf.getEnvironment();
assertEquals("myauthtype", env.get(Context.SECURITY_AUTHENTICATION));
// Check extra vars
Hashtable extraVars = new Hashtable();
extraVars.put("extravar", "extravarvalue");
idf.setExtraEnvVars(extraVars);
env = idf.getEnvironment();
assertEquals("extravarvalue", env.get("extravar"));
}
public void testBaseDnIsParsedFromCorrectlyFromUrl() throws Exception {
DefaultInitialDirContextFactory idf = new DefaultInitialDirContextFactory();
idf.setUrl("ldap://acegisecurity.org/dc=acegisecurity,dc=org");
idf.afterPropertiesSet();
assertEquals("dc=acegisecurity,dc=org", idf.getRootDn());
// Check with an empty root
idf = new DefaultInitialDirContextFactory();
idf.setUrl("ldap://acegisecurity.org/");
idf.afterPropertiesSet();
assertEquals("", idf.getRootDn());
// Empty root without trailing slash
idf = new DefaultInitialDirContextFactory();
idf.setUrl("ldap://acegisecurity.org");
idf.afterPropertiesSet();
assertEquals("", idf.getRootDn());
}
}
@@ -0,0 +1,102 @@
package org.acegisecurity.providers.ldap;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.Authentication;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.providers.ldap.authenticator.FilterBasedLdapUserSearch;
import org.acegisecurity.providers.ldap.authenticator.BindAuthenticator;
import org.acegisecurity.providers.ldap.populator.DefaultLdapAuthoritiesPopulator;
import org.acegisecurity.userdetails.UserDetails;
/**
* @author Luke Taylor
* @version $Id$
*/
public class LdapAuthenticationProviderTests extends AbstractLdapServerTestCase {
DefaultInitialDirContextFactory dirCtxFactory;
public LdapAuthenticationProviderTests(String string) {
super(string);
}
public LdapAuthenticationProviderTests() {
super();
}
public void testNormalUsage() throws Exception {
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider();
ldapProvider.setAuthenticator(new MockAuthenticator());
ldapProvider.setLdapAuthoritiesPopulator(new MockAuthoritiesPopulator());
ldapProvider.afterPropertiesSet();
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("bob","bobspassword");
UserDetails user = ldapProvider.retrieveUser("bob", token);
assertEquals(1, user.getAuthorities().length);
assertTrue(user.getAuthorities()[0].equals("ROLE_USER"));
ldapProvider.additionalAuthenticationChecks(user, token);
}
public void testIntegration() throws Exception {
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider();
// Connection information
DefaultInitialDirContextFactory dirCtxFactory = new DefaultInitialDirContextFactory();
dirCtxFactory.setUrl(PROVIDER_URL);
dirCtxFactory.setManagerDn(MANAGER_USER);
dirCtxFactory.setManagerPassword(MANAGER_PASSWORD);
dirCtxFactory.afterPropertiesSet();
BindAuthenticator authenticator = new BindAuthenticator();
//PasswordComparisonAuthenticator authenticator = new PasswordComparisonAuthenticator();
authenticator.setInitialDirContextFactory(dirCtxFactory);
//authenticator.setUserDnPattern("cn={0},ou=people");
FilterBasedLdapUserSearch userSearch = new FilterBasedLdapUserSearch();
userSearch.setSearchBase("ou=people");
userSearch.setSearchFilter("(cn={0})");
userSearch.setInitialDirContextFactory(dirCtxFactory);
userSearch.afterPropertiesSet();
authenticator.setUserSearch(userSearch);
authenticator.afterPropertiesSet();
DefaultLdapAuthoritiesPopulator populator;
populator = new DefaultLdapAuthoritiesPopulator();
populator.setRolePrefix("ROLE_");
populator.setInitialDirContextFactory(dirCtxFactory);
populator.setGroupSearchBase("ou=groups");
populator.afterPropertiesSet();
ldapProvider.setLdapAuthoritiesPopulator(populator);
ldapProvider.setAuthenticator(authenticator);
Authentication auth = ldapProvider.authenticate(new UsernamePasswordAuthenticationToken("Ben Alex","benspassword"));
assertEquals(2, auth.getAuthorities().length);
}
class MockAuthoritiesPopulator implements LdapAuthoritiesPopulator {
public GrantedAuthority[] getGrantedAuthorities(String userDn, String dn, Attributes userAttributes) {
return new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_USER") };
}
}
class MockAuthenticator implements LdapAuthenticator {
Attributes userAttributes = new BasicAttributes("cn","bob");
public LdapUserDetails authenticate(String username, String password) {
if(username.equals("bob") && password.equals("bobspassword")) {
return new LdapUserDetails("cn=bob,ou=people,dc=acegisecurity,dc=org", userAttributes);
}
throw new BadCredentialsException("Authentication of Bob failed.");
}
}
}
@@ -0,0 +1,94 @@
package org.acegisecurity.providers.ldap;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.apache.ldap.server.configuration.MutableServerStartupConfiguration;
import org.apache.ldap.server.jndi.ServerContextFactory;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.NameAlreadyBoundException;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.Attribute;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import java.io.IOException;
import java.util.Properties;
/**
* @author Luke Taylor
* @version $Id$
*/
public class LdapTestServer {
//~ Instance fields ========================================================
private DirContext serverContext;
//~ Constructors ================================================================
public LdapTestServer() {
startLdapServer();
createManagerUser();
}
//~ Methods ================================================================
private void startLdapServer() {
ApplicationContext factory = new ClassPathXmlApplicationContext( "org/acegisecurity/providers/ldap/apacheds-context.xml");
MutableServerStartupConfiguration cfg = ( MutableServerStartupConfiguration ) factory.getBean( "configuration" );
ClassPathResource ldifDir = new ClassPathResource("org/acegisecurity/providers/ldap/ldif");
try {
cfg.setLdifDirectory(ldifDir.getFile());
} catch (IOException e) {
System.err.println("Failed to set LDIF directory for server");
e.printStackTrace();
}
Properties env = ( Properties ) factory.getBean( "environment" );
env.setProperty( Context.PROVIDER_URL, "dc=acegisecurity,dc=org" );
env.setProperty( Context.INITIAL_CONTEXT_FACTORY, ServerContextFactory.class.getName() );
env.putAll( cfg.toJndiEnvironment() );
try {
serverContext = new InitialDirContext( env );
} catch (NamingException e) {
System.err.println("Failed to start Apache DS");
e.printStackTrace();
}
}
private void createManagerUser() {
Attributes user = new BasicAttributes( "cn", "manager" , true );
user.put( "userPassword", "acegisecurity" );
Attribute objectClass = new BasicAttribute("objectClass");
user.put( objectClass );
objectClass.add( "top" );
objectClass.add( "person" );
objectClass.add( "organizationalPerson" );
objectClass.add( "inetOrgPerson" );
user.put( "sn", "Manager" );
user.put( "cn", "manager" );
try {
serverContext.createSubcontext("cn=manager", user );
} catch(NameAlreadyBoundException ignore) {
System.out.println("Manager user already exists.");
} catch (NamingException ne) {
System.err.println("Failed to create manager user.");
ne.printStackTrace();
}
}
public DirContext getServerContext() {
return serverContext;
}
public static void main(String[] args) {
new LdapTestServer();
}
}
@@ -0,0 +1,73 @@
package org.acegisecurity.providers.ldap.authenticator;
import org.acegisecurity.providers.ldap.DefaultInitialDirContextFactory;
import org.acegisecurity.providers.ldap.LdapUserDetails;
import org.acegisecurity.providers.ldap.AbstractLdapServerTestCase;
import org.acegisecurity.BadCredentialsException;
/**
* Tests {@link BindAuthenticator}.
*
* @author Luke Taylor
* @version $Id$
*/
public class BindAuthenticatorTests extends AbstractLdapServerTestCase {
private DefaultInitialDirContextFactory dirCtxFactory;
private BindAuthenticator authenticator;
public void setUp() throws Exception {
// Connection information
dirCtxFactory = new DefaultInitialDirContextFactory();
dirCtxFactory.setUrl(PROVIDER_URL);
dirCtxFactory.afterPropertiesSet();
authenticator = new BindAuthenticator();
authenticator.setInitialDirContextFactory(dirCtxFactory);
}
public void testUserDnPatternReturnsCorrectDn() throws Exception {
authenticator.setUserDnPattern("cn={0},ou=people");
assertEquals("cn=Joe,ou=people,"+ ROOT_DN, authenticator.getUserDn("Joe"));
}
public void testAuthenticationWithCorrectPasswordSucceeds() throws Exception {
authenticator.setUserDnPattern("uid={0},ou=people");
LdapUserDetails user = authenticator.authenticate("bob","bobspassword");
}
public void testAuthenticationWithWrongPasswordFails() {
BindAuthenticator authenticator = new BindAuthenticator();
authenticator.setInitialDirContextFactory(dirCtxFactory);
authenticator.setUserDnPattern("uid={0},ou=people");
try {
authenticator.authenticate("bob","wrongpassword");
fail("Shouldn't be able to bind with wrong password");
} catch(BadCredentialsException expected) {
}
}
public void testAuthenticationWithUserSearch() throws Exception {
LdapUserDetails user = new LdapUserDetails("uid=bob,ou=people," + ROOT_DN, null);
authenticator.setUserSearch(new MockUserSearch(user));
authenticator.afterPropertiesSet();
authenticator.authenticate("bob","bobspassword");
}
// Apache DS falls apart with unknown DNs.
//
// public void testAuthenticationWithInvalidUserNameFails() {
// BindAuthenticator authenticator = new BindAuthenticator();
//
// authenticator.setInitialDirContextFactory(dirCtxFactory);
// authenticator.setUserDnPattern("cn={0},ou=people");
// try {
// authenticator.authenticate("Baz","bobspassword");
// fail("Shouldn't be able to bind with invalid username");
// } catch(BadCredentialsException expected) {
// }
// }
}
@@ -0,0 +1,87 @@
package org.acegisecurity.providers.ldap.authenticator;
import org.acegisecurity.providers.ldap.AbstractLdapServerTestCase;
import org.acegisecurity.providers.ldap.DefaultInitialDirContextFactory;
import org.acegisecurity.providers.ldap.LdapUserDetails;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.acegisecurity.BadCredentialsException;
/**
* Tests for FilterBasedLdapUserSearch.
*
* @author Luke Taylor
* @version $Id$
*/
public class FilterBasedLdapUserSearchTests extends AbstractLdapServerTestCase {
private DefaultInitialDirContextFactory dirCtxFactory;
private FilterBasedLdapUserSearch locator;
public void setUp() throws Exception {
dirCtxFactory = new DefaultInitialDirContextFactory();
dirCtxFactory.setUrl(PROVIDER_URL);
dirCtxFactory.setManagerDn(MANAGER_USER);
dirCtxFactory.setManagerPassword(MANAGER_PASSWORD);
dirCtxFactory.afterPropertiesSet();
locator = new FilterBasedLdapUserSearch();
locator.setSearchSubtree(false);
locator.setSearchTimeLimit(0);
locator.setInitialDirContextFactory(dirCtxFactory);
}
public FilterBasedLdapUserSearchTests(String string) {
super(string);
}
public FilterBasedLdapUserSearchTests() {
super();
}
public void testBasicSearch() throws Exception {
locator.setSearchBase("ou=people");
locator.setSearchFilter("(uid={0})");
locator.afterPropertiesSet();
LdapUserDetails bob = locator.searchForUser("Bob");
assertEquals("uid=bob,ou=people,"+ROOT_DN, bob.getDn());
}
public void testSubTreeSearchSucceeds() throws Exception {
// Don't set the searchBase, so search from the root.
locator.setSearchFilter("(uid={0})");
locator.setSearchSubtree(true);
locator.afterPropertiesSet();
LdapUserDetails bob = locator.searchForUser("Bob");
assertEquals("uid=bob,ou=people,"+ROOT_DN, bob.getDn());
}
public void testSearchForInvalidUserFails() {
locator.setSearchBase("ou=people");
locator.setSearchFilter("(uid={0})");
try {
locator.searchForUser("Joe");
fail("Expected UsernameNotFoundException for non-existent user.");
} catch (UsernameNotFoundException expected) {
}
}
public void testFailsOnMultipleMatches() {
locator.setSearchBase("ou=people");
locator.setSearchFilter("(cn=*)");
try {
locator.searchForUser("Ignored");
fail("Expected exception for multiple search matches.");
} catch (BadCredentialsException expected) {
}
}
/** Try some funny business with filters. */
public void testExtraFilterPartToExcludeBob() {
locator.setSearchBase("ou=people");
locator.setSearchFilter("(&(cn=*)(!(uid={0})))");
// Search for bob, get back ben...
LdapUserDetails ben = locator.searchForUser("bob");
assertEquals("cn=Ben Alex,ou=people,"+ROOT_DN, ben.getDn());
}
}
@@ -0,0 +1,19 @@
package org.acegisecurity.providers.ldap.authenticator;
import org.acegisecurity.providers.ldap.LdapUserDetails;
/**
* @author Luke Taylor
* @version $Id$
*/
public class MockUserSearch implements LdapUserSearch {
LdapUserDetails user;
public MockUserSearch(LdapUserDetails user) {
this.user = user;
}
public LdapUserDetails searchForUser(String username) {
return user;
}
}
@@ -0,0 +1,58 @@
package org.acegisecurity.providers.ldap.authenticator;
import org.jmock.Mock;
import org.jmock.MockObjectTestCase;
import org.acegisecurity.providers.ldap.InitialDirContextFactory;
import javax.naming.directory.DirContext;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.Attributes;
/**
* @author Luke Taylor
* @version $Id$
*/
public class PasswordComparisonAuthenticatorMockTests extends MockObjectTestCase {
public void testLdapCompareIsUsedWhenPasswordIsNotRetrieved() throws Exception {
Mock mockCtx = new Mock(DirContext.class);
PasswordComparisonAuthenticator authenticator = new PasswordComparisonAuthenticator();
authenticator.setUserDnPattern("cn={0},ou=people");
authenticator.setInitialDirContextFactory(
new MockInitialDirContextFactory((DirContext)mockCtx.proxy(),
"dc=acegisecurity,dc=org"));
// Get the mock to return an empty attribute set
mockCtx.expects(atLeastOnce()).method("getNameInNamespace").will(returnValue("dc=acegisecurity,dc=org"));
mockCtx.expects(once()).method("getAttributes").with(eq("cn=Bob,ou=people"), NULL).will(returnValue(new BasicAttributes()));
// Setup a single return value (i.e. success)
Attributes searchResults = new BasicAttributes("", null);
mockCtx.expects(once()).method("search").with(eq("cn=Bob,ou=people"),
eq("(userPassword={0})"), NOT_NULL, NOT_NULL).will(returnValue(searchResults.getAll()));
mockCtx.expects(once()).method("close");
authenticator.authenticate("Bob", "bobspassword");
}
class MockInitialDirContextFactory implements InitialDirContextFactory {
DirContext ctx;
String baseDn;
public MockInitialDirContextFactory(DirContext ctx, String baseDn) {
this.baseDn = baseDn;
this.ctx = ctx;
}
public DirContext newInitialDirContext() {
return ctx;
}
public DirContext newInitialDirContext(String username, String password) {
return ctx;
}
public String getRootDn() {
return baseDn;
}
}
}
@@ -0,0 +1,133 @@
package org.acegisecurity.providers.ldap.authenticator;
import org.acegisecurity.providers.ldap.DefaultInitialDirContextFactory;
import org.acegisecurity.providers.ldap.LdapUserDetails;
import org.acegisecurity.providers.ldap.AbstractLdapServerTestCase;
import org.acegisecurity.providers.encoding.PlaintextPasswordEncoder;
import org.acegisecurity.BadCredentialsException;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import javax.naming.directory.BasicAttributes;
/**
* @author Luke Taylor
* @version $Id$
*/
public class PasswordComparisonAuthenticatorTests extends AbstractLdapServerTestCase {
private DefaultInitialDirContextFactory dirCtxFactory;
private PasswordComparisonAuthenticator authenticator;
public void setUp() throws Exception {
// Connection information
dirCtxFactory = new DefaultInitialDirContextFactory();
dirCtxFactory.setUrl(PROVIDER_URL);
dirCtxFactory.setManagerDn(MANAGER_USER);
dirCtxFactory.setManagerPassword(MANAGER_PASSWORD);
dirCtxFactory.afterPropertiesSet();
authenticator = new PasswordComparisonAuthenticator();
authenticator.setInitialDirContextFactory(dirCtxFactory);
authenticator.setUserDnPattern("uid={0},ou=people");
}
public void tearDown() {
// com.sun.jndi.ldap.LdapPoolManager.showStats(System.out);
}
public void testLdapCompareSucceedsWithCorrectPassword() {
// Don't retrieve the password
authenticator.setUserAttributes(new String[] {"cn", "sn"});
// Bob has a plaintext password.
authenticator.setPasswordEncoder(new PlaintextPasswordEncoder());
authenticator.authenticate("Bob", "bobspassword");
}
public void testLdapCompareSucceedsWithShaEncodedPassword() {
authenticator = new PasswordComparisonAuthenticator();
authenticator.setInitialDirContextFactory(dirCtxFactory);
authenticator.setUserDnPattern("cn={0},ou=people");
// Don't retrieve the password
authenticator.setUserAttributes(new String[] {"cn", "sn"});
authenticator.authenticate("Ben Alex", "benspassword");
}
public void testPasswordEncoderCantBeNull() {
try {
authenticator.setPasswordEncoder(null);
fail("Password encoder can't be null");
} catch(IllegalArgumentException expected) {
}
}
public void testLdapPasswordCompareFailsWithWrongPassword() {
// Don't retrieve the password
authenticator.setUserAttributes(new String[] {"cn", "sn"});
try {
authenticator.authenticate("Bob", "wrongpassword");
fail("Authentication should fail with wrong password.");
} catch(BadCredentialsException expected) {
}
}
public void testLocalPasswordComparisonSucceedsWithCorrectPassword() {
authenticator.authenticate("Bob", "bobspassword");
}
public void testLocalCompareSucceedsWithShaEncodedPassword() {
authenticator = new PasswordComparisonAuthenticator();
authenticator.setInitialDirContextFactory(dirCtxFactory);
authenticator.setUserDnPattern("cn={0},ou=people");
authenticator.authenticate("Ben Alex", "benspassword");
}
public void testLocalPasswordComparisonFailsWithWrongPassword() {
try {
authenticator.authenticate("Bob", "wrongpassword");
fail("Authentication should fail with wrong password.");
} catch(BadCredentialsException expected) {
}
}
public void testAllAttributesAreRetrivedByDefault() {
LdapUserDetails user = authenticator.authenticate("Bob", "bobspassword");
System.out.println(user.getAttributes().toString());
assertEquals("User should have 5 attributes", 5, user.getAttributes().size());
}
public void testOnlySpecifiedAttributesAreRetrieved() throws Exception {
authenticator.setUserAttributes(new String[] {"cn", "sn"});
authenticator.setPasswordEncoder(new PlaintextPasswordEncoder());
LdapUserDetails user = authenticator.authenticate("Bob", "bobspassword");
assertEquals("Should have retrieved 2 attributes (cn, sn)",2, user.getAttributes().size());
assertEquals("Bob Hamilton", user.getAttributes().get("cn").get());
assertEquals("Hamilton", user.getAttributes().get("sn").get());
}
public void testUseOfDifferentPasswordAttribute() {
authenticator.setPasswordAttributeName("sn");
authenticator.authenticate("Bob", "Hamilton");
}
public void testWithUserSearch() {
LdapUserDetails user = new LdapUserDetails("uid=Bob,ou=people" + ROOT_DN,
new BasicAttributes("userPassword","bobspassword"));
authenticator.setUserDnPattern(null);
assertNull(authenticator.getUserDnPattern());
assertNull(authenticator.getUserDn("Bob"));
authenticator.setUserSearch(new MockUserSearch(user));
authenticator.authenticate("ShouldntBeUsed","bobspassword");
}
public void testFailedSearchGivesUserNotFoundException() throws Exception {
authenticator.setUserDnPattern(null);
authenticator.setUserSearch(new MockUserSearch(null));
authenticator.afterPropertiesSet();
try {
authenticator.authenticate("Joe","password");
fail("Expected exception on failed user search");
} catch (UsernameNotFoundException expected) {
}
}
}
@@ -0,0 +1,76 @@
package org.acegisecurity.providers.ldap.populator;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.BasicAttribute;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.providers.ldap.AbstractLdapServerTestCase;
import org.acegisecurity.providers.ldap.DefaultInitialDirContextFactory;
import java.util.Set;
import java.util.HashSet;
/**
* @author Luke Taylor
* @version $Id$
*/
public class DefaultLdapAuthoritiesPopulatorTests extends AbstractLdapServerTestCase {
private DefaultInitialDirContextFactory dirCtxFactory;
private DefaultLdapAuthoritiesPopulator populator;
public void setUp() {
dirCtxFactory = new DefaultInitialDirContextFactory();
dirCtxFactory.setUrl(PROVIDER_URL);
dirCtxFactory.setManagerDn(MANAGER_USER);
dirCtxFactory.setManagerPassword(MANAGER_PASSWORD);
populator = new DefaultLdapAuthoritiesPopulator();
populator.setRolePrefix("ROLE_");
}
public void testCtxFactoryMustBeSetIfSearchBaseIsSet() throws Exception {
populator.setGroupSearchBase("");
try {
populator.afterPropertiesSet();
fail("expected exception.");
} catch (IllegalArgumentException expected) {
}
}
public void testUserAttributeMappingToRoles() {
populator.setUserRoleAttributes(new String[] {"userRole", "otherUserRole"});
populator.getUserRoleAttributes();
Attributes userAttrs = new BasicAttributes();
BasicAttribute attr = new BasicAttribute("userRole", "role1");
attr.add("role2");
userAttrs.put(attr);
attr = new BasicAttribute("otherUserRole", "role3");
attr.add("role2"); // duplicate
userAttrs.put(attr);
GrantedAuthority[] authorities = populator.getGrantedAuthorities("Ignored", "Ignored", userAttrs);
assertEquals("User should have three roles", 3, authorities.length);
}
public void testGroupSearch() throws Exception {
populator.setInitialDirContextFactory(dirCtxFactory);
populator.setGroupSearchBase("ou=groups");
populator.setGroupRoleAttribute("ou");
populator.setSearchSubtree(true);
populator.setSearchSubtree(false);
populator.setConvertToUpperCase(true);
populator.setGroupSearchFilter("member={0}");
populator.afterPropertiesSet();
GrantedAuthority[] authorities = populator.getGrantedAuthorities("Ben", "cn=Ben Alex,ou=people,"+ROOT_DN, new BasicAttributes());
assertEquals("Should have 2 roles", 2, authorities.length);
Set roles = new HashSet();
roles.add(authorities[0].toString());
roles.add(authorities[1].toString());
assertTrue(roles.contains("ROLE_DEVELOPER"));
assertTrue(roles.contains("ROLE_MANAGER"));
}
}
@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- JNDI environment variable -->
<bean id="environment" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties">
<props>
<!--prop key="asn.1.berlib.provider">org.apache.ldap.common.berlib.asn1.SnickersProvider</prop -->
<!--prop key="asn.1.berlib.provider">org.apache.asn1new.ldap.TwixProvider</prop-->
<prop key="java.naming.security.authentication">simple</prop>
<prop key="java.naming.security.principal">uid=admin,ou=system</prop>
<prop key="java.naming.security.credentials">secret</prop>
<prop key="java.naming.ldap.attributes.binary">
photo personalSignature audio jpegPhoto javaSerializedData userPassword
userCertificate cACertificate authorityRevocationList certificateRevocationList
crossCertificatePair x500UniqueIdentifier krb5Key
</prop>
</props>
</property>
</bean>
<!-- StartupConfiguration to start ApacheDS -->
<bean id="configuration" class="org.apache.ldap.server.configuration.MutableServerStartupConfiguration">
<property name="workingDirectory"><value>${java.io.tmpdir}/apache_ds</value></property>
<property name="allowAnonymousAccess"><value>true</value></property>
<property name="accessControlEnabled"><value>false</value></property>
<property name="ldapPort"><value>10389</value></property>
<property name="contextPartitionConfigurations">
<set>
<ref bean="acegiPartitionConfiguration"/>
</set>
</property>
<!-- Bootstrap schemas -->
<!-- <property name="bootstrapSchemas">
<set>
<bean class="org.apache.ldap.server.schema.bootstrap.AutofsSchema"/>
<bean class="org.apache.ldap.server.schema.bootstrap.CorbaSchema"/>
<bean class="org.apache.ldap.server.schema.bootstrap.CoreSchema"/>
</set>
</property>
-->
<!-- Interceptor configurations -->
<!--property name="interceptorConfigurations">
<list>
<bean class="org.apache.ldap.server.configuration.MutableInterceptorConfiguration">
<property name="name"><value>normalizationService</value></property>
<property name="interceptor">
<bean class="org.apache.ldap.server.normalization.NormalizationService" />
</property>
</bean>
<bean class="org.apache.ldap.server.configuration.MutableInterceptorConfiguration">
<property name="name"><value>authenticationService</value></property>
<property name="interceptor">
<bean class="org.apache.ldap.server.authn.AuthenticationService" />
</property>
</bean>
</list>
</property>
-->
</bean>
<!-- Additional ContextPartitionConfiguration -->
<bean id="acegiPartitionConfiguration" class="org.apache.ldap.server.configuration.MutableDirectoryPartitionConfiguration">
<property name="name"><value>acegisecurity</value></property>
<property name="suffix"><value>dc=acegisecurity,dc=org</value></property>
<property name="indexedAttributes">
<set>
<value>objectClass</value>
<value>ou</value>
<value>uid</value>
</set>
</property>
<property name="contextEntry">
<value>
objectClass: top
objectClass: domain
objectClass: extensibleObject
dc: apache
</value>
</property>
</bean>
<!-- Custom editors required to launch ApacheDS -->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="javax.naming.directory.Attributes">
<bean class="org.apache.ldap.server.configuration.AttributesPropertyEditor"/>
</entry>
</map>
</property>
</bean>
</beans>
@@ -0,0 +1,54 @@
version: 1
dn: dc=acegisecurity,dc=org
objectClass: dcObject
objectClass: organization
dc: acegisecurity
description: Acegi Security (Test LDAP DIT)
o: Monkey Machine Ltd.
dn: ou=people,dc=acegisecurity,dc=org
objectClass: organizationalUnit
description: All people in organisation
ou: people
dn: cn=Ben Alex,ou=people,dc=acegisecurity,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Ben Alex
sn: Alex
uid: Ben
userPassword:: e3NoYX1uRkNlYldqeGZhTGJISEcxUWs1VVU0dHJidlE9
dn: uid=bob,ou=people,dc=acegisecurity,dc=org
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
cn: Bob Hamilton
sn: Hamilton
uid: bob
userPassword:: Ym9ic3Bhc3N3b3Jk
dn: ou=groups,dc=acegisecurity,dc=org
objectClass: top
objectClass: organizationalUnit
ou: groups
dn: cn=developers,ou=groups,dc=acegisecurity,dc=org
objectClass: groupOfNames
objectClass: top
cn: developers
description: Acegi Security Developers
member: uid=bob,ou=people,dc=acegisecurity,dc=org
member: cn=Ben Alex,ou=people,dc=acegisecurity,dc=org
o: Acegi Security System for Spring
ou: developer
dn: cn=managers,ou=groups,dc=acegisecurity,dc=org
objectClass: groupOfNames
objectClass: top
cn: managers
member: cn=Ben Alex,ou=people,dc=acegisecurity,dc=org
ou: manager