SEC-1124: Refactored LDAP code into separate module
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
package org.springframework.security;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.SecurityConfigurationException;
|
||||
import org.springframework.security.providers.ProviderManager;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.providers.ldap.LdapAuthenticationProvider;
|
||||
import org.springframework.security.userdetails.ldap.InetOrgPersonContextMapper;
|
||||
import org.springframework.security.userdetails.ldap.LdapUserDetailsImpl;
|
||||
import org.springframework.security.util.FieldUtils;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class LdapProviderBeanDefinitionParserTests {
|
||||
InMemoryXmlApplicationContext appCtx;
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appCtx != null) {
|
||||
appCtx.close();
|
||||
appCtx = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleProviderAuthenticatesCorrectly() {
|
||||
setContext("<ldap-server /> <ldap-authentication-provider group-search-filter='member={0}' />");
|
||||
|
||||
LdapAuthenticationProvider provider = getProvider();
|
||||
Authentication auth = provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
|
||||
LdapUserDetailsImpl ben = (LdapUserDetailsImpl) auth.getPrincipal();
|
||||
|
||||
assertEquals(3, ben.getAuthorities().size());
|
||||
}
|
||||
|
||||
@Test(expected = SecurityConfigurationException.class)
|
||||
public void missingServerEltCausesConfigException() {
|
||||
setContext("<ldap-authentication-provider />");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void supportsPasswordComparisonAuthentication() {
|
||||
setContext("<ldap-server /> " +
|
||||
"<ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>" +
|
||||
" <password-compare />" +
|
||||
"</ldap-authentication-provider>");
|
||||
LdapAuthenticationProvider provider = getProvider();
|
||||
provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void supportsPasswordComparisonAuthenticationWithHashAttribute() {
|
||||
setContext("<ldap-server /> " +
|
||||
"<ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>" +
|
||||
" <password-compare password-attribute='uid' hash='plaintext'/>" +
|
||||
"</ldap-authentication-provider>");
|
||||
LdapAuthenticationProvider provider = getProvider();
|
||||
provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsPasswordComparisonAuthenticationWithPasswordEncoder() {
|
||||
setContext("<ldap-server /> " +
|
||||
"<ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>" +
|
||||
" <password-compare password-attribute='uid'>" +
|
||||
" <password-encoder hash='plaintext'/>" +
|
||||
" </password-compare>" +
|
||||
"</ldap-authentication-provider>");
|
||||
LdapAuthenticationProvider provider = getProvider();
|
||||
provider.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void detectsNonStandardServerId() {
|
||||
setContext("<ldap-server id='myServer'/> " +
|
||||
"<ldap-authentication-provider />");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inetOrgContextMapperIsSupported() throws Exception {
|
||||
setContext(
|
||||
"<ldap-server id='someServer' url='ldap://127.0.0.1:343/dc=springframework,dc=org'/>" +
|
||||
"<ldap-authentication-provider user-details-class='inetOrgPerson'/>");
|
||||
LdapAuthenticationProvider provider = getProvider();
|
||||
assertTrue(FieldUtils.getFieldValue(provider, "userDetailsContextMapper") instanceof InetOrgPersonContextMapper);
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appCtx = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
|
||||
private LdapAuthenticationProvider getProvider() {
|
||||
ProviderManager authManager = (ProviderManager) appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER);
|
||||
|
||||
assertEquals(1, authManager.getProviders().size());
|
||||
|
||||
LdapAuthenticationProvider provider = (LdapAuthenticationProvider) authManager.getProviders().get(0);
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package org.springframework.security;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ldap.core.LdapTemplate;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class LdapServerBeanDefinitionParserTests {
|
||||
InMemoryXmlApplicationContext appCtx;
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appCtx != null) {
|
||||
appCtx.close();
|
||||
appCtx = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void embeddedServerCreationContainsExpectedContextSourceAndData() {
|
||||
appCtx = new InMemoryXmlApplicationContext("<ldap-server />");
|
||||
|
||||
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx.getBean(BeanIds.CONTEXT_SOURCE);
|
||||
|
||||
// Check data is loaded
|
||||
LdapTemplate template = new LdapTemplate(contextSource);
|
||||
template.lookup("uid=ben,ou=people");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useOfUrlAttributeCreatesCorrectContextSource() {
|
||||
// Create second "server" with a url pointing at embedded one
|
||||
appCtx = new InMemoryXmlApplicationContext("<ldap-server port='33388'/>" +
|
||||
"<ldap-server id='blah' url='ldap://127.0.0.1:33388/dc=springframework,dc=org' />");
|
||||
|
||||
// Check the default context source is still there.
|
||||
appCtx.getBean(BeanIds.CONTEXT_SOURCE);
|
||||
|
||||
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx.getBean("blah");
|
||||
|
||||
// Check data is loaded as before
|
||||
LdapTemplate template = new LdapTemplate(contextSource);
|
||||
template.lookup("uid=ben,ou=people");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadingSpecificLdifFileIsSuccessful() {
|
||||
appCtx = new InMemoryXmlApplicationContext(
|
||||
"<ldap-server ldif='classpath*:test-server2.xldif' root='dc=monkeymachine,dc=co,dc=uk' />");
|
||||
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx.getBean(BeanIds.CONTEXT_SOURCE);
|
||||
|
||||
LdapTemplate template = new LdapTemplate(contextSource);
|
||||
template.lookup("uid=pg,ou=gorillas");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package org.springframework.security;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
import org.springframework.security.userdetails.ldap.InetOrgPerson;
|
||||
import org.springframework.security.userdetails.ldap.Person;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.After;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class LdapUserServiceBeanDefinitionParserTests {
|
||||
private InMemoryXmlApplicationContext appCtx;
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appCtx != null) {
|
||||
appCtx.close();
|
||||
appCtx = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void minimalConfigurationIsParsedOk() throws Exception {
|
||||
setContext("<ldap-user-service user-search-filter='(uid={0})' /><ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org' />");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userServiceReturnsExpectedData() throws Exception {
|
||||
setContext("<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-search-filter='member={0}' /><ldap-server />");
|
||||
|
||||
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
|
||||
UserDetails ben = uds.loadUserByUsername("ben");
|
||||
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(ben.getAuthorities());
|
||||
assertEquals(3, authorities.size());
|
||||
assertTrue(authorities.contains("ROLE_DEVELOPERS"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void differentUserSearchBaseWorksAsExpected() throws Exception {
|
||||
setContext("<ldap-user-service id='ldapUDS' " +
|
||||
" user-search-base='ou=otherpeople' " +
|
||||
" user-search-filter='(cn={0})' " +
|
||||
" group-search-filter='member={0}' /><ldap-server />");
|
||||
|
||||
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
|
||||
UserDetails joe = uds.loadUserByUsername("Joe Smeth");
|
||||
|
||||
assertEquals("Joe Smeth", joe.getUsername());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rolePrefixIsSupported() throws Exception {
|
||||
setContext(
|
||||
"<ldap-user-service id='ldapUDS' " +
|
||||
" user-search-filter='(uid={0})' " +
|
||||
" group-search-filter='member={0}' role-prefix='PREFIX_'/>" +
|
||||
"<ldap-user-service id='ldapUDSNoPrefix' " +
|
||||
" user-search-filter='(uid={0})' " +
|
||||
" group-search-filter='member={0}' role-prefix='none'/><ldap-server />");
|
||||
|
||||
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
|
||||
UserDetails ben = uds.loadUserByUsername("ben");
|
||||
assertTrue(AuthorityUtils.authorityListToSet(ben.getAuthorities()).contains("PREFIX_DEVELOPERS"));
|
||||
|
||||
uds = (UserDetailsService) appCtx.getBean("ldapUDSNoPrefix");
|
||||
ben = uds.loadUserByUsername("ben");
|
||||
assertTrue(AuthorityUtils.authorityListToSet(ben.getAuthorities()).contains("DEVELOPERS"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void differentGroupRoleAttributeWorksAsExpected() throws Exception {
|
||||
setContext("<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-role-attribute='ou' group-search-filter='member={0}' /><ldap-server />");
|
||||
|
||||
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
|
||||
UserDetails ben = uds.loadUserByUsername("ben");
|
||||
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(ben.getAuthorities());
|
||||
assertEquals(3, authorities.size());
|
||||
assertTrue(authorities.contains(new GrantedAuthorityImpl("ROLE_DEVELOPER")));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSupportedByAuthenticationProviderElement() {
|
||||
setContext(
|
||||
"<ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org'/>" +
|
||||
"<authentication-provider>" +
|
||||
" <ldap-user-service user-search-filter='(uid={0})' />" +
|
||||
"</authentication-provider>");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void personContextMapperIsSupported() {
|
||||
setContext(
|
||||
"<ldap-server />" +
|
||||
"<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' user-details-class='person'/>");
|
||||
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
|
||||
UserDetails ben = uds.loadUserByUsername("ben");
|
||||
assertTrue(ben instanceof Person);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void inetOrgContextMapperIsSupported() {
|
||||
setContext(
|
||||
"<ldap-server id='someServer'/>" +
|
||||
"<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' user-details-class='inetOrgPerson'/>");
|
||||
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
|
||||
UserDetails ben = uds.loadUserByUsername("ben");
|
||||
assertTrue(ben instanceof InetOrgPerson);
|
||||
}
|
||||
|
||||
|
||||
private void setContext(String context) {
|
||||
appCtx = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/* 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.Binding;
|
||||
import javax.naming.ContextNotEmptyException;
|
||||
import javax.naming.Name;
|
||||
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.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public abstract class AbstractLdapIntegrationTests {
|
||||
private static InMemoryXmlApplicationContext appContext;
|
||||
|
||||
protected AbstractLdapIntegrationTests() {
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void loadContext() throws NamingException {
|
||||
shutdownRunningServers();
|
||||
appContext = new InMemoryXmlApplicationContext("<ldap-server port='53389' ldif='classpath:test-server.ldif'/>");
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void closeContext() throws Exception {
|
||||
if(appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
shutdownRunningServers();
|
||||
}
|
||||
|
||||
private static void shutdownRunningServers() throws NamingException {
|
||||
DirectoryService ds = DirectoryService.getInstance();
|
||||
|
||||
if (ds.isStarted()) {
|
||||
System.out.println("WARNING: Discovered running DirectoryService with configuration: " + ds.getConfiguration().getStartupConfiguration().toString());
|
||||
System.out.println("Shutting it down...");
|
||||
ds.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
public void onSetUp() throws Exception {
|
||||
}
|
||||
|
||||
|
||||
@After
|
||||
public final void reloadServerDataIfDirty() throws Exception {
|
||||
ClassPathResource ldifs = new ClassPathResource("test-server.ldif");
|
||||
|
||||
if (!ldifs.getFile().exists()) {
|
||||
throw new IllegalStateException("Ldif file not found: " + ldifs.getFile().getAbsolutePath());
|
||||
}
|
||||
|
||||
DirContext ctx = getContextSource().getReadWriteContext();
|
||||
|
||||
// First of all, make sure the database is empty.
|
||||
Name startingPoint = new DistinguishedName("dc=springframework,dc=org");
|
||||
|
||||
try {
|
||||
clearSubContexts(ctx, startingPoint);
|
||||
LdifFileLoader loader = new LdifFileLoader(ctx, ldifs.getFile().getAbsolutePath());
|
||||
loader.execute();
|
||||
} finally {
|
||||
ctx.close();
|
||||
}
|
||||
}
|
||||
|
||||
public BaseLdapPathContextSource getContextSource() {
|
||||
return (BaseLdapPathContextSource)appContext.getBean(BeanIds.CONTEXT_SOURCE);
|
||||
}
|
||||
|
||||
|
||||
private void clearSubContexts(DirContext ctx, Name name) throws NamingException {
|
||||
|
||||
NamingEnumeration<Binding> enumeration = null;
|
||||
try {
|
||||
enumeration = ctx.listBindings(name);
|
||||
while (enumeration.hasMore()) {
|
||||
Binding element = (Binding) enumeration.next();
|
||||
DistinguishedName childName = new DistinguishedName(element.getName());
|
||||
childName.prepend((DistinguishedName) name);
|
||||
|
||||
try {
|
||||
ctx.destroySubcontext(childName);
|
||||
} catch (ContextNotEmptyException e) {
|
||||
clearSubContexts(ctx, childName);
|
||||
ctx.destroySubcontext(childName);
|
||||
}
|
||||
}
|
||||
} catch(NameNotFoundException ignored) {
|
||||
}
|
||||
catch (NamingException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
enumeration.close();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package org.springframework.security.ldap;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.ldap.core.support.AbstractContextSource;
|
||||
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class DefaultSpringSecurityContextSourceTests {
|
||||
|
||||
@Test
|
||||
public void instantiationSucceedsWithExpectedProperties() {
|
||||
DefaultSpringSecurityContextSource ctxSrc =
|
||||
new DefaultSpringSecurityContextSource("ldap://blah:789/dc=springframework,dc=org");
|
||||
assertFalse(ctxSrc.isAnonymousReadOnly());
|
||||
assertTrue(ctxSrc.isPooled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsSpacesInUrl() {
|
||||
new DefaultSpringSecurityContextSource("ldap://myhost:10389/dc=spring%20framework,dc=org");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void poolingFlagIsSetWhenAuthenticationDnMatchesManagerUserDn() throws Exception {
|
||||
EnvExposingDefaultSpringSecurityContextSource ctxSrc =
|
||||
new EnvExposingDefaultSpringSecurityContextSource("ldap://blah:789/dc=springframework,dc=org");
|
||||
ctxSrc.setUserDn("manager");
|
||||
ctxSrc.setPassword("password");
|
||||
ctxSrc.afterPropertiesSet();
|
||||
assertTrue(ctxSrc.getAuthenticatedEnvForTest("manager", "password").containsKey(AbstractContextSource.SUN_LDAP_POOLING_FLAG));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void poolingFlagIsNotSetWhenAuthenticationDnIsNotManagerUserDn() throws Exception {
|
||||
EnvExposingDefaultSpringSecurityContextSource ctxSrc =
|
||||
new EnvExposingDefaultSpringSecurityContextSource("ldap://blah:789/dc=springframework,dc=org");
|
||||
ctxSrc.setUserDn("manager");
|
||||
ctxSrc.setPassword("password");
|
||||
ctxSrc.afterPropertiesSet();
|
||||
assertFalse(ctxSrc.getAuthenticatedEnvForTest("user", "password").containsKey(AbstractContextSource.SUN_LDAP_POOLING_FLAG));
|
||||
}
|
||||
|
||||
static class EnvExposingDefaultSpringSecurityContextSource extends DefaultSpringSecurityContextSource {
|
||||
public EnvExposingDefaultSpringSecurityContextSource(String providerUrl) {
|
||||
super(providerUrl);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Hashtable getAuthenticatedEnvForTest(String userDn, String password) {
|
||||
return getAuthenticatedEnv(userDn, password);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/* 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 static org.junit.Assert.assertEquals;
|
||||
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.Mockery;
|
||||
import org.jmock.integration.junit4.JMock;
|
||||
import org.jmock.integration.junit4.JUnit4Mockery;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link LdapUtils}
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
@RunWith(JMock.class)
|
||||
public class LdapUtilsTests {
|
||||
Mockery context = new JUnit4Mockery();
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Test
|
||||
public void testCloseContextSwallowsNamingException() throws Exception {
|
||||
final DirContext dirCtx = context.mock(DirContext.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(dirCtx).close(); will(throwException(new NamingException()));
|
||||
}});
|
||||
|
||||
LdapUtils.closeContext(dirCtx);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRelativeNameReturnsEmptyStringForDnEqualToBaseName() throws Exception {
|
||||
final DirContext mockCtx = context.mock(DirContext.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
atLeast(1).of(mockCtx).getNameInNamespace(); will(returnValue("dc=springframework,dc=org"));
|
||||
}});
|
||||
|
||||
assertEquals("", LdapUtils.getRelativeName("dc=springframework,dc=org", mockCtx));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRelativeNameReturnsFullDnWithEmptyBaseName() throws Exception {
|
||||
final DirContext mockCtx = context.mock(DirContext.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
atLeast(1).of(mockCtx).getNameInNamespace(); will(returnValue(""));
|
||||
}});
|
||||
|
||||
assertEquals("cn=jane,dc=springframework,dc=org",
|
||||
LdapUtils.getRelativeName("cn=jane,dc=springframework,dc=org", mockCtx));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetRelativeNameWorksWithArbitrarySpaces() throws Exception {
|
||||
final DirContext mockCtx = context.mock(DirContext.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
atLeast(1).of(mockCtx).getNameInNamespace(); will(returnValue("dc=springsecurity,dc = org"));
|
||||
}});
|
||||
|
||||
assertEquals("cn=jane smith",
|
||||
LdapUtils.getRelativeName("cn=jane smith, dc = springsecurity , dc=org", mockCtx));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRootDnsAreParsedFromUrlsCorrectly() {
|
||||
assertEquals("", LdapUtils.parseRootDnFromUrl("ldap://monkeymachine"));
|
||||
assertEquals("", LdapUtils.parseRootDnFromUrl("ldap://monkeymachine:11389"));
|
||||
assertEquals("", LdapUtils.parseRootDnFromUrl("ldap://monkeymachine/"));
|
||||
assertEquals("", LdapUtils.parseRootDnFromUrl("ldap://monkeymachine.co.uk/"));
|
||||
assertEquals("dc=springframework,dc=org",
|
||||
LdapUtils.parseRootDnFromUrl("ldaps://monkeymachine.co.uk/dc=springframework,dc=org"));
|
||||
assertEquals("dc=springframework,dc=org", LdapUtils.parseRootDnFromUrl("ldap:///dc=springframework,dc=org"));
|
||||
assertEquals("dc=springframework,dc=org",
|
||||
LdapUtils.parseRootDnFromUrl("ldap://monkeymachine/dc=springframework,dc=org"));
|
||||
assertEquals("dc=springframework,dc=org/ou=blah",
|
||||
LdapUtils.parseRootDnFromUrl("ldap://monkeymachine.co.uk/dc=springframework,dc=org/ou=blah"));
|
||||
assertEquals("dc=springframework,dc=org/ou=blah",
|
||||
LdapUtils.parseRootDnFromUrl("ldap://monkeymachine.co.uk:389/dc=springframework,dc=org/ou=blah"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.springframework.security.ldap;
|
||||
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.TestingAuthenticationToken;
|
||||
import org.springframework.security.providers.anonymous.AnonymousAuthenticationToken;
|
||||
import org.springframework.security.userdetails.ldap.LdapUserDetailsImpl;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
import org.springframework.ldap.core.AuthenticationSource;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
|
||||
import org.junit.After;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SpringSecurityAuthenticationSourceTests {
|
||||
@Before
|
||||
@After
|
||||
public void clearContext() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void principalAndCredentialsAreEmptyWithNoAuthentication() {
|
||||
AuthenticationSource source = new SpringSecurityAuthenticationSource();
|
||||
assertEquals("", source.getPrincipal());
|
||||
assertEquals("", source.getCredentials());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void principalIsEmptyForAnonymousUser() {
|
||||
AuthenticationSource source = new SpringSecurityAuthenticationSource();
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new AnonymousAuthenticationToken("key", "anonUser", AuthorityUtils.createAuthorityList("ignored")));
|
||||
assertEquals("", source.getPrincipal());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void getPrincipalRejectsNonLdapUserDetailsObject() {
|
||||
AuthenticationSource source = new SpringSecurityAuthenticationSource();
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken(new Object(), "password"));
|
||||
|
||||
source.getPrincipal();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void expectedCredentialsAreReturned() {
|
||||
AuthenticationSource source = new SpringSecurityAuthenticationSource();
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken(new Object(), "password"));
|
||||
|
||||
assertEquals("password", source.getCredentials());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void expectedPrincipalIsReturned() {
|
||||
LdapUserDetailsImpl.Essence user = new LdapUserDetailsImpl.Essence();
|
||||
user.setUsername("joe");
|
||||
user.setDn(new DistinguishedName("uid=joe,ou=users"));
|
||||
AuthenticationSource source = new SpringSecurityAuthenticationSource();
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken(user.createUserDetails(), null));
|
||||
|
||||
assertEquals("uid=joe,ou=users", source.getPrincipal());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/* 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 static org.junit.Assert.*;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.SearchControls;
|
||||
import javax.naming.directory.SearchResult;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.ldap.UncategorizedLdapException;
|
||||
import org.springframework.ldap.core.ContextExecutor;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SpringSecurityLdapTemplateTests extends AbstractLdapIntegrationTests {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private SpringSecurityLdapTemplate template;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void onSetUp() throws Exception {
|
||||
super.onSetUp();
|
||||
|
||||
template = new SpringSecurityLdapTemplate(getContextSource());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareOfCorrectValueSucceeds() {
|
||||
assertTrue(template.compare("uid=bob,ou=people", "uid", "bob"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareOfCorrectByteValueSucceeds() {
|
||||
assertTrue(template.compare("uid=bob,ou=people", "userPassword", LdapUtils.getUtf8Bytes("bobspassword")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareOfWrongByteValueFails() {
|
||||
assertFalse(template.compare("uid=bob,ou=people", "userPassword", LdapUtils.getUtf8Bytes("wrongvalue")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareOfWrongValueFails() {
|
||||
assertFalse(template.compare("uid=bob,ou=people", "uid", "wrongvalue"));
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void testNameExistsForInValidNameFails() {
|
||||
// assertFalse(template.nameExists("ou=doesntexist,dc=springframework,dc=org"));
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void testNameExistsForValidNameSucceeds() {
|
||||
// assertTrue(template.nameExists("ou=groups,dc=springframework,dc=org"));
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void namingExceptionIsTranslatedCorrectly() {
|
||||
try {
|
||||
template.executeReadOnly(new ContextExecutor() {
|
||||
public Object executeWithContext(DirContext dirContext) throws NamingException {
|
||||
throw new NamingException();
|
||||
}
|
||||
});
|
||||
fail("Expected UncategorizedLdapException on NamingException");
|
||||
} catch (UncategorizedLdapException expected) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void roleSearchReturnsCorrectNumberOfRoles() {
|
||||
String param = "uid=ben,ou=people,dc=springframework,dc=org";
|
||||
|
||||
Set<String> values = template.searchForSingleAttributeValues("ou=groups", "(member={0})", new String[] {param}, "ou");
|
||||
|
||||
assertEquals("Expected 3 results from search", 3, values.size());
|
||||
assertTrue(values.contains("developer"));
|
||||
assertTrue(values.contains("manager"));
|
||||
assertTrue(values.contains("submanager"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoleSearchForMissingAttributeFailsGracefully() {
|
||||
String param = "uid=ben,ou=people,dc=springframework,dc=org";
|
||||
|
||||
Set<String> values = template.searchForSingleAttributeValues("ou=groups", "(member={0})", new String[] {param}, "mail");
|
||||
|
||||
assertEquals(0, values.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void roleSearchWithEscapedCharacterSucceeds() throws Exception {
|
||||
String param = "cn=mouse\\, jerry,ou=people,dc=springframework,dc=org";
|
||||
|
||||
Set<String> values = template.searchForSingleAttributeValues("ou=groups", "(member={0})", new String[] {param}, "cn");
|
||||
|
||||
assertEquals(1, values.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonSpringLdapSearchCodeTestMethod() throws Exception {
|
||||
java.util.Hashtable<String, String> env = new java.util.Hashtable<String, String>();
|
||||
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
||||
env.put(Context.PROVIDER_URL, "ldap://localhost:53389");
|
||||
env.put(Context.SECURITY_PRINCIPAL, "");
|
||||
env.put(Context.SECURITY_CREDENTIALS, "");
|
||||
|
||||
DirContext ctx = new javax.naming.directory.InitialDirContext(env);
|
||||
SearchControls controls = new SearchControls();
|
||||
controls.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
||||
controls.setReturningObjFlag(true);
|
||||
controls.setReturningAttributes(null);
|
||||
String param = "cn=mouse\\, jerry,ou=people,dc=springframework,dc=org";
|
||||
|
||||
javax.naming.NamingEnumeration<SearchResult> results =
|
||||
ctx.search("ou=groups,dc=springframework,dc=org",
|
||||
"(member={0})", new String[] {param},
|
||||
controls);
|
||||
|
||||
assertTrue("Expected a result", results.hasMore());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchForSingleEntryWithEscapedCharsInDnSucceeds() {
|
||||
String param = "mouse, jerry";
|
||||
|
||||
template.searchForSingleEntry("ou=people", "(cn={0})", new String[] {param});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/* 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.populator;
|
||||
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
|
||||
import org.springframework.security.ldap.AbstractLdapIntegrationTests;
|
||||
import org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator;
|
||||
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class DefaultLdapAuthoritiesPopulatorTests extends AbstractLdapIntegrationTests {
|
||||
private DefaultLdapAuthoritiesPopulator populator;
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void onSetUp() throws Exception {
|
||||
super.onSetUp();
|
||||
|
||||
populator = new DefaultLdapAuthoritiesPopulator(getContextSource(), "ou=groups");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultRoleIsAssignedWhenSet() {
|
||||
|
||||
populator.setDefaultRole("ROLE_USER");
|
||||
|
||||
DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("cn=notfound"));
|
||||
|
||||
List<GrantedAuthority> authorities = populator.getGrantedAuthorities(ctx, "notfound");
|
||||
assertEquals(1, authorities.size());
|
||||
assertEquals("ROLE_USER", authorities.get(0).getAuthority());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGroupSearchReturnsExpectedRoles() {
|
||||
populator.setRolePrefix("ROLE_");
|
||||
populator.setGroupRoleAttribute("ou");
|
||||
populator.setSearchSubtree(true);
|
||||
populator.setSearchSubtree(false);
|
||||
populator.setConvertToUpperCase(true);
|
||||
populator.setGroupSearchFilter("(member={0})");
|
||||
|
||||
DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=ben,ou=people,dc=springframework,dc=org"));
|
||||
|
||||
List<GrantedAuthority> authorities = populator.getGrantedAuthorities(ctx, "ben");
|
||||
|
||||
assertEquals("Should have 2 roles", 2, authorities.size());
|
||||
|
||||
Set<String> roles = new HashSet<String>();
|
||||
roles.add(authorities.get(0).toString());
|
||||
roles.add(authorities.get(1).toString());
|
||||
assertTrue(roles.contains("ROLE_DEVELOPER"));
|
||||
assertTrue(roles.contains("ROLE_MANAGER"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUseOfUsernameParameterReturnsExpectedRoles() {
|
||||
populator.setGroupRoleAttribute("ou");
|
||||
populator.setConvertToUpperCase(true);
|
||||
populator.setGroupSearchFilter("(ou={1})");
|
||||
|
||||
DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=ben,ou=people,dc=springframework,dc=org"));
|
||||
|
||||
List<GrantedAuthority> authorities = populator.getGrantedAuthorities(ctx, "manager");
|
||||
|
||||
assertEquals("Should have 1 role", 1, authorities.size());
|
||||
assertEquals("ROLE_MANAGER", authorities.get(0).getAuthority());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubGroupRolesAreNotFoundByDefault() {
|
||||
populator.setGroupRoleAttribute("ou");
|
||||
populator.setConvertToUpperCase(true);
|
||||
|
||||
DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=ben,ou=people,dc=springframework,dc=org"));
|
||||
|
||||
List<GrantedAuthority> authorities = populator.getGrantedAuthorities(ctx, "manager");
|
||||
|
||||
assertEquals("Should have 2 roles", 2, authorities.size());
|
||||
Set<String> roles = new HashSet<String>(2);
|
||||
roles.add(authorities.get(0).getAuthority());
|
||||
roles.add(authorities.get(1).getAuthority());
|
||||
assertTrue(roles.contains("ROLE_MANAGER"));
|
||||
assertTrue(roles.contains("ROLE_DEVELOPER"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubGroupRolesAreFoundWhenSubtreeSearchIsEnabled() {
|
||||
populator.setGroupRoleAttribute("ou");
|
||||
populator.setConvertToUpperCase(true);
|
||||
populator.setSearchSubtree(true);
|
||||
|
||||
DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=ben,ou=people,dc=springframework,dc=org"));
|
||||
|
||||
List<GrantedAuthority> authorities = populator.getGrantedAuthorities(ctx, "manager");
|
||||
|
||||
assertEquals("Should have 3 roles", 3, authorities.size());
|
||||
Set<String> roles = new HashSet<String>(3);
|
||||
roles.add(authorities.get(0).getAuthority());
|
||||
roles.add(authorities.get(1).getAuthority());
|
||||
roles.add(authorities.get(2).getAuthority());
|
||||
assertTrue(roles.contains("ROLE_MANAGER"));
|
||||
assertTrue(roles.contains("ROLE_DEVELOPER"));
|
||||
assertTrue(roles.contains("ROLE_SUBMANAGER"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserDnWithEscapedCharacterParameterReturnsExpectedRoles() {
|
||||
populator.setGroupRoleAttribute("ou");
|
||||
populator.setConvertToUpperCase(true);
|
||||
populator.setGroupSearchFilter("(member={0})");
|
||||
|
||||
DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("cn=mouse\\, jerry,ou=people,dc=springframework,dc=org"));
|
||||
|
||||
List<GrantedAuthority> authorities = populator.getGrantedAuthorities(ctx, "notused");
|
||||
|
||||
assertEquals("Should have 1 role", 1, authorities.size());
|
||||
assertEquals("ROLE_MANAGER", authorities.get(0).getAuthority());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.springframework.security.ldap.populator;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class UserDetailsServiceLdapAuthoritiesPopulatorTests {
|
||||
|
||||
@Test
|
||||
public void delegationToUserDetailsServiceReturnsCorrectRoles() throws Exception {
|
||||
UserDetailsService uds = mock(UserDetailsService.class);
|
||||
UserDetails user = mock(UserDetails.class);
|
||||
when(uds.loadUserByUsername("joe")).thenReturn(user);
|
||||
when(user.getAuthorities()).thenReturn(AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
|
||||
UserDetailsServiceLdapAuthoritiesPopulator populator = new UserDetailsServiceLdapAuthoritiesPopulator(uds);
|
||||
List<GrantedAuthority> auths = populator.getGrantedAuthorities(new DirContextAdapter(), "joe");
|
||||
|
||||
assertEquals(1, auths.size());
|
||||
assertEquals("ROLE_USER", auths.get(0).getAuthority());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/* 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.search;
|
||||
|
||||
import org.springframework.security.ldap.AbstractLdapIntegrationTests;
|
||||
import org.springframework.security.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.ldap.core.DirContextOperations;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for FilterBasedLdapUserSearch.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class FilterBasedLdapUserSearchTests extends AbstractLdapIntegrationTests {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private BaseLdapPathContextSource dirCtxFactory;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void onSetUp() throws Exception {
|
||||
super.onSetUp();
|
||||
dirCtxFactory = getContextSource();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicSearchSucceeds() {
|
||||
FilterBasedLdapUserSearch locator = new FilterBasedLdapUserSearch("ou=people", "(uid={0})", dirCtxFactory);
|
||||
locator.setSearchSubtree(false);
|
||||
locator.setSearchTimeLimit(0);
|
||||
locator.setDerefLinkFlag(false);
|
||||
|
||||
DirContextOperations bob = locator.searchForUser("bob");
|
||||
assertEquals("bob", bob.getStringAttribute("uid"));
|
||||
|
||||
assertEquals(new DistinguishedName("uid=bob,ou=people"), bob.getDn());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchForNameWithCommaSucceeds() {
|
||||
FilterBasedLdapUserSearch locator = new FilterBasedLdapUserSearch("ou=people", "(uid={0})", dirCtxFactory);
|
||||
locator.setSearchSubtree(false);
|
||||
|
||||
DirContextOperations jerry = locator.searchForUser("jerry");
|
||||
assertEquals("jerry", jerry.getStringAttribute("uid"));
|
||||
|
||||
assertEquals(new DistinguishedName("cn=mouse\\, jerry,ou=people"), jerry.getDn());
|
||||
}
|
||||
|
||||
// Try some funny business with filters.
|
||||
@Test
|
||||
public void extraFilterPartToExcludeBob() throws Exception {
|
||||
FilterBasedLdapUserSearch locator = new FilterBasedLdapUserSearch("ou=people",
|
||||
"(&(cn=*)(!(|(uid={0})(uid=rod)(uid=jerry))))", dirCtxFactory);
|
||||
|
||||
// Search for bob, get back ben...
|
||||
DirContextOperations ben = locator.searchForUser("bob");
|
||||
assertEquals("Ben Alex", ben.getStringAttribute("cn"));
|
||||
|
||||
// assertEquals("uid=ben,ou=people,"+ROOT_DN, ben.getDn());
|
||||
}
|
||||
|
||||
@Test(expected=IncorrectResultSizeDataAccessException.class)
|
||||
public void searchFailsOnMultipleMatches() {
|
||||
FilterBasedLdapUserSearch locator = new FilterBasedLdapUserSearch("ou=people", "(cn=*)", dirCtxFactory);
|
||||
locator.searchForUser("Ignored");
|
||||
}
|
||||
|
||||
@Test(expected=UsernameNotFoundException.class)
|
||||
public void searchForInvalidUserFails() {
|
||||
FilterBasedLdapUserSearch locator = new FilterBasedLdapUserSearch("ou=people", "(uid={0})", dirCtxFactory);
|
||||
locator.searchForUser("Joe");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subTreeSearchSucceeds() {
|
||||
// Don't set the searchBase, so search from the root.
|
||||
FilterBasedLdapUserSearch locator = new FilterBasedLdapUserSearch("", "(cn={0})", dirCtxFactory);
|
||||
locator.setSearchSubtree(true);
|
||||
|
||||
DirContextOperations ben = locator.searchForUser("Ben Alex");
|
||||
assertEquals("ben", ben.getStringAttribute("uid"));
|
||||
|
||||
assertEquals(new DistinguishedName("uid=ben,ou=people"), ben.getDn());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchWithDifferentSearchBaseIsSuccessful() throws Exception {
|
||||
FilterBasedLdapUserSearch locator = new FilterBasedLdapUserSearch("ou=otherpeople", "(cn={0})", dirCtxFactory);
|
||||
DirContextOperations joe = locator.searchForUser("Joe Smeth");
|
||||
assertEquals("Joe Smeth", joe.getStringAttribute("cn"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
/* 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.providers.ldap;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.Mockery;
|
||||
import org.jmock.integration.junit4.JUnit4Mockery;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DirContextOperations;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.BadCredentialsException;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.ldap.LdapAuthoritiesPopulator;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
import org.springframework.security.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.userdetails.ldap.LdapUserDetailsMapper;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link LdapAuthenticationProvider}.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class LdapAuthenticationProviderTests {
|
||||
Mockery jmock = new JUnit4Mockery();
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Test
|
||||
public void testSupportsUsernamePasswordAuthenticationToken() {
|
||||
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(),
|
||||
new MockAuthoritiesPopulator());
|
||||
|
||||
assertTrue(ldapProvider.supports(UsernamePasswordAuthenticationToken.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultMapperIsSet() {
|
||||
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(),
|
||||
new MockAuthoritiesPopulator());
|
||||
|
||||
assertTrue(ldapProvider.getUserDetailsContextMapper() instanceof LdapUserDetailsMapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyOrNullUserNameThrowsException() {
|
||||
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(),
|
||||
new MockAuthoritiesPopulator());
|
||||
|
||||
try {
|
||||
ldapProvider.authenticate(new UsernamePasswordAuthenticationToken(null, "password"));
|
||||
fail("Expected BadCredentialsException for empty username");
|
||||
} catch (BadCredentialsException expected) {}
|
||||
|
||||
try {
|
||||
ldapProvider.authenticate(new UsernamePasswordAuthenticationToken("", "bobspassword"));
|
||||
fail("Expected BadCredentialsException for null username");
|
||||
} catch (BadCredentialsException expected) {}
|
||||
}
|
||||
|
||||
@Test(expected=BadCredentialsException.class)
|
||||
public void emptyPasswordIsRejected() {
|
||||
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator());
|
||||
ldapProvider.authenticate(new UsernamePasswordAuthenticationToken("jen", ""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usernameNotFoundExceptionIsHiddenByDefault() {
|
||||
final LdapAuthenticator authenticator = jmock.mock(LdapAuthenticator.class);
|
||||
final UsernamePasswordAuthenticationToken joe = new UsernamePasswordAuthenticationToken("joe", "password");
|
||||
jmock.checking(new Expectations() {{
|
||||
oneOf(authenticator).authenticate(joe); will(throwException(new UsernameNotFoundException("nobody")));
|
||||
}});
|
||||
|
||||
LdapAuthenticationProvider provider = new LdapAuthenticationProvider(authenticator);
|
||||
try {
|
||||
provider.authenticate(joe);
|
||||
fail();
|
||||
} catch (BadCredentialsException expected) {
|
||||
if (expected instanceof UsernameNotFoundException) {
|
||||
fail("Exception should have been hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=UsernameNotFoundException.class)
|
||||
public void usernameNotFoundExceptionIsNotHiddenIfConfigured() {
|
||||
final LdapAuthenticator authenticator = jmock.mock(LdapAuthenticator.class);
|
||||
final UsernamePasswordAuthenticationToken joe = new UsernamePasswordAuthenticationToken("joe", "password");
|
||||
jmock.checking(new Expectations() {{
|
||||
oneOf(authenticator).authenticate(joe); will(throwException(new UsernameNotFoundException("nobody")));
|
||||
}});
|
||||
|
||||
LdapAuthenticationProvider provider = new LdapAuthenticationProvider(authenticator);
|
||||
provider.setHideUserNotFoundExceptions(false);
|
||||
provider.authenticate(joe);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalUsage() {
|
||||
MockAuthoritiesPopulator populator = new MockAuthoritiesPopulator();
|
||||
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(), populator);
|
||||
LdapUserDetailsMapper userMapper = new LdapUserDetailsMapper();
|
||||
userMapper.setRoleAttributes(new String[] {"ou"});
|
||||
ldapProvider.setUserDetailsContextMapper(userMapper);
|
||||
|
||||
assertNotNull(ldapProvider.getAuthoritiesPopulator());
|
||||
|
||||
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken("ben", "benspassword");
|
||||
Authentication authResult = ldapProvider.authenticate(authRequest);
|
||||
assertEquals("benspassword", authResult.getCredentials());
|
||||
UserDetails user = (UserDetails) authResult.getPrincipal();
|
||||
assertEquals(2, user.getAuthorities().size());
|
||||
assertEquals("{SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=", user.getPassword());
|
||||
assertEquals("ben", user.getUsername());
|
||||
assertEquals("ben", populator.getRequestedUsername());
|
||||
|
||||
ArrayList<String> authorities = new ArrayList<String>();
|
||||
authorities.add(user.getAuthorities().get(0).getAuthority());
|
||||
authorities.add(user.getAuthorities().get(1).getAuthority());
|
||||
|
||||
assertTrue(authorities.contains("ROLE_FROM_ENTRY"));
|
||||
assertTrue(authorities.contains("ROLE_FROM_POPULATOR"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void passwordIsSetFromUserDataIfUseAuthenticationRequestCredentialsIsFalse() {
|
||||
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator(),
|
||||
new MockAuthoritiesPopulator());
|
||||
ldapProvider.setUseAuthenticationRequestCredentials(false);
|
||||
|
||||
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken("ben", "benspassword");
|
||||
Authentication authResult = ldapProvider.authenticate(authRequest);
|
||||
assertEquals("{SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=", authResult.getCredentials());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useWithNullAuthoritiesPopulatorReturnsCorrectRole() {
|
||||
LdapAuthenticationProvider ldapProvider = new LdapAuthenticationProvider(new MockAuthenticator());
|
||||
LdapUserDetailsMapper userMapper = new LdapUserDetailsMapper();
|
||||
userMapper.setRoleAttributes(new String[] {"ou"});
|
||||
ldapProvider.setUserDetailsContextMapper(userMapper);
|
||||
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken("ben", "benspassword");
|
||||
UserDetails user = (UserDetails) ldapProvider.authenticate(authRequest).getPrincipal();
|
||||
assertEquals(1, user.getAuthorities().size());
|
||||
assertEquals("ROLE_FROM_ENTRY", user.getAuthorities().get(0).getAuthority());
|
||||
}
|
||||
|
||||
//~ Inner Classes ==================================================================================================
|
||||
|
||||
class MockAuthenticator implements LdapAuthenticator {
|
||||
|
||||
public DirContextOperations authenticate(Authentication authentication) {
|
||||
DirContextAdapter ctx = new DirContextAdapter();
|
||||
ctx.setAttributeValue("ou", "FROM_ENTRY");
|
||||
String username = authentication.getName();
|
||||
String password = (String) authentication.getCredentials();
|
||||
|
||||
|
||||
if (username.equals("ben") && password.equals("benspassword")) {
|
||||
ctx.setDn(new DistinguishedName("cn=ben,ou=people,dc=springframework,dc=org"));
|
||||
ctx.setAttributeValue("userPassword","{SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=");
|
||||
|
||||
return ctx;
|
||||
} else if (username.equals("jen") && password.equals("")) {
|
||||
ctx.setDn(new DistinguishedName("cn=jen,ou=people,dc=springframework,dc=org"));
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
throw new BadCredentialsException("Authentication failed.");
|
||||
}
|
||||
}
|
||||
|
||||
class MockAuthoritiesPopulator implements LdapAuthoritiesPopulator {
|
||||
String username;
|
||||
|
||||
public List<GrantedAuthority> getGrantedAuthorities(DirContextOperations userCtx, String username) {
|
||||
this.username = username;
|
||||
return AuthorityUtils.createAuthorityList("ROLE_FROM_POPULATOR");
|
||||
}
|
||||
|
||||
String getRequestedUsername() {
|
||||
return username;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/* 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.providers.ldap.authenticator;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.BadCredentialsException;
|
||||
import org.springframework.security.SpringSecurityMessageSource;
|
||||
import org.springframework.security.ldap.AbstractLdapIntegrationTests;
|
||||
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}.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class BindAuthenticatorTests extends AbstractLdapIntegrationTests {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private BindAuthenticator authenticator;
|
||||
private Authentication bob;
|
||||
// private Authentication ben;
|
||||
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void onSetUp() {
|
||||
authenticator = new BindAuthenticator(getContextSource());
|
||||
authenticator.setMessageSource(new SpringSecurityMessageSource());
|
||||
bob = new UsernamePasswordAuthenticationToken("bob", "bobspassword");
|
||||
// ben = new UsernamePasswordAuthenticationToken("ben", "benspassword");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticationWithCorrectPasswordSucceeds() {
|
||||
authenticator.setUserDnPatterns(new String[] {"uid={0},ou=people"});
|
||||
|
||||
DirContextOperations user = authenticator.authenticate(bob);
|
||||
assertEquals("bob", user.getStringAttribute("uid"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticationWithInvalidUserNameFails() {
|
||||
authenticator.setUserDnPatterns(new String[] {"uid={0},ou=people"});
|
||||
|
||||
try {
|
||||
authenticator.authenticate(new UsernamePasswordAuthenticationToken("nonexistentsuser", "password"));
|
||||
fail("Shouldn't be able to bind with invalid username");
|
||||
} catch (BadCredentialsException expected) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticationWithUserSearch() throws Exception {
|
||||
DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=bob,ou=people"));
|
||||
|
||||
authenticator.setUserSearch(new MockUserSearch(ctx));
|
||||
authenticator.afterPropertiesSet();
|
||||
authenticator.authenticate(bob);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthenticationWithWrongPasswordFails() {
|
||||
authenticator.setUserDnPatterns(new String[] {"uid={0},ou=people"});
|
||||
|
||||
try {
|
||||
authenticator.authenticate(new UsernamePasswordAuthenticationToken("bob", "wrongpassword"));
|
||||
fail("Shouldn't be able to bind with wrong password");
|
||||
} catch (BadCredentialsException expected) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserDnPatternReturnsCorrectDn() {
|
||||
authenticator.setUserDnPatterns(new String[] {"cn={0},ou=people"});
|
||||
assertEquals("cn=Joe,ou=people", authenticator.getUserDns("Joe").get(0));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/* 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.providers.ldap.authenticator;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.security.providers.encoding.LdapShaPasswordEncoder;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link LdapShaPasswordEncoder}.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class LdapShaPasswordEncoderTests {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
LdapShaPasswordEncoder sha;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
sha = new LdapShaPasswordEncoder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidPasswordFails() {
|
||||
assertFalse(sha.isPasswordValid("{SHA}ddSFGmjXYPbZC+NXR2kCzBRjqiE=", "wrongpassword", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidSaltedPasswordFails() {
|
||||
assertFalse(sha.isPasswordValid("{SSHA}25ro4PKC8jhQZ26jVsozhX/xaP0suHgX", "wrongpassword", null));
|
||||
assertFalse(sha.isPasswordValid("{SSHA}PQy2j+6n5ytA+YlAKkM8Fh4p6u2JxfVd", "wrongpassword", null));
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void nonByteArraySaltThrowsException() {
|
||||
sha.encodePassword("password", "AStringNotAByteArray");
|
||||
}
|
||||
|
||||
/**
|
||||
* Test values generated by 'slappasswd -h {SHA} -s boabspasswurd'
|
||||
*/
|
||||
@Test
|
||||
public void validPasswordSucceeds() {
|
||||
sha.setForceLowerCasePrefix(false);
|
||||
assertTrue(sha.isPasswordValid("{SHA}ddSFGmjXYPbZC+NXR2kCzBRjqiE=", "boabspasswurd", null));
|
||||
assertTrue(sha.isPasswordValid("{sha}ddSFGmjXYPbZC+NXR2kCzBRjqiE=", "boabspasswurd", null));
|
||||
sha.setForceLowerCasePrefix(true);
|
||||
assertTrue(sha.isPasswordValid("{SHA}ddSFGmjXYPbZC+NXR2kCzBRjqiE=", "boabspasswurd", null));
|
||||
assertTrue(sha.isPasswordValid("{sha}ddSFGmjXYPbZC+NXR2kCzBRjqiE=", "boabspasswurd", null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test values generated by 'slappasswd -s boabspasswurd'
|
||||
*/
|
||||
@Test
|
||||
public void validSaltedPasswordSucceeds() {
|
||||
sha.setForceLowerCasePrefix(false);
|
||||
assertTrue(sha.isPasswordValid("{SSHA}25ro4PKC8jhQZ26jVsozhX/xaP0suHgX", "boabspasswurd", null));
|
||||
assertTrue(sha.isPasswordValid("{ssha}PQy2j+6n5ytA+YlAKkM8Fh4p6u2JxfVd", "boabspasswurd", null));
|
||||
sha.setForceLowerCasePrefix(true);
|
||||
assertTrue(sha.isPasswordValid("{SSHA}25ro4PKC8jhQZ26jVsozhX/xaP0suHgX", "boabspasswurd", null));
|
||||
assertTrue(sha.isPasswordValid("{ssha}PQy2j+6n5ytA+YlAKkM8Fh4p6u2JxfVd", "boabspasswurd", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
// SEC-1031
|
||||
public void fullLengthOfHashIsUsedInComparison() throws Exception {
|
||||
// Change the first hash character from '2' to '3'
|
||||
assertFalse(sha.isPasswordValid("{SSHA}35ro4PKC8jhQZ26jVsozhX/xaP0suHgX", "boabspasswurd", null));
|
||||
// Change the last hash character from 'X' to 'Y'
|
||||
assertFalse(sha.isPasswordValid("{SSHA}25ro4PKC8jhQZ26jVsozhX/xaP0suHgY", "boabspasswurd", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void correctPrefixCaseIsUsed() {
|
||||
sha.setForceLowerCasePrefix(false);
|
||||
assertEquals("{SHA}ddSFGmjXYPbZC+NXR2kCzBRjqiE=", sha.encodePassword("boabspasswurd", null));
|
||||
assertTrue(sha.encodePassword("somepassword", "salt".getBytes()).startsWith("{SSHA}"));
|
||||
|
||||
sha.setForceLowerCasePrefix(true);
|
||||
assertEquals("{sha}ddSFGmjXYPbZC+NXR2kCzBRjqiE=", sha.encodePassword("boabspasswurd", null));
|
||||
assertTrue(sha.encodePassword("somepassword", "salt".getBytes()).startsWith("{ssha}"));
|
||||
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void invalidPrefixIsRejected() {
|
||||
sha.isPasswordValid("{MD9}xxxxxxxxxx" , "somepassword", null);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void malformedPrefixIsRejected() {
|
||||
// No right brace
|
||||
sha.isPasswordValid("{SSHA25ro4PKC8jhQZ26jVsozhX/xaP0suHgX" , "somepassword", null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/* 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.providers.ldap.authenticator;
|
||||
|
||||
import org.springframework.security.ldap.LdapUserSearch;
|
||||
|
||||
import org.springframework.ldap.core.DirContextOperations;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class MockUserSearch implements LdapUserSearch {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
DirContextOperations user;
|
||||
|
||||
//~ Constructors ===================================================================================================
|
||||
|
||||
public MockUserSearch() {
|
||||
}
|
||||
|
||||
public MockUserSearch(DirContextOperations user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public DirContextOperations searchForUser(String username) {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/* 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.providers.ldap.authenticator;
|
||||
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.BasicAttribute;
|
||||
import javax.naming.directory.BasicAttributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.SearchControls;
|
||||
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.Mockery;
|
||||
import org.jmock.integration.junit4.JUnit4Mockery;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class PasswordComparisonAuthenticatorMockTests {
|
||||
Mockery jmock = new JUnit4Mockery();
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@Test
|
||||
public void ldapCompareOperationIsUsedWhenPasswordIsNotRetrieved() throws Exception {
|
||||
final DirContext dirCtx = jmock.mock(DirContext.class);
|
||||
final BaseLdapPathContextSource source = jmock.mock(BaseLdapPathContextSource.class);
|
||||
final BasicAttributes attrs = new BasicAttributes();
|
||||
attrs.put(new BasicAttribute("uid", "bob"));
|
||||
|
||||
PasswordComparisonAuthenticator authenticator = new PasswordComparisonAuthenticator(source);
|
||||
|
||||
authenticator.setUserDnPatterns(new String[] {"cn={0},ou=people"});
|
||||
|
||||
// Get the mock to return an empty attribute set
|
||||
jmock.checking(new Expectations() {{
|
||||
allowing(source).getReadOnlyContext(); will(returnValue(dirCtx));
|
||||
oneOf(dirCtx).getAttributes(with(equal("cn=Bob,ou=people")), with(aNull(String[].class))); will(returnValue(attrs));
|
||||
oneOf(dirCtx).getNameInNamespace(); will(returnValue("dc=springframework,dc=org"));
|
||||
}});
|
||||
|
||||
// Setup a single return value (i.e. success)
|
||||
final Attributes searchResults = new BasicAttributes("", null);
|
||||
|
||||
jmock.checking(new Expectations() {{
|
||||
oneOf(dirCtx).search(with(equal("cn=Bob,ou=people")),
|
||||
with(equal("(userPassword={0})")),
|
||||
with(aNonNull(Object[].class)),
|
||||
with(aNonNull(SearchControls.class)));
|
||||
will(returnValue(searchResults.getAll()));
|
||||
atLeast(1).of(dirCtx).close();
|
||||
}});
|
||||
|
||||
authenticator.authenticate(new UsernamePasswordAuthenticationToken("Bob","bobspassword"));
|
||||
|
||||
jmock.assertIsSatisfied();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/* 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.providers.ldap.authenticator;
|
||||
|
||||
import org.springframework.security.BadCredentialsException;
|
||||
import org.springframework.security.Authentication;
|
||||
|
||||
import org.springframework.security.ldap.AbstractLdapIntegrationTests;
|
||||
|
||||
import org.springframework.security.providers.encoding.LdapShaPasswordEncoder;
|
||||
import org.springframework.security.providers.encoding.PlaintextPasswordEncoder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
|
||||
import org.springframework.security.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link PasswordComparisonAuthenticator}.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class PasswordComparisonAuthenticatorTests extends AbstractLdapIntegrationTests {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private PasswordComparisonAuthenticator authenticator;
|
||||
private Authentication bob;
|
||||
private Authentication ben;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void onSetUp() throws Exception {
|
||||
super.onSetUp();
|
||||
authenticator = new PasswordComparisonAuthenticator(getContextSource());
|
||||
authenticator.setPasswordEncoder(new PlaintextPasswordEncoder());
|
||||
authenticator.setUserDnPatterns(new String[] {"uid={0},ou=people"});
|
||||
bob = new UsernamePasswordAuthenticationToken("bob", "bobspassword");
|
||||
ben = new UsernamePasswordAuthenticationToken("ben", "benspassword");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllAttributesAreRetrievedByDefault() {
|
||||
DirContextAdapter user = (DirContextAdapter) authenticator.authenticate(bob);
|
||||
//System.out.println(user.getAttributes().toString());
|
||||
assertEquals("User should have 5 attributes", 5, user.getAttributes().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailedSearchGivesUserNotFoundException() throws Exception {
|
||||
authenticator = new PasswordComparisonAuthenticator(getContextSource());
|
||||
assertTrue("User DN matches shouldn't be available", authenticator.getUserDns("Bob").isEmpty());
|
||||
authenticator.setUserSearch(new MockUserSearch(null));
|
||||
authenticator.afterPropertiesSet();
|
||||
|
||||
try {
|
||||
authenticator.authenticate(new UsernamePasswordAuthenticationToken("Joe", "pass"));
|
||||
fail("Expected exception on failed user search");
|
||||
} catch (UsernameNotFoundException expected) {}
|
||||
}
|
||||
|
||||
@Test(expected = BadCredentialsException.class)
|
||||
public void testLdapPasswordCompareFailsWithWrongPassword() {
|
||||
// Don't retrieve the password
|
||||
authenticator.setUserAttributes(new String[] {"uid", "cn", "sn"});
|
||||
authenticator.authenticate(new UsernamePasswordAuthenticationToken("bob", "wrongpass"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleDnPatternsWorkOk() {
|
||||
authenticator.setUserDnPatterns(new String[] {"uid={0},ou=nonexistent", "uid={0},ou=people"});
|
||||
authenticator.authenticate(bob);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnlySpecifiedAttributesAreRetrieved() throws Exception {
|
||||
authenticator.setUserAttributes(new String[] {"uid", "userPassword"});
|
||||
|
||||
DirContextAdapter user = (DirContextAdapter) authenticator.authenticate(bob);
|
||||
assertEquals("Should have retrieved 2 attribute (uid, userPassword)", 2, user.getAttributes().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLdapCompareSucceedsWithCorrectPassword() {
|
||||
// Don't retrieve the password
|
||||
authenticator.setUserAttributes(new String[] {"uid"});
|
||||
authenticator.authenticate(bob);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLdapCompareSucceedsWithShaEncodedPassword() {
|
||||
// Don't retrieve the password
|
||||
authenticator.setUserAttributes(new String[] {"uid"});
|
||||
authenticator.setPasswordEncoder(new LdapShaPasswordEncoder());
|
||||
authenticator.authenticate(ben);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testPasswordEncoderCantBeNull() {
|
||||
authenticator.setPasswordEncoder(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUseOfDifferentPasswordAttributeSucceeds() {
|
||||
authenticator.setPasswordAttributeName("uid");
|
||||
authenticator.authenticate(new UsernamePasswordAuthenticationToken("bob", "bob"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLdapCompareWithDifferentPasswordAttributeSucceeds() {
|
||||
authenticator.setUserAttributes(new String[] {"uid"});
|
||||
authenticator.setPasswordAttributeName("cn");
|
||||
authenticator.authenticate(new UsernamePasswordAuthenticationToken("ben", "Ben Alex"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithUserSearch() {
|
||||
authenticator = new PasswordComparisonAuthenticator(getContextSource());
|
||||
authenticator.setPasswordEncoder(new PlaintextPasswordEncoder());
|
||||
assertTrue("User DN matches shouldn't be available", authenticator.getUserDns("Bob").isEmpty());
|
||||
|
||||
DirContextAdapter ctx = new DirContextAdapter(new DistinguishedName("uid=Bob,ou=people"));
|
||||
ctx.setAttributeValue("userPassword", "bobspassword");
|
||||
|
||||
authenticator.setUserSearch(new MockUserSearch(ctx));
|
||||
authenticator.authenticate(new UsernamePasswordAuthenticationToken("shouldntbeused", "bobspassword"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package org.springframework.security.userdetails.ldap;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class InetOrgPersonTests extends TestCase {
|
||||
|
||||
public void testUsernameIsMappedFromContextUidIfNotSet() {
|
||||
InetOrgPerson.Essence essence = new InetOrgPerson.Essence(createUserContext());
|
||||
InetOrgPerson p = (InetOrgPerson) essence.createUserDetails();
|
||||
|
||||
assertEquals("ghengis", p.getUsername());
|
||||
}
|
||||
|
||||
public void testUsernameIsDifferentFromContextUidIfSet() {
|
||||
InetOrgPerson.Essence essence = new InetOrgPerson.Essence(createUserContext());
|
||||
essence.setUsername("joe");
|
||||
InetOrgPerson p = (InetOrgPerson) essence.createUserDetails();
|
||||
|
||||
assertEquals("joe", p.getUsername());
|
||||
assertEquals("ghengis", p.getUid());
|
||||
}
|
||||
|
||||
public void testAttributesMapCorrectlyFromContext() {
|
||||
InetOrgPerson.Essence essence = new InetOrgPerson.Essence(createUserContext());
|
||||
InetOrgPerson p = (InetOrgPerson) essence.createUserDetails();
|
||||
|
||||
assertEquals("HORS1", p.getCarLicense());
|
||||
assertEquals("ghengis@mongolia", p.getMail());
|
||||
assertEquals("Khan", p.getSn());
|
||||
assertEquals("Ghengis Khan", p.getCn()[0]);
|
||||
assertEquals("00001", p.getEmployeeNumber());
|
||||
assertEquals("+442075436521", p.getTelephoneNumber());
|
||||
assertEquals("Steppes", p.getHomePostalAddress());
|
||||
assertEquals("+467575436521", p.getHomePhone());
|
||||
assertEquals("Hordes", p.getO());
|
||||
assertEquals("Horde1", p.getOu());
|
||||
assertEquals("On the Move", p.getPostalAddress());
|
||||
assertEquals("Changes Frequently", p.getPostalCode());
|
||||
assertEquals("Yurt 1", p.getRoomNumber());
|
||||
assertEquals("Westward Avenue", p.getStreet());
|
||||
assertEquals("Scary", p.getDescription());
|
||||
assertEquals("Ghengis McCann", p.getDisplayName());
|
||||
assertEquals("G", p.getInitials());
|
||||
}
|
||||
|
||||
public void testPasswordIsSetFromContextUserPassword() {
|
||||
InetOrgPerson.Essence essence = new InetOrgPerson.Essence(createUserContext());
|
||||
InetOrgPerson p = (InetOrgPerson) essence.createUserDetails();
|
||||
|
||||
assertEquals("pillage", p.getPassword());
|
||||
}
|
||||
|
||||
public void testMappingBackToContextMatchesOriginalData() {
|
||||
DirContextAdapter ctx1 = createUserContext();
|
||||
DirContextAdapter ctx2 = new DirContextAdapter();
|
||||
ctx1.setAttributeValues("objectclass", new String[] {"top", "person", "organizationalPerson", "inetOrgPerson"});
|
||||
ctx2.setDn(new DistinguishedName("ignored=ignored"));
|
||||
InetOrgPerson p = (InetOrgPerson) (new InetOrgPerson.Essence(ctx1)).createUserDetails();
|
||||
p.populateContext(ctx2);
|
||||
|
||||
assertEquals(ctx1, ctx2);
|
||||
}
|
||||
|
||||
public void testCopyMatchesOriginalData() {
|
||||
DirContextAdapter ctx1 = createUserContext();
|
||||
DirContextAdapter ctx2 = new DirContextAdapter();
|
||||
ctx2.setDn(new DistinguishedName("ignored=ignored"));
|
||||
ctx1.setAttributeValues("objectclass", new String[] {"top", "person", "organizationalPerson", "inetOrgPerson"});
|
||||
InetOrgPerson p = (InetOrgPerson) (new InetOrgPerson.Essence(ctx1)).createUserDetails();
|
||||
InetOrgPerson p2 = (InetOrgPerson) new InetOrgPerson.Essence(p).createUserDetails();
|
||||
p2.populateContext(ctx2);
|
||||
|
||||
assertEquals(ctx1, ctx2);
|
||||
}
|
||||
|
||||
private DirContextAdapter createUserContext() {
|
||||
DirContextAdapter ctx = new DirContextAdapter();
|
||||
|
||||
ctx.setDn(new DistinguishedName("ignored=ignored"));
|
||||
ctx.setAttributeValue("uid", "ghengis");
|
||||
ctx.setAttributeValue("userPassword", "pillage");
|
||||
ctx.setAttributeValue("carLicense", "HORS1");
|
||||
ctx.setAttributeValue("cn", "Ghengis Khan");
|
||||
ctx.setAttributeValue("description", "Scary");
|
||||
ctx.setAttributeValue("destinationIndicator", "West");
|
||||
ctx.setAttributeValue("displayName", "Ghengis McCann");
|
||||
ctx.setAttributeValue("homePhone", "+467575436521");
|
||||
ctx.setAttributeValue("initials", "G");
|
||||
ctx.setAttributeValue("employeeNumber", "00001");
|
||||
ctx.setAttributeValue("homePostalAddress", "Steppes");
|
||||
ctx.setAttributeValue("mail", "ghengis@mongolia");
|
||||
ctx.setAttributeValue("mobile", "always");
|
||||
ctx.setAttributeValue("o", "Hordes");
|
||||
ctx.setAttributeValue("ou", "Horde1");
|
||||
ctx.setAttributeValue("postalAddress", "On the Move");
|
||||
ctx.setAttributeValue("postalCode", "Changes Frequently");
|
||||
ctx.setAttributeValue("roomNumber", "Yurt 1");
|
||||
ctx.setAttributeValue("roomNumber", "Yurt 1");
|
||||
ctx.setAttributeValue("sn", "Khan");
|
||||
ctx.setAttributeValue("street", "Westward Avenue");
|
||||
ctx.setAttributeValue("telephoneNumber", "+442075436521");
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/* 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.userdetails.ldap;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.security.BadCredentialsException;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.ldap.AbstractLdapIntegrationTests;
|
||||
import org.springframework.security.ldap.DefaultLdapUsernameToDnMapper;
|
||||
import org.springframework.security.ldap.SpringSecurityLdapTemplate;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class LdapUserDetailsManagerTests extends AbstractLdapIntegrationTests {
|
||||
private static final List<GrantedAuthority> TEST_AUTHORITIES = AuthorityUtils.createAuthorityList("ROLE_CLOWNS","ROLE_ACROBATS");
|
||||
private LdapUserDetailsManager mgr;
|
||||
private SpringSecurityLdapTemplate template;
|
||||
|
||||
public void onSetUp() throws Exception {
|
||||
super.onSetUp();
|
||||
mgr = new LdapUserDetailsManager(getContextSource());
|
||||
template = new SpringSecurityLdapTemplate(getContextSource());
|
||||
DirContextAdapter ctx = new DirContextAdapter();
|
||||
|
||||
ctx.setAttributeValue("objectclass", "organizationalUnit");
|
||||
ctx.setAttributeValue("ou", "test people");
|
||||
template.bind("ou=test people", ctx, null);
|
||||
|
||||
ctx.setAttributeValue("ou", "testgroups");
|
||||
template.bind("ou=testgroups", ctx, null);
|
||||
|
||||
DirContextAdapter group = new DirContextAdapter();
|
||||
|
||||
group.setAttributeValue("objectclass", "groupOfNames");
|
||||
group.setAttributeValue("cn", "clowns");
|
||||
group.setAttributeValue("member", "cn=nobody,ou=test people,dc=springframework,dc=org");
|
||||
template.bind("cn=clowns,ou=testgroups", group, null);
|
||||
|
||||
group.setAttributeValue("cn", "acrobats");
|
||||
template.bind("cn=acrobats,ou=testgroups", group, null);
|
||||
|
||||
mgr.setUsernameMapper(new DefaultLdapUsernameToDnMapper("ou=test people","uid"));
|
||||
mgr.setGroupSearchBase("ou=testgroups");
|
||||
mgr.setGroupRoleAttributeName("cn");
|
||||
mgr.setGroupMemberAttributeName("member");
|
||||
mgr.setUserDetailsMapper(new PersonContextMapper());
|
||||
}
|
||||
|
||||
@After
|
||||
public void onTearDown() throws Exception {
|
||||
// Iterator people = template.list("ou=testpeople").iterator();
|
||||
|
||||
// DirContext rootCtx = new DirContextAdapter(new DistinguishedName(getInitialCtxFactory().getRootDn()));
|
||||
//
|
||||
// while(people.hasNext()) {
|
||||
// template.unbind((String) people.next() + ",ou=testpeople");
|
||||
// }
|
||||
|
||||
template.unbind("ou=test people",true);
|
||||
template.unbind("ou=testgroups",true);
|
||||
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadUserByUsernameReturnsCorrectData() {
|
||||
mgr.setUsernameMapper(new DefaultLdapUsernameToDnMapper("ou=people","uid"));
|
||||
mgr.setGroupSearchBase("ou=groups");
|
||||
LdapUserDetails bob = (LdapUserDetails) mgr.loadUserByUsername("bob");
|
||||
assertEquals("bob", bob.getUsername());
|
||||
assertEquals("uid=bob,ou=people,dc=springframework,dc=org", bob.getDn());
|
||||
assertEquals("bobspassword", bob.getPassword());
|
||||
|
||||
assertEquals(1, bob.getAuthorities().size());
|
||||
}
|
||||
|
||||
@Test(expected = UsernameNotFoundException.class)
|
||||
public void testLoadingInvalidUsernameThrowsUsernameNotFoundException() {
|
||||
mgr.loadUserByUsername("jim");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserExistsReturnsTrueForValidUser() {
|
||||
mgr.setUsernameMapper(new DefaultLdapUsernameToDnMapper("ou=people","uid"));
|
||||
assertTrue(mgr.userExists("bob"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUserExistsReturnsFalseForInValidUser() {
|
||||
assertFalse(mgr.userExists("jim"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateNewUserSucceeds() {
|
||||
InetOrgPerson.Essence p = new InetOrgPerson.Essence();
|
||||
p.setCarLicense("XXX");
|
||||
p.setCn(new String[] {"Joe Smeth"});
|
||||
p.setDepartmentNumber("5679");
|
||||
p.setDescription("Some description");
|
||||
p.setDn("whocares");
|
||||
p.setEmployeeNumber("E781");
|
||||
p.setInitials("J");
|
||||
p.setMail("joe@smeth.com");
|
||||
p.setMobile("+44776542911");
|
||||
p.setOu("Joes Unit");
|
||||
p.setO("Organization");
|
||||
p.setRoomNumber("500X");
|
||||
p.setSn("Smeth");
|
||||
p.setUid("joe");
|
||||
|
||||
p.setAuthorities(TEST_AUTHORITIES);
|
||||
|
||||
mgr.createUser(p.createUserDetails());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteUserSucceeds() {
|
||||
InetOrgPerson.Essence p = new InetOrgPerson.Essence();
|
||||
p.setDn("whocares");
|
||||
p.setCn(new String[] {"Don Smeth"});
|
||||
p.setSn("Smeth");
|
||||
p.setUid("don");
|
||||
p.setAuthorities(TEST_AUTHORITIES);
|
||||
|
||||
mgr.createUser(p.createUserDetails());
|
||||
mgr.setUserDetailsMapper(new InetOrgPersonContextMapper());
|
||||
|
||||
InetOrgPerson don = (InetOrgPerson) mgr.loadUserByUsername("don");
|
||||
|
||||
assertEquals(2, don.getAuthorities().size());
|
||||
|
||||
mgr.deleteUser("don");
|
||||
|
||||
try {
|
||||
mgr.loadUserByUsername("don");
|
||||
fail("Expected UsernameNotFoundException after deleting user");
|
||||
} catch(UsernameNotFoundException expected) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// Check that no authorities are left
|
||||
assertEquals(0, mgr.getUserAuthorities(mgr.usernameMapper.buildDn("don"), "don").size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPasswordChangeWithCorrectOldPasswordSucceeds() {
|
||||
InetOrgPerson.Essence p = new InetOrgPerson.Essence();
|
||||
p.setDn("whocares");
|
||||
p.setCn(new String[] {"John Yossarian"});
|
||||
p.setSn("Yossarian");
|
||||
p.setUid("johnyossarian");
|
||||
p.setPassword("yossarianspassword");
|
||||
p.setAuthorities(TEST_AUTHORITIES);
|
||||
|
||||
mgr.createUser(p.createUserDetails());
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new UsernamePasswordAuthenticationToken("johnyossarian", "yossarianspassword", TEST_AUTHORITIES));
|
||||
|
||||
mgr.changePassword("yossarianspassword", "yossariansnewpassword");
|
||||
|
||||
assertTrue(template.compare("uid=johnyossarian,ou=test people",
|
||||
"userPassword", "yossariansnewpassword"));
|
||||
}
|
||||
|
||||
@Test(expected = BadCredentialsException.class)
|
||||
public void testPasswordChangeWithWrongOldPasswordFails() {
|
||||
InetOrgPerson.Essence p = new InetOrgPerson.Essence();
|
||||
p.setDn("whocares");
|
||||
p.setCn(new String[] {"John Yossarian"});
|
||||
p.setSn("Yossarian");
|
||||
p.setUid("johnyossarian");
|
||||
p.setPassword("yossarianspassword");
|
||||
p.setAuthorities(TEST_AUTHORITIES);
|
||||
|
||||
mgr.createUser(p.createUserDetails());
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new UsernamePasswordAuthenticationToken("johnyossarian", "yossarianspassword", TEST_AUTHORITIES));
|
||||
|
||||
mgr.changePassword("wrongpassword", "yossariansnewpassword");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/* 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.userdetails.ldap;
|
||||
|
||||
import javax.naming.directory.BasicAttribute;
|
||||
import javax.naming.directory.BasicAttributes;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
|
||||
/**
|
||||
* Tests {@link LdapUserDetailsMapper}.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class LdapUserDetailsMapperTests extends TestCase {
|
||||
|
||||
public void testMultipleRoleAttributeValuesAreMappedToAuthorities() throws Exception {
|
||||
LdapUserDetailsMapper mapper = new LdapUserDetailsMapper();
|
||||
mapper.setConvertToUpperCase(false);
|
||||
mapper.setRolePrefix("");
|
||||
|
||||
mapper.setRoleAttributes(new String[] {"userRole"});
|
||||
|
||||
DirContextAdapter ctx = new DirContextAdapter();
|
||||
|
||||
ctx.setAttributeValues("userRole", new String[] {"X", "Y", "Z"});
|
||||
ctx.setAttributeValue("uid", "ani");
|
||||
|
||||
LdapUserDetailsImpl user = (LdapUserDetailsImpl) mapper.mapUserFromContext(ctx, "ani", AuthorityUtils.NO_AUTHORITIES);
|
||||
|
||||
assertEquals(3, user.getAuthorities().size());
|
||||
}
|
||||
|
||||
/**
|
||||
* SEC-303. Non-retrieved role attribute causes NullPointerException
|
||||
*/
|
||||
public void testNonRetrievedRoleAttributeIsIgnored() throws Exception {
|
||||
LdapUserDetailsMapper mapper = new LdapUserDetailsMapper();
|
||||
|
||||
mapper.setRoleAttributes(new String[] {"userRole", "nonRetrievedAttribute"});
|
||||
|
||||
BasicAttributes attrs = new BasicAttributes();
|
||||
attrs.put(new BasicAttribute("userRole", "x"));
|
||||
|
||||
DirContextAdapter ctx = new DirContextAdapter(attrs, new DistinguishedName("cn=someName"));
|
||||
ctx.setAttributeValue("uid", "ani");
|
||||
|
||||
LdapUserDetailsImpl user = (LdapUserDetailsImpl) mapper.mapUserFromContext(ctx, "ani", AuthorityUtils.NO_AUTHORITIES);
|
||||
|
||||
assertEquals(1, user.getAuthorities().size());
|
||||
assertEquals("ROLE_X", user.getAuthorities().get(0).getAuthority());
|
||||
}
|
||||
|
||||
public void testPasswordAttributeIsMappedCorrectly() throws Exception {
|
||||
LdapUserDetailsMapper mapper = new LdapUserDetailsMapper();
|
||||
|
||||
mapper.setPasswordAttributeName("myappsPassword");
|
||||
BasicAttributes attrs = new BasicAttributes();
|
||||
attrs.put(new BasicAttribute("myappsPassword", "mypassword".getBytes()));
|
||||
|
||||
DirContextAdapter ctx = new DirContextAdapter(attrs, new DistinguishedName("cn=someName"));
|
||||
ctx.setAttributeValue("uid", "ani");
|
||||
|
||||
LdapUserDetails user = (LdapUserDetailsImpl) mapper.mapUserFromContext(ctx, "ani", AuthorityUtils.NO_AUTHORITIES);
|
||||
|
||||
assertEquals("mypassword", user.getPassword());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.springframework.security.userdetails.ldap;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.ldap.core.DirContextAdapter;
|
||||
import org.springframework.ldap.core.DirContextOperations;
|
||||
import org.springframework.ldap.core.DistinguishedName;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.ldap.LdapAuthoritiesPopulator;
|
||||
import org.springframework.security.providers.ldap.authenticator.MockUserSearch;
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
import org.springframework.security.util.AuthorityUtils;
|
||||
|
||||
/**
|
||||
* Tests for {@link LdapUserDetailsService}
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class LdapUserDetailsServiceTests {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsNullSearchObject() {
|
||||
new LdapUserDetailsService(null, new MockAuthoritiesPopulator());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void rejectsNullAuthoritiesPopulator() {
|
||||
new LdapUserDetailsService(new MockUserSearch(), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void correctAuthoritiesAreReturned() {
|
||||
DirContextAdapter userData = new DirContextAdapter(new DistinguishedName("uid=joe"));
|
||||
|
||||
LdapUserDetailsService service =
|
||||
new LdapUserDetailsService(new MockUserSearch(userData), new MockAuthoritiesPopulator());
|
||||
service.setUserDetailsMapper(new LdapUserDetailsMapper());
|
||||
|
||||
UserDetails user = service.loadUserByUsername("doesntmatterwegetjoeanyway");
|
||||
|
||||
Set<String> authorities = AuthorityUtils.authorityListToSet(user.getAuthorities());
|
||||
assertEquals(1, authorities.size());
|
||||
assertTrue(authorities.contains("ROLE_FROM_POPULATOR"));
|
||||
}
|
||||
|
||||
class MockAuthoritiesPopulator implements LdapAuthoritiesPopulator {
|
||||
public List<GrantedAuthority> getGrantedAuthorities(DirContextOperations userCtx, String username) {
|
||||
return AuthorityUtils.createAuthorityList("ROLE_FROM_POPULATOR");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user