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