Added getContext(principal, credentials) method to ContextSource to enable explicit authentication.

Refactored AbstractContextSource to enable the new method and so that DirContextAuthenticationStrategy does not interfere with anonymous contexts.
Changed defaults in integraion-tests-openldap to target server spring-ldap-test.dyndns.org and use TLS.
This commit is contained in:
Mattias Arthursson
2008-08-18 18:51:58 +00:00
parent a2fdf4e695
commit a0da075ec4
9 changed files with 619 additions and 589 deletions

View File

@@ -21,7 +21,10 @@ import javax.naming.directory.DirContext;
import org.springframework.ldap.NamingException;
/**
* Interface used by {@link LdapTemplate} to create LDAP contexts.
* A <code>ContextSource</code> is responsible for configuring and creating
* <code>DirContext</code> instances. It is typically used from
* {@link LdapTemplate} to acquiring contexts for LDAP operations, but may be
* used standalone to perform LDAP authentication.
*
* @see org.springframework.ldap.core.LdapTemplate
*
@@ -30,22 +33,34 @@ import org.springframework.ldap.NamingException;
*/
public interface ContextSource {
/**
* Gets a read-only DirContext. The returned DirContext must be possible to
* perform read-only operations on.
*
* @return A DirContext instance, never null.
* @throws NamingException
* if some error occurs creating an DirContext.
*/
public DirContext getReadOnlyContext() throws NamingException;
/**
* Gets a read-only <code>DirContext</code>. The returned
* <code>DirContext</code> must be possible to perform read-only operations
* on.
*
* @return A DirContext instance, never null.
* @throws NamingException if some error occurs creating an DirContext.
*/
public DirContext getReadOnlyContext() throws NamingException;
/**
* Gets a read-write DirContext.
*
* @return A DirContext instance, never null.
* @throws NamingException
* if some error occurs creating an DirContext.
*/
public DirContext getReadWriteContext() throws NamingException;
/**
* Gets a read-write <code>DirContext</code> instance.
*
* @return A <code>DirContext</code> instance, never <code>null</code>.
* @throws NamingException if some error occurs creating an
* <code>DirContext</code>.
*/
public DirContext getReadWriteContext() throws NamingException;
/**
* Gets a <code>DirContext</code> instance authenticated using the supplied
* principal and credentials.
*
* @param principal The principal (typically a distinguished name of a user
* in the LDAP tree) to use for authentication.
* @param credentials The credentials to use for authentication.
* @return an authenticated <code>DirContext</code> instance, never
* <code>null</code>.
*/
public DirContext getContext(String principal, String credentials) throws NamingException;
}

View File

@@ -38,15 +38,16 @@ import org.springframework.ldap.support.LdapUtils;
* returns an authenticated
* <code>DirContext<code> implementation for both read-only and
* read-write operations. To have an anonymous environment created for read-only
* operations, set the <code>anonymousReadOnly</code> property to <code>true</code>.
* operations, set the <code>anonymousReadOnly</code> property to
* <code>true</code>.
* <p>
* Implementing classes need to implement
* {@link #getDirContextInstance(Hashtable)} to create a <code>DirContext</code> instance of
* the desired type.
* {@link #getDirContextInstance(Hashtable)} to create a <code>DirContext</code>
* instance of the desired type.
* <p>
* If an {@link AuthenticationSource} is set, this will be used for getting user principal
* and password for each new connection, otherwise a default one will be created
* using the specified <code>userDn<code> and <code>password</code>.
* If an {@link AuthenticationSource} is set, this will be used for getting user
* principal and password for each new connection, otherwise a default one will
* be created using the specified <code>userDn<code> and <code>password</code>.
* <p>
* <b>Note:</b> When using implementations of this class outside of a Spring
* Context it is necessary to call {@link #afterPropertiesSet()} when all
@@ -99,6 +100,19 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource
private DirContextAuthenticationStrategy authenticationStrategy = new SimpleDirContextAuthenticationStrategy();
public DirContext getContext(String principal, String credentials) {
DirContext ctx = createContext(getAuthenticatedEnv(principal, credentials));
try {
authenticationStrategy.processContextAfterCreation(ctx, principal, credentials);
return ctx;
}
catch (NamingException e) {
closeContext(ctx);
throw LdapUtils.convertLdapException(e);
}
}
/*
* (non-Javadoc)
*
@@ -106,7 +120,7 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource
*/
public DirContext getReadOnlyContext() {
if (!anonymousReadOnly) {
return createContext(getAuthenticatedEnv());
return getContext(authenticationSource.getPrincipal(), authenticationSource.getCredentials());
}
else {
return createContext(getAnonymousEnv());
@@ -119,7 +133,7 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource
* @see org.springframework.ldap.core.ContextSource#getReadWriteContext()
*/
public DirContext getReadWriteContext() {
return createContext(getAuthenticatedEnv());
return getContext(authenticationSource.getPrincipal(), authenticationSource.getCredentials());
}
/**
@@ -129,13 +143,14 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource
* {@link DirContextAuthenticationStrategy} on this instance.
*
* @param env the environment to modify.
* @param principal the principal to authenticate with.
* @param credentials the credentials to authenticate with.
* @see DirContextAuthenticationStrategy
* @see #setAuthenticationStrategy(DirContextAuthenticationStrategy)
*/
protected void setupAuthenticatedEnvironment(Hashtable env) {
protected void setupAuthenticatedEnvironment(Hashtable env, String principal, String credentials) {
try {
authenticationStrategy.setupEnvironment(env, authenticationSource.getPrincipal(), authenticationSource
.getCredentials());
authenticationStrategy.setupEnvironment(env, principal, credentials);
}
catch (NamingException e) {
throw LdapUtils.convertLdapException(e);
@@ -203,7 +218,10 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource
/*
* (non-Javadoc)
* @see org.springframework.ldap.core.support.BaseLdapPathSource#getBaseLdapPath()
*
* @see
* org.springframework.ldap.core.support.BaseLdapPathSource#getBaseLdapPath
* ()
*/
public DistinguishedName getBaseLdapPath() {
return getBase().immutableDistinguishedName();
@@ -211,7 +229,9 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource
/*
* (non-Javadoc)
* @see org.springframework.ldap.core.support.BaseLdapPathSource#getBaseLdapPathAsString()
*
* @seeorg.springframework.ldap.core.support.BaseLdapPathSource#
* getBaseLdapPathAsString()
*/
public String getBaseLdapPathAsString() {
return getBaseLdapPath().toString();
@@ -231,9 +251,6 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource
try {
ctx = getDirContextInstance(environment);
authenticationStrategy.processContextAfterCreation(ctx, authenticationSource.getPrincipal(),
authenticationSource.getCredentials());
if (log.isInfoEnabled()) {
Hashtable ctxEnv = ctx.getEnvironment();
String ldapUrl = (String) ctxEnv.get(Context.PROVIDER_URL);
@@ -283,8 +300,8 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource
/**
* Get the DirObjectFactory to use.
*
* @return the DirObjectFactory to be used. <code>null</code> means that
* no DirObjectFactory will be used.
* @return the DirObjectFactory to be used. <code>null</code> means that no
* DirObjectFactory will be used.
*/
public Class getDirObjectFactory() {
return dirObjectFactory;
@@ -445,10 +462,10 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource
}
}
protected Hashtable getAuthenticatedEnv() {
protected Hashtable getAuthenticatedEnv(String principal, String credentials) {
// The authenticated environment should always be rebuilt.
Hashtable env = new Hashtable(getAnonymousEnv());
setupAuthenticatedEnvironment(env);
setupAuthenticatedEnvironment(env, principal, credentials);
return env;
}
@@ -502,8 +519,8 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource
* Get whether an anonymous environment should be used for read-only
* operations.
*
* @return <code>true</code> if an anonymous environment should be used
* for read-only operations, <code>false</code> otherwise.
* @return <code>true</code> if an anonymous environment should be used for
* read-only operations, <code>false</code> otherwise.
*/
public boolean isAnonymousReadOnly() {
return anonymousReadOnly;
@@ -511,8 +528,7 @@ public abstract class AbstractContextSource implements BaseLdapPathContextSource
/**
* Set the {@link DirContextAuthenticationStrategy} to use for preparing the
* environment and processing the created <code>DirContext</code>
* instances.
* environment and processing the created <code>DirContext</code> instances.
*
* @param authenticationStrategy the
* {@link DirContextAuthenticationStrategy} to use; default is

View File

@@ -32,375 +32,408 @@ import org.springframework.ldap.pool.DirContextType;
import org.springframework.ldap.pool.validation.DirContextValidator;
/**
* A {@link ContextSource} implementation that wraps an object pool and another {@link ContextSource}.
* {@link DirContext}s are retrieved from the pool which maintains them.
* A {@link ContextSource} implementation that wraps an object pool and another
* {@link ContextSource}. {@link DirContext}s are retrieved from the pool which
* maintains them.
*
*
* <br>
* <br>
* Configuration:
* <table border="1">
* <tr>
* <th align="left">Property</th>
* <th align="left">Description</th>
* <th align="left">Required</th>
* <th align="left">Default</th>
* </tr>
* <tr>
* <td valign="top">contextSource</td>
* <td valign="top">
* The {@link ContextSource} to get {@link DirContext}s from for adding to the pool.
* </td>
* <td valign="top">Yes</td>
* <td valign="top">null</td>
* </tr>
* <tr>
* <td valign="top">dirContextValidator</td>
* <td valign="top">
* The {@link DirContextValidator} to use for validating {@link DirContext}s. Required
* if any of the test/validate options are enabled.
* </td>
* <td valign="top">No</td>
* <td valign="top">null</td>
* </tr>
* <tr>
* <td valign="top">minIdle</td>
* <td valign="top">{@link GenericKeyedObjectPool#setMinIdle(int)}</td>
* <td valign="top">No</td>
* <td valign="top">0</td>
* </tr>
* <tr>
* <td valign="top">maxIdle</td>
* <td valign="top">{@link GenericKeyedObjectPool#setMaxIdle(int)}</td>
* <td valign="top">No</td>
* <td valign="top">8</td>
* </tr>
* <tr>
* <td valign="top">maxActive</td>
* <td valign="top">{@link GenericKeyedObjectPool#setMaxActive(int)}</td>
* <td valign="top">No</td>
* <td valign="top">8</td>
* </tr>
* <tr>
* <td valign="top">maxTotal</td>
* <td valign="top">{@link GenericKeyedObjectPool#setMaxTotal(int)}</td>
* <td valign="top">No</td>
* <td valign="top">-1</td>
* </tr>
* <tr>
* <td valign="top">maxWait</td>
* <td valign="top">{@link GenericKeyedObjectPool#setMaxWait(long)}</td>
* <td valign="top">No</td>
* <td valign="top">-1L</td>
* </tr>
* <tr>
* <td valign="top">whenExhaustedAction</td>
* <td valign="top">{@link GenericKeyedObjectPool#setWhenExhaustedAction(byte)}</td>
* <td valign="top">No</td>
* <td valign="top">{@link GenericKeyedObjectPool#WHEN_EXHAUSTED_BLOCK}</td>
* </tr>
* <tr>
* <td valign="top">testOnBorrow</td>
* <td valign="top">{@link GenericKeyedObjectPool#setTestOnBorrow(boolean)}</td>
* <td valign="top">No</td>
* <td valign="top">false</td>
* </tr>
* <tr>
* <td valign="top">testOnReturn</td>
* <td valign="top">{@link GenericKeyedObjectPool#setTestOnReturn(boolean)}</td>
* <td valign="top">No</td>
* <td valign="top">false</td>
* </tr>
* <tr>
* <td valign="top">testWhileIdle</td>
* <td valign="top">{@link GenericKeyedObjectPool#setTestWhileIdle(boolean)}</td>
* <td valign="top">No</td>
* <td valign="top">false</td>
* </tr>
* <tr>
* <td valign="top">timeBetweenEvictionRunsMillis</td>
* <td valign="top">{@link GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis(long)}</td>
* <td valign="top">No</td>
* <td valign="top">-1L</td>
* </tr>
* <tr>
* <td valign="top">minEvictableIdleTimeMillis</td>
* <td valign="top">{@link GenericKeyedObjectPool#setMinEvictableIdleTimeMillis(long)}</td>
* <td valign="top">No</td>
* <td valign="top">1000L * 60L * 30L</td>
* </tr>
* <tr>
* <td valign="top">numTestsPerEvictionRun</td>
* <td valign="top">{@link GenericKeyedObjectPool#setNumTestsPerEvictionRun(int)}</td>
* <td valign="top">No</td>
* <td valign="top">3</td>
* </tr>
* <tr>
* <th align="left">Property</th> <th align="left">Description</th> <th
* align="left">Required</th> <th align="left">Default</th>
* </tr>
* <tr>
* <td valign="top">contextSource</td>
* <td valign="top">
* The {@link ContextSource} to get {@link DirContext}s from for adding to the
* pool.</td>
* <td valign="top">Yes</td>
* <td valign="top">null</td>
* </tr>
* <tr>
* <td valign="top">dirContextValidator</td>
* <td valign="top">
* The {@link DirContextValidator} to use for validating {@link DirContext}s.
* Required if any of the test/validate options are enabled.</td>
* <td valign="top">No</td>
* <td valign="top">null</td>
* </tr>
* <tr>
* <td valign="top">minIdle</td>
* <td valign="top">{@link GenericKeyedObjectPool#setMinIdle(int)}</td>
* <td valign="top">No</td>
* <td valign="top">0</td>
* </tr>
* <tr>
* <td valign="top">maxIdle</td>
* <td valign="top">{@link GenericKeyedObjectPool#setMaxIdle(int)}</td>
* <td valign="top">No</td>
* <td valign="top">8</td>
* </tr>
* <tr>
* <td valign="top">maxActive</td>
* <td valign="top">{@link GenericKeyedObjectPool#setMaxActive(int)}</td>
* <td valign="top">No</td>
* <td valign="top">8</td>
* </tr>
* <tr>
* <td valign="top">maxTotal</td>
* <td valign="top">{@link GenericKeyedObjectPool#setMaxTotal(int)}</td>
* <td valign="top">No</td>
* <td valign="top">-1</td>
* </tr>
* <tr>
* <td valign="top">maxWait</td>
* <td valign="top">{@link GenericKeyedObjectPool#setMaxWait(long)}</td>
* <td valign="top">No</td>
* <td valign="top">-1L</td>
* </tr>
* <tr>
* <td valign="top">whenExhaustedAction</td>
* <td valign="top">{@link GenericKeyedObjectPool#setWhenExhaustedAction(byte)}</td>
* <td valign="top">No</td>
* <td valign="top">{@link GenericKeyedObjectPool#WHEN_EXHAUSTED_BLOCK}</td>
* </tr>
* <tr>
* <td valign="top">testOnBorrow</td>
* <td valign="top">{@link GenericKeyedObjectPool#setTestOnBorrow(boolean)}</td>
* <td valign="top">No</td>
* <td valign="top">false</td>
* </tr>
* <tr>
* <td valign="top">testOnReturn</td>
* <td valign="top">{@link GenericKeyedObjectPool#setTestOnReturn(boolean)}</td>
* <td valign="top">No</td>
* <td valign="top">false</td>
* </tr>
* <tr>
* <td valign="top">testWhileIdle</td>
* <td valign="top">{@link GenericKeyedObjectPool#setTestWhileIdle(boolean)}</td>
* <td valign="top">No</td>
* <td valign="top">false</td>
* </tr>
* <tr>
* <td valign="top">timeBetweenEvictionRunsMillis</td>
* <td valign="top">
* {@link GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis(long)}</td>
* <td valign="top">No</td>
* <td valign="top">-1L</td>
* </tr>
* <tr>
* <td valign="top">minEvictableIdleTimeMillis</td>
* <td valign="top">
* {@link GenericKeyedObjectPool#setMinEvictableIdleTimeMillis(long)}</td>
* <td valign="top">No</td>
* <td valign="top">1000L * 60L * 30L</td>
* </tr>
* <tr>
* <td valign="top">numTestsPerEvictionRun</td>
* <td valign="top">
* {@link GenericKeyedObjectPool#setNumTestsPerEvictionRun(int)}</td>
* <td valign="top">No</td>
* <td valign="top">3</td>
* </tr>
* </table>
*
*
* @author Eric Dalquist
*/
public class PoolingContextSource implements ContextSource, DisposableBean {
/**
* The logger for this class and sub-classes
*/
protected final Log logger = LogFactory.getLog(this.getClass());
protected final GenericKeyedObjectPool keyedObjectPool;
private final DirContextPoolableObjectFactory dirContextPoolableObjectFactory;
/**
* Creates a new pooling context source, setting up the DirContext object factory
* and generic keyed object pool.
*/
public PoolingContextSource() {
this.dirContextPoolableObjectFactory = new DirContextPoolableObjectFactory();
this.keyedObjectPool = new GenericKeyedObjectPool();
this.keyedObjectPool.setFactory(this.dirContextPoolableObjectFactory);
}
//***** Pool Property Configuration *****//
/**
* The logger for this class and sub-classes
*/
protected final Log logger = LogFactory.getLog(this.getClass());
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxActive()
*/
public int getMaxActive() {
return this.keyedObjectPool.getMaxActive();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxIdle()
*/
public int getMaxIdle() {
return this.keyedObjectPool.getMaxIdle();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxTotal()
*/
public int getMaxTotal() {
return this.keyedObjectPool.getMaxTotal();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxWait()
*/
public long getMaxWait() {
return this.keyedObjectPool.getMaxWait();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMinEvictableIdleTimeMillis()
*/
public long getMinEvictableIdleTimeMillis() {
return this.keyedObjectPool.getMinEvictableIdleTimeMillis();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMinIdle()
*/
public int getMinIdle() {
return this.keyedObjectPool.getMinIdle();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getNumActive()
*/
public int getNumActive() {
return this.keyedObjectPool.getNumActive();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getNumIdle()
*/
public int getNumIdle() {
return this.keyedObjectPool.getNumIdle();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getNumTestsPerEvictionRun()
*/
public int getNumTestsPerEvictionRun() {
return this.keyedObjectPool.getNumTestsPerEvictionRun();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTestOnBorrow()
*/
public boolean getTestOnBorrow() {
return this.keyedObjectPool.getTestOnBorrow();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTestOnReturn()
*/
public boolean getTestOnReturn() {
return this.keyedObjectPool.getTestOnReturn();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTestWhileIdle()
*/
public boolean getTestWhileIdle() {
return this.keyedObjectPool.getTestWhileIdle();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis()
*/
public long getTimeBetweenEvictionRunsMillis() {
return this.keyedObjectPool.getTimeBetweenEvictionRunsMillis();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getWhenExhaustedAction()
*/
public byte getWhenExhaustedAction() {
return this.keyedObjectPool.getWhenExhaustedAction();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxActive(int)
*/
public void setMaxActive(int maxActive) {
this.keyedObjectPool.setMaxActive(maxActive);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxIdle(int)
*/
public void setMaxIdle(int maxIdle) {
this.keyedObjectPool.setMaxIdle(maxIdle);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxTotal(int)
*/
public void setMaxTotal(int maxTotal) {
this.keyedObjectPool.setMaxTotal(maxTotal);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxWait(long)
*/
public void setMaxWait(long maxWait) {
this.keyedObjectPool.setMaxWait(maxWait);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMinEvictableIdleTimeMillis(long)
*/
public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
this.keyedObjectPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMinIdle(int)
*/
public void setMinIdle(int poolSize) {
this.keyedObjectPool.setMinIdle(poolSize);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setNumTestsPerEvictionRun(int)
*/
public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
this.keyedObjectPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTestOnBorrow(boolean)
*/
public void setTestOnBorrow(boolean testOnBorrow) {
this.keyedObjectPool.setTestOnBorrow(testOnBorrow);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTestOnReturn(boolean)
*/
public void setTestOnReturn(boolean testOnReturn) {
this.keyedObjectPool.setTestOnReturn(testOnReturn);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTestWhileIdle(boolean)
*/
public void setTestWhileIdle(boolean testWhileIdle) {
this.keyedObjectPool.setTestWhileIdle(testWhileIdle);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis(long)
*/
public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
this.keyedObjectPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setWhenExhaustedAction(byte)
*/
public void setWhenExhaustedAction(byte whenExhaustedAction) {
this.keyedObjectPool.setWhenExhaustedAction(whenExhaustedAction);
}
//***** Object Factory Property Configuration *****//
/**
* @return the contextSource
*/
public ContextSource getContextSource() {
return this.dirContextPoolableObjectFactory.getContextSource();
}
/**
* @return the dirContextValidator
*/
public DirContextValidator getDirContextValidator() {
return this.dirContextPoolableObjectFactory.getDirContextValidator();
}
/**
* @param contextSource the contextSource to set
* @Required
*/
public void setContextSource(ContextSource contextSource) {
this.dirContextPoolableObjectFactory.setContextSource(contextSource);
}
/**
* @param dirContextValidator the dirContextValidator to set
* @Required
*/
public void setDirContextValidator(DirContextValidator dirContextValidator) {
this.dirContextPoolableObjectFactory.setDirContextValidator(dirContextValidator);
}
protected final GenericKeyedObjectPool keyedObjectPool;
//***** DisposableBean interface methods *****//
private final DirContextPoolableObjectFactory dirContextPoolableObjectFactory;
/* (non-Javadoc)
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
public void destroy() throws Exception {
try {
this.keyedObjectPool.close();
}
catch (Exception e) {
this.logger.warn("An exception occured while closing the underlying pool.", e);
}
}
//***** ContextSource interface methods *****//
/*
* @see ContextSource#getReadOnlyContext()
*/
public DirContext getReadOnlyContext() throws NamingException {
return this.getContext(DirContextType.READ_ONLY);
}
/**
* Creates a new pooling context source, setting up the DirContext object
* factory and generic keyed object pool.
*/
public PoolingContextSource() {
this.dirContextPoolableObjectFactory = new DirContextPoolableObjectFactory();
this.keyedObjectPool = new GenericKeyedObjectPool();
this.keyedObjectPool.setFactory(this.dirContextPoolableObjectFactory);
}
/*
* @see ContextSource#getReadWriteContext()
*/
public DirContext getReadWriteContext() throws NamingException {
return this.getContext(DirContextType.READ_WRITE);
}
// ***** Pool Property Configuration *****//
/**
* Gets a DirContext of the specified type from the keyed object pool.
*
* @param dirContextType The type of context to return.
* @return A wrapped DirContext of the specified type.
* @throws DataAccessResourceFailureException If retreiving the object from the pool throws an exception
*/
protected DirContext getContext(DirContextType dirContextType) {
final DirContext dirContext;
try {
dirContext = (DirContext)this.keyedObjectPool.borrowObject(dirContextType);
}
catch (Exception e) {
throw new DataAccessResourceFailureException("Failed to borrow DirContext from pool.", e);
}
if (dirContext instanceof LdapContext) {
return new DelegatingLdapContext(this.keyedObjectPool, (LdapContext)dirContext, dirContextType);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxActive()
*/
public int getMaxActive() {
return this.keyedObjectPool.getMaxActive();
}
return new DelegatingDirContext(this.keyedObjectPool, dirContext, dirContextType);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxIdle()
*/
public int getMaxIdle() {
return this.keyedObjectPool.getMaxIdle();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxTotal()
*/
public int getMaxTotal() {
return this.keyedObjectPool.getMaxTotal();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMaxWait()
*/
public long getMaxWait() {
return this.keyedObjectPool.getMaxWait();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMinEvictableIdleTimeMillis()
*/
public long getMinEvictableIdleTimeMillis() {
return this.keyedObjectPool.getMinEvictableIdleTimeMillis();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getMinIdle()
*/
public int getMinIdle() {
return this.keyedObjectPool.getMinIdle();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getNumActive()
*/
public int getNumActive() {
return this.keyedObjectPool.getNumActive();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getNumIdle()
*/
public int getNumIdle() {
return this.keyedObjectPool.getNumIdle();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getNumTestsPerEvictionRun()
*/
public int getNumTestsPerEvictionRun() {
return this.keyedObjectPool.getNumTestsPerEvictionRun();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTestOnBorrow()
*/
public boolean getTestOnBorrow() {
return this.keyedObjectPool.getTestOnBorrow();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTestOnReturn()
*/
public boolean getTestOnReturn() {
return this.keyedObjectPool.getTestOnReturn();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTestWhileIdle()
*/
public boolean getTestWhileIdle() {
return this.keyedObjectPool.getTestWhileIdle();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getTimeBetweenEvictionRunsMillis()
*/
public long getTimeBetweenEvictionRunsMillis() {
return this.keyedObjectPool.getTimeBetweenEvictionRunsMillis();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#getWhenExhaustedAction()
*/
public byte getWhenExhaustedAction() {
return this.keyedObjectPool.getWhenExhaustedAction();
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxActive(int)
*/
public void setMaxActive(int maxActive) {
this.keyedObjectPool.setMaxActive(maxActive);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxIdle(int)
*/
public void setMaxIdle(int maxIdle) {
this.keyedObjectPool.setMaxIdle(maxIdle);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxTotal(int)
*/
public void setMaxTotal(int maxTotal) {
this.keyedObjectPool.setMaxTotal(maxTotal);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMaxWait(long)
*/
public void setMaxWait(long maxWait) {
this.keyedObjectPool.setMaxWait(maxWait);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMinEvictableIdleTimeMillis(long)
*/
public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
this.keyedObjectPool.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setMinIdle(int)
*/
public void setMinIdle(int poolSize) {
this.keyedObjectPool.setMinIdle(poolSize);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setNumTestsPerEvictionRun(int)
*/
public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
this.keyedObjectPool.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTestOnBorrow(boolean)
*/
public void setTestOnBorrow(boolean testOnBorrow) {
this.keyedObjectPool.setTestOnBorrow(testOnBorrow);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTestOnReturn(boolean)
*/
public void setTestOnReturn(boolean testOnReturn) {
this.keyedObjectPool.setTestOnReturn(testOnReturn);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTestWhileIdle(boolean)
*/
public void setTestWhileIdle(boolean testWhileIdle) {
this.keyedObjectPool.setTestWhileIdle(testWhileIdle);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setTimeBetweenEvictionRunsMillis(long)
*/
public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
this.keyedObjectPool.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
}
/**
* @see org.apache.commons.pool.impl.GenericKeyedObjectPool#setWhenExhaustedAction(byte)
*/
public void setWhenExhaustedAction(byte whenExhaustedAction) {
this.keyedObjectPool.setWhenExhaustedAction(whenExhaustedAction);
}
// ***** Object Factory Property Configuration *****//
/**
* @return the contextSource
*/
public ContextSource getContextSource() {
return this.dirContextPoolableObjectFactory.getContextSource();
}
/**
* @return the dirContextValidator
*/
public DirContextValidator getDirContextValidator() {
return this.dirContextPoolableObjectFactory.getDirContextValidator();
}
/**
* @param contextSource the contextSource to set
* @Required
*/
public void setContextSource(ContextSource contextSource) {
this.dirContextPoolableObjectFactory.setContextSource(contextSource);
}
/**
* @param dirContextValidator the dirContextValidator to set
* @Required
*/
public void setDirContextValidator(DirContextValidator dirContextValidator) {
this.dirContextPoolableObjectFactory.setDirContextValidator(dirContextValidator);
}
// ***** DisposableBean interface methods *****//
/*
* (non-Javadoc)
*
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
public void destroy() throws Exception {
try {
this.keyedObjectPool.close();
}
catch (Exception e) {
this.logger.warn("An exception occured while closing the underlying pool.", e);
}
}
// ***** ContextSource interface methods *****//
/*
* @see ContextSource#getReadOnlyContext()
*/
public DirContext getReadOnlyContext() throws NamingException {
return this.getContext(DirContextType.READ_ONLY);
}
/*
* @see ContextSource#getReadWriteContext()
*/
public DirContext getReadWriteContext() throws NamingException {
return this.getContext(DirContextType.READ_WRITE);
}
/**
* Gets a DirContext of the specified type from the keyed object pool.
*
* @param dirContextType The type of context to return.
* @return A wrapped DirContext of the specified type.
* @throws DataAccessResourceFailureException If retreiving the object from
* the pool throws an exception
*/
protected DirContext getContext(DirContextType dirContextType) {
final DirContext dirContext;
try {
dirContext = (DirContext) this.keyedObjectPool.borrowObject(dirContextType);
}
catch (Exception e) {
throw new DataAccessResourceFailureException("Failed to borrow DirContext from pool.", e);
}
if (dirContext instanceof LdapContext) {
return new DelegatingLdapContext(this.keyedObjectPool, (LdapContext) dirContext, dirContextType);
}
return new DelegatingDirContext(this.keyedObjectPool, dirContext, dirContextType);
}
public DirContext getContext(String principal, String credentials) throws NamingException {
throw new UnsupportedOperationException("Not supported for this implementation");
}
}

View File

@@ -40,155 +40,144 @@ import org.springframework.transaction.compensating.CompensatingTransactionOpera
* @author Mattias Arthursson
* @since 1.2
*/
public class LdapCompensatingTransactionOperationFactory implements
CompensatingTransactionOperationFactory {
private static Log log = LogFactory
.getLog(LdapCompensatingTransactionOperationFactory.class);
public class LdapCompensatingTransactionOperationFactory implements CompensatingTransactionOperationFactory {
private static Log log = LogFactory.getLog(LdapCompensatingTransactionOperationFactory.class);
private TempEntryRenamingStrategy renamingStrategy;
private TempEntryRenamingStrategy renamingStrategy;
/**
* Constructor.
*
* @param renamingStrategy
* the {@link TempEntryRenamingStrategy} to supply to relevant
* operations.
*/
public LdapCompensatingTransactionOperationFactory(
TempEntryRenamingStrategy renamingStrategy) {
this.renamingStrategy = renamingStrategy;
}
/**
* Constructor.
*
* @param renamingStrategy the {@link TempEntryRenamingStrategy} to supply
* to relevant operations.
*/
public LdapCompensatingTransactionOperationFactory(TempEntryRenamingStrategy renamingStrategy) {
this.renamingStrategy = renamingStrategy;
}
/*
* @see org.springframework.transaction.compensating.CompensatingTransactionOperationFactory#createRecordingOperation(java.lang.Object,
* java.lang.String)
*/
public CompensatingTransactionOperationRecorder createRecordingOperation(
Object resource, String operation) {
if (StringUtils
.equals(operation, LdapTransactionUtils.BIND_METHOD_NAME)) {
log.debug("Bind operation recorded");
return new BindOperationRecorder(
createLdapOperationsInstance((DirContext) resource));
} else if (StringUtils.equals(operation,
LdapTransactionUtils.REBIND_METHOD_NAME)) {
log.debug("Rebind operation recorded");
return new RebindOperationRecorder(
createLdapOperationsInstance((DirContext) resource),
renamingStrategy);
} else if (StringUtils.equals(operation,
LdapTransactionUtils.RENAME_METHOD_NAME)) {
log.debug("Rename operation recorded");
return new RenameOperationRecorder(
createLdapOperationsInstance((DirContext) resource));
} else if (StringUtils.equals(operation,
LdapTransactionUtils.MODIFY_ATTRIBUTES_METHOD_NAME)) {
return new ModifyAttributesOperationRecorder(
createLdapOperationsInstance((DirContext) resource));
} else if (StringUtils.equals(operation,
LdapTransactionUtils.UNBIND_METHOD_NAME)) {
return new UnbindOperationRecorder(
createLdapOperationsInstance((DirContext) resource),
renamingStrategy);
}
/*
* @seeorg.springframework.transaction.compensating.
* CompensatingTransactionOperationFactory
* #createRecordingOperation(java.lang.Object, java.lang.String)
*/
public CompensatingTransactionOperationRecorder createRecordingOperation(Object resource, String operation) {
if (StringUtils.equals(operation, LdapTransactionUtils.BIND_METHOD_NAME)) {
log.debug("Bind operation recorded");
return new BindOperationRecorder(createLdapOperationsInstance((DirContext) resource));
}
else if (StringUtils.equals(operation, LdapTransactionUtils.REBIND_METHOD_NAME)) {
log.debug("Rebind operation recorded");
return new RebindOperationRecorder(createLdapOperationsInstance((DirContext) resource), renamingStrategy);
}
else if (StringUtils.equals(operation, LdapTransactionUtils.RENAME_METHOD_NAME)) {
log.debug("Rename operation recorded");
return new RenameOperationRecorder(createLdapOperationsInstance((DirContext) resource));
}
else if (StringUtils.equals(operation, LdapTransactionUtils.MODIFY_ATTRIBUTES_METHOD_NAME)) {
return new ModifyAttributesOperationRecorder(createLdapOperationsInstance((DirContext) resource));
}
else if (StringUtils.equals(operation, LdapTransactionUtils.UNBIND_METHOD_NAME)) {
return new UnbindOperationRecorder(createLdapOperationsInstance((DirContext) resource), renamingStrategy);
}
log
.warn("No suitable CompensatingTransactionOperationRecorder found for method "
+ operation + ". Operation will not be transacted.");
return new NullOperationRecorder();
}
log.warn("No suitable CompensatingTransactionOperationRecorder found for method " + operation
+ ". Operation will not be transacted.");
return new NullOperationRecorder();
}
LdapOperations createLdapOperationsInstance(DirContext ctx) {
return new LdapTemplate(new SingleContextSource(ctx));
}
LdapOperations createLdapOperationsInstance(DirContext ctx) {
return new LdapTemplate(new SingleContextSource(ctx));
}
/**
* A {@link ContextSource} implementation using returning
* {@link NonClosingDirContextInvocationHandler} proxies on the same
* DirContext instance for each call.
*
* @author Mattias Arthursson
*/
static class SingleContextSource implements ContextSource {
private DirContext ctx;
/**
* A {@link ContextSource} implementation using returning
* {@link NonClosingDirContextInvocationHandler} proxies on the same
* DirContext instance for each call.
*
* @author Mattias Arthursson
*/
static class SingleContextSource implements ContextSource {
private DirContext ctx;
/**
* Constructor.
*
* @param ctx
* the target DirContext.
*/
public SingleContextSource(DirContext ctx) {
this.ctx = ctx;
}
/**
* Constructor.
*
* @param ctx the target DirContext.
*/
public SingleContextSource(DirContext ctx) {
this.ctx = ctx;
}
/*
* @see org.springframework.ldap.ContextSource#getReadOnlyContext()
*/
public DirContext getReadOnlyContext() throws NamingException {
return getNonClosingDirContextProxy(ctx);
}
/*
* @see org.springframework.ldap.ContextSource#getReadOnlyContext()
*/
public DirContext getReadOnlyContext() throws NamingException {
return getNonClosingDirContextProxy(ctx);
}
/*
* @see org.springframework.ldap.ContextSource#getReadWriteContext()
*/
public DirContext getReadWriteContext() throws NamingException {
return getNonClosingDirContextProxy(ctx);
}
/*
* @see org.springframework.ldap.ContextSource#getReadWriteContext()
*/
public DirContext getReadWriteContext() throws NamingException {
return getNonClosingDirContextProxy(ctx);
}
private DirContext getNonClosingDirContextProxy(DirContext context) {
return (DirContext) Proxy.newProxyInstance(DirContextProxy.class
.getClassLoader(), new Class[] {
LdapTransactionUtils.getActualTargetClass(context),
DirContextProxy.class },
new NonClosingDirContextInvocationHandler(context));
private DirContext getNonClosingDirContextProxy(DirContext context) {
return (DirContext) Proxy.newProxyInstance(DirContextProxy.class.getClassLoader(), new Class[] {
LdapTransactionUtils.getActualTargetClass(context), DirContextProxy.class },
new NonClosingDirContextInvocationHandler(context));
}
}
}
/**
* A proxy for DirContext forwarding all operation to the target DirContext,
* but making sure that no <code>close</code> operations will be
* performed.
*
* @author Mattias Arthursson
*/
public static class NonClosingDirContextInvocationHandler implements
InvocationHandler {
public DirContext getContext(String principal, String credentials) throws NamingException {
throw new UnsupportedOperationException("Not a valid operation for this type of ContextSource");
}
}
private DirContext target;
/**
* A proxy for DirContext forwarding all operation to the target DirContext,
* but making sure that no <code>close</code> operations will be performed.
*
* @author Mattias Arthursson
*/
public static class NonClosingDirContextInvocationHandler implements InvocationHandler {
public NonClosingDirContextInvocationHandler(DirContext target) {
this.target = target;
}
private DirContext target;
/*
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
* java.lang.reflect.Method, java.lang.Object[])
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
public NonClosingDirContextInvocationHandler(DirContext target) {
this.target = target;
}
String methodName = method.getName();
if (methodName.equals("getTargetContext")) {
return target;
} else if (methodName.equals("equals")) {
// Only consider equal when proxies are identical.
return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
} else if (methodName.equals("hashCode")) {
// Use hashCode of Connection proxy.
return new Integer(proxy.hashCode());
} else if (methodName.equals("close")) {
// Never close the target context, as this class will only be
// used for operations concerning the compensating transactions.
return null;
}
/*
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
* java.lang.reflect.Method, java.lang.Object[])
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
return method.invoke(target, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}
String methodName = method.getName();
if (methodName.equals("getTargetContext")) {
return target;
}
else if (methodName.equals("equals")) {
// Only consider equal when proxies are identical.
return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
}
else if (methodName.equals("hashCode")) {
// Use hashCode of Connection proxy.
return new Integer(proxy.hashCode());
}
else if (methodName.equals("close")) {
// Never close the target context, as this class will only be
// used for operations concerning the compensating transactions.
return null;
}
try {
return method.invoke(target, args);
}
catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}
}

View File

@@ -98,4 +98,8 @@ public class TransactionAwareContextSourceProxy implements ContextSource {
}
return getTransactionAwareDirContextProxy(ctx, target);
}
public DirContext getContext(String principal, String credentials) throws NamingException {
throw new UnsupportedOperationException("Not supported on a transacted ContextSource");
}
}

View File

@@ -23,7 +23,6 @@ import javax.naming.Context;
import junit.framework.TestCase;
import org.springframework.ldap.core.AuthenticationSource;
import org.springframework.ldap.core.DistinguishedName;
/**
@@ -200,7 +199,7 @@ public class LdapContextSourceTest extends TestCase {
tested.setPassword("secret");
tested.afterPropertiesSet();
Hashtable env = tested.getAuthenticatedEnv();
Hashtable env = tested.getAuthenticatedEnv("cn=Some User", "secret");
assertEquals("ldap://ldap.example.com:389/dc=example,dc=se", env.get(Context.PROVIDER_URL));
assertEquals("true", env.get(LdapContextSource.SUN_LDAP_POOLING_FLAG));
assertEquals("cn=Some User", env.get(Context.SECURITY_PRINCIPAL));
@@ -210,41 +209,6 @@ public class LdapContextSourceTest extends TestCase {
assertEquals(new DistinguishedName("dc=example,dc=se"), env.get(DefaultDirObjectFactory.JNDI_ENV_BASE_PATH_KEY));
}
public void testGetAuthenticatedEnv_DummyAuthenticationProvider() throws Exception {
tested.setBase("dc=example,dc=se");
tested.setUrl("ldap://ldap.example.com:389");
tested.setPooled(true);
DummyAuthenticationProvider authenticationProvider = new DummyAuthenticationProvider();
tested.setAuthenticationSource(authenticationProvider);
authenticationProvider.setPrincipal("cn=Some User");
authenticationProvider.setCredentials("secret");
tested.afterPropertiesSet();
Hashtable env = tested.getAuthenticatedEnv();
assertEquals("ldap://ldap.example.com:389/dc=example,dc=se", env.get(Context.PROVIDER_URL));
assertEquals("true", env.get(LdapContextSource.SUN_LDAP_POOLING_FLAG));
assertEquals("cn=Some User", env.get(Context.SECURITY_PRINCIPAL));
assertEquals("secret", env.get(Context.SECURITY_CREDENTIALS));
}
public void testGetAuthenticatedEnv_DummyAuthenticationProvider_Changed() throws Exception {
tested.setBase("dc=example,dc=se");
tested.setUrl("ldap://ldap.example.com:389");
tested.setPooled(true);
DummyAuthenticationProvider authenticationProvider = new DummyAuthenticationProvider();
tested.setAuthenticationSource(authenticationProvider);
authenticationProvider.setPrincipal("cn=Some User");
authenticationProvider.setCredentials("secret");
tested.afterPropertiesSet();
authenticationProvider.setPrincipal("cn=Some Other User");
authenticationProvider.setCredentials("other secret");
Hashtable env = tested.getAuthenticatedEnv();
assertEquals("cn=Some Other User", env.get(Context.SECURITY_PRINCIPAL));
assertEquals("other secret", env.get(Context.SECURITY_CREDENTIALS));
}
public void testGetAnonymousEnvWhenCacheIsOff() throws Exception {
tested.setBase("dc=example,dc=se");
tested.setUrl("ldap://ldap.example.com:389");
@@ -263,26 +227,4 @@ public class LdapContextSourceTest extends TestCase {
env = tested.getAnonymousEnv();
assertEquals("ldap://ldap2.example.com:389/dc=example,dc=se", env.get(Context.PROVIDER_URL));
}
private class DummyAuthenticationProvider implements AuthenticationSource {
private String principal;
private String credentials;
public void setCredentials(String credentials) {
this.credentials = credentials;
}
public void setPrincipal(String principal) {
this.principal = principal;
}
public String getPrincipal() {
return principal;
}
public String getCredentials() {
return credentials;
}
}
}

View File

@@ -1,4 +1,4 @@
itest.openldap.serverAddress=127.0.0.1
itest.openldap.serverAddress=spring-ldap-test.dyndns.org
userDn=cn=admin,dc=jayway,dc=se
password=secret
base=dc=jayway,dc=se

View File

@@ -15,6 +15,10 @@
<property name="userDn" value="${userDn}" />
<property name="password" value="${password}" />
<property name="url" value="ldap://${itest.openldap.serverAddress}:389" />
<property name="authenticationStrategy">
<bean class="org.springframework.ldap.core.support.DefaultTlsDirContextAuthenticationStrategy" />
</property>
<property name="pooled" value="false" />
</bean>
<bean id="ldapTemplate"

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.ldap.core.support;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
@@ -90,4 +91,30 @@ public class LdapContextSourcelITest extends AbstractLdapTemplateIntegrationTest
}
}
}
@Test
public void testGetContext() throws NamingException {
DirContext ctx = null;
try {
String expectedPrincipal = "cn=Some Person,ou=company1,c=Sweden,dc=jayway,dc=se";
String expectedCredentials = "password";
ctx = tested.getContext(expectedPrincipal, expectedCredentials);
assertNotNull(ctx);
// Double check to see that we are authenticated.
Hashtable environment = ctx.getEnvironment();
assertEquals(expectedPrincipal, environment.get(Context.SECURITY_PRINCIPAL));
assertEquals(expectedCredentials, environment.get(Context.SECURITY_CREDENTIALS));
}
finally {
// Always clean up.
if (ctx != null) {
try {
ctx.close();
}
catch (Exception e) {
// Never mind this
}
}
}
}
}