diff --git a/core/pom.xml b/core/pom.xml index 6a72e1c36e..ee20510aea 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -56,7 +56,7 @@ org.springframework.ldap spring-ldap - 1.2 + 1.2.1-SNAPSHOT true diff --git a/core/src/main/java/org/springframework/security/config/LdapBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/LdapBeanDefinitionParser.java index 7f80ed4b2b..44fb2206fc 100644 --- a/core/src/main/java/org/springframework/security/config/LdapBeanDefinitionParser.java +++ b/core/src/main/java/org/springframework/security/config/LdapBeanDefinitionParser.java @@ -1,22 +1,23 @@ package org.springframework.security.config; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; +import org.springframework.security.ldap.DefaultSpringSecurityContextSource; +import org.springframework.security.providers.ldap.LdapAuthenticationProvider; +import org.springframework.security.providers.ldap.authenticator.BindAuthenticator; +import org.springframework.security.providers.ldap.populator.DefaultLdapAuthoritiesPopulator; +import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.beans.factory.BeanDefinitionStoreException; -import org.springframework.util.StringUtils; -import org.springframework.util.Assert; -import org.springframework.security.ldap.DefaultInitialDirContextFactory; -import org.springframework.security.providers.ldap.LdapAuthenticationProvider; -import org.springframework.security.providers.ldap.populator.DefaultLdapAuthoritiesPopulator; -import org.springframework.security.providers.ldap.authenticator.BindAuthenticator; +import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; import org.springframework.ldap.core.DirContextAdapter; -import org.w3c.dom.Element; -import org.apache.directory.server.configuration.MutableServerStartupConfiguration; -import org.apache.directory.server.core.partition.impl.btree.MutableBTreePartitionConfiguration; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.directory.server.configuration.MutableServerStartupConfiguration; +import org.apache.directory.server.core.partition.impl.btree.MutableBTreePartitionConfiguration; +import org.w3c.dom.Element; import javax.naming.NamingException; import java.util.HashSet; @@ -63,13 +64,13 @@ public class LdapBeanDefinitionParser extends AbstractBeanDefinitionParser { protected AbstractBeanDefinition parseInternal(Element elt, ParserContext parserContext) { String url = elt.getAttribute(URL_ATTRIBUTE); - RootBeanDefinition initialDirContextFactory; + RootBeanDefinition contextSource; if (!StringUtils.hasText(url)) { - initialDirContextFactory = createEmbeddedServer(elt, parserContext); + contextSource = createEmbeddedServer(elt, parserContext); } else { - initialDirContextFactory = new RootBeanDefinition(DefaultInitialDirContextFactory.class); - initialDirContextFactory.getConstructorArgumentValues().addIndexedArgumentValue(0, url); + contextSource = new RootBeanDefinition(DefaultSpringSecurityContextSource.class); + contextSource.getConstructorArgumentValues().addIndexedArgumentValue(0, url); } String managerDn = elt.getAttribute(PRINCIPAL_ATTRIBUTE); @@ -79,14 +80,14 @@ public class LdapBeanDefinitionParser extends AbstractBeanDefinitionParser { Assert.hasText(managerPassword, "You must specify the " + PASSWORD_ATTRIBUTE + " if you supply a " + managerDn); - initialDirContextFactory.getPropertyValues().addPropertyValue("managerDn", managerDn); - initialDirContextFactory.getPropertyValues().addPropertyValue("managerPassword", managerPassword); + contextSource.getPropertyValues().addPropertyValue("userDn", managerDn); + contextSource.getPropertyValues().addPropertyValue("password", managerPassword); } // TODO: Make these default values for 2.0 - initialDirContextFactory.getPropertyValues().addPropertyValue("useLdapContext", Boolean.TRUE); - initialDirContextFactory.getPropertyValues().addPropertyValue("dirObjectFactory", "org.springframework.ldap.core.support.DefaultDirObjectFactory"); +// contextSource.getPropertyValues().addPropertyValue("useLdapContext", Boolean.TRUE); +// contextSource.getPropertyValues().addPropertyValue("dirObjectFactory", "org.springframework.ldap.core.support.DefaultDirObjectFactory"); String id = elt.getAttribute(ID_ATTRIBUTE); String contextSourceId = "contextSource"; @@ -99,13 +100,13 @@ public class LdapBeanDefinitionParser extends AbstractBeanDefinitionParser { logger.warn("Bean already exists with Id '" + contextSourceId + "'"); } - parserContext.getRegistry().registerBeanDefinition(contextSourceId, initialDirContextFactory); + parserContext.getRegistry().registerBeanDefinition(contextSourceId, contextSource); RootBeanDefinition bindAuthenticator = new RootBeanDefinition(BindAuthenticator.class); - bindAuthenticator.getConstructorArgumentValues().addGenericArgumentValue(initialDirContextFactory); + bindAuthenticator.getConstructorArgumentValues().addGenericArgumentValue(contextSource); bindAuthenticator.getPropertyValues().addPropertyValue("userDnPatterns", new String[] {DEFAULT_DN_PATTERN}); RootBeanDefinition authoritiesPopulator = new RootBeanDefinition(DefaultLdapAuthoritiesPopulator.class); - authoritiesPopulator.getConstructorArgumentValues().addGenericArgumentValue(initialDirContextFactory); + authoritiesPopulator.getConstructorArgumentValues().addGenericArgumentValue(contextSource); authoritiesPopulator.getConstructorArgumentValues().addGenericArgumentValue(DEFAULT_GROUP_CONTEXT); RootBeanDefinition ldapProvider = new RootBeanDefinition(LdapAuthenticationProvider.class); @@ -170,16 +171,15 @@ public class LdapBeanDefinitionParser extends AbstractBeanDefinitionParser { configuration.setExitVmOnShutdown(false); configuration.setContextPartitionConfigurations(partitions); - RootBeanDefinition initialDirContextFactory = new RootBeanDefinition(DefaultInitialDirContextFactory.class); - initialDirContextFactory.getConstructorArgumentValues().addIndexedArgumentValue(0, - "ldap://127.0.0.1:" + port + "/" + suffix); + RootBeanDefinition contextSource = new RootBeanDefinition(DefaultSpringSecurityContextSource.class); + contextSource.getConstructorArgumentValues().addIndexedArgumentValue(0, "ldap://127.0.0.1:" + port + "/" + suffix); - initialDirContextFactory.getPropertyValues().addPropertyValue("managerDn", "uid=admin,ou=system"); - initialDirContextFactory.getPropertyValues().addPropertyValue("managerPassword", "secret"); + contextSource.getPropertyValues().addPropertyValue("userDn", "uid=admin,ou=system"); + contextSource.getPropertyValues().addPropertyValue("password", "secret"); RootBeanDefinition apacheDSStartStop = new RootBeanDefinition(ApacheDSContainer.class); apacheDSStartStop.getConstructorArgumentValues().addGenericArgumentValue(configuration); - apacheDSStartStop.getConstructorArgumentValues().addGenericArgumentValue(initialDirContextFactory); + apacheDSStartStop.getConstructorArgumentValues().addGenericArgumentValue(contextSource); if (parserContext.getRegistry().containsBeanDefinition("_apacheDSStartStopBean")) { parserContext.getReaderContext().error("Only one embedded server bean is allowed per application context", @@ -188,7 +188,7 @@ public class LdapBeanDefinitionParser extends AbstractBeanDefinitionParser { parserContext.getRegistry().registerBeanDefinition("_apacheDSStartStopBean", apacheDSStartStop); - return initialDirContextFactory; + return contextSource; } diff --git a/core/src/main/java/org/springframework/security/ldap/DefaultInitialDirContextFactory.java b/core/src/main/java/org/springframework/security/ldap/DefaultInitialDirContextFactory.java index a136fac716..c6f673de29 100644 --- a/core/src/main/java/org/springframework/security/ldap/DefaultInitialDirContextFactory.java +++ b/core/src/main/java/org/springframework/security/ldap/DefaultInitialDirContextFactory.java @@ -28,6 +28,7 @@ import org.springframework.context.support.MessageSourceAccessor; import org.springframework.util.Assert; import org.springframework.ldap.UncategorizedLdapException; import org.springframework.ldap.core.support.DefaultDirObjectFactory; +import org.springframework.ldap.core.DistinguishedName; import org.springframework.dao.DataAccessException; import java.util.Hashtable; @@ -64,10 +65,14 @@ import javax.naming.directory.InitialDirContext; * @author Luke Taylor * @version $Id$ * + * + * @deprecated use {@link DefaultSpringSecurityContextSource} instead. + * * @see The Java tutorial's guide to LDAP * connection pooling */ -public class DefaultInitialDirContextFactory implements InitialDirContextFactory, MessageSourceAware { +public class DefaultInitialDirContextFactory implements InitialDirContextFactory, + SpringSecurityContextSource, MessageSourceAware { //~ Static fields/initializers ===================================================================================== private static final Log logger = LogFactory.getLog(DefaultInitialDirContextFactory.class); @@ -344,4 +349,16 @@ public class DefaultInitialDirContextFactory implements InitialDirContextFactory public void setDirObjectFactory(String dirObjectFactory) { this.dirObjectFactoryClass = dirObjectFactory; } + + public DirContext getReadWriteContext(String userDn, Object credentials) { + return newInitialDirContext(userDn, (String) credentials); + } + + public DistinguishedName getBaseLdapPath() { + return new DistinguishedName(rootDn); + } + + public String getBaseLdapPathAsString() { + return getBaseLdapPath().toString(); + } } diff --git a/core/src/main/java/org/springframework/security/ldap/DefaultLdapUsernameToDnMapper.java b/core/src/main/java/org/springframework/security/ldap/DefaultLdapUsernameToDnMapper.java new file mode 100644 index 0000000000..dfba6c7d9a --- /dev/null +++ b/core/src/main/java/org/springframework/security/ldap/DefaultLdapUsernameToDnMapper.java @@ -0,0 +1,34 @@ +package org.springframework.security.ldap; + +import org.springframework.ldap.core.DistinguishedName; + +/** + * @author Luke Taylor + * @version $Id$ + */ +public class DefaultLdapUsernameToDnMapper implements LdapUsernameToDnMapper { + private String userDnBase; + private String usernameAttribute; + + /** + * This implementation appends a name component to the userDnBase context using the + * usernameAttributeName property. So if the uid attribute is used to store the username, and the + * base DN is cn=users and we are creating a new user called "sam", then the DN will be + * uid=sam,cn=users. + * + * @param userDnBase the base name of the DN + * @param usernameAttribute the attribute to append for the username component. + */ + public DefaultLdapUsernameToDnMapper(String userDnBase, String usernameAttribute) { + this.userDnBase = userDnBase; + this.usernameAttribute = usernameAttribute; + } + + public DistinguishedName buildDn(String username) { + DistinguishedName dn = new DistinguishedName(userDnBase); + + dn.add(usernameAttribute, username); + + return dn; + } +} diff --git a/core/src/main/java/org/springframework/security/ldap/DefaultSpringSecurityContextSource.java b/core/src/main/java/org/springframework/security/ldap/DefaultSpringSecurityContextSource.java new file mode 100644 index 0000000000..a5b2cb7801 --- /dev/null +++ b/core/src/main/java/org/springframework/security/ldap/DefaultSpringSecurityContextSource.java @@ -0,0 +1,116 @@ +package org.springframework.security.ldap; + +import org.springframework.security.BadCredentialsException; +import org.springframework.security.SpringSecurityMessageSource; +import org.springframework.context.MessageSource; +import org.springframework.context.MessageSourceAware; +import org.springframework.context.support.MessageSourceAccessor; +import org.springframework.ldap.core.support.LdapContextSource; +import org.springframework.util.Assert; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.naming.Context; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.StringTokenizer; + +/** + * SpringSecurityContextSource implementation which uses Spring LDAP's LdapContextSource as a base + * class. Intended as a replacement for DefaultInitialDirContextFactory from versions of the framework prior + * to 2.0. + * + * @author Luke Taylor + * @version $Id$ + * @since 2.0 + */ +public class DefaultSpringSecurityContextSource extends LdapContextSource implements SpringSecurityContextSource, + MessageSourceAware { + + private static final Log logger = LogFactory.getLog(DefaultSpringSecurityContextSource.class); + private String rootDn; + + protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); + + /** + * Create and initialize an instance which will connect to the supplied LDAP URL. + * + * @param providerUrl an LDAP URL of the form ldap://localhost:389/base_dn + */ + public DefaultSpringSecurityContextSource(String providerUrl) { + Assert.hasLength(providerUrl, "An LDAP connection URL must be supplied."); + + StringTokenizer st = new StringTokenizer(providerUrl); + + ArrayList urls = new ArrayList(); + + // Work out rootDn from the first URL and check that the other URLs (if any) match + while (st.hasMoreTokens()) { + String url = st.nextToken(); + String urlRootDn = LdapUtils.parseRootDnFromUrl(url); + + urls.add(url.substring(0, url.lastIndexOf(urlRootDn))); + + logger.info(" URL '" + url + "', root DN is '" + urlRootDn + "'"); + + if (rootDn == null) { + rootDn = urlRootDn; + } else if (!rootDn.equals(urlRootDn)) { + throw new IllegalArgumentException("Root DNs must be the same when using multiple URLs"); + } + } + + super.setUrls((String[]) urls.toArray(new String[urls.size()])); + super.setBase(rootDn); + } + + public DirContext getReadWriteContext(String userDn, Object credentials) { + Hashtable env = new Hashtable(getAnonymousEnv()); + + env.put(Context.SECURITY_PRINCIPAL, userDn); + env.put(Context.SECURITY_CREDENTIALS, credentials); + + if (logger.isDebugEnabled()) { + logger.debug("Creating context with principal: '" + userDn + "'"); + } + + try { + return createContext(env); + } catch (org.springframework.ldap.NamingException e) { + if ((e instanceof org.springframework.ldap.AuthenticationException) + || (e instanceof org.springframework.ldap.OperationNotSupportedException)) { + throw new BadCredentialsException( + messages.getMessage("DefaultSpringSecurityContextSource.badCredentials", "Bad credentials"), e); + } + throw e; + } + } + + /** Copied from parent AbstractContextSource as package private */ + DirContext createContext(Hashtable environment) { + DirContext ctx = null; + + try { + ctx = getDirContextInstance(environment); + + if (logger.isInfoEnabled()) { + Hashtable ctxEnv = ctx.getEnvironment(); + String ldapUrl = (String) ctxEnv.get(Context.PROVIDER_URL); + logger.debug("Got Ldap context on server '" + ldapUrl + "'"); + } + + return ctx; + } + catch (NamingException e) { + LdapUtils.closeContext(ctx); + throw org.springframework.ldap.support.LdapUtils.convertLdapException(e); + } + } + + public void setMessageSource(MessageSource messageSource) { + this.messages = new MessageSourceAccessor(messageSource); + } +} diff --git a/core/src/main/java/org/springframework/security/ldap/InitialDirContextFactory.java b/core/src/main/java/org/springframework/security/ldap/InitialDirContextFactory.java index b00224ff7f..48c61e7c2a 100644 --- a/core/src/main/java/org/springframework/security/ldap/InitialDirContextFactory.java +++ b/core/src/main/java/org/springframework/security/ldap/InitialDirContextFactory.java @@ -28,7 +28,7 @@ import javax.naming.directory.DirContext; * @author Luke Taylor * @version $Id$ */ -public interface InitialDirContextFactory extends ContextSource { +public interface InitialDirContextFactory { //~ Methods ======================================================================================================== /** diff --git a/core/src/main/java/org/springframework/security/ldap/LdapUsernameToDnMapper.java b/core/src/main/java/org/springframework/security/ldap/LdapUsernameToDnMapper.java new file mode 100644 index 0000000000..fe712d0b7c --- /dev/null +++ b/core/src/main/java/org/springframework/security/ldap/LdapUsernameToDnMapper.java @@ -0,0 +1,13 @@ +package org.springframework.security.ldap; + +import org.springframework.ldap.core.DistinguishedName; + +/** + * Constructs an Ldap Distinguished Name from a username. + * + * @author Luke Taylor + * @version $Id$ + */ +public interface LdapUsernameToDnMapper { + DistinguishedName buildDn(String username); +} diff --git a/core/src/main/java/org/springframework/security/ldap/LdapUtils.java b/core/src/main/java/org/springframework/security/ldap/LdapUtils.java index 8e5807cb91..a6c4f9097a 100644 --- a/core/src/main/java/org/springframework/security/ldap/LdapUtils.java +++ b/core/src/main/java/org/springframework/security/ldap/LdapUtils.java @@ -15,17 +15,18 @@ package org.springframework.security.ldap; +import org.springframework.ldap.core.DirContextAdapter; +import org.springframework.ldap.core.DistinguishedName; +import org.springframework.util.Assert; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.util.Assert; -import org.springframework.ldap.core.DirContextAdapter; -import org.springframework.ldap.core.DistinguishedName; - -import java.io.UnsupportedEncodingException; - import javax.naming.Context; import javax.naming.NamingException; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; /** @@ -156,20 +157,8 @@ public final class LdapUtils { String urlRootDn = ""; if (url.startsWith("ldap:") || url.startsWith("ldaps:")) { -// URI uri = parseLdapUrl(url); - -// urlRootDn = uri.getPath(); - // skip past the "://" - int colon = url.indexOf(':'); - - url = url.substring(colon + 3); - - // Match the slash at the end of the address (if there) - int slash = url.indexOf('/'); - - if (slash >= 0) { - urlRootDn = url.substring(slash); - } + URI uri = parseLdapUrl(url); + urlRootDn = uri.getPath(); } else { // Assume it's an embedded server urlRootDn = url; @@ -182,7 +171,6 @@ public final class LdapUtils { return urlRootDn; } - // removed for 1.3 compatibility /** * Parses the supplied LDAP URL. * @param url the URL (e.g. ldap://monkeymachine:11389/dc=springframework,dc=org). @@ -190,15 +178,15 @@ public final class LdapUtils { * @throws IllegalArgumentException if the URL is null, empty or the URI syntax is invalid. */ -// private static URI parseLdapUrl(String url) { -// Assert.hasLength(url); -// -// try { -// return new URI(url); -// } catch (URISyntaxException e) { -// IllegalArgumentException iae = new IllegalArgumentException("Unable to parse url: " + url); -// iae.initCause(e); -// throw iae; -// } -// } + private static URI parseLdapUrl(String url) { + Assert.hasLength(url); + + try { + return new URI(url); + } catch (URISyntaxException e) { + IllegalArgumentException iae = new IllegalArgumentException("Unable to parse url: " + url); + iae.initCause(e); + throw iae; + } + } } diff --git a/core/src/main/java/org/springframework/security/ldap/SpringSecurityContextSource.java b/core/src/main/java/org/springframework/security/ldap/SpringSecurityContextSource.java new file mode 100644 index 0000000000..89663d6c4b --- /dev/null +++ b/core/src/main/java/org/springframework/security/ldap/SpringSecurityContextSource.java @@ -0,0 +1,26 @@ +package org.springframework.security.ldap; + +import org.springframework.ldap.core.support.BaseLdapPathContextSource; +import org.springframework.ldap.core.ContextSource; + +import javax.naming.directory.DirContext; + +/** + * Extension of {@link ContextSource} which allows binding explicitly as a particular user. + * + * @author Luke Taylor + * @version $Id$ + * @since 2.0 + */ +public interface SpringSecurityContextSource extends BaseLdapPathContextSource { + + /** + * Obtains a context using the supplied distinguished name and credentials. + * + * @param userDn the distinguished name of the user to authenticate as + * @param credentials the user's password + * @return a context authenticated as the supplied user + */ + DirContext getReadWriteContext(String userDn, Object credentials); + +} diff --git a/core/src/main/java/org/springframework/security/ldap/SpringSecurityLdapTemplate.java b/core/src/main/java/org/springframework/security/ldap/SpringSecurityLdapTemplate.java index 6d9dcaeec9..ac2a893956 100644 --- a/core/src/main/java/org/springframework/security/ldap/SpringSecurityLdapTemplate.java +++ b/core/src/main/java/org/springframework/security/ldap/SpringSecurityLdapTemplate.java @@ -18,7 +18,6 @@ package org.springframework.security.ldap; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.util.Assert; -import org.springframework.util.StringUtils; import org.springframework.ldap.core.ContextExecutor; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DirContextAdapter; @@ -35,10 +34,8 @@ import java.util.List; import java.util.ArrayList; import java.text.MessageFormat; -import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; -import javax.naming.Context; import javax.naming.NameClassPair; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; @@ -97,9 +94,9 @@ public class SpringSecurityLdapTemplate extends org.springframework.ldap.core.Ld ctls.setReturningAttributes(NO_ATTRS); ctls.setSearchScope(SearchControls.OBJECT_SCOPE); - String relativeName = LdapUtils.getRelativeName(dn, ctx); +// String relativeName = LdapUtils.getRelativeName(dn, ctx); - NamingEnumeration results = ctx.search(relativeName, comparisonFilter, new Object[] {value}, ctls); + NamingEnumeration results = ctx.search(dn, comparisonFilter, new Object[] {value}, ctls); return Boolean.valueOf(results.hasMore()); } @@ -110,25 +107,25 @@ public class SpringSecurityLdapTemplate extends org.springframework.ldap.core.Ld return matches.booleanValue(); } - public boolean nameExists(final String dn) { - Boolean exists = (Boolean) executeReadOnly(new ContextExecutor() { - public Object executeWithContext(DirContext ctx) throws NamingException { - try { - Object obj = ctx.lookup(LdapUtils.getRelativeName(dn, ctx)); - if (obj instanceof Context) { - LdapUtils.closeContext((Context) obj); - } - - } catch (NameNotFoundException nnfe) { - return Boolean.FALSE; - } - - return Boolean.TRUE; - } - }); - - return exists.booleanValue(); - } +// public boolean nameExists(final String dn) { +// Boolean exists = (Boolean) executeReadOnly(new ContextExecutor() { +// public Object executeWithContext(DirContext ctx) throws NamingException { +// try { +// Object obj = ctx.lookup(dn); +// if (obj instanceof Context) { +// LdapUtils.closeContext((Context) obj); +// } +// +// } catch (NameNotFoundException nnfe) { +// return Boolean.FALSE; +// } +// +// return Boolean.TRUE; +// } +// }); +// +// return exists.booleanValue(); +// } /** * Composes an object from the attributes of the given DN. @@ -142,7 +139,7 @@ public class SpringSecurityLdapTemplate extends org.springframework.ldap.core.Ld return (DirContextOperations) executeReadOnly(new ContextExecutor() { public Object executeWithContext(DirContext ctx) throws NamingException { - Attributes attrs = ctx.getAttributes(LdapUtils.getRelativeName(dn, ctx), attributesToRetrieve); + Attributes attrs = ctx.getAttributes(dn, attributesToRetrieve); // Object object = ctx.lookup(LdapUtils.getRelativeName(dn, ctx)); @@ -255,12 +252,12 @@ public class SpringSecurityLdapTemplate extends org.springframework.ldap.core.Ld dn.append(base); } - String nameInNamespace = ctx.getNameInNamespace(); - - if (StringUtils.hasLength(nameInNamespace)) { - dn.append(","); - dn.append(nameInNamespace); - } +// String nameInNamespace = ctx.getNameInNamespace(); +// +// if (StringUtils.hasLength(nameInNamespace)) { +// dn.append(","); +// dn.append(nameInNamespace); +// } return new DirContextAdapter(searchResult.getAttributes(), new DistinguishedName(dn.toString())); } diff --git a/core/src/main/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearch.java b/core/src/main/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearch.java index 79f9dbc826..6307f4a9c3 100644 --- a/core/src/main/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearch.java +++ b/core/src/main/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearch.java @@ -15,7 +15,6 @@ package org.springframework.security.ldap.search; -import org.springframework.security.ldap.InitialDirContextFactory; import org.springframework.security.ldap.SpringSecurityLdapTemplate; import org.springframework.security.ldap.LdapUserSearch; @@ -30,6 +29,7 @@ import org.springframework.util.Assert; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DirContextOperations; +import org.springframework.ldap.core.support.BaseLdapPathContextSource; import javax.naming.directory.SearchControls; @@ -50,7 +50,7 @@ public class FilterBasedLdapUserSearch implements LdapUserSearch { //~ Instance fields ================================================================================================ - private ContextSource initialDirContextFactory; + private ContextSource contextSource; /** * The LDAP SearchControls object used for the search. Shared between searches so shouldn't be modified @@ -58,14 +58,15 @@ public class FilterBasedLdapUserSearch implements LdapUserSearch { */ private SearchControls searchControls = new SearchControls(); - /** Context name to search in, relative to the root DN of the configured InitialDirContextFactory. */ + /** Context name to search in, relative to the base of the configured ContextSource. */ private String searchBase = ""; /** * The filter expression used in the user search. This is an LDAP search filter (as defined in 'RFC 2254') * with optional arguments. See the documentation for the search methods in {@link - * javax.naming.directory.DirContext DirContext} for more information.

In this case, the username is the - * only parameter.

+ * javax.naming.directory.DirContext DirContext} for more information. + * + *

In this case, the username is the only parameter.

* Possible examples are: *
    *
  • (uid={0}) - this would search for a username match on the uid attribute.
  • @@ -75,19 +76,18 @@ public class FilterBasedLdapUserSearch implements LdapUserSearch { //~ Constructors =================================================================================================== - public FilterBasedLdapUserSearch(String searchBase, String searchFilter, - InitialDirContextFactory initialDirContextFactory) { - Assert.notNull(initialDirContextFactory, "initialDirContextFactory must not be null"); + public FilterBasedLdapUserSearch(String searchBase, String searchFilter, BaseLdapPathContextSource contextSource) { + Assert.notNull(contextSource, "contextSource must not be null"); Assert.notNull(searchFilter, "searchFilter must not be null."); Assert.notNull(searchBase, "searchBase must not be null (an empty string is acceptable)."); this.searchFilter = searchFilter; - this.initialDirContextFactory = initialDirContextFactory; + this.contextSource = contextSource; this.searchBase = searchBase; if (searchBase.length() == 0) { logger.info("SearchBase not set. Searches will be performed from the root: " - + initialDirContextFactory.getRootDn()); + + contextSource.getBaseLdapPath()); } } @@ -104,11 +104,10 @@ public class FilterBasedLdapUserSearch implements LdapUserSearch { */ public DirContextOperations searchForUser(String username) { if (logger.isDebugEnabled()) { - logger.debug("Searching for user '" + username + "', with user search " - + this.toString()); + logger.debug("Searching for user '" + username + "', with user search " + this.toString()); } - SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate(initialDirContextFactory); + SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate(contextSource); template.setSearchControls(searchControls); diff --git a/core/src/main/java/org/springframework/security/providers/ldap/authenticator/AbstractLdapAuthenticator.java b/core/src/main/java/org/springframework/security/providers/ldap/authenticator/AbstractLdapAuthenticator.java index 5bf172a07f..82788e454f 100644 --- a/core/src/main/java/org/springframework/security/providers/ldap/authenticator/AbstractLdapAuthenticator.java +++ b/core/src/main/java/org/springframework/security/providers/ldap/authenticator/AbstractLdapAuthenticator.java @@ -16,13 +16,13 @@ package org.springframework.security.providers.ldap.authenticator; import org.springframework.security.SpringSecurityMessageSource; -import org.springframework.security.ldap.InitialDirContextFactory; import org.springframework.security.ldap.LdapUserSearch; import org.springframework.security.providers.ldap.LdapAuthenticator; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.MessageSource; import org.springframework.context.MessageSourceAware; import org.springframework.context.support.MessageSourceAccessor; +import org.springframework.ldap.core.ContextSource; import org.springframework.util.Assert; import java.text.MessageFormat; @@ -40,18 +40,12 @@ import java.util.List; public abstract class AbstractLdapAuthenticator implements LdapAuthenticator, InitializingBean, MessageSourceAware { //~ Instance fields ================================================================================================ - private InitialDirContextFactory initialDirContextFactory; + private ContextSource contextSource; /** Optional search object which can be used to locate a user when a simple DN match isn't sufficient */ private LdapUserSearch userSearch; protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); - /** - * The suffix to be added to the DN patterns, worked out internally from the root DN of the configured - * InitialDirContextFactory. - */ - private String dnSuffix = ""; - /** The attributes which will be retrieved from the directory. Null means all attributes */ private String[] userAttributes = null; @@ -62,12 +56,13 @@ public abstract class AbstractLdapAuthenticator implements LdapAuthenticator, In //~ Constructors =================================================================================================== /** - * Create an initialized instance to the {@link InitialDirContextFactory} provided. + * Create an initialized instance with the {@link ContextSource} provided. * - * @param initialDirContextFactory + * @param contextSource */ - public AbstractLdapAuthenticator(InitialDirContextFactory initialDirContextFactory) { - this.setInitialDirContextFactory(initialDirContextFactory); + public AbstractLdapAuthenticator(ContextSource contextSource) { + Assert.notNull(contextSource, "contextSource must not be null."); + this.contextSource = contextSource; } //~ Methods ======================================================================================================== @@ -77,24 +72,8 @@ public abstract class AbstractLdapAuthenticator implements LdapAuthenticator, In "Either an LdapUserSearch or DN pattern (or both) must be supplied."); } - /** - * Set the {@link InitialDirContextFactory} and initialize this instance from its data. - * - * @param initialDirContextFactory - */ - private void setInitialDirContextFactory(InitialDirContextFactory initialDirContextFactory) { - Assert.notNull(initialDirContextFactory, "initialDirContextFactory must not be null."); - this.initialDirContextFactory = initialDirContextFactory; - - String rootDn = initialDirContextFactory.getRootDn(); - - if (rootDn.length() > 0) { - dnSuffix = "," + rootDn; - } - } - - protected InitialDirContextFactory getInitialDirContextFactory() { - return initialDirContextFactory; + protected ContextSource getContextSource() { + return contextSource; } public String[] getUserAttributes() { @@ -102,9 +81,7 @@ public abstract class AbstractLdapAuthenticator implements LdapAuthenticator, In } /** - * Builds list of possible DNs for the user, worked out from the userDnPatterns property. The - * returned value includes the root DN of the provider URL used to configure the - * InitialDirContextfactory. + * Builds list of possible DNs for the user, worked out from the userDnPatterns property. * * @param username the user's login name * @@ -120,7 +97,7 @@ public abstract class AbstractLdapAuthenticator implements LdapAuthenticator, In synchronized (userDnFormat) { for (int i = 0; i < userDnFormat.length; i++) { - userDns.add(userDnFormat[i].format(args) + dnSuffix); + userDns.add(userDnFormat[i].format(args)); } } @@ -150,8 +127,7 @@ public abstract class AbstractLdapAuthenticator implements LdapAuthenticator, In * Sets the pattern which will be used to supply a DN for the user. The pattern should be the name relative * to the root DN. The pattern argument {0} will contain the username. An example would be "cn={0},ou=people". * - * @param dnPattern the array of patterns which will be tried when obtaining a username - * to a DN. + * @param dnPattern the array of patterns which will be tried when converting a username to a DN. */ public void setUserDnPatterns(String[] dnPattern) { Assert.notNull(dnPattern, "The array of DN patterns cannot be set to null"); diff --git a/core/src/main/java/org/springframework/security/providers/ldap/authenticator/BindAuthenticator.java b/core/src/main/java/org/springframework/security/providers/ldap/authenticator/BindAuthenticator.java index 2814c6ade8..82b4af5cb8 100644 --- a/core/src/main/java/org/springframework/security/providers/ldap/authenticator/BindAuthenticator.java +++ b/core/src/main/java/org/springframework/security/providers/ldap/authenticator/BindAuthenticator.java @@ -15,20 +15,20 @@ package org.springframework.security.providers.ldap.authenticator; -import org.springframework.security.BadCredentialsException; import org.springframework.security.Authentication; -import org.springframework.security.providers.UsernamePasswordAuthenticationToken; - -import org.springframework.security.ldap.InitialDirContextFactory; +import org.springframework.security.BadCredentialsException; +import org.springframework.security.ldap.SpringSecurityContextSource; import org.springframework.security.ldap.SpringSecurityLdapTemplate; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.springframework.security.providers.UsernamePasswordAuthenticationToken; import org.springframework.dao.DataAccessException; import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.DirContextOperations; +import org.springframework.ldap.core.DistinguishedName; import org.springframework.util.Assert; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + import javax.naming.directory.DirContext; import java.util.Iterator; @@ -49,12 +49,14 @@ public class BindAuthenticator extends AbstractLdapAuthenticator { //~ Constructors =================================================================================================== /** - * Create an initialized instance to the {@link InitialDirContextFactory} provided. + * Create an initialized instance using the {@link SpringSecurityContextSource} provided. + * + * @param contextSource the SpringSecurityContextSource instance against which bind operations will be + * performed. * - * @param initialDirContextFactory */ - public BindAuthenticator(InitialDirContextFactory initialDirContextFactory) { - super(initialDirContextFactory); + public BindAuthenticator(SpringSecurityContextSource contextSource) { + super(contextSource); } //~ Methods ======================================================================================================== @@ -91,7 +93,7 @@ public class BindAuthenticator extends AbstractLdapAuthenticator { private DirContextOperations bindWithDn(String userDn, String username, String password) { SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate( - new BindWithSpecificDnContextSource(getInitialDirContextFactory(), userDn, password)); + new BindWithSpecificDnContextSource((SpringSecurityContextSource) getContextSource(), userDn, password)); try { return template.retrieveEntry(userDn, getUserAttributes()); @@ -110,25 +112,26 @@ public class BindAuthenticator extends AbstractLdapAuthenticator { * Allows subclasses to inspect the exception thrown by an attempt to bind with a particular DN. * The default implementation just reports the failure to the debug log. */ - void handleBindException(String userDn, String username, Throwable cause) { + protected void handleBindException(String userDn, String username, Throwable cause) { if (logger.isDebugEnabled()) { logger.debug("Failed to bind as " + userDn + ": " + cause); } } private class BindWithSpecificDnContextSource implements ContextSource { - private InitialDirContextFactory ctxFactory; - private String userDn; + private SpringSecurityContextSource ctxFactory; + DistinguishedName userDn; private String password; - public BindWithSpecificDnContextSource(InitialDirContextFactory ctxFactory, String userDn, String password) { + public BindWithSpecificDnContextSource(SpringSecurityContextSource ctxFactory, String userDn, String password) { this.ctxFactory = ctxFactory; - this.userDn = userDn; + this.userDn = new DistinguishedName(userDn); + this.userDn.prepend(ctxFactory.getBaseLdapPath()); this.password = password; } public DirContext getReadOnlyContext() throws DataAccessException { - return ctxFactory.newInitialDirContext(userDn, password); + return ctxFactory.getReadWriteContext(userDn.toString(), password); } public DirContext getReadWriteContext() throws DataAccessException { diff --git a/core/src/main/java/org/springframework/security/providers/ldap/authenticator/PasswordComparisonAuthenticator.java b/core/src/main/java/org/springframework/security/providers/ldap/authenticator/PasswordComparisonAuthenticator.java index 5b894d5136..ea909b26f2 100644 --- a/core/src/main/java/org/springframework/security/providers/ldap/authenticator/PasswordComparisonAuthenticator.java +++ b/core/src/main/java/org/springframework/security/providers/ldap/authenticator/PasswordComparisonAuthenticator.java @@ -15,24 +15,21 @@ package org.springframework.security.providers.ldap.authenticator; -import org.springframework.security.BadCredentialsException; import org.springframework.security.Authentication; - -import org.springframework.security.ldap.InitialDirContextFactory; -import org.springframework.security.ldap.SpringSecurityLdapTemplate; +import org.springframework.security.BadCredentialsException; import org.springframework.security.ldap.LdapUtils; - -import org.springframework.security.providers.encoding.PasswordEncoder; +import org.springframework.security.ldap.SpringSecurityLdapTemplate; import org.springframework.security.providers.UsernamePasswordAuthenticationToken; - +import org.springframework.security.providers.encoding.PasswordEncoder; import org.springframework.security.userdetails.UsernameNotFoundException; +import org.springframework.ldap.NameNotFoundException; +import org.springframework.ldap.core.DirContextOperations; +import org.springframework.ldap.core.support.BaseLdapPathContextSource; +import org.springframework.util.Assert; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.util.Assert; -import org.springframework.ldap.core.DirContextOperations; - import java.util.Iterator; @@ -65,8 +62,8 @@ public final class PasswordComparisonAuthenticator extends AbstractLdapAuthentic //~ Constructors =================================================================================================== - public PasswordComparisonAuthenticator(InitialDirContextFactory initialDirContextFactory) { - super(initialDirContextFactory); + public PasswordComparisonAuthenticator(BaseLdapPathContextSource contextSource) { + super(contextSource); } //~ Methods ======================================================================================================== @@ -82,13 +79,14 @@ public final class PasswordComparisonAuthenticator extends AbstractLdapAuthentic Iterator dns = getUserDns(username).iterator(); - SpringSecurityLdapTemplate ldapTemplate = new SpringSecurityLdapTemplate(getInitialDirContextFactory()); + SpringSecurityLdapTemplate ldapTemplate = new SpringSecurityLdapTemplate(getContextSource()); while (dns.hasNext() && user == null) { final String userDn = (String) dns.next(); - if (ldapTemplate.nameExists(userDn)) { + try { user = ldapTemplate.retrieveEntry(userDn, getUserAttributes()); + } catch (NameNotFoundException ignore) { } } diff --git a/core/src/main/java/org/springframework/security/providers/ldap/populator/DefaultLdapAuthoritiesPopulator.java b/core/src/main/java/org/springframework/security/providers/ldap/populator/DefaultLdapAuthoritiesPopulator.java index 3aa6ebf67f..71b807d321 100644 --- a/core/src/main/java/org/springframework/security/providers/ldap/populator/DefaultLdapAuthoritiesPopulator.java +++ b/core/src/main/java/org/springframework/security/providers/ldap/populator/DefaultLdapAuthoritiesPopulator.java @@ -17,24 +17,20 @@ package org.springframework.security.providers.ldap.populator; import org.springframework.security.GrantedAuthority; import org.springframework.security.GrantedAuthorityImpl; - -import org.springframework.security.ldap.InitialDirContextFactory; import org.springframework.security.ldap.SpringSecurityLdapTemplate; - import org.springframework.security.providers.ldap.LdapAuthoritiesPopulator; +import org.springframework.ldap.core.ContextSource; +import org.springframework.ldap.core.DirContextOperations; +import org.springframework.util.Assert; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.util.Assert; -import org.springframework.ldap.core.DirContextOperations; - +import javax.naming.directory.SearchControls; import java.util.HashSet; import java.util.Iterator; import java.util.Set; -import javax.naming.directory.SearchControls; - /** * The default strategy for obtaining user role information from the directory. @@ -73,7 +69,7 @@ import javax.naming.directory.SearchControls; *
      * <bean id="ldapAuthoritiesPopulator"
      *       class="org.springframework.security.providers.ldap.populator.DefaultLdapAuthoritiesPopulator">
    - *   <constructor-arg><ref local="initialDirContextFactory"/></constructor-arg>
    + *   <constructor-arg><ref local="contextSource"/></constructor-arg>
      *   <constructor-arg><value>ou=groups</value></constructor-arg>
      *   <property name="groupRoleAttribute"><value>ou</value></property>
      * <!-- the following properties are shown with their default values -->
    @@ -104,10 +100,8 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
          */
         private GrantedAuthority defaultRole = null;
     
    -    /**
    -     * An initial context factory is only required if searching for groups is required.
    -     */
    -    private InitialDirContextFactory initialDirContextFactory = null;
    +    private ContextSource contextSource = null;
    +
         private SpringSecurityLdapTemplate ldapTemplate;
     
         /**
    @@ -145,12 +139,12 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
          * Constructor for group search scenarios. userRoleAttributes may still be
          * set as a property.
          *
    -     * @param initialDirContextFactory supplies the contexts used to search for user roles.
    +     * @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
          *                                 context factory.
          */
    -    public DefaultLdapAuthoritiesPopulator(InitialDirContextFactory initialDirContextFactory, String groupSearchBase) {
    -        this.setInitialDirContextFactory(initialDirContextFactory);
    +    public DefaultLdapAuthoritiesPopulator(ContextSource contextSource, String groupSearchBase) {
    +        this.setContextSource(contextSource);
             this.setGroupSearchBase(groupSearchBase);
         }
     
    @@ -232,20 +226,20 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
             return authorities;
         }
     
    -    protected InitialDirContextFactory getInitialDirContextFactory() {
    -        return initialDirContextFactory;
    +    protected ContextSource getContextSource() {
    +        return contextSource;
         }
     
         /**
    -     * Set the {@link InitialDirContextFactory}
    +     * Set the {@link ContextSource}
          *
    -     * @param initialDirContextFactory supplies the contexts used to search for user roles.
    +     * @param contextSource supplies the contexts used to search for user roles.
          */
    -    private void setInitialDirContextFactory(InitialDirContextFactory initialDirContextFactory) {
    -        Assert.notNull(initialDirContextFactory, "InitialDirContextFactory must not be null");
    -        this.initialDirContextFactory = initialDirContextFactory;
    +    private void setContextSource(ContextSource contextSource) {
    +        Assert.notNull(contextSource, "contextSource must not be null");
    +        this.contextSource = contextSource;
     
    -        ldapTemplate = new SpringSecurityLdapTemplate(initialDirContextFactory);
    +        ldapTemplate = new SpringSecurityLdapTemplate(contextSource);
             ldapTemplate.setSearchControls(searchControls);
         }
     
    @@ -259,8 +253,7 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
             Assert.notNull(groupSearchBase, "The groupSearchBase (name to search under), must not be null.");
             this.groupSearchBase = groupSearchBase;
             if (groupSearchBase.length() == 0) {
    -            logger.info("groupSearchBase is empty. Searches will be performed from the root: "
    -                    + getInitialDirContextFactory().getRootDn());
    +            logger.info("groupSearchBase is empty. Searches will be performed from the context source base");
             }
         }
     
    diff --git a/core/src/main/java/org/springframework/security/userdetails/ldap/LdapUserDetailsManager.java b/core/src/main/java/org/springframework/security/userdetails/ldap/LdapUserDetailsManager.java
    index 9c05e8e798..003db6aba0 100644
    --- a/core/src/main/java/org/springframework/security/userdetails/ldap/LdapUserDetailsManager.java
    +++ b/core/src/main/java/org/springframework/security/userdetails/ldap/LdapUserDetailsManager.java
    @@ -14,42 +14,46 @@
      */
     package org.springframework.security.userdetails.ldap;
     
    -import org.springframework.security.userdetails.UserDetails;
    -import org.springframework.security.userdetails.UsernameNotFoundException;
    -import org.springframework.security.userdetails.UserDetailsManager;
    -import org.springframework.security.ldap.LdapUtils;
    -import org.springframework.security.GrantedAuthority;
    -import org.springframework.security.GrantedAuthorityImpl;
     import org.springframework.security.Authentication;
     import org.springframework.security.BadCredentialsException;
    +import org.springframework.security.GrantedAuthority;
    +import org.springframework.security.GrantedAuthorityImpl;
     import org.springframework.security.context.SecurityContextHolder;
    +import org.springframework.security.ldap.LdapUsernameToDnMapper;
    +import org.springframework.security.ldap.LdapUtils;
    +import org.springframework.security.ldap.DefaultLdapUsernameToDnMapper;
    +import org.springframework.security.userdetails.UserDetails;
    +import org.springframework.security.userdetails.UserDetailsManager;
    +import org.springframework.security.userdetails.UsernameNotFoundException;
     import org.springframework.dao.DataAccessException;
    -import org.springframework.util.Assert;
    -import org.springframework.ldap.core.DistinguishedName;
     import org.springframework.ldap.core.AttributesMapper;
    -import org.springframework.ldap.core.LdapTemplate;
    +import org.springframework.ldap.core.AttributesMapperCallbackHandler;
    +import org.springframework.ldap.core.ContextExecutor;
     import org.springframework.ldap.core.ContextSource;
     import org.springframework.ldap.core.DirContextAdapter;
    -import org.springframework.ldap.core.ContextExecutor;
    +import org.springframework.ldap.core.DistinguishedName;
    +import org.springframework.ldap.core.LdapTemplate;
     import org.springframework.ldap.core.SearchExecutor;
    -import org.springframework.ldap.core.AttributesMapperCallbackHandler;
    +import org.springframework.util.Assert;
    +
     import org.apache.commons.logging.Log;
     import org.apache.commons.logging.LogFactory;
     
    -import javax.naming.ldap.LdapContext;
    +import javax.naming.Context;
    +import javax.naming.NameNotFoundException;
     import javax.naming.NamingEnumeration;
     import javax.naming.NamingException;
    -import javax.naming.Context;
    -import javax.naming.Name;
    -import javax.naming.NameNotFoundException;
    -import javax.naming.directory.Attributes;
     import javax.naming.directory.Attribute;
    +import javax.naming.directory.Attributes;
    +import javax.naming.directory.BasicAttribute;
     import javax.naming.directory.DirContext;
     import javax.naming.directory.ModificationItem;
    -import javax.naming.directory.BasicAttribute;
     import javax.naming.directory.SearchControls;
    -
    -import java.util.*;
    +import javax.naming.ldap.LdapContext;
    +import java.util.Arrays;
    +import java.util.LinkedList;
    +import java.util.List;
    +import java.util.ListIterator;
     
     /**
      * An Ldap implementation of UserDetailsManager.
    @@ -71,13 +75,15 @@ import java.util.*;
     public class LdapUserDetailsManager implements UserDetailsManager {
         private final Log logger = LogFactory.getLog(LdapUserDetailsManager.class);
     
    -    /** The DN under which users entries are stored */
    -    private DistinguishedName userDnBase = new DistinguishedName("cn=users");
    +    /**
    +     * The strategy for mapping usernames to LDAP distinguished names.
    +     * This will be used when building DNs for creating new users etc.
    +     */
    +    LdapUsernameToDnMapper usernameMapper = new DefaultLdapUsernameToDnMapper("cn=users", "uid");
    +
         /** The DN under which groups are stored */
         private DistinguishedName groupSearchBase = new DistinguishedName("cn=groups");
     
    -    /** The attribute which contains the user login name, and which is used by default to build the DN for new users */
    -    private String usernameAttributeName = "uid";
         /** Password attribute name */
         private String passwordAttributeName = "userPassword";
     
    @@ -120,7 +126,7 @@ public class LdapUserDetailsManager implements UserDetailsManager {
         }
     
         public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
    -        DistinguishedName dn = buildDn(username);
    +        DistinguishedName dn = usernameMapper.buildDn(username);
             GrantedAuthority[] authorities = getUserAuthorities(dn, username);
     
             logger.debug("Loading user '"+ username + "' with DN '" + dn + "'");
    @@ -130,12 +136,12 @@ public class LdapUserDetailsManager implements UserDetailsManager {
             return userDetailsMapper.mapUserFromContext(userCtx, username, authorities);
         }
     
    -    private UserContext loadUserAsContext(final DistinguishedName dn, final String username) {
    -        return (UserContext) template.executeReadOnly(new ContextExecutor() {
    +    private DirContextAdapter loadUserAsContext(final DistinguishedName dn, final String username) {
    +        return (DirContextAdapter) template.executeReadOnly(new ContextExecutor() {
                 public Object executeWithContext(DirContext ctx) throws NamingException {
                     try {
                         Attributes attrs = ctx.getAttributes(dn, attributesToRetrieve);
    -                    return new UserContext(attrs, LdapUtils.getFullDn(dn, ctx));
    +                    return new DirContextAdapter(attrs, LdapUtils.getFullDn(dn, ctx));
                     } catch(NameNotFoundException notFound) {
                         throw new UsernameNotFoundException("User " + username + " not found", notFound);
                     }
    @@ -163,7 +169,7 @@ public class LdapUserDetailsManager implements UserDetailsManager {
     
             logger.debug("Changing password for user '"+ username);
     
    -        final DistinguishedName dn = buildDn(username);
    +        final DistinguishedName dn = usernameMapper.buildDn(username);
             final ModificationItem[] passwordChange = new ModificationItem[] {
                     new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute(passwordAttributeName, newPassword))
             };
    @@ -227,7 +233,7 @@ public class LdapUserDetailsManager implements UserDetailsManager {
         public void createUser(UserDetails user) {
             DirContextAdapter ctx = new DirContextAdapter();
             copyToContext(user, ctx);
    -        DistinguishedName dn = buildDn(user.getUsername());
    +        DistinguishedName dn = usernameMapper.buildDn(user.getUsername());
             // Check for any existing authorities which might be set for this DN
             GrantedAuthority[] authorities = getUserAuthorities(dn, user.getUsername());
     
    @@ -244,13 +250,13 @@ public class LdapUserDetailsManager implements UserDetailsManager {
     
         public void updateUser(UserDetails user) {
     //        Assert.notNull(attributesToRetrieve, "Configuration must specify a list of attributes in order to use update.");
    -        DistinguishedName dn = buildDn(user.getUsername());
    +        DistinguishedName dn = usernameMapper.buildDn(user.getUsername());
     
             logger.debug("Updating user '"+ user.getUsername() + "' with DN '" + dn + "'");
     
             GrantedAuthority[] authorities = getUserAuthorities(dn, user.getUsername());
     
    -        UserContext ctx = loadUserAsContext(dn, user.getUsername());
    +        DirContextAdapter ctx = loadUserAsContext(dn, user.getUsername());
             ctx.setUpdateMode(true);
             copyToContext(user, ctx);
     
    @@ -275,13 +281,13 @@ public class LdapUserDetailsManager implements UserDetailsManager {
         }
     
         public void deleteUser(String username) {
    -        DistinguishedName dn = buildDn(username);
    +        DistinguishedName dn = usernameMapper.buildDn(username);
             removeAuthorities(dn, getUserAuthorities(dn, username));
             template.unbind(dn);
         }
     
         public boolean userExists(String username) {
    -        DistinguishedName dn = buildDn(username);
    +        DistinguishedName dn = usernameMapper.buildDn(username);
     
             try {
                 Object obj = template.lookup(dn);
    @@ -294,25 +300,6 @@ public class LdapUserDetailsManager implements UserDetailsManager {
             }
         }
     
    -    /**
    -     * Constructs a DN from a username.
    -     * 

    - * The default implementation appends a name component to the userDnBase context using the - * usernameAttributeName property. So if the uid attribute is used to store the username, and the - * base DN is cn=users and we are creating a new user called "sam", then the DN will be - * uid=sam,cn=users. - * - * @param username the user name used for authentication. - * @return the corresponding DN, relative to the base context. - */ - protected DistinguishedName buildDn(String username) { - DistinguishedName dn = new DistinguishedName(userDnBase); - - dn.add(usernameAttributeName, username); - - return dn; - } - /** * Creates a DN from a group name. * @@ -365,8 +352,8 @@ public class LdapUserDetailsManager implements UserDetailsManager { return group; } - public void setUsernameAttributeName(String usernameAttributeName) { - this.usernameAttributeName = usernameAttributeName; + public void setUsernameMapper(LdapUsernameToDnMapper usernameMapper) { + this.usernameMapper = usernameMapper; } public void setPasswordAttributeName(String passwordAttributeName) { @@ -381,10 +368,6 @@ public class LdapUserDetailsManager implements UserDetailsManager { this.groupRoleAttributeName = groupRoleAttributeName; } - public void setUserDnBase(String userDnBase) { - this.userDnBase = new DistinguishedName(userDnBase); - } - public void setAttributesToRetrieve(String[] attributesToRetrieve) { Assert.notNull(attributesToRetrieve); this.attributesToRetrieve = attributesToRetrieve; @@ -411,18 +394,4 @@ public class LdapUserDetailsManager implements UserDetailsManager { public void setRoleMapper(AttributesMapper roleMapper) { this.roleMapper = roleMapper; } - - /** - * This class allows us to set the updateMode property of DirContextAdapter when updating existing users. - * TODO: No longer needed as of Ldap 1.2. - */ - private static class UserContext extends DirContextAdapter { - public UserContext(Attributes pAttrs, Name dn) { - super(pAttrs, dn); - } - - public void setUpdateMode(boolean mode) { - super.setUpdateMode(mode); - } - } } diff --git a/core/src/test/java/org/springframework/security/config/LdapBeanDefinitionParserTests.java b/core/src/test/java/org/springframework/security/config/LdapBeanDefinitionParserTests.java index 128e5c3610..c25a056979 100644 --- a/core/src/test/java/org/springframework/security/config/LdapBeanDefinitionParserTests.java +++ b/core/src/test/java/org/springframework/security/config/LdapBeanDefinitionParserTests.java @@ -1,12 +1,12 @@ package org.springframework.security.config; -import org.springframework.security.ldap.InitialDirContextFactory; -import org.springframework.ldap.core.LdapTemplate; import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.ldap.core.LdapTemplate; +import org.springframework.ldap.core.support.BaseLdapPathContextSource; +import org.junit.AfterClass; import static org.junit.Assert.*; import org.junit.BeforeClass; -import org.junit.AfterClass; import org.junit.Test; @@ -32,14 +32,13 @@ public class LdapBeanDefinitionParserTests { @Test public void testContextContainsExpectedBeansAndData() { - InitialDirContextFactory idcf = (InitialDirContextFactory) appContext.getBean("contextSource"); + BaseLdapPathContextSource idcf = (BaseLdapPathContextSource) appContext.getBean("contextSource"); - assertEquals("dc=springframework,dc=org", idcf.getRootDn()); +// assertEquals("dc=springframework, dc=org", idcf.getBaseLdapPathAsString()); // Check data is loaded LdapTemplate template = new LdapTemplate(idcf); template.lookup("uid=ben,ou=people"); - } } diff --git a/core/src/test/java/org/springframework/security/ldap/AbstractLdapIntegrationTests.java b/core/src/test/java/org/springframework/security/ldap/AbstractLdapIntegrationTests.java index 1a3099a1e5..40248af79a 100644 --- a/core/src/test/java/org/springframework/security/ldap/AbstractLdapIntegrationTests.java +++ b/core/src/test/java/org/springframework/security/ldap/AbstractLdapIntegrationTests.java @@ -107,11 +107,11 @@ public abstract class AbstractLdapIntegrationTests { loader.execute(); } finally { ctx.close(); - } + } } - public ContextSource getContextSource() { - return (ContextSource) appContext.getBean("contextSource"); + public SpringSecurityContextSource getContextSource() { + return (SpringSecurityContextSource) appContext.getBean("contextSource"); } /** diff --git a/core/src/test/java/org/springframework/security/ldap/DefaultSpringSecurityContextSourceTests.java b/core/src/test/java/org/springframework/security/ldap/DefaultSpringSecurityContextSourceTests.java new file mode 100644 index 0000000000..5240988957 --- /dev/null +++ b/core/src/test/java/org/springframework/security/ldap/DefaultSpringSecurityContextSourceTests.java @@ -0,0 +1,15 @@ +package org.springframework.security.ldap; + +import org.junit.Test; + +/** + * @author Luke Taylor + * @version $Id$ + */ +public class DefaultSpringSecurityContextSourceTests { + + @Test + public void instantiationSucceeds() { + new DefaultSpringSecurityContextSource("ldap://blah:789/dc=springframework,dc=org"); + } +} diff --git a/core/src/test/java/org/springframework/security/ldap/LdapUtilsTests.java b/core/src/test/java/org/springframework/security/ldap/LdapUtilsTests.java index 127f78a5c7..ae4046c4b5 100644 --- a/core/src/test/java/org/springframework/security/ldap/LdapUtilsTests.java +++ b/core/src/test/java/org/springframework/security/ldap/LdapUtilsTests.java @@ -71,6 +71,7 @@ public class LdapUtilsTests extends MockObjectTestCase { public void testRootDnsAreParsedFromUrlsCorrectly() { assertEquals("", LdapUtils.parseRootDnFromUrl("ldap://monkeymachine")); + assertEquals("", LdapUtils.parseRootDnFromUrl("ldap://monkeymachine:11389")); assertEquals("", LdapUtils.parseRootDnFromUrl("ldap://monkeymachine/")); assertEquals("", LdapUtils.parseRootDnFromUrl("ldap://monkeymachine.co.uk/")); assertEquals("dc=springframework,dc=org", @@ -80,5 +81,7 @@ public class LdapUtilsTests extends MockObjectTestCase { LdapUtils.parseRootDnFromUrl("ldap://monkeymachine/dc=springframework,dc=org")); assertEquals("dc=springframework,dc=org/ou=blah", LdapUtils.parseRootDnFromUrl("ldap://monkeymachine.co.uk/dc=springframework,dc=org/ou=blah")); + assertEquals("dc=springframework,dc=org/ou=blah", + LdapUtils.parseRootDnFromUrl("ldap://monkeymachine.co.uk:389/dc=springframework,dc=org/ou=blah")); } } diff --git a/core/src/test/java/org/springframework/security/ldap/MockInitialDirContextFactory.java b/core/src/test/java/org/springframework/security/ldap/MockSpringSecurityContextSource.java similarity index 73% rename from core/src/test/java/org/springframework/security/ldap/MockInitialDirContextFactory.java rename to core/src/test/java/org/springframework/security/ldap/MockSpringSecurityContextSource.java index 944166dcf7..7a7ed644e0 100644 --- a/core/src/test/java/org/springframework/security/ldap/MockInitialDirContextFactory.java +++ b/core/src/test/java/org/springframework/security/ldap/MockSpringSecurityContextSource.java @@ -16,6 +16,7 @@ package org.springframework.security.ldap; import org.springframework.dao.DataAccessException; +import org.springframework.ldap.core.DistinguishedName; import javax.naming.directory.DirContext; @@ -25,7 +26,7 @@ import javax.naming.directory.DirContext; * @author Luke Taylor * @version $Id$ */ -public class MockInitialDirContextFactory implements InitialDirContextFactory { +public class MockSpringSecurityContextSource implements SpringSecurityContextSource { //~ Instance fields ================================================================================================ private DirContext ctx; @@ -33,25 +34,13 @@ public class MockInitialDirContextFactory implements InitialDirContextFactory { //~ Constructors =================================================================================================== - public MockInitialDirContextFactory(DirContext ctx, String baseDn) { + public MockSpringSecurityContextSource(DirContext ctx, String baseDn) { this.baseDn = baseDn; this.ctx = ctx; } //~ Methods ======================================================================================================== - public String getRootDn() { - return baseDn; - } - - public DirContext newInitialDirContext() { - return ctx; - } - - public DirContext newInitialDirContext(String username, String password) { - return ctx; - } - public DirContext getReadOnlyContext() throws DataAccessException { return ctx; } @@ -59,4 +48,16 @@ public class MockInitialDirContextFactory implements InitialDirContextFactory { public DirContext getReadWriteContext() throws DataAccessException { return ctx; } + + public DirContext getReadWriteContext(String userDn, Object credentials) { + return ctx; + } + + public DistinguishedName getBaseLdapPath() { + return new DistinguishedName(baseDn); + } + + public String getBaseLdapPathAsString() { + return getBaseLdapPath().toString(); + } } diff --git a/core/src/test/java/org/springframework/security/ldap/SpringSecurityLdapTemplateTests.java b/core/src/test/java/org/springframework/security/ldap/SpringSecurityLdapTemplateTests.java index 7d2083c08c..79f337c402 100644 --- a/core/src/test/java/org/springframework/security/ldap/SpringSecurityLdapTemplateTests.java +++ b/core/src/test/java/org/springframework/security/ldap/SpringSecurityLdapTemplateTests.java @@ -44,33 +44,33 @@ public class SpringSecurityLdapTemplateTests extends AbstractLdapIntegrationTest @Test public void testCompareOfCorrectValueSucceeds() { - assertTrue(template.compare("uid=bob,ou=people,dc=springframework,dc=org", "uid", "bob")); + assertTrue(template.compare("uid=bob,ou=people", "uid", "bob")); } @Test public void testCompareOfCorrectByteValueSucceeds() { - assertTrue(template.compare("uid=bob,ou=people,dc=springframework,dc=org", "userPassword", LdapUtils.getUtf8Bytes("bobspassword"))); + assertTrue(template.compare("uid=bob,ou=people", "userPassword", LdapUtils.getUtf8Bytes("bobspassword"))); } @Test public void testCompareOfWrongByteValueFails() { - assertFalse(template.compare("uid=bob,ou=people,dc=springframework,dc=org", "userPassword", LdapUtils.getUtf8Bytes("wrongvalue"))); + assertFalse(template.compare("uid=bob,ou=people", "userPassword", LdapUtils.getUtf8Bytes("wrongvalue"))); } @Test public void testCompareOfWrongValueFails() { - assertFalse(template.compare("uid=bob,ou=people,dc=springframework,dc=org", "uid", "wrongvalue")); + assertFalse(template.compare("uid=bob,ou=people", "uid", "wrongvalue")); } - @Test - public void testNameExistsForInValidNameFails() { - assertFalse(template.nameExists("ou=doesntexist,dc=springframework,dc=org")); - } - - @Test - public void testNameExistsForValidNameSucceeds() { - assertTrue(template.nameExists("ou=groups,dc=springframework,dc=org")); - } +// @Test +// public void testNameExistsForInValidNameFails() { +// assertFalse(template.nameExists("ou=doesntexist,dc=springframework,dc=org")); +// } +// +// @Test +// public void testNameExistsForValidNameSucceeds() { +// assertTrue(template.nameExists("ou=groups,dc=springframework,dc=org")); +// } @Test public void testNamingExceptionIsTranslatedCorrectly() { diff --git a/core/src/test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchTests.java b/core/src/test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchTests.java index 41a076005f..3577fab60d 100644 --- a/core/src/test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchTests.java +++ b/core/src/test/java/org/springframework/security/ldap/search/FilterBasedLdapUserSearchTests.java @@ -15,16 +15,15 @@ package org.springframework.security.ldap.search; -import org.springframework.security.ldap.DefaultInitialDirContextFactory; import org.springframework.security.ldap.AbstractLdapIntegrationTests; - import org.springframework.security.userdetails.UsernameNotFoundException; - import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.ldap.core.DirContextOperations; -import org.junit.Test; +import org.springframework.ldap.core.DistinguishedName; +import org.springframework.ldap.core.support.BaseLdapPathContextSource; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import org.junit.Test; /** * Tests for FilterBasedLdapUserSearch. @@ -35,13 +34,13 @@ import static org.junit.Assert.*; public class FilterBasedLdapUserSearchTests extends AbstractLdapIntegrationTests { //~ Instance fields ================================================================================================ - private DefaultInitialDirContextFactory dirCtxFactory; + private BaseLdapPathContextSource dirCtxFactory; //~ Methods ======================================================================================================== public void onSetUp() throws Exception { super.onSetUp(); - dirCtxFactory = (DefaultInitialDirContextFactory) getContextSource(); + dirCtxFactory = getContextSource(); } @Test @@ -54,8 +53,7 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapIntegrationTests DirContextOperations bob = locator.searchForUser("bob"); assertEquals("bob", bob.getStringAttribute("uid")); - // name is wrong with embedded apacheDS -// assertEquals("uid=bob,ou=people,dc=springframework,dc=org", bob.getDn()); + assertEquals(new DistinguishedName("uid=bob,ou=people"), bob.getDn()); } // Try some funny business with filters. @@ -71,24 +69,16 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapIntegrationTests // assertEquals("uid=ben,ou=people,"+ROOT_DN, ben.getDn()); } - @Test + @Test(expected=IncorrectResultSizeDataAccessException.class) public void testFailsOnMultipleMatches() { FilterBasedLdapUserSearch locator = new FilterBasedLdapUserSearch("ou=people", "(cn=*)", dirCtxFactory); - - try { - locator.searchForUser("Ignored"); - fail("Expected exception for multiple search matches."); - } catch (IncorrectResultSizeDataAccessException expected) {} + locator.searchForUser("Ignored"); } - @Test + @Test(expected=UsernameNotFoundException.class) public void testSearchForInvalidUserFails() { FilterBasedLdapUserSearch locator = new FilterBasedLdapUserSearch("ou=people", "(uid={0})", dirCtxFactory); - - try { - locator.searchForUser("Joe"); - fail("Expected UsernameNotFoundException for non-existent user."); - } catch (UsernameNotFoundException expected) {} + locator.searchForUser("Joe"); } @Test @@ -100,7 +90,7 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapIntegrationTests DirContextOperations ben = locator.searchForUser("Ben Alex"); assertEquals("ben", ben.getStringAttribute("uid")); -// assertEquals("uid=ben,ou=people,dc=springframework,dc=org", ben.getDn()); + assertEquals(new DistinguishedName("uid=ben,ou=people"), ben.getDn()); } // TODO: Add test with non-uid username diff --git a/core/src/test/java/org/springframework/security/providers/ldap/authenticator/BindAuthenticatorTests.java b/core/src/test/java/org/springframework/security/providers/ldap/authenticator/BindAuthenticatorTests.java index 8aa6d74e9a..934df0481d 100644 --- a/core/src/test/java/org/springframework/security/providers/ldap/authenticator/BindAuthenticatorTests.java +++ b/core/src/test/java/org/springframework/security/providers/ldap/authenticator/BindAuthenticatorTests.java @@ -15,19 +15,17 @@ package org.springframework.security.providers.ldap.authenticator; -import org.springframework.security.SpringSecurityMessageSource; -import org.springframework.security.BadCredentialsException; import org.springframework.security.Authentication; -import org.springframework.security.providers.UsernamePasswordAuthenticationToken; - +import org.springframework.security.BadCredentialsException; +import org.springframework.security.SpringSecurityMessageSource; import org.springframework.security.ldap.AbstractLdapIntegrationTests; -import org.springframework.security.ldap.InitialDirContextFactory; - +import org.springframework.security.providers.UsernamePasswordAuthenticationToken; import org.springframework.ldap.core.DirContextAdapter; -import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.core.DirContextOperations; +import org.springframework.ldap.core.DistinguishedName; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import org.junit.Test; /** @@ -41,16 +39,16 @@ public class BindAuthenticatorTests extends AbstractLdapIntegrationTests { private BindAuthenticator authenticator; private Authentication bob; - private Authentication ben; +// private Authentication ben; //~ Methods ======================================================================================================== public void onSetUp() { - authenticator = new BindAuthenticator((InitialDirContextFactory) getContextSource()); + authenticator = new BindAuthenticator(getContextSource()); authenticator.setMessageSource(new SpringSecurityMessageSource()); bob = new UsernamePasswordAuthenticationToken("bob", "bobspassword"); - ben = new UsernamePasswordAuthenticationToken("ben", "benspassword"); +// ben = new UsernamePasswordAuthenticationToken("ben", "benspassword"); } @@ -74,7 +72,7 @@ public class BindAuthenticatorTests extends AbstractLdapIntegrationTests { @Test public void testAuthenticationWithUserSearch() throws Exception { - DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=bob,ou=people,dc=springframework,dc=org")); + DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=bob,ou=people")); authenticator.setUserSearch(new MockUserSearch(ctx)); authenticator.afterPropertiesSet(); @@ -94,6 +92,6 @@ public class BindAuthenticatorTests extends AbstractLdapIntegrationTests { @Test public void testUserDnPatternReturnsCorrectDn() { authenticator.setUserDnPatterns(new String[] {"cn={0},ou=people"}); - assertEquals("cn=Joe,ou=people," + ((InitialDirContextFactory)getContextSource()).getRootDn(), authenticator.getUserDns("Joe").get(0)); + assertEquals("cn=Joe,ou=people", authenticator.getUserDns("Joe").get(0)); } } diff --git a/core/src/test/java/org/springframework/security/providers/ldap/authenticator/PasswordComparisonAuthenticatorMockTests.java b/core/src/test/java/org/springframework/security/providers/ldap/authenticator/PasswordComparisonAuthenticatorMockTests.java index c3e078fdcf..35276d3817 100644 --- a/core/src/test/java/org/springframework/security/providers/ldap/authenticator/PasswordComparisonAuthenticatorMockTests.java +++ b/core/src/test/java/org/springframework/security/providers/ldap/authenticator/PasswordComparisonAuthenticatorMockTests.java @@ -15,7 +15,7 @@ package org.springframework.security.providers.ldap.authenticator; -import org.springframework.security.ldap.MockInitialDirContextFactory; +import org.springframework.security.ldap.MockSpringSecurityContextSource; import org.springframework.security.providers.UsernamePasswordAuthenticationToken; import org.jmock.Mock; @@ -40,15 +40,15 @@ public class PasswordComparisonAuthenticatorMockTests extends MockObjectTestCase BasicAttributes attrs = new BasicAttributes(); attrs.put(new BasicAttribute("uid", "bob")); - PasswordComparisonAuthenticator authenticator = new PasswordComparisonAuthenticator(new MockInitialDirContextFactory( - (DirContext) mockCtx.proxy(), "dc=springframework,dc=org")); + PasswordComparisonAuthenticator authenticator = new PasswordComparisonAuthenticator(new MockSpringSecurityContextSource( + (DirContext) mockCtx.proxy(), "")); authenticator.setUserDnPatterns(new String[] {"cn={0},ou=people"}); // Get the mock to return an empty attribute set - mockCtx.expects(atLeastOnce()).method("getNameInNamespace").will(returnValue("dc=springframework,dc=org")); - mockCtx.expects(once()).method("lookup").with(eq("cn=Bob, ou=people")).will(returnValue(true)); - mockCtx.expects(once()).method("getAttributes").with(eq("cn=Bob, ou=people"), NULL) +// mockCtx.expects(atLeastOnce()).method("getNameInNamespace").will(returnValue("dc=springframework,dc=org")); +// mockCtx.expects(once()).method("lookup").with(eq("cn=Bob,ou=people")).will(returnValue(true)); + mockCtx.expects(once()).method("getAttributes").with(eq("cn=Bob,ou=people"), NULL) .will(returnValue(attrs)); // Setup a single return value (i.e. success) diff --git a/core/src/test/java/org/springframework/security/providers/ldap/authenticator/PasswordComparisonAuthenticatorTests.java b/core/src/test/java/org/springframework/security/providers/ldap/authenticator/PasswordComparisonAuthenticatorTests.java index cdba0bb024..2fddb7d87b 100644 --- a/core/src/test/java/org/springframework/security/providers/ldap/authenticator/PasswordComparisonAuthenticatorTests.java +++ b/core/src/test/java/org/springframework/security/providers/ldap/authenticator/PasswordComparisonAuthenticatorTests.java @@ -19,7 +19,6 @@ import org.springframework.security.BadCredentialsException; import org.springframework.security.Authentication; import org.springframework.security.ldap.AbstractLdapIntegrationTests; -import org.springframework.security.ldap.InitialDirContextFactory; import org.springframework.security.providers.encoding.PlaintextPasswordEncoder; import org.springframework.security.providers.UsernamePasswordAuthenticationToken; @@ -49,7 +48,7 @@ public class PasswordComparisonAuthenticatorTests extends AbstractLdapIntegratio public void onSetUp() throws Exception { super.onSetUp(); - authenticator = new PasswordComparisonAuthenticator((InitialDirContextFactory) getContextSource()); + authenticator = new PasswordComparisonAuthenticator(getContextSource()); authenticator.setUserDnPatterns(new String[] {"uid={0},ou=people"}); bob = new UsernamePasswordAuthenticationToken("bob", "bobspassword"); ben = new UsernamePasswordAuthenticationToken("ben", "benspassword"); @@ -64,7 +63,7 @@ public class PasswordComparisonAuthenticatorTests extends AbstractLdapIntegratio @Test public void testFailedSearchGivesUserNotFoundException() throws Exception { - authenticator = new PasswordComparisonAuthenticator((InitialDirContextFactory) getContextSource()); + authenticator = new PasswordComparisonAuthenticator(getContextSource()); assertTrue("User DN matches shouldn't be available", authenticator.getUserDns("Bob").isEmpty()); authenticator.setUserSearch(new MockUserSearch(null)); authenticator.afterPropertiesSet(); @@ -164,7 +163,7 @@ public class PasswordComparisonAuthenticatorTests extends AbstractLdapIntegratio @Test public void testWithUserSearch() { - authenticator = new PasswordComparisonAuthenticator((InitialDirContextFactory) getContextSource()); + authenticator = new PasswordComparisonAuthenticator(getContextSource()); assertTrue("User DN matches shouldn't be available", authenticator.getUserDns("Bob").isEmpty()); DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=Bob,ou=people,dc=springframework,dc=org")); diff --git a/core/src/test/java/org/springframework/security/providers/ldap/populator/DefaultLdapAuthoritiesPopulatorTests.java b/core/src/test/java/org/springframework/security/providers/ldap/populator/DefaultLdapAuthoritiesPopulatorTests.java index 69b5a455f9..636bc9db68 100644 --- a/core/src/test/java/org/springframework/security/providers/ldap/populator/DefaultLdapAuthoritiesPopulatorTests.java +++ b/core/src/test/java/org/springframework/security/providers/ldap/populator/DefaultLdapAuthoritiesPopulatorTests.java @@ -18,7 +18,6 @@ package org.springframework.security.providers.ldap.populator; import org.springframework.security.GrantedAuthority; import org.springframework.security.ldap.AbstractLdapIntegrationTests; -import org.springframework.security.ldap.InitialDirContextFactory; import org.springframework.ldap.core.DirContextAdapter; import org.springframework.ldap.core.DistinguishedName; @@ -42,7 +41,7 @@ public class DefaultLdapAuthoritiesPopulatorTests extends AbstractLdapIntegratio public void onSetUp() throws Exception { super.onSetUp(); - populator = new DefaultLdapAuthoritiesPopulator((InitialDirContextFactory) getContextSource(), "ou=groups"); + populator = new DefaultLdapAuthoritiesPopulator(getContextSource(), "ou=groups"); } diff --git a/core/src/test/java/org/springframework/security/userdetails/ldap/LdapUserDetailsManagerTests.java b/core/src/test/java/org/springframework/security/userdetails/ldap/LdapUserDetailsManagerTests.java index 7cb3d599cb..02431df257 100644 --- a/core/src/test/java/org/springframework/security/userdetails/ldap/LdapUserDetailsManagerTests.java +++ b/core/src/test/java/org/springframework/security/userdetails/ldap/LdapUserDetailsManagerTests.java @@ -14,20 +14,20 @@ */ package org.springframework.security.userdetails.ldap; -import org.springframework.security.ldap.SpringSecurityLdapTemplate; -import org.springframework.security.ldap.AbstractLdapIntegrationTests; -import org.springframework.security.userdetails.UserDetails; -import org.springframework.security.userdetails.UsernameNotFoundException; +import org.springframework.security.BadCredentialsException; import org.springframework.security.GrantedAuthority; import org.springframework.security.GrantedAuthorityImpl; -import org.springframework.security.BadCredentialsException; -import org.springframework.security.providers.UsernamePasswordAuthenticationToken; import org.springframework.security.context.SecurityContextHolder; - +import org.springframework.security.ldap.AbstractLdapIntegrationTests; +import org.springframework.security.ldap.DefaultLdapUsernameToDnMapper; +import org.springframework.security.ldap.SpringSecurityLdapTemplate; +import org.springframework.security.providers.UsernamePasswordAuthenticationToken; +import org.springframework.security.userdetails.UserDetails; +import org.springframework.security.userdetails.UsernameNotFoundException; import org.springframework.ldap.core.DirContextAdapter; -import static org.junit.Assert.*; import org.junit.After; +import static org.junit.Assert.*; import org.junit.Test; /** @@ -63,7 +63,7 @@ public class LdapUserDetailsManagerTests extends AbstractLdapIntegrationTests { group.setAttributeValue("cn", "acrobats"); template.bind("cn=acrobats,ou=testgroups", group, null); - mgr.setUserDnBase("ou=testpeople"); + mgr.setUsernameMapper(new DefaultLdapUsernameToDnMapper("ou=testpeople","uid")); mgr.setGroupSearchBase("ou=testgroups"); mgr.setGroupRoleAttributeName("cn"); mgr.setGroupMemberAttributeName("member"); @@ -88,7 +88,7 @@ public class LdapUserDetailsManagerTests extends AbstractLdapIntegrationTests { @Test public void testLoadUserByUsernameReturnsCorrectData() { - mgr.setUserDnBase("ou=people"); + mgr.setUsernameMapper(new DefaultLdapUsernameToDnMapper("ou=people","uid")); mgr.setGroupSearchBase("ou=groups"); UserDetails bob = mgr.loadUserByUsername("bob"); assertEquals("bob", bob.getUsername()); @@ -111,7 +111,7 @@ public class LdapUserDetailsManagerTests extends AbstractLdapIntegrationTests { @Test public void testUserExistsReturnsTrueForValidUser() { - mgr.setUserDnBase("ou=people"); + mgr.setUsernameMapper(new DefaultLdapUsernameToDnMapper("ou=people","uid")); assertTrue(mgr.userExists("bob")); } @@ -156,7 +156,7 @@ public class LdapUserDetailsManagerTests extends AbstractLdapIntegrationTests { } // Check that no authorities are left - assertEquals(0, mgr.getUserAuthorities(mgr.buildDn("don"), "don").length); + assertEquals(0, mgr.getUserAuthorities(mgr.usernameMapper.buildDn("don"), "don").length); } @Test @@ -175,7 +175,7 @@ public class LdapUserDetailsManagerTests extends AbstractLdapIntegrationTests { mgr.changePassword("yossarianspassword", "yossariansnewpassword"); - assertTrue(template.compare("uid=johnyossarian,ou=testpeople,dc=springframework,dc=org", + assertTrue(template.compare("uid=johnyossarian,ou=testpeople", "userPassword", "yossariansnewpassword")); } diff --git a/ntlm/src/main/java/org/springframework/security/ui/ntlm/ldap/authenticator/NtlmAwareLdapAuthenticator.java b/ntlm/src/main/java/org/springframework/security/ui/ntlm/ldap/authenticator/NtlmAwareLdapAuthenticator.java index aacec3b506..39f100c13d 100755 --- a/ntlm/src/main/java/org/springframework/security/ui/ntlm/ldap/authenticator/NtlmAwareLdapAuthenticator.java +++ b/ntlm/src/main/java/org/springframework/security/ui/ntlm/ldap/authenticator/NtlmAwareLdapAuthenticator.java @@ -3,18 +3,19 @@ */ package org.springframework.security.ui.ntlm.ldap.authenticator; -import java.util.Iterator; - -import org.springframework.security.BadCredentialsException; import org.springframework.security.Authentication; -import org.springframework.security.ldap.InitialDirContextFactory; +import org.springframework.security.BadCredentialsException; +import org.springframework.security.ldap.SpringSecurityContextSource; import org.springframework.security.ldap.SpringSecurityLdapTemplate; import org.springframework.security.providers.ldap.authenticator.BindAuthenticator; import org.springframework.security.ui.ntlm.NtlmUsernamePasswordAuthenticationToken; +import org.springframework.ldap.NameNotFoundException; +import org.springframework.ldap.core.DirContextOperations; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.ldap.core.DirContextOperations; -import org.springframework.ldap.NameNotFoundException; + +import java.util.Iterator; /** * Loads the UserDetails if authentication was already performed by NTLM (indicated by the type of authentication @@ -31,8 +32,8 @@ public class NtlmAwareLdapAuthenticator extends BindAuthenticator { //~ Constructors =================================================================================================== - public NtlmAwareLdapAuthenticator(InitialDirContextFactory initialDirContextFactory) { - super(initialDirContextFactory); + public NtlmAwareLdapAuthenticator(SpringSecurityContextSource contextSource) { + super(contextSource); } //~ Methods ======================================================================================================== @@ -41,7 +42,7 @@ public class NtlmAwareLdapAuthenticator extends BindAuthenticator { * Loads the user context information without binding. */ protected DirContextOperations loadUser(String aUserDn, String aUserName) { - SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate(getInitialDirContextFactory()); + SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate(getContextSource()); try { DirContextOperations user = template.retrieveEntry(aUserDn, getUserAttributes()); diff --git a/pom.xml b/pom.xml index b4876eb640..7442d200a4 100644 --- a/pom.xml +++ b/pom.xml @@ -76,15 +76,19 @@ - sourceforge.net + acegisnapshots Acegi snapshot repository - - http://acegisecurity.sourceforge.net/repository/snapshots - + http://acegisecurity.sourceforge.net/repository/snapshots false + + + acegirepo + Acegi maven repository + http://acegisecurity.sourceforge.net/maven + spring-milestone Springframework Maven Milestone Repository diff --git a/samples/contacts/src/main/webapp/WEB-INF/applicationContext-acegi-security-ldap.xml b/samples/contacts/src/main/webapp/WEB-INF/applicationContext-acegi-security-ldap.xml index 077f1bdf6d..0343d64980 100644 --- a/samples/contacts/src/main/webapp/WEB-INF/applicationContext-acegi-security-ldap.xml +++ b/samples/contacts/src/main/webapp/WEB-INF/applicationContext-acegi-security-ldap.xml @@ -36,22 +36,22 @@ - + - - + + - + uid={0},ou=people - + ou=groups ou