SEC-1036: Upgraded Spring LDAP to 1.3 and made corresponding code changes. Also some general tidying up of LDAP code. Removed deprecated context factory classes.
This commit is contained in:
parent
1918c50fd7
commit
66897e1849
|
@ -62,7 +62,7 @@
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.ldap</groupId>
|
<groupId>org.springframework.ldap</groupId>
|
||||||
<artifactId>spring-ldap</artifactId>
|
<artifactId>spring-ldap-core</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -15,22 +15,9 @@
|
||||||
|
|
||||||
package org.springframework.security.context;
|
package org.springframework.security.context;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import javax.servlet.http.HttpServletResponseWrapper;
|
|
||||||
import javax.servlet.http.HttpSession;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.ReflectionUtils;
|
|
||||||
import org.springframework.security.AuthenticationTrustResolver;
|
|
||||||
import org.springframework.security.AuthenticationTrustResolverImpl;
|
|
||||||
import org.springframework.security.ui.SpringSecurityFilter;
|
|
||||||
import org.springframework.security.ui.FilterChainOrder;
|
import org.springframework.security.ui.FilterChainOrder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -110,8 +97,6 @@ public class HttpSessionContextIntegrationFilter extends SecurityContextPersiste
|
||||||
|
|
||||||
private Class<? extends SecurityContext> contextClass = SecurityContextImpl.class;
|
private Class<? extends SecurityContext> contextClass = SecurityContextImpl.class;
|
||||||
|
|
||||||
// private Object contextObject;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates if this filter can create a <code>HttpSession</code> if
|
* Indicates if this filter can create a <code>HttpSession</code> if
|
||||||
* needed (sessions are always created sparingly, but setting this value to
|
* needed (sessions are always created sparingly, but setting this value to
|
||||||
|
@ -160,7 +145,6 @@ public class HttpSessionContextIntegrationFilter extends SecurityContextPersiste
|
||||||
private HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
|
private HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
|
||||||
|
|
||||||
public HttpSessionContextIntegrationFilter() throws ServletException {
|
public HttpSessionContextIntegrationFilter() throws ServletException {
|
||||||
// this.contextObject = generateNewContext();
|
|
||||||
super.setSecurityContextRepository(repo);
|
super.setSecurityContextRepository(repo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,364 +0,0 @@
|
||||||
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.security.ldap;
|
|
||||||
|
|
||||||
import org.springframework.security.SpringSecurityMessageSource;
|
|
||||||
import org.springframework.security.BadCredentialsException;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
|
|
||||||
import org.springframework.context.MessageSource;
|
|
||||||
import org.springframework.context.MessageSourceAware;
|
|
||||||
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;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.StringTokenizer;
|
|
||||||
|
|
||||||
import javax.naming.CommunicationException;
|
|
||||||
import javax.naming.Context;
|
|
||||||
import javax.naming.NamingException;
|
|
||||||
import javax.naming.OperationNotSupportedException;
|
|
||||||
import javax.naming.ldap.InitialLdapContext;
|
|
||||||
import javax.naming.directory.DirContext;
|
|
||||||
import javax.naming.directory.InitialDirContext;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encapsulates the information for connecting to an LDAP server and provides an access point for obtaining
|
|
||||||
* <tt>DirContext</tt> references.
|
|
||||||
* <p>
|
|
||||||
* The directory location is configured using by setting the constructor argument
|
|
||||||
* <tt>providerUrl</tt>. This should be in the form <tt>ldap://monkeymachine.co.uk:389/dc=springframework,dc=org</tt>.
|
|
||||||
* The Sun JNDI provider also supports lists of space-separated URLs, each of which will be tried in turn until a
|
|
||||||
* connection is obtained.
|
|
||||||
* </p>
|
|
||||||
* <p>To obtain an initial context, the client calls the <tt>newInitialDirContext</tt> method. There are two
|
|
||||||
* signatures - one with no arguments and one which allows binding with a specific username and password.
|
|
||||||
* </p>
|
|
||||||
* <p>The no-args version will bind anonymously unless a manager login has been configured using the properties
|
|
||||||
* <tt>managerDn</tt> and <tt>managerPassword</tt>, in which case it will bind as the manager user.</p>
|
|
||||||
* <p>Connection pooling is enabled by default for anonymous or manager connections, but not when binding as a
|
|
||||||
* specific user.</p>
|
|
||||||
*
|
|
||||||
* @author Robert Sanders
|
|
||||||
* @author Luke Taylor
|
|
||||||
* @version $Id$
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @deprecated use {@link DefaultSpringSecurityContextSource} instead.
|
|
||||||
*
|
|
||||||
* @see <a href="http://java.sun.com/products/jndi/tutorial/ldap/connect/pool.html">The Java tutorial's guide to LDAP
|
|
||||||
* connection pooling</a>
|
|
||||||
*/
|
|
||||||
public class DefaultInitialDirContextFactory implements InitialDirContextFactory,
|
|
||||||
SpringSecurityContextSource, MessageSourceAware {
|
|
||||||
//~ Static fields/initializers =====================================================================================
|
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(DefaultInitialDirContextFactory.class);
|
|
||||||
private static final String CONNECTION_POOL_KEY = "com.sun.jndi.ldap.connect.pool";
|
|
||||||
private static final String AUTH_TYPE_NONE = "none";
|
|
||||||
|
|
||||||
//~ Instance fields ================================================================================================
|
|
||||||
|
|
||||||
/** Allows extra environment variables to be added at config time. */
|
|
||||||
private Map extraEnvVars = null;
|
|
||||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
|
||||||
|
|
||||||
/** Type of authentication within LDAP; default is simple. */
|
|
||||||
private String authenticationType = "simple";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The INITIAL_CONTEXT_FACTORY used to create the JNDI Factory. Default is
|
|
||||||
* "com.sun.jndi.ldap.LdapCtxFactory"; you <b>should not</b> need to set this unless you have unusual needs.
|
|
||||||
*/
|
|
||||||
private String initialContextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
|
|
||||||
|
|
||||||
private String dirObjectFactoryClass = DefaultDirObjectFactory.class.getName();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If your LDAP server does not allow anonymous searches then you will need to provide a "manager" user's
|
|
||||||
* DN to log in with.
|
|
||||||
*/
|
|
||||||
private String managerDn = null;
|
|
||||||
|
|
||||||
/** The manager user's password. */
|
|
||||||
private String managerPassword = "manager_password_not_set";
|
|
||||||
|
|
||||||
/** The LDAP url of the server (and root context) to connect to. */
|
|
||||||
private String providerUrl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The root DN. This is worked out from the url. It is used by client classes when forming a full DN for
|
|
||||||
* bind authentication (for example).
|
|
||||||
*/
|
|
||||||
private String rootDn = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use the LDAP Connection pool; if true, then the LDAP environment property
|
|
||||||
* "com.sun.jndi.ldap.connect.pool" is added to any other JNDI properties.
|
|
||||||
*/
|
|
||||||
private boolean useConnectionPool = true;
|
|
||||||
|
|
||||||
/** Set to true for ldap v3 compatible servers */
|
|
||||||
private boolean useLdapContext = false;
|
|
||||||
|
|
||||||
//~ Constructors ===================================================================================================
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create and initialize an instance to the LDAP url provided
|
|
||||||
*
|
|
||||||
* @param providerUrl a String of the form <code>ldap://localhost:389/base_dn<code>
|
|
||||||
*/
|
|
||||||
public DefaultInitialDirContextFactory(String providerUrl) {
|
|
||||||
this.setProviderUrl(providerUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
//~ Methods ========================================================================================================
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the LDAP url
|
|
||||||
*
|
|
||||||
* @param providerUrl a String of the form <code>ldap://localhost:389/base_dn<code>
|
|
||||||
*/
|
|
||||||
private void setProviderUrl(String providerUrl) {
|
|
||||||
Assert.hasLength(providerUrl, "An LDAP connection URL must be supplied.");
|
|
||||||
|
|
||||||
this.providerUrl = providerUrl;
|
|
||||||
|
|
||||||
StringTokenizer st = new StringTokenizer(providerUrl);
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This doesn't necessarily hold for embedded servers.
|
|
||||||
//Assert.isTrue(uri.getScheme().equals("ldap"), "Ldap URL must start with 'ldap://'");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the LDAP url
|
|
||||||
*
|
|
||||||
* @return the url
|
|
||||||
*/
|
|
||||||
private String getProviderUrl() {
|
|
||||||
return providerUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
private InitialDirContext connect(Hashtable env) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
Hashtable envClone = (Hashtable) env.clone();
|
|
||||||
|
|
||||||
if (envClone.containsKey(Context.SECURITY_CREDENTIALS)) {
|
|
||||||
envClone.put(Context.SECURITY_CREDENTIALS, "******");
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug("Creating InitialDirContext with environment " + envClone);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return useLdapContext ? new InitialLdapContext(env, null) : new InitialDirContext(env);
|
|
||||||
} catch (NamingException ne) {
|
|
||||||
if ((ne instanceof javax.naming.AuthenticationException)
|
|
||||||
|| (ne instanceof OperationNotSupportedException)) {
|
|
||||||
throw new BadCredentialsException(messages.getMessage("DefaultIntitalDirContextFactory.badCredentials",
|
|
||||||
"Bad credentials"), ne);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ne instanceof CommunicationException) {
|
|
||||||
throw new UncategorizedLdapException(messages.getMessage(
|
|
||||||
"DefaultIntitalDirContextFactory.communicationFailure", "Unable to connect to LDAP server"), ne);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new UncategorizedLdapException(messages.getMessage(
|
|
||||||
"DefaultIntitalDirContextFactory.unexpectedException",
|
|
||||||
"Failed to obtain InitialDirContext due to unexpected exception"), ne);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets up the environment parameters for creating a new context.
|
|
||||||
*
|
|
||||||
* @return the Hashtable describing the base DirContext that will be created, minus the username/password if any.
|
|
||||||
*/
|
|
||||||
protected Hashtable getEnvironment() {
|
|
||||||
Hashtable env = new Hashtable();
|
|
||||||
|
|
||||||
env.put(Context.SECURITY_AUTHENTICATION, authenticationType);
|
|
||||||
env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
|
|
||||||
env.put(Context.PROVIDER_URL, getProviderUrl());
|
|
||||||
|
|
||||||
if (useConnectionPool) {
|
|
||||||
env.put(CONNECTION_POOL_KEY, "true");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((extraEnvVars != null) && (extraEnvVars.size() > 0)) {
|
|
||||||
env.putAll(extraEnvVars);
|
|
||||||
}
|
|
||||||
|
|
||||||
return env;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the root DN of the configured provider URL. For example, if the URL is
|
|
||||||
* <tt>ldap://monkeymachine.co.uk:389/dc=springframework,dc=org</tt> the value will be
|
|
||||||
* <tt>dc=springframework,dc=org</tt>.
|
|
||||||
*
|
|
||||||
* @return the root DN calculated from the path of the LDAP url.
|
|
||||||
*/
|
|
||||||
public String getRootDn() {
|
|
||||||
return rootDn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connects anonymously unless a manager user has been specified, in which case it will bind as the
|
|
||||||
* manager.
|
|
||||||
*
|
|
||||||
* @return the resulting context object.
|
|
||||||
*/
|
|
||||||
public DirContext newInitialDirContext() {
|
|
||||||
if (managerDn != null) {
|
|
||||||
return newInitialDirContext(managerDn, managerPassword);
|
|
||||||
}
|
|
||||||
|
|
||||||
Hashtable env = getEnvironment();
|
|
||||||
env.put(Context.SECURITY_AUTHENTICATION, AUTH_TYPE_NONE);
|
|
||||||
|
|
||||||
return connect(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DirContext newInitialDirContext(String username, String password) {
|
|
||||||
Hashtable env = getEnvironment();
|
|
||||||
|
|
||||||
// Don't pool connections for individual users
|
|
||||||
if (!username.equals(managerDn)) {
|
|
||||||
env.remove(CONNECTION_POOL_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
env.put(Context.SECURITY_PRINCIPAL, username);
|
|
||||||
env.put(Context.SECURITY_CREDENTIALS, password);
|
|
||||||
|
|
||||||
if(dirObjectFactoryClass != null) {
|
|
||||||
env.put(Context.OBJECT_FACTORIES, dirObjectFactoryClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
return connect(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Spring LDAP <tt>ContextSource</tt> method */
|
|
||||||
public DirContext getReadOnlyContext() throws DataAccessException {
|
|
||||||
return newInitialDirContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Spring LDAP <tt>ContextSource</tt> method */
|
|
||||||
public DirContext getReadWriteContext() throws DataAccessException {
|
|
||||||
return newInitialDirContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAuthenticationType(String authenticationType) {
|
|
||||||
Assert.hasLength(authenticationType, "LDAP Authentication type must not be empty or null");
|
|
||||||
this.authenticationType = authenticationType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets any custom environment variables which will be added to the those returned
|
|
||||||
* by the <tt>getEnvironment</tt> method.
|
|
||||||
*
|
|
||||||
* @param extraEnvVars extra environment variables to be added at config time.
|
|
||||||
*/
|
|
||||||
public void setExtraEnvVars(Map extraEnvVars) {
|
|
||||||
Assert.notNull(extraEnvVars, "Extra environment map cannot be null.");
|
|
||||||
this.extraEnvVars = extraEnvVars;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setInitialContextFactory(String initialContextFactory) {
|
|
||||||
Assert.hasLength(initialContextFactory, "Initial context factory name cannot be empty or null");
|
|
||||||
this.initialContextFactory = initialContextFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the directory user to authenticate as when obtaining a context using the
|
|
||||||
* <tt>newInitialDirContext()</tt> method.
|
|
||||||
* If no name is supplied then the context will be obtained anonymously.
|
|
||||||
*
|
|
||||||
* @param managerDn The name of the "manager" user for default authentication.
|
|
||||||
*/
|
|
||||||
public void setManagerDn(String managerDn) {
|
|
||||||
Assert.hasLength(managerDn, "Manager user name cannot be empty or null.");
|
|
||||||
this.managerDn = managerDn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the password which will be used in combination with the manager DN.
|
|
||||||
*
|
|
||||||
* @param managerPassword The "manager" user's password.
|
|
||||||
*/
|
|
||||||
public void setManagerPassword(String managerPassword) {
|
|
||||||
Assert.hasLength(managerPassword, "Manager password must not be empty or null.");
|
|
||||||
this.managerPassword = managerPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMessageSource(MessageSource messageSource) {
|
|
||||||
this.messages = new MessageSourceAccessor(messageSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connection pooling is enabled by default for anonymous or "manager" connections when using the default
|
|
||||||
* Sun provider. To disable all connection pooling, set this property to false.
|
|
||||||
*
|
|
||||||
* @param useConnectionPool whether to pool connections for non-specific users.
|
|
||||||
*/
|
|
||||||
public void setUseConnectionPool(boolean useConnectionPool) {
|
|
||||||
this.useConnectionPool = useConnectionPool;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUseLdapContext(boolean useLdapContext) {
|
|
||||||
this.useLdapContext = useLdapContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,58 +0,0 @@
|
||||||
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.security.ldap;
|
|
||||||
|
|
||||||
import javax.naming.directory.DirContext;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Access point for obtaining LDAP contexts.
|
|
||||||
*
|
|
||||||
* @see org.springframework.security.ldap.DefaultInitialDirContextFactory
|
|
||||||
*
|
|
||||||
* @deprecated Use SpringSecurityContextSource instead
|
|
||||||
* @author Luke Taylor
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public interface InitialDirContextFactory {
|
|
||||||
//~ Methods ========================================================================================================
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the root DN of the contexts supplied by this factory.
|
|
||||||
* The names for searches etc. which are performed against contexts
|
|
||||||
* returned by this factory should be relative to the root DN.
|
|
||||||
*
|
|
||||||
* @return The DN of the contexts returned by this factory.
|
|
||||||
*/
|
|
||||||
String getRootDn();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides an initial context without specific user information.
|
|
||||||
*
|
|
||||||
* @return An initial context for the LDAP directory
|
|
||||||
*/
|
|
||||||
DirContext newInitialDirContext();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides an initial context by binding as a specific user.
|
|
||||||
*
|
|
||||||
* @param userDn the user to authenticate as when obtaining the context.
|
|
||||||
* @param password the user's password.
|
|
||||||
*
|
|
||||||
* @return An initial context for the LDAP directory
|
|
||||||
*/
|
|
||||||
DirContext newInitialDirContext(String userDn, String password);
|
|
||||||
}
|
|
|
@ -11,6 +11,8 @@ import javax.naming.directory.DirContext;
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
|
*
|
||||||
|
* @deprecated As of Spring LDAP 1.3, ContextSource provides this method itself.
|
||||||
*/
|
*/
|
||||||
public interface SpringSecurityContextSource extends BaseLdapPathContextSource {
|
public interface SpringSecurityContextSource extends BaseLdapPathContextSource {
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
|
||||||
ctls.setReturningAttributes(NO_ATTRS);
|
ctls.setReturningAttributes(NO_ATTRS);
|
||||||
ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
|
ctls.setSearchScope(SearchControls.OBJECT_SCOPE);
|
||||||
|
|
||||||
NamingEnumeration results = ctx.search(dn, comparisonFilter, new Object[] {value}, ctls);
|
NamingEnumeration<SearchResult> results = ctx.search(dn, comparisonFilter, new Object[] {value}, ctls);
|
||||||
|
|
||||||
return Boolean.valueOf(results.hasMore());
|
return Boolean.valueOf(results.hasMore());
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
|
||||||
*
|
*
|
||||||
* @return the set of String values for the attribute as a union of the values found in all the matching entries.
|
* @return the set of String values for the attribute as a union of the values found in all the matching entries.
|
||||||
*/
|
*/
|
||||||
public Set searchForSingleAttributeValues(final String base, final String filter, final Object[] params,
|
public Set<String> searchForSingleAttributeValues(final String base, final String filter, final Object[] params,
|
||||||
final String attributeName) {
|
final String attributeName) {
|
||||||
// Escape the params acording to RFC2254
|
// Escape the params acording to RFC2254
|
||||||
Object[] encodedParams = new String[params.length];
|
Object[] encodedParams = new String[params.length];
|
||||||
|
@ -147,7 +147,7 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
|
||||||
String formattedFilter = MessageFormat.format(filter, encodedParams);
|
String formattedFilter = MessageFormat.format(filter, encodedParams);
|
||||||
logger.debug("Using filter: " + formattedFilter);
|
logger.debug("Using filter: " + formattedFilter);
|
||||||
|
|
||||||
final HashSet set = new HashSet();
|
final HashSet<String> set = new HashSet<String>();
|
||||||
|
|
||||||
ContextMapper roleMapper = new ContextMapper() {
|
ContextMapper roleMapper = new ContextMapper() {
|
||||||
public Object mapFromContext(Object ctx) {
|
public Object mapFromContext(Object ctx) {
|
||||||
|
@ -193,12 +193,12 @@ public class SpringSecurityLdapTemplate extends LdapTemplate {
|
||||||
return (DirContextOperations) executeReadOnly(new ContextExecutor() {
|
return (DirContextOperations) executeReadOnly(new ContextExecutor() {
|
||||||
public Object executeWithContext(DirContext ctx) throws NamingException {
|
public Object executeWithContext(DirContext ctx) throws NamingException {
|
||||||
DistinguishedName ctxBaseDn = new DistinguishedName(ctx.getNameInNamespace());
|
DistinguishedName ctxBaseDn = new DistinguishedName(ctx.getNameInNamespace());
|
||||||
NamingEnumeration resultsEnum = ctx.search(base, filter, params, searchControls);
|
NamingEnumeration<SearchResult> resultsEnum = ctx.search(base, filter, params, searchControls);
|
||||||
Set results = new HashSet();
|
Set<DirContextOperations> results = new HashSet<DirContextOperations>();
|
||||||
try {
|
try {
|
||||||
while (resultsEnum.hasMore()) {
|
while (resultsEnum.hasMore()) {
|
||||||
|
|
||||||
SearchResult searchResult = (SearchResult) resultsEnum.next();
|
SearchResult searchResult = resultsEnum.next();
|
||||||
// Work out the DN of the matched entry
|
// Work out the DN of the matched entry
|
||||||
StringBuffer dn = new StringBuffer(searchResult.getName());
|
StringBuffer dn = new StringBuffer(searchResult.getName());
|
||||||
|
|
||||||
|
|
|
@ -15,22 +15,21 @@
|
||||||
|
|
||||||
package org.springframework.security.providers.ldap.authenticator;
|
package org.springframework.security.providers.ldap.authenticator;
|
||||||
|
|
||||||
import org.springframework.security.Authentication;
|
import javax.naming.directory.Attributes;
|
||||||
import org.springframework.security.BadCredentialsException;
|
import javax.naming.directory.DirContext;
|
||||||
import org.springframework.security.ldap.SpringSecurityContextSource;
|
|
||||||
import org.springframework.security.ldap.SpringSecurityLdapTemplate;
|
|
||||||
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.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.ldap.NamingException;
|
||||||
import javax.naming.directory.DirContext;
|
import org.springframework.ldap.core.DirContextAdapter;
|
||||||
import java.util.Iterator;
|
import org.springframework.ldap.core.DirContextOperations;
|
||||||
|
import org.springframework.ldap.core.DistinguishedName;
|
||||||
|
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
|
||||||
|
import org.springframework.ldap.support.LdapUtils;
|
||||||
|
import org.springframework.security.Authentication;
|
||||||
|
import org.springframework.security.BadCredentialsException;
|
||||||
|
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,7 +54,7 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
|
||||||
* performed.
|
* performed.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public BindAuthenticator(SpringSecurityContextSource contextSource) {
|
public BindAuthenticator(BaseLdapPathContextSource contextSource) {
|
||||||
super(contextSource);
|
super(contextSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,14 +69,11 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
|
||||||
String password = (String)authentication.getCredentials();
|
String password = (String)authentication.getCredentials();
|
||||||
|
|
||||||
// If DN patterns are configured, try authenticating with them directly
|
// If DN patterns are configured, try authenticating with them directly
|
||||||
Iterator dns = getUserDns(username).iterator();
|
for (String dn : getUserDns(username)) {
|
||||||
|
user = bindWithDn(dn, username, password);
|
||||||
while (dns.hasNext() && user == null) {
|
|
||||||
user = bindWithDn((String) dns.next(), username, password);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise use the configured locator to find the user
|
// Otherwise use the configured search object to find the user and authenticate with the returned DN.
|
||||||
// and authenticate with the returned DN.
|
|
||||||
if (user == null && getUserSearch() != null) {
|
if (user == null && getUserSearch() != null) {
|
||||||
DirContextOperations userFromSearch = getUserSearch().searchForUser(username);
|
DirContextOperations userFromSearch = getUserSearch().searchForUser(username);
|
||||||
user = bindWithDn(userFromSearch.getDn().toString(), username, password);
|
user = bindWithDn(userFromSearch.getDn().toString(), username, password);
|
||||||
|
@ -92,17 +88,29 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private DirContextOperations bindWithDn(String userDn, String username, String password) {
|
private DirContextOperations bindWithDn(String userDn, String username, String password) {
|
||||||
SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate(
|
BaseLdapPathContextSource ctxSource = (BaseLdapPathContextSource) getContextSource();
|
||||||
new BindWithSpecificDnContextSource((SpringSecurityContextSource) getContextSource(), userDn, password));
|
DistinguishedName fullDn = new DistinguishedName(userDn);
|
||||||
|
fullDn.prepend(ctxSource.getBaseLdapPath());
|
||||||
|
|
||||||
|
logger.debug("Attempting to bind as " + fullDn);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return template.retrieveEntry(userDn, getUserAttributes());
|
DirContext ctx = getContextSource().getContext(fullDn.toString(), password);
|
||||||
|
Attributes attrs = ctx.getAttributes(userDn, getUserAttributes());
|
||||||
|
|
||||||
} catch (BadCredentialsException e) {
|
return new DirContextAdapter(attrs, new DistinguishedName(userDn), ctxSource.getBaseLdapPath());
|
||||||
|
} catch (NamingException e) {
|
||||||
// This will be thrown if an invalid user name is used and the method may
|
// This will be thrown if an invalid user name is used and the method may
|
||||||
// be called multiple times to try different names, so we trap the exception
|
// be called multiple times to try different names, so we trap the exception
|
||||||
// unless a subclass wishes to implement more specialized behaviour.
|
// unless a subclass wishes to implement more specialized behaviour.
|
||||||
handleBindException(userDn, username, e.getCause());
|
if ((e instanceof org.springframework.ldap.AuthenticationException)
|
||||||
|
|| (e instanceof org.springframework.ldap.OperationNotSupportedException)) {
|
||||||
|
handleBindException(userDn, username, e);
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} catch (javax.naming.NamingException e) {
|
||||||
|
throw LdapUtils.convertLdapException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -117,26 +125,4 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
|
||||||
logger.debug("Failed to bind as " + userDn + ": " + cause);
|
logger.debug("Failed to bind as " + userDn + ": " + cause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BindWithSpecificDnContextSource implements ContextSource {
|
|
||||||
private SpringSecurityContextSource ctxFactory;
|
|
||||||
DistinguishedName userDn;
|
|
||||||
private String password;
|
|
||||||
|
|
||||||
public BindWithSpecificDnContextSource(SpringSecurityContextSource ctxFactory, String userDn, String password) {
|
|
||||||
this.ctxFactory = ctxFactory;
|
|
||||||
this.userDn = new DistinguishedName(userDn);
|
|
||||||
this.userDn.prepend(ctxFactory.getBaseLdapPath());
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DirContext getReadOnlyContext() throws DataAccessException {
|
|
||||||
return ctxFactory.getReadWriteContext(userDn.toString(), password);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DirContext getReadWriteContext() throws DataAccessException {
|
|
||||||
return getReadOnlyContext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,24 +14,25 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.security.ldap;
|
package org.springframework.security.ldap;
|
||||||
|
|
||||||
import org.springframework.security.config.BeanIds;
|
|
||||||
import org.springframework.ldap.core.DistinguishedName;
|
|
||||||
import org.springframework.core.io.ClassPathResource;
|
|
||||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
|
||||||
import org.junit.BeforeClass;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.AfterClass;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.apache.directory.server.protocol.shared.store.LdifFileLoader;
|
|
||||||
import org.apache.directory.server.core.DirectoryService;
|
|
||||||
|
|
||||||
import javax.naming.directory.DirContext;
|
|
||||||
import javax.naming.Name;
|
|
||||||
import javax.naming.NamingException;
|
|
||||||
import javax.naming.NamingEnumeration;
|
|
||||||
import javax.naming.Binding;
|
import javax.naming.Binding;
|
||||||
import javax.naming.ContextNotEmptyException;
|
import javax.naming.ContextNotEmptyException;
|
||||||
|
import javax.naming.Name;
|
||||||
import javax.naming.NameNotFoundException;
|
import javax.naming.NameNotFoundException;
|
||||||
|
import javax.naming.NamingEnumeration;
|
||||||
|
import javax.naming.NamingException;
|
||||||
|
import javax.naming.directory.DirContext;
|
||||||
|
|
||||||
|
import org.apache.directory.server.core.DirectoryService;
|
||||||
|
import org.apache.directory.server.protocol.shared.store.LdifFileLoader;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.ldap.core.DistinguishedName;
|
||||||
|
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
|
||||||
|
import org.springframework.security.config.BeanIds;
|
||||||
|
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Based on class borrowed from Spring Ldap project.
|
* Based on class borrowed from Spring Ldap project.
|
||||||
|
@ -40,7 +41,7 @@ import javax.naming.NameNotFoundException;
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractLdapIntegrationTests {
|
public abstract class AbstractLdapIntegrationTests {
|
||||||
private static ClassPathXmlApplicationContext appContext;
|
private static InMemoryXmlApplicationContext appContext;
|
||||||
|
|
||||||
protected AbstractLdapIntegrationTests() {
|
protected AbstractLdapIntegrationTests() {
|
||||||
}
|
}
|
||||||
|
@ -48,7 +49,7 @@ public abstract class AbstractLdapIntegrationTests {
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void loadContext() throws NamingException {
|
public static void loadContext() throws NamingException {
|
||||||
shutdownRunningServers();
|
shutdownRunningServers();
|
||||||
appContext = new ClassPathXmlApplicationContext("/org/springframework/security/ldap/ldapIntegrationTestContext.xml");
|
appContext = new InMemoryXmlApplicationContext("<ldap-server port='53389' ldif='classpath:test-server.ldif'/>");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,22 +99,14 @@ public abstract class AbstractLdapIntegrationTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpringSecurityContextSource getContextSource() {
|
public BaseLdapPathContextSource getContextSource() {
|
||||||
return (SpringSecurityContextSource) appContext.getBean(BeanIds.CONTEXT_SOURCE);
|
return (BaseLdapPathContextSource)appContext.getBean(BeanIds.CONTEXT_SOURCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* We have both a context source and intitialdircontextfactory. The former is also used in
|
|
||||||
* the cleanAndSetup method so any mods during tests can mess it up.
|
|
||||||
* TODO: Once the initialdircontextfactory stuff has been refactored, revisit this and remove this property.
|
|
||||||
*/
|
|
||||||
protected DefaultInitialDirContextFactory getInitialDirContextFactory() {
|
|
||||||
return (DefaultInitialDirContextFactory) appContext.getBean("initialDirContextFactory");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void clearSubContexts(DirContext ctx, Name name) throws NamingException {
|
private void clearSubContexts(DirContext ctx, Name name) throws NamingException {
|
||||||
|
|
||||||
NamingEnumeration enumeration = null;
|
NamingEnumeration<Binding> enumeration = null;
|
||||||
try {
|
try {
|
||||||
enumeration = ctx.listBindings(name);
|
enumeration = ctx.listBindings(name);
|
||||||
while (enumeration.hasMore()) {
|
while (enumeration.hasMore()) {
|
||||||
|
|
|
@ -1,209 +0,0 @@
|
||||||
/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.springframework.security.ldap;
|
|
||||||
|
|
||||||
import org.springframework.security.SpringSecurityMessageSource;
|
|
||||||
import org.springframework.security.BadCredentialsException;
|
|
||||||
import org.springframework.ldap.UncategorizedLdapException;
|
|
||||||
|
|
||||||
import java.util.Hashtable;
|
|
||||||
|
|
||||||
import javax.naming.Context;
|
|
||||||
import javax.naming.directory.DirContext;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link org.springframework.security.ldap.DefaultInitialDirContextFactory}.
|
|
||||||
*
|
|
||||||
* @author Luke Taylor
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class DefaultInitialDirContextFactoryTests extends AbstractLdapIntegrationTests {
|
|
||||||
//~ Instance fields ================================================================================================
|
|
||||||
|
|
||||||
DefaultInitialDirContextFactory idf;
|
|
||||||
|
|
||||||
//~ Methods ========================================================================================================
|
|
||||||
|
|
||||||
public void onSetUp() throws Exception {
|
|
||||||
super.onSetUp();
|
|
||||||
idf = getInitialDirContextFactory();
|
|
||||||
idf.setMessageSource(new SpringSecurityMessageSource());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAnonymousBindSucceeds() throws Exception {
|
|
||||||
DirContext ctx = idf.newInitialDirContext();
|
|
||||||
// Connection pooling should be set by default for anon users.
|
|
||||||
// Can't rely on this property being there with embedded server
|
|
||||||
// assertEquals("true",ctx.getEnvironment().get("com.sun.jndi.ldap.connect.pool"));
|
|
||||||
ctx.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testBaseDnIsParsedFromCorrectlyFromUrl() {
|
|
||||||
idf = new DefaultInitialDirContextFactory("ldap://springsecurity.org/dc=springframework,dc=org");
|
|
||||||
assertEquals("dc=springframework,dc=org", idf.getRootDn());
|
|
||||||
|
|
||||||
// Check with an empty root
|
|
||||||
idf = new DefaultInitialDirContextFactory("ldap://springsecurity.org/");
|
|
||||||
assertEquals("", idf.getRootDn());
|
|
||||||
|
|
||||||
// Empty root without trailing slash
|
|
||||||
idf = new DefaultInitialDirContextFactory("ldap://springsecurity.org");
|
|
||||||
assertEquals("", idf.getRootDn());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testBindAsManagerFailsIfNoPasswordSet() throws Exception {
|
|
||||||
idf.setManagerDn("uid=bob,ou=people,dc=springframework,dc=org");
|
|
||||||
|
|
||||||
DirContext ctx = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
ctx = idf.newInitialDirContext();
|
|
||||||
fail("Binding with no manager password should fail.");
|
|
||||||
|
|
||||||
// Can't rely on this property being there with embedded server
|
|
||||||
// assertEquals("true",ctx.getEnvironment().get("com.sun.jndi.ldap.connect.pool"));
|
|
||||||
} catch (BadCredentialsException expected) {}
|
|
||||||
|
|
||||||
LdapUtils.closeContext(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testBindAsManagerSucceeds() throws Exception {
|
|
||||||
idf.setManagerPassword("bobspassword");
|
|
||||||
idf.setManagerDn("uid=bob,ou=people,dc=springframework,dc=org");
|
|
||||||
|
|
||||||
DirContext ctx = idf.newInitialDirContext();
|
|
||||||
// Can't rely on this property being there with embedded server
|
|
||||||
// assertEquals("true",ctx.getEnvironment().get("com.sun.jndi.ldap.connect.pool"));
|
|
||||||
ctx.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testConnectionAsSpecificUserSucceeds() throws Exception {
|
|
||||||
DirContext ctx = idf.newInitialDirContext("uid=Bob,ou=people,dc=springframework,dc=org", "bobspassword");
|
|
||||||
// We don't want pooling for specific users.
|
|
||||||
// assertNull(ctx.getEnvironment().get("com.sun.jndi.ldap.connect.pool"));
|
|
||||||
// com.sun.jndi.ldap.LdapPoolManager.showStats(System.out);
|
|
||||||
ctx.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testConnectionFailure() throws Exception {
|
|
||||||
// Use the wrong port
|
|
||||||
idf = new DefaultInitialDirContextFactory("ldap://localhost:60389");
|
|
||||||
idf.setInitialContextFactory("com.sun.jndi.ldap.LdapCtxFactory");
|
|
||||||
|
|
||||||
Hashtable env = new Hashtable();
|
|
||||||
env.put("com.sun.jndi.ldap.connect.timeout", "200");
|
|
||||||
idf.setExtraEnvVars(env);
|
|
||||||
idf.setUseConnectionPool(false); // coverage purposes only
|
|
||||||
|
|
||||||
try {
|
|
||||||
idf.newInitialDirContext();
|
|
||||||
fail("Connection succeeded unexpectedly");
|
|
||||||
} catch (UncategorizedLdapException expected) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEnvironment() {
|
|
||||||
idf = new DefaultInitialDirContextFactory("ldap://springsecurity.org/");
|
|
||||||
|
|
||||||
// check basic env
|
|
||||||
Hashtable env = idf.getEnvironment();
|
|
||||||
//assertEquals("com.sun.jndi.ldap.LdapCtxFactory", env.get(Context.INITIAL_CONTEXT_FACTORY));
|
|
||||||
assertEquals("ldap://springsecurity.org/", env.get(Context.PROVIDER_URL));
|
|
||||||
assertEquals("simple", env.get(Context.SECURITY_AUTHENTICATION));
|
|
||||||
assertNull(env.get(Context.SECURITY_PRINCIPAL));
|
|
||||||
assertNull(env.get(Context.SECURITY_CREDENTIALS));
|
|
||||||
|
|
||||||
// Ctx factory.
|
|
||||||
idf.setInitialContextFactory("org.springframework.security.NonExistentCtxFactory");
|
|
||||||
env = idf.getEnvironment();
|
|
||||||
assertEquals("org.springframework.security.NonExistentCtxFactory", env.get(Context.INITIAL_CONTEXT_FACTORY));
|
|
||||||
|
|
||||||
// Auth type
|
|
||||||
idf.setAuthenticationType("myauthtype");
|
|
||||||
env = idf.getEnvironment();
|
|
||||||
assertEquals("myauthtype", env.get(Context.SECURITY_AUTHENTICATION));
|
|
||||||
|
|
||||||
// Check extra vars
|
|
||||||
Hashtable extraVars = new Hashtable();
|
|
||||||
extraVars.put("extravar", "extravarvalue");
|
|
||||||
idf.setExtraEnvVars(extraVars);
|
|
||||||
env = idf.getEnvironment();
|
|
||||||
assertEquals("extravarvalue", env.get("extravar"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testInvalidPasswordCausesBadCredentialsException() throws Exception {
|
|
||||||
idf.setManagerDn("uid=bob,ou=people,dc=springframework,dc=org");
|
|
||||||
idf.setManagerPassword("wrongpassword");
|
|
||||||
|
|
||||||
DirContext ctx = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
ctx = idf.newInitialDirContext();
|
|
||||||
fail("Binding with wrong credentials should fail.");
|
|
||||||
} catch (BadCredentialsException expected) {}
|
|
||||||
|
|
||||||
LdapUtils.closeContext(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMultipleProviderUrlsAreAccepted() {
|
|
||||||
idf = new DefaultInitialDirContextFactory("ldaps://security.org/dc=springframework,dc=org "
|
|
||||||
+ "ldap://monkeymachine.co.uk/dc=springframework,dc=org");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMultipleProviderUrlsWithDifferentRootsAreRejected() {
|
|
||||||
try {
|
|
||||||
idf = new DefaultInitialDirContextFactory("ldap://security.org/dc=springframework,dc=org "
|
|
||||||
+ "ldap://monkeymachine.co.uk/dc=someotherplace,dc=org");
|
|
||||||
fail("Different root DNs should cause an exception");
|
|
||||||
} catch (IllegalArgumentException expected) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSecureLdapUrlIsSupported() {
|
|
||||||
idf = new DefaultInitialDirContextFactory("ldaps://localhost/dc=springframework,dc=org");
|
|
||||||
assertEquals("dc=springframework,dc=org", idf.getRootDn());
|
|
||||||
}
|
|
||||||
|
|
||||||
// public void testNonLdapUrlIsRejected() throws Exception {
|
|
||||||
// DefaultInitialDirContextFactory idf = new DefaultInitialDirContextFactory();
|
|
||||||
//
|
|
||||||
// idf.setUrl("http://security.org/dc=springframework,dc=org");
|
|
||||||
// idf.setInitialContextFactory(CoreContextFactory.class.getName());
|
|
||||||
//
|
|
||||||
// try {
|
|
||||||
// idf.afterPropertiesSet();
|
|
||||||
// fail("Expected exception for non 'ldap://' URL");
|
|
||||||
// } catch(IllegalArgumentException expected) {
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@Test
|
|
||||||
public void testServiceLocationUrlIsSupported() {
|
|
||||||
idf = new DefaultInitialDirContextFactory("ldap:///dc=springframework,dc=org");
|
|
||||||
assertEquals("dc=springframework,dc=org", idf.getRootDn());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -15,18 +15,20 @@
|
||||||
|
|
||||||
package org.springframework.security.ldap;
|
package org.springframework.security.ldap;
|
||||||
|
|
||||||
import org.springframework.dao.DataAccessException;
|
|
||||||
import org.springframework.ldap.core.DistinguishedName;
|
|
||||||
|
|
||||||
import javax.naming.directory.DirContext;
|
import javax.naming.directory.DirContext;
|
||||||
|
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
|
import org.springframework.ldap.NamingException;
|
||||||
|
import org.springframework.ldap.core.DistinguishedName;
|
||||||
|
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
*/
|
*/
|
||||||
public class MockSpringSecurityContextSource implements SpringSecurityContextSource {
|
public class MockSpringSecurityContextSource implements BaseLdapPathContextSource {
|
||||||
//~ Instance fields ================================================================================================
|
//~ Instance fields ================================================================================================
|
||||||
|
|
||||||
private DirContext ctx;
|
private DirContext ctx;
|
||||||
|
@ -52,7 +54,7 @@ public class MockSpringSecurityContextSource implements SpringSecurityContextSou
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DirContext getReadWriteContext(String userDn, Object credentials) {
|
public DirContext getContext(String principal, String credentials) throws NamingException {
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,8 +64,8 @@ public class SpringSecurityAuthenticationSourceTests {
|
||||||
user.setDn(new DistinguishedName("uid=joe,ou=users"));
|
user.setDn(new DistinguishedName("uid=joe,ou=users"));
|
||||||
AuthenticationSource source = new SpringSecurityAuthenticationSource();
|
AuthenticationSource source = new SpringSecurityAuthenticationSource();
|
||||||
SecurityContextHolder.getContext().setAuthentication(
|
SecurityContextHolder.getContext().setAuthentication(
|
||||||
new TestingAuthenticationToken(user.createUserDetails(), null));
|
new TestingAuthenticationToken(user.createUserDetails(), null));
|
||||||
|
|
||||||
assertEquals("uid=joe, ou=users", source.getPrincipal());
|
assertEquals("uid=joe,ou=users", source.getPrincipal());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ public class PasswordComparisonAuthenticatorMockTests {
|
||||||
final Attributes searchResults = new BasicAttributes("", null);
|
final Attributes searchResults = new BasicAttributes("", null);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
oneOf(dirCtx).search(with(equal("cn=Bob, ou=people")),
|
oneOf(dirCtx).search(with(equal("cn=Bob,ou=people")),
|
||||||
with(equal("(userPassword={0})")),
|
with(equal("(userPassword={0})")),
|
||||||
with(aNonNull(Object[].class)),
|
with(aNonNull(Object[].class)),
|
||||||
with(aNonNull(SearchControls.class)));
|
with(aNonNull(SearchControls.class)));
|
||||||
|
|
|
@ -95,7 +95,7 @@ public class LdapUserDetailsManagerTests extends AbstractLdapIntegrationTests {
|
||||||
mgr.setGroupSearchBase("ou=groups");
|
mgr.setGroupSearchBase("ou=groups");
|
||||||
LdapUserDetails bob = (LdapUserDetails) mgr.loadUserByUsername("bob");
|
LdapUserDetails bob = (LdapUserDetails) mgr.loadUserByUsername("bob");
|
||||||
assertEquals("bob", bob.getUsername());
|
assertEquals("bob", bob.getUsername());
|
||||||
assertEquals("uid=bob, ou=people, dc=springframework, dc=org", bob.getDn());
|
assertEquals("uid=bob,ou=people,dc=springframework,dc=org", bob.getDn());
|
||||||
assertEquals("bobspassword", bob.getPassword());
|
assertEquals("bobspassword", bob.getPassword());
|
||||||
|
|
||||||
assertEquals(1, bob.getAuthorities().size());
|
assertEquals(1, bob.getAuthorities().size());
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
|
||||||
xmlns:security="http://www.springframework.org/schema/security"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
|
||||||
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
|
|
||||||
|
|
||||||
<security:ldap-server port="53389" ldif="classpath:test-server.ldif"/>
|
|
||||||
|
|
||||||
<!--<import resource="classpath:/org/springframework/security/ldap/apacheDsContext.xml"/>-->
|
|
||||||
|
|
||||||
<bean id="initialDirContextFactory" class="org.springframework.security.ldap.DefaultInitialDirContextFactory" >
|
|
||||||
<constructor-arg value="ldap://127.0.0.1:53389/dc=springframework,dc=org"/>
|
|
||||||
<property name="useLdapContext" value="true"/>
|
|
||||||
<property name="dirObjectFactory" value="org.springframework.ldap.core.support.DefaultDirObjectFactory" />
|
|
||||||
</bean>
|
|
||||||
|
|
||||||
</beans>
|
|
Loading…
Reference in New Issue