diff --git a/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.groovy b/config/src/integration-test/groovy/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.groovy similarity index 76% rename from config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.groovy rename to config/src/integration-test/groovy/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.groovy index d03bda4ae7..46d7b37f46 100644 --- a/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.groovy +++ b/config/src/integration-test/groovy/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderBuilderSecurityBuilderTests.groovy @@ -15,10 +15,12 @@ */ package org.springframework.security.config.annotation.authentication.ldap +import org.springframework.beans.factory.config.AutowireCapableBeanFactory import org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Import import org.springframework.ldap.core.ContextSource; import org.springframework.ldap.core.support.BaseLdapPathContextSource; import org.springframework.security.authentication.AuthenticationManager @@ -27,7 +29,12 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio import org.springframework.security.config.annotation.BaseSpringSpec import org.springframework.security.config.annotation.SecurityBuilder; import org.springframework.security.config.annotation.authentication.AuthenticationManagerBuilder -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder +import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication +import org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessor +import org.springframework.security.config.annotation.configuration.AutowireBeanFactoryObjectPostProcessorTests +import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.security.ldap.DefaultSpringSecurityContextSource; import org.springframework.security.ldap.authentication.LdapAuthenticationProvider; @@ -58,6 +65,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp auth .ldapAuthentication() .contextSource(contextSource()) + .userDnPatterns("uid={0},ou=people") } } @@ -75,6 +83,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp auth .ldapAuthentication() .contextSource(contextSource()) + .userDnPatterns("uid={0},ou=people") .groupRoleAttribute("group") } } @@ -93,6 +102,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp auth .ldapAuthentication() .contextSource(contextSource()) + .userDnPatterns("uid={0},ou=people") .groupSearchFilter("ou=groupName"); } } @@ -111,6 +121,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp auth .ldapAuthentication() .contextSource(contextSource()) + .userDnPatterns("uid={0},ou=people") .rolePrefix("role_") } } @@ -121,7 +132,7 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp AuthenticationManager auth = context.getBean(AuthenticationManager) then: auth - auth.authenticate(new UsernamePasswordAuthenticationToken("admin","password")).authorities.collect { it.authority }.sort() == ["ROLE_ADMIN","ROLE_USER"] + auth.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword")).authorities.collect { it.authority }.sort() == ["ROLE_DEVELOPERS"] } @Configuration @@ -131,30 +142,29 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp .ldapAuthentication() .contextSource(contextSource()) .groupSearchBase("ou=groups") + .groupSearchFilter("(member={0})") .userDnPatterns("uid={0},ou=people"); } } def "SEC-2472: Can use crypto PasswordEncoder"() { setup: - PasswordEncoderConfig.PE = Mock(PasswordEncoder) loadConfig(PasswordEncoderConfig) when: AuthenticationManager auth = context.getBean(AuthenticationManager) then: - auth.authenticate(new UsernamePasswordAuthenticationToken("admin","password")).authorities.collect { it.authority }.sort() == ["ROLE_ADMIN","ROLE_USER"] - PasswordEncoderConfig.PE.matches(_, _) << true + auth.authenticate(new UsernamePasswordAuthenticationToken("bcrypt","password")).authorities.collect { it.authority }.sort() == ["ROLE_DEVELOPERS"] } @Configuration static class PasswordEncoderConfig extends BaseLdapServerConfig { - static PasswordEncoder PE protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .ldapAuthentication() .contextSource(contextSource()) - .passwordEncoder(PE) + .passwordEncoder(new BCryptPasswordEncoder()) .groupSearchBase("ou=groups") + .groupSearchFilter("(member={0})") .userDnPatterns("uid={0},ou=people"); } } @@ -167,23 +177,44 @@ class LdapAuthenticationProviderBuilderSecurityBuilderTests extends BaseSpringSp static abstract class BaseLdapServerConfig extends BaseLdapProviderConfig { @Bean public ApacheDSContainer ldapServer() throws Exception { - ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/users.ldif"); - apacheDSContainer.setPort(33389); + ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif"); + apacheDSContainer.setPort(getPort()); return apacheDSContainer; } } @Configuration + @EnableGlobalAuthentication + @Import(ObjectPostProcessorConfiguration) static abstract class BaseLdapProviderConfig { @Bean public BaseLdapPathContextSource contextSource() throws Exception { DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource( - "ldap://127.0.0.1:33389/dc=springframework,dc=org") + "ldap://127.0.0.1:"+ getPort() + "/dc=springframework,dc=org") contextSource.userDn = "uid=admin,ou=system" contextSource.password = "secret" - contextSource.afterPropertiesSet(); + contextSource.afterPropertiesSet() return contextSource; } + + @Bean + public AuthenticationManager authenticationManager(AuthenticationManagerBuilder auth) { + configure(auth) + auth.build() + } + + abstract protected void configure(AuthenticationManagerBuilder auth) + } + + static Integer port; + + static int getPort() { + if(port == null) { + ServerSocket socket = new ServerSocket(0) + port = socket.localPort + socket.close() + } + port } } diff --git a/config/src/integration-test/groovy/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderConfigurerTests.groovy b/config/src/integration-test/groovy/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderConfigurerTests.groovy new file mode 100644 index 0000000000..5301b39c17 --- /dev/null +++ b/config/src/integration-test/groovy/org/springframework/security/config/annotation/authentication/ldap/LdapAuthenticationProviderConfigurerTests.groovy @@ -0,0 +1,61 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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.config.annotation.authentication.ldap + +import org.springframework.context.annotation.Configuration +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +import org.springframework.security.config.annotation.BaseSpringSpec +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder +import org.springframework.security.config.annotation.authentication.ldap.NamespaceLdapAuthenticationProviderTestsConfigs.LdapAuthenticationProviderConfig +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter +import org.springframework.security.ldap.authentication.LdapAuthenticationProvider +import org.springframework.security.ldap.authentication.PasswordComparisonAuthenticator +import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator +import org.springframework.security.ldap.userdetails.PersonContextMapper +import org.springframework.test.util.ReflectionTestUtils + +import static org.springframework.security.config.annotation.authentication.ldap.NamespaceLdapAuthenticationProviderTestsConfigs.* + +/** + * + * @author Rob Winch + * + */ +class LdapAuthenticationProviderConfigurerTests extends BaseSpringSpec { + + def "authentication-manager support multiple default ldap contexts (ports dynamically allocated)"() { + when: + loadConfig(MultiLdapAuthenticationProvidersConfig) + then: + authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword")) + } + + @EnableWebSecurity + @Configuration + static class MultiLdapAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter { + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth + .ldapAuthentication() + .groupSearchBase("ou=groups") + .userDnPatterns("uid={0},ou=people") +// .and() +// .ldapAuthentication() +// .groupSearchBase("ou=groups") +// .userDnPatterns("uid={0},ou=people") + } + } +} diff --git a/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/NamespaceLdapAuthenticationProviderTests.groovy b/config/src/integration-test/groovy/org/springframework/security/config/annotation/authentication/ldap/NamespaceLdapAuthenticationProviderTests.groovy similarity index 95% rename from config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/NamespaceLdapAuthenticationProviderTests.groovy rename to config/src/integration-test/groovy/org/springframework/security/config/annotation/authentication/ldap/NamespaceLdapAuthenticationProviderTests.groovy index 7501dc6986..35589b33e0 100644 --- a/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/NamespaceLdapAuthenticationProviderTests.groovy +++ b/config/src/integration-test/groovy/org/springframework/security/config/annotation/authentication/ldap/NamespaceLdapAuthenticationProviderTests.groovy @@ -40,7 +40,7 @@ class NamespaceLdapAuthenticationProviderTests extends BaseSpringSpec { when: loadConfig(LdapAuthenticationProviderConfig) then: - authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password")).authorities*.authority.sort() == ['ROLE_USER'] + authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword")) } def "ldap-authentication-provider custom"() { @@ -75,6 +75,6 @@ class NamespaceLdapAuthenticationProviderTests extends BaseSpringSpec { LdapAuthenticationProvider provider = findAuthenticationProvider(LdapAuthenticationProvider) then: provider.authenticator instanceof PasswordComparisonAuthenticator - authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password")).authorities*.authority.sort() == ['ROLE_USER'] + authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob","bobspassword")) } } diff --git a/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/NamespaceLdapAuthenticationProviderTestsConfigs.java b/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/NamespaceLdapAuthenticationProviderTestsConfigs.java index 2ef0c08969..4759ffe6e6 100644 --- a/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/NamespaceLdapAuthenticationProviderTestsConfigs.java +++ b/config/src/integration-test/java/org/springframework/security/config/annotation/authentication/ldap/NamespaceLdapAuthenticationProviderTestsConfigs.java @@ -56,7 +56,7 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs { .userSearchFilter("(uid={0})") // ldap-authentication-provider@user-search-filter // .contextSource(contextSource) // ldap-authentication-provider@server-ref .contextSource() - .ldif("classpath:user.ldif") // ldap-server@ldif + .ldif("classpath:users.xldif") // ldap-server@ldif .managerDn("uid=admin,ou=system") // ldap-server@manager-dn .managerPassword("secret") // ldap-server@manager-password .port(33399) // ldap-server@port diff --git a/config/src/integration-test/resources/test-server.ldif b/config/src/integration-test/resources/test-server.ldif index 39104a4829..d6f4a560d3 100644 --- a/config/src/integration-test/resources/test-server.ldif +++ b/config/src/integration-test/resources/test-server.ldif @@ -68,11 +68,22 @@ sn: Mouse uid: jerry userPassword: jerryspassword +dn: uid=bcrypt,ou=people,dc=springframework,dc=org +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +cn: BCrypt user +sn: BCrypt +uid: bcrypt +userPassword: $2a$10$lDa0YFNHAt63MjIzK/wUqeM0qjIhzPhp3RNI/MLUQEAUbzhB/SnnS + dn: cn=developers,ou=groups,dc=springframework,dc=org objectclass: top objectclass: groupOfNames cn: developers ou: developer +member: uid=bcrypt,ou=people,dc=springframework,dc=org member: uid=ben,ou=people,dc=springframework,dc=org member: uid=bob,ou=people,dc=springframework,dc=org diff --git a/config/src/integration-test/resources/users.ldif b/config/src/integration-test/resources/users.ldif deleted file mode 100644 index fde2456d46..0000000000 --- a/config/src/integration-test/resources/users.ldif +++ /dev/null @@ -1,42 +0,0 @@ -dn: ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: organizationalUnit -ou: groups - -dn: ou=people,dc=springframework,dc=org -objectclass: top -objectclass: organizationalUnit -ou: people - -dn: uid=admin,ou=people,dc=springframework,dc=org -objectclass: top -objectclass: person -objectclass: organizationalPerson -objectclass: inetOrgPerson -cn: Rod Johnson -sn: Johnson -uid: admin -userPassword: password - -dn: uid=user,ou=people,dc=springframework,dc=org -objectclass: top -objectclass: person -objectclass: organizationalPerson -objectclass: inetOrgPerson -cn: Dianne Emu -sn: Emu -uid: user -userPassword: password - -dn: cn=user,ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: groupOfNames -cn: user -uniqueMember: uid=admin,ou=people,dc=springframework,dc=org -uniqueMember: uid=user,ou=people,dc=springframework,dc=org - -dn: cn=admin,ou=groups,dc=springframework,dc=org -objectclass: top -objectclass: groupOfNames -cn: admin -uniqueMember: uid=admin,ou=people,dc=springframework,dc=org \ No newline at end of file diff --git a/config/src/integration-test/resources/users.xldif b/config/src/integration-test/resources/users.xldif new file mode 100644 index 0000000000..90e715fd0d --- /dev/null +++ b/config/src/integration-test/resources/users.xldif @@ -0,0 +1,92 @@ +dn: ou=groups,dc=springframework,dc=org +objectclass: top +objectclass: organizationalUnit +ou: groups + +dn: ou=subgroups,ou=groups,dc=springframework,dc=org +objectclass: top +objectclass: organizationalUnit +ou: subgroups + +dn: ou=people,dc=springframework,dc=org +objectclass: top +objectclass: organizationalUnit +ou: people + +dn: ou=otherpeople,dc=springframework,dc=org +objectclass: top +objectclass: organizationalUnit +ou: otherpeople + +dn: uid=ben,ou=people,dc=springframework,dc=org +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +cn: Ben Alex +sn: Alex +uid: ben +userPassword: {SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ= + +dn: uid=bcrypt,ou=people,dc=springframework,dc=org +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +cn: BCrypt user +sn: BCrypt +uid: bcrypt +userPassword: $2a$10$lDa0YFNHAt63MjIzK/wUqeM0qjIhzPhp3RNI/MLUQEAUbzhB/SnnS + +dn: uid=bob,ou=people,dc=springframework,dc=org +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +cn: Bob Hamilton +sn: Hamilton +uid: bob +userPassword: bobspassword + +dn: uid=joe,ou=otherpeople,dc=springframework,dc=org +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +cn: Joe Smeth +sn: Smeth +uid: joe +userPassword: joespassword + +dn: cn=mouse\, jerry,ou=people,dc=springframework,dc=org +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +cn: Mouse, Jerry +sn: Mouse +uid: jerry +userPassword: jerryspassword + +dn: cn=developers,ou=groups,dc=springframework,dc=org +objectclass: top +objectclass: groupOfNames +cn: developers +ou: developer +member: uid=ben,ou=people,dc=springframework,dc=org +member: uid=bob,ou=people,dc=springframework,dc=org + +dn: cn=managers,ou=groups,dc=springframework,dc=org +objectclass: top +objectclass: groupOfNames +cn: managers +ou: manager +member: uid=ben,ou=people,dc=springframework,dc=org +member: cn=mouse\, jerry,ou=people,dc=springframework,dc=org + +dn: cn=submanagers,ou=subgroups,ou=groups,dc=springframework,dc=org +objectclass: top +objectclass: groupOfNames +cn: submanagers +ou: submanager +member: uid=ben,ou=people,dc=springframework,dc=org