diff --git a/config/src/test/groovy/org/springframework/security/config/annotation/authentication/AuthenticationManagerBuilderTests.groovy b/config/src/test/groovy/org/springframework/security/config/annotation/authentication/AuthenticationManagerBuilderTests.groovy deleted file mode 100644 index 6a33a133a7..0000000000 --- a/config/src/test/groovy/org/springframework/security/config/annotation/authentication/AuthenticationManagerBuilderTests.groovy +++ /dev/null @@ -1,223 +0,0 @@ -/* - * 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 - -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.beans.factory.annotation.Value -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration -import org.springframework.context.annotation.Import -import org.springframework.core.io.Resource; -import org.springframework.security.authentication.AuthenticationEventPublisher -import org.springframework.security.authentication.AuthenticationManager -import org.springframework.security.authentication.AuthenticationProvider -import org.springframework.security.authentication.ProviderManager -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken -import org.springframework.security.authentication.dao.DaoAuthenticationProvider; -import org.springframework.security.config.annotation.BaseSpringSpec -import org.springframework.security.config.annotation.ObjectPostProcessor -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder -import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration -import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication -import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.core.Authentication -import org.springframework.security.core.userdetails.PasswordEncodedUser -import org.springframework.security.core.userdetails.UserDetailsService -import org.springframework.security.crypto.password.NoOpPasswordEncoder -import org.springframework.security.crypto.password.PasswordEncoder -import org.springframework.security.provisioning.InMemoryUserDetailsManager; - -/** - * - * @author Rob Winch - * - */ -class AuthenticationManagerBuilderTests extends BaseSpringSpec { - def "add(AuthenticationProvider) does not perform registration"() { - setup: - ObjectPostProcessor opp = Mock() - AuthenticationProvider provider = Mock() - AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder(objectPostProcessor).objectPostProcessor(opp) - when: "Adding an AuthenticationProvider" - builder.authenticationProvider(provider) - builder.build() - then: "AuthenticationProvider is not passed into LifecycleManager (it should be managed externally)" - 0 * opp._(_ as AuthenticationProvider) - } - - // https://github.com/SpringSource/spring-security-javaconfig/issues/132 - def "#132 Custom AuthenticationEventPublisher with Web configure(AuthenticationManagerBuilder)"() { - setup: - AuthenticationEventPublisher aep = Mock() - when: - AuthenticationManager am = new AuthenticationManagerBuilder(objectPostProcessor) - .authenticationEventPublisher(aep) - .inMemoryAuthentication() - .and() - .build() - then: - am.eventPublisher == aep - } - - def "PasswordEncoder bean is used for Global"() { - setup: - loadConfig(PasswordEncoderGlobalConfig) - when: - Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password")) - then: - auth.name == "user" - auth.authorities*.authority == ['ROLE_USER'] - } - - @EnableWebSecurity - static class PasswordEncoderGlobalConfig extends WebSecurityConfigurerAdapter { - @Autowired - void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { - auth - .inMemoryAuthentication() - .withUser("user").password("password").roles("USER") - } - - @Bean - PasswordEncoder passwordEncoder() { - return NoOpPasswordEncoder.getInstance(); - } - } - - def "PasswordEncoder bean is used for protected"() { - setup: - loadConfig(PasswordEncoderConfig) - when: - Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password")) - then: - auth.name == "user" - auth.authorities*.authority == ['ROLE_USER'] - } - - @EnableWebSecurity - static class PasswordEncoderConfig extends WebSecurityConfigurerAdapter { - void configure(AuthenticationManagerBuilder auth) throws Exception { - auth - .inMemoryAuthentication() - .withUser("user").password("password").roles("USER") - } - - @Bean - PasswordEncoder passwordEncoder() { - return NoOpPasswordEncoder.getInstance(); - } - } - - def "authentication-manager support multiple DaoAuthenticationProvider's"() { - setup: - loadConfig(MultiAuthenticationProvidersConfig) - when: - Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user","password")) - then: - auth.name == "user" - auth.authorities*.authority == ['ROLE_USER'] - when: - auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("admin","password")) - then: - auth.name == "admin" - auth.authorities*.authority.sort() == ['ROLE_ADMIN','ROLE_USER'] - } - - @EnableWebSecurity - static class MultiAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter { - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth - .inMemoryAuthentication() - .withUser(PasswordEncodedUser.user()) - .and() - .inMemoryAuthentication() - .withUser(PasswordEncodedUser.admin()) - } - } - - def "isConfigured with AuthenticationProvider"() { - setup: - ObjectPostProcessor opp = Mock() - AuthenticationProvider provider = Mock() - AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(opp) - when: - auth - .authenticationProvider(provider) - then: - auth.isConfigured() - } - - def "isConfigured with parent"() { - setup: - ObjectPostProcessor opp = Mock() - AuthenticationManager parent = Mock() - AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(opp) - when: - auth - .parentAuthenticationManager(parent) - then: - auth.isConfigured() - } - - def "isConfigured not configured"() { - setup: - ObjectPostProcessor opp = Mock() - when: - AuthenticationManagerBuilder auth = new AuthenticationManagerBuilder(opp) - then: - auth.isConfigured() == false - } - - def "user from properties"() { - setup: - loadConfig(UserFromPropertiesConfig) - AuthenticationManager manager = context.getBean(AuthenticationConfiguration).authenticationManager - when: - manager.authenticate(new UsernamePasswordAuthenticationToken("joe","joespassword")) - then: - noExceptionThrown() - } - - @Configuration - @EnableGlobalAuthentication - @Import(ObjectPostProcessorConfiguration.class) - static class UserFromPropertiesConfig { - - @Value("classpath:org/springframework/security/config/users.properties") - Resource users; - - @Bean - public AuthenticationManager authenticationManager() { - return new ProviderManager(Arrays.asList(authenticationProvider())); - } - - @Bean - public AuthenticationProvider authenticationProvider() { - DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); - provider.setUserDetailsService(userDetailsService()) - return provider; - } - - @Bean - public UserDetailsService userDetailsService() { - Properties properties = new Properties(); - properties.load(users.getInputStream()); - return new InMemoryUserDetailsManager(properties); - } - } -} diff --git a/config/src/test/java/org/springframework/security/config/annotation/authentication/AuthenticationManagerBuilderTests.java b/config/src/test/java/org/springframework/security/config/annotation/authentication/AuthenticationManagerBuilderTests.java new file mode 100644 index 0000000000..f11f42eac1 --- /dev/null +++ b/config/src/test/java/org/springframework/security/config/annotation/authentication/AuthenticationManagerBuilderTests.java @@ -0,0 +1,249 @@ +/* + * Copyright 2002-2018 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; + +import org.junit.Rule; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.io.Resource; +import org.springframework.security.authentication.AuthenticationEventPublisher; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.ProviderManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.annotation.ObjectPostProcessor; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication; +import org.springframework.security.config.annotation.configuration.ObjectPostProcessorConfiguration; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.test.SpringTestRule; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.PasswordEncodedUser; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.NoOpPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.Arrays; +import java.util.Properties; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin; +import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated; + +/** + * @author Rob Winch + */ +public class AuthenticationManagerBuilderTests { + @Rule + public final SpringTestRule spring = new SpringTestRule(); + + @Test + public void buildWhenAddAuthenticationProviderThenDoesNotPerformRegistration() throws Exception { + ObjectPostProcessor opp = mock(ObjectPostProcessor.class); + AuthenticationProvider provider = mock(AuthenticationProvider.class); + + AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder(opp); + builder.authenticationProvider(provider); + builder.build(); + + verify(opp, never()).postProcess(provider); + } + + // https://github.com/SpringSource/spring-security-javaconfig/issues/132 + @Test + public void customAuthenticationEventPublisherWithWeb() throws Exception { + ObjectPostProcessor opp = mock(ObjectPostProcessor.class); + AuthenticationEventPublisher aep = mock(AuthenticationEventPublisher.class); + when(opp.postProcess(any())).thenAnswer(a -> a.getArgument(0)); + AuthenticationManager am = new AuthenticationManagerBuilder(opp) + .authenticationEventPublisher(aep) + .inMemoryAuthentication() + .and() + .build(); + + try { + am.authenticate(new UsernamePasswordAuthenticationToken("user", "password")); + } catch (AuthenticationException success) {} + + verify(aep).publishAuthenticationFailure(any(), any()); + } + + @Test + public void getAuthenticationManagerWhenGlobalPasswordEncoderBeanThenUsed() throws Exception { + this.spring.register(PasswordEncoderGlobalConfig.class).autowire(); + AuthenticationManager manager = this.spring.getContext() + .getBean(AuthenticationConfiguration.class).getAuthenticationManager(); + + Authentication auth = manager.authenticate(new UsernamePasswordAuthenticationToken("user", "password")); + + assertThat(auth.getName()).isEqualTo("user"); + assertThat(auth.getAuthorities()).extracting(GrantedAuthority::getAuthority).containsOnly("ROLE_USER"); + } + + @EnableWebSecurity + static class PasswordEncoderGlobalConfig extends WebSecurityConfigurerAdapter { + @Autowired + void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + auth + .inMemoryAuthentication() + .withUser("user").password("password").roles("USER"); + } + + @Bean + PasswordEncoder passwordEncoder() { + return NoOpPasswordEncoder.getInstance(); + } + } + + @Test + public void getAuthenticationManagerWhenProtectedPasswordEncoderBeanThenUsed() throws Exception { + this.spring.register(PasswordEncoderGlobalConfig.class).autowire(); + AuthenticationManager manager = this.spring.getContext() + .getBean(AuthenticationConfiguration.class).getAuthenticationManager(); + + Authentication auth = manager.authenticate(new UsernamePasswordAuthenticationToken("user", "password")); + + assertThat(auth.getName()).isEqualTo("user"); + assertThat(auth.getAuthorities()).extracting(GrantedAuthority::getAuthority).containsOnly("ROLE_USER"); + } + + @EnableWebSecurity + static class PasswordEncoderConfig extends WebSecurityConfigurerAdapter { + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth + .inMemoryAuthentication() + .withUser("user").password("password").roles("USER"); + } + + @Bean + PasswordEncoder passwordEncoder() { + return NoOpPasswordEncoder.getInstance(); + } + } + + @Autowired(required = false) + MockMvc mockMvc; + + @Test + public void authenticationManagerWhenMultipleProvidersThenWorks() throws Exception { + this.spring.register(MultiAuthenticationProvidersConfig.class).autowire(); + + this.mockMvc.perform(formLogin()) + .andExpect(authenticated().withUsername("user").withRoles("USER")); + + this.mockMvc.perform(formLogin().user("admin")) + .andExpect(authenticated().withUsername("admin").withRoles("USER", "ADMIN")); + } + + @EnableWebSecurity + static class MultiAuthenticationProvidersConfig + extends WebSecurityConfigurerAdapter { + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.inMemoryAuthentication() + .withUser(PasswordEncodedUser.user()) + .and() + .inMemoryAuthentication() + .withUser(PasswordEncodedUser.admin()); + } + + } + + @Test + public void buildWhenAuthenticationProviderThenIsConfigured() throws Exception { + ObjectPostProcessor opp = mock(ObjectPostProcessor.class); + AuthenticationProvider provider = mock(AuthenticationProvider.class); + + AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder(opp); + builder.authenticationProvider(provider); + builder.build(); + + assertThat(builder.isConfigured()).isTrue(); + } + + @Test + public void buildWhenParentThenIsConfigured() throws Exception { + ObjectPostProcessor opp = mock(ObjectPostProcessor.class); + AuthenticationManager parent = mock(AuthenticationManager.class); + + AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder(opp); + builder.parentAuthenticationManager(parent); + builder.build(); + + assertThat(builder.isConfigured()).isTrue(); + } + + @Test + public void buildWhenNotConfiguredThenIsConfiguredFalse() throws Exception { + ObjectPostProcessor opp = mock(ObjectPostProcessor.class); + + AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder(opp); + builder.build(); + + assertThat(builder.isConfigured()).isFalse(); + } + + public void buildWhenUserFromProperties() throws Exception { + this.spring.register(UserFromPropertiesConfig.class).autowire(); + + this.mockMvc.perform(formLogin().user("joe", "joespassword")) + .andExpect(authenticated().withUsername("joe").withRoles("USER")); + } + + @Configuration + @EnableGlobalAuthentication + @Import(ObjectPostProcessorConfiguration.class) + static class UserFromPropertiesConfig { + + @Value("classpath:org/springframework/security/config/users.properties") + Resource users; + + @Bean + public AuthenticationManager authenticationManager() throws Exception { + return new ProviderManager(Arrays.asList(authenticationProvider())); + } + + @Bean + public AuthenticationProvider authenticationProvider() throws Exception { + DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setUserDetailsService(userDetailsService()); + return provider; + } + + @Bean + public UserDetailsService userDetailsService() throws Exception { + Properties properties = new Properties(); + properties.load(this.users.getInputStream()); + return new InMemoryUserDetailsManager(properties); + } + } + +}