mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-28 23:02:15 +00:00
SEC-1444: Backport of changes to 2.0.x
This commit is contained in:
parent
4361211c21
commit
d6f6a54455
@ -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");
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user