AuthenticationManagerBuilderTests -> .java

Issue: gh-4939
This commit is contained in:
Rob Winch 2018-01-26 16:50:33 -06:00
parent 8d96e83767
commit 87a216a6e6
2 changed files with 249 additions and 223 deletions

View File

@ -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);
}
}
}

View File

@ -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<Object> 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<Object> 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<Object> 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<Object> 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<Object> 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);
}
}
}