SEC-1444: Backport of changes to 2.0.x

This commit is contained in:
Luke Taylor 2010-04-16 15:14:01 +01:00
parent 4361211c21
commit d6f6a54455
5 changed files with 89 additions and 52 deletions

View File

@ -193,22 +193,27 @@ 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());
if (logger.isDebugEnabled()) {
logger.debug("Searching for entry in under DN '" + ctxBaseDn
+ "', base = '" + base + "', filter = '" + filter + "'");
}
NamingEnumeration resultsEnum = ctx.search(base, filter, params, searchControls); NamingEnumeration resultsEnum = ctx.search(base, filter, params, searchControls);
Set results = new HashSet(); Set results = new HashSet();
try { try {
while (resultsEnum.hasMore()) { while (resultsEnum.hasMore()) {
SearchResult searchResult = (SearchResult) resultsEnum.next(); SearchResult 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()); DistinguishedName dn = new DistinguishedName(searchResult.getName());
if (base.length() > 0) { if (base.length() > 0) {
dn.append(","); dn.prepend(new DistinguishedName(base));
dn.append(base);
} }
results.add(new DirContextAdapter(searchResult.getAttributes(), if (logger.isDebugEnabled()) {
new DistinguishedName(dn.toString()), ctxBaseDn)); logger.debug("Found DN: " + dn);
}
results.add(new DirContextAdapter(searchResult.getAttributes(), dn, ctxBaseDn));
} }
} catch (PartialResultException e) { } catch (PartialResultException e) {
logger.info("Ignoring PartialResultException"); logger.info("Ignoring PartialResultException");

View File

@ -15,22 +15,26 @@
package org.springframework.security.providers.ldap.authenticator; package org.springframework.security.providers.ldap.authenticator;
import org.springframework.security.Authentication; import java.util.Iterator;
import org.springframework.security.BadCredentialsException;
import org.springframework.security.ldap.SpringSecurityContextSource; import javax.naming.directory.Attributes;
import org.springframework.security.ldap.SpringSecurityLdapTemplate; import javax.naming.directory.DirContext;
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.dao.DataAccessException;
import javax.naming.directory.DirContext; import org.springframework.ldap.NamingException;
import java.util.Iterator; import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.DirContextAdapter;
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.ldap.SpringSecurityContextSource;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.util.Assert;
/** /**
@ -91,21 +95,42 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
return user; return user;
} }
private DirContextOperations bindWithDn(String userDn, String username, String password) { private DirContextOperations bindWithDn(String userDnStr, String username, String password) {
SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate( BaseLdapPathContextSource ctxSource = (BaseLdapPathContextSource) getContextSource();
new BindWithSpecificDnContextSource((SpringSecurityContextSource) getContextSource(), userDn, password)); DistinguishedName userDn = new DistinguishedName(userDnStr);
DistinguishedName fullDn = new DistinguishedName(userDn);
fullDn.prepend(ctxSource.getBaseLdapPath());
BindWithSpecificDnContextSource specificDnContextSource = new BindWithSpecificDnContextSource(
(SpringSecurityContextSource) getContextSource(), fullDn,
password);
logger.debug("Attemptimg to bind as " + fullDn);
DirContext ctx = null;
try {
ctx = specificDnContextSource.getReadOnlyContext();
try { Attributes attrs = ctx.getAttributes(userDn, getUserAttributes());
return template.retrieveEntry(userDn, getUserAttributes());
} catch (BadCredentialsException e) { DirContextAdapter result = new DirContextAdapter(attrs, userDn, ctxSource.getBaseLdapPath());
// 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 return result;
// unless a subclass wishes to implement more specialized behaviour. } catch (NamingException e) {
handleBindException(userDn, username, e.getCause()); // 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
// unless a subclass wishes to implement more specialized behaviour.
if ((e instanceof org.springframework.ldap.AuthenticationException)
|| (e instanceof org.springframework.ldap.OperationNotSupportedException)) {
handleBindException(userDnStr, username, e);
} else {
throw e;
}
} catch (javax.naming.NamingException e) {
throw LdapUtils.convertLdapException(e);
} finally {
LdapUtils.closeContext(ctx);
}
return null;
return null;
} }
/** /**
@ -120,13 +145,12 @@ public class BindAuthenticator extends AbstractLdapAuthenticator {
private class BindWithSpecificDnContextSource implements ContextSource { private class BindWithSpecificDnContextSource implements ContextSource {
private SpringSecurityContextSource ctxFactory; private SpringSecurityContextSource ctxFactory;
DistinguishedName userDn; private DistinguishedName userDn;
private String password; private String password;
public BindWithSpecificDnContextSource(SpringSecurityContextSource ctxFactory, String userDn, String password) { public BindWithSpecificDnContextSource(SpringSecurityContextSource ctxFactory, DistinguishedName userDn, String password) {
this.ctxFactory = ctxFactory; this.ctxFactory = ctxFactory;
this.userDn = new DistinguishedName(userDn); this.userDn = userDn;
this.userDn.prepend(ctxFactory.getBaseLdapPath());
this.password = password; this.password = password;
} }

View File

@ -71,13 +71,11 @@ public class FilterBasedLdapUserSearchTests extends AbstractLdapIntegrationTests
@Test @Test
public void extraFilterPartToExcludeBob() throws Exception { public void extraFilterPartToExcludeBob() throws Exception {
FilterBasedLdapUserSearch locator = new FilterBasedLdapUserSearch("ou=people", FilterBasedLdapUserSearch locator = new FilterBasedLdapUserSearch("ou=people",
"(&(cn=*)(!(|(uid={0})(uid=rod)(uid=jerry))))", dirCtxFactory); "(&(cn=*)(!(|(uid={0})(uid=rod)(uid=jerry)(uid=slashguy))))", dirCtxFactory);
// Search for bob, get back ben... // Search for bob, get back ben...
DirContextOperations ben = locator.searchForUser("bob"); DirContextOperations ben = locator.searchForUser("bob");
assertEquals("Ben Alex", ben.getStringAttribute("cn")); assertEquals("Ben Alex", ben.getStringAttribute("cn"));
// assertEquals("uid=ben,ou=people,"+ROOT_DN, ben.getDn());
} }
@Test(expected=IncorrectResultSizeDataAccessException.class) @Test(expected=IncorrectResultSizeDataAccessException.class)

View File

@ -15,18 +15,17 @@
package org.springframework.security.providers.ldap.authenticator; package org.springframework.security.providers.ldap.authenticator;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import org.junit.Test;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.Authentication; import org.springframework.security.Authentication;
import org.springframework.security.BadCredentialsException; import org.springframework.security.BadCredentialsException;
import org.springframework.security.SpringSecurityMessageSource; import org.springframework.security.SpringSecurityMessageSource;
import org.springframework.security.ldap.AbstractLdapIntegrationTests; import org.springframework.security.ldap.AbstractLdapIntegrationTests;
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
import org.springframework.security.providers.UsernamePasswordAuthenticationToken; import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.DistinguishedName;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import org.junit.Test;
/** /**
* Tests for {@link BindAuthenticator}. * Tests for {@link BindAuthenticator}.
@ -39,7 +38,6 @@ public class BindAuthenticatorTests extends AbstractLdapIntegrationTests {
private BindAuthenticator authenticator; private BindAuthenticator authenticator;
private Authentication bob; private Authentication bob;
// private Authentication ben;
//~ Methods ======================================================================================================== //~ Methods ========================================================================================================
@ -48,7 +46,6 @@ public class BindAuthenticatorTests extends AbstractLdapIntegrationTests {
authenticator = new BindAuthenticator(getContextSource()); authenticator = new BindAuthenticator(getContextSource());
authenticator.setMessageSource(new SpringSecurityMessageSource()); authenticator.setMessageSource(new SpringSecurityMessageSource());
bob = new UsernamePasswordAuthenticationToken("bob", "bobspassword"); bob = new UsernamePasswordAuthenticationToken("bob", "bobspassword");
// ben = new UsernamePasswordAuthenticationToken("ben", "benspassword");
} }
@ -72,11 +69,14 @@ public class BindAuthenticatorTests extends AbstractLdapIntegrationTests {
@Test @Test
public void testAuthenticationWithUserSearch() throws Exception { public void testAuthenticationWithUserSearch() throws Exception {
DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=bob,ou=people")); // DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=bob,ou=people"));
authenticator.setUserSearch(new FilterBasedLdapUserSearch("ou=people", "(uid={0})", getContextSource()));
authenticator.setUserSearch(new MockUserSearch(ctx)); authenticator.afterPropertiesSet();
authenticator.afterPropertiesSet(); authenticator.authenticate(bob);
authenticator.authenticate(bob); // SEC-1444
authenticator.setUserSearch(new FilterBasedLdapUserSearch("ou=people", "(cn={0})", getContextSource()));
authenticator.authenticate(new UsernamePasswordAuthenticationToken("mouse, jerry", "jerryspassword"));
authenticator.authenticate(new UsernamePasswordAuthenticationToken("slash/guy", "slashguyspassword"));
} }
@Test @Test

View File

@ -58,6 +58,16 @@ sn: Mouse
uid: jerry uid: jerry
userPassword: jerryspassword userPassword: jerryspassword
dn: cn=slash/guy,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: slash/guy
sn: Slash
uid: slashguy
userPassword: slashguyspassword
dn: cn=developers,ou=groups,dc=springframework,dc=org dn: cn=developers,ou=groups,dc=springframework,dc=org
objectclass: top objectclass: top
objectclass: groupOfNames objectclass: groupOfNames