AuthenticationConfigurationTests -> java

Issue: gh-4939
This commit is contained in:
Rob Winch
2018-01-26 15:14:34 -06:00
parent f7e49ace9f
commit e5d40c0599
2 changed files with 478 additions and 518 deletions

View File

@@ -0,0 +1,478 @@
/*
* 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.configuration;
import org.apache.http.auth.AUTH;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.TestAuthentication;
import org.springframework.security.authentication.TestingAuthenticationToken;
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.configuration.ObjectPostProcessorConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.config.users.AuthenticationTestConfiguration;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class AuthenticationConfigurationTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@Autowired(required = false)
private Service service;
@After
public void cleanup() {
SecurityContextHolder.clearContext();
}
@Test
public void orderingAutowiredOnEnableGlobalMethodSecurity() {
this.spring.register(AuthenticationTestConfiguration.class, GlobalMethodSecurityAutowiredConfig.class, ServicesConfig.class).autowire();
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
this.service.run();
}
@EnableGlobalMethodSecurity(securedEnabled = true)
static class GlobalMethodSecurityAutowiredConfig {
}
@Test
public void orderingAutowiredOnEnableWebSecurity() {
this.spring.register(AuthenticationTestConfiguration.class, WebSecurityConfig.class, GlobalMethodSecurityAutowiredConfig.class, ServicesConfig.class).autowire();
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
this.service.run();
}
@EnableWebSecurity
static class WebSecurityConfig {}
@Test
public void orderingAutowiredOnEnableWebMvcSecurity() {
this.spring.register(AuthenticationTestConfiguration.class, WebMvcSecurityConfig.class, GlobalMethodSecurityAutowiredConfig.class, ServicesConfig.class).autowire();
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
this.service.run();
}
@EnableWebMvcSecurity
static class WebMvcSecurityConfig {}
@Test
public void getAuthenticationManagerWhenNoAuthenticationThenNull() throws Exception {
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class).autowire();
assertThat(this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager()).isNull();
}
@Test
public void getAuthenticationManagerWhenNoOpGlobalAuthenticationConfigurerAdapterThenNull() throws Exception {
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class, NoOpGlobalAuthenticationConfigurerAdapter.class).autowire();
assertThat(this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager()).isNull();
}
@Configuration
static class NoOpGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {}
@Test
public void getAuthenticationWhenGlobalAuthenticationConfigurerAdapterThenAuthenticates() throws Exception {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "password");
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class, UserGlobalAuthenticationConfigurerAdapter.class).autowire();
AuthenticationManager authentication = this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
assertThat(authentication.authenticate(token).getName()).isEqualTo(token.getName());
}
@Configuration
static class UserGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
}
}
@Test
public void getAuthenticationWhenAuthenticationManagerBeanThenAuthenticates() throws Exception {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "password");
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class, AuthenticationManagerBeanConfig.class).autowire();
AuthenticationManager authentication = this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
when(authentication.authenticate(token)).thenReturn(TestAuthentication.authenticatedUser());
assertThat(authentication.authenticate(token).getName()).isEqualTo(token.getName());
}
@Configuration
static class AuthenticationManagerBeanConfig {
AuthenticationManager authenticationManager = mock(AuthenticationManager.class);
@Bean
public AuthenticationManager authenticationManager() {
return authenticationManager;
}
}
//
// //
//
@Configuration
static class ServicesConfig {
@Bean
public Service service() {
return new ServiceImpl();
}
}
interface Service {
void run();
}
static class ServiceImpl implements Service {
@Secured("ROLE_USER")
public void run() {}
}
@Test
public void getAuthenticationWhenMultipleThenOrdered() throws Exception {
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class, AuthenticationManagerBeanConfig.class).autowire();
AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class);
config.setGlobalAuthenticationConfigurers(Arrays.asList(new LowestOrderGlobalAuthenticationConfigurerAdapter(), new HighestOrderGlobalAuthenticationConfigurerAdapter(), new DefaultOrderGlobalAuthenticationConfigurerAdapter()));
}
static class DefaultOrderGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
static List<Class<?>> inits = new ArrayList<>();
static List<Class<?>> configs = new ArrayList<>();
public void init(AuthenticationManagerBuilder auth) throws Exception {
inits.add(getClass());
}
public void configure(AuthenticationManagerBuilder auth) throws Exception {
configs.add(getClass());
}
}
@Order(Ordered.LOWEST_PRECEDENCE)
static class LowestOrderGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {}
@Order(Ordered.HIGHEST_PRECEDENCE)
static class HighestOrderGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {}
@Test
public void getAuthenticationWhenConfiguredThenBootNotTrigger() throws Exception {
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class).autowire();
AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class);
config.setGlobalAuthenticationConfigurers(Arrays.asList(new ConfiguresInMemoryConfigurerAdapter(), new BootGlobalAuthenticationConfigurerAdapter()));
AuthenticationManager authenticationManager = config.getAuthenticationManager();
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
assertThatThrownBy(() -> authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("boot", "password")))
.isInstanceOf(AuthenticationException.class);
}
@Test
public void getAuthenticationWhenNotConfiguredThenBootTrigger() throws Exception {
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class).autowire();
AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class);
config.setGlobalAuthenticationConfigurers(Arrays.asList(new BootGlobalAuthenticationConfigurerAdapter()));
AuthenticationManager authenticationManager = config.getAuthenticationManager();
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("boot", "password"));
}
static class ConfiguresInMemoryConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
}
}
@Order(Ordered.LOWEST_PRECEDENCE)
static class BootGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.apply(new DefaultBootGlobalAuthenticationConfigurerAdapter());
}
}
static class DefaultBootGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
if (auth.isConfigured()) {
return;
}
UserDetails user = User.withUserDetails(PasswordEncodedUser.user()).username("boot").build();
List<UserDetails> users = Arrays.asList(user);
InMemoryUserDetailsManager inMemory = new InMemoryUserDetailsManager(users);
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(inMemory);
auth.authenticationProvider(provider);
}
}
// gh-2531
@Test
public void getAuthenticationManagerWhenPostProcessThenUsesBeanClassLoaderOnProxyFactoryBean() throws Exception {
this.spring.register(Sec2531Config.class).autowire();
ObjectPostProcessor<Object> opp = this.spring.getContext().getBean(ObjectPostProcessor.class);
when(opp.postProcess(any())).thenAnswer(a -> a.getArgument(0));
AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class);
config.getAuthenticationManager();
verify(opp).postProcess(any(ProxyFactoryBean.class));
}
@Configuration
@Import(AuthenticationConfiguration.class)
static class Sec2531Config {
@Bean
public ObjectPostProcessor objectPostProcessor() {
return mock(ObjectPostProcessor.class);
}
@Bean
public AuthenticationManager manager() {
return null;
}
}
@Test
public void getAuthenticationManagerWhenSec2822ThenCannotForceAuthenticationAlreadyBuilt() throws Exception {
this.spring.register(Sec2822WebSecurity.class, Sec2822UseAuth.class, Sec2822Config.class).autowire();
this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
// no exception
}
@Configuration
@Import(AuthenticationConfiguration.class)
static class Sec2822Config {}
@Configuration
@EnableWebSecurity
static class Sec2822WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication();
}
}
@Configuration
static class Sec2822UseAuth {
@Autowired
public void useAuthenticationManager(AuthenticationConfiguration auth) throws Exception {
auth.getAuthenticationManager();
}
// Ensures that Sec2822UseAuth is initialized before Sec2822WebSecurity
// must have additional GlobalAuthenticationConfigurerAdapter to trigger SEC-2822
@Bean
public static GlobalAuthenticationConfigurerAdapter bootGlobalAuthenticationConfigurerAdapter() {
return new BootGlobalAuthenticationConfigurerAdapter();
}
static class BootGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter { }
}
// sec-2868
@Test
public void getAuthenticationWhenUserDetailsServiceBeanThenAuthenticationManagerUsesUserDetailsServiceBean() throws Exception {
this.spring.register(UserDetailsServiceBeanConfig.class).autowire();
UserDetailsService uds = this.spring.getContext().getBean(UserDetailsService.class);
AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
when(uds.loadUserByUsername("user")).thenReturn(PasswordEncodedUser.user(), PasswordEncodedUser.user());
am.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
assertThatThrownBy(() -> am.authenticate(new UsernamePasswordAuthenticationToken("user", "invalid")))
.isInstanceOf(AuthenticationException.class);
}
@Configuration
@Import({AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class})
static class UserDetailsServiceBeanConfig {
UserDetailsService uds = mock(UserDetailsService.class);
@Bean
UserDetailsService userDetailsService() {
return this.uds;
}
}
@Test
public void getAuthenticationWhenUserDetailsServiceAndPasswordEncoderBeanThenEncoderUsed() throws Exception {
UserDetails user = new User("user", "$2a$10$FBAKClV1zBIOOC9XMXf3AO8RoGXYVYsfvUdoLxGkd/BnXEn4tqT3u",
AuthorityUtils.createAuthorityList("ROLE_USER"));
this.spring.register(UserDetailsServiceBeanWithPasswordEncoderConfig.class).autowire();
UserDetailsService uds = this.spring.getContext().getBean(UserDetailsService.class);
AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
when(uds.loadUserByUsername("user")).thenReturn(User.withUserDetails(user).build(), User.withUserDetails(user).build());
am.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
assertThatThrownBy(() -> am.authenticate(new UsernamePasswordAuthenticationToken("user", "invalid")))
.isInstanceOf(AuthenticationException.class);
}
@Configuration
@Import({AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class})
static class UserDetailsServiceBeanWithPasswordEncoderConfig {
UserDetailsService uds = mock(UserDetailsService.class);
@Bean
UserDetailsService userDetailsService() {
return this.uds;
}
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
//gh-3091
@Test
public void getAuthenticationWhenAuthenticationProviderBeanThenUsed() throws Exception {
this.spring.register(AuthenticationProviderBeanConfig.class).autowire();
AuthenticationProvider ap = this.spring.getContext().getBean(AuthenticationProvider.class);
AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
when(ap.supports(any())).thenReturn(true);
when(ap.authenticate(any())).thenReturn(TestAuthentication.authenticatedUser());
am.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
}
@Configuration
@Import({AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class})
static class AuthenticationProviderBeanConfig {
AuthenticationProvider provider = mock(AuthenticationProvider.class);
@Bean
AuthenticationProvider authenticationProvider() {
return this.provider;
}
}
@Test
public void getAuthenticationWhenAuthenticationProviderAndUserDetailsBeanThenAuthenticationProviderUsed() throws Exception {
this.spring.register(AuthenticationProviderBeanAndUserDetailsServiceConfig.class).autowire();
AuthenticationProvider ap = this.spring.getContext().getBean(AuthenticationProvider.class);
AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
when(ap.supports(any())).thenReturn(true);
when(ap.authenticate(any())).thenReturn(TestAuthentication.authenticatedUser());
am.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
}
@Configuration
@Import({AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class})
static class AuthenticationProviderBeanAndUserDetailsServiceConfig {
AuthenticationProvider provider = mock(AuthenticationProvider.class);
UserDetailsService uds = mock(UserDetailsService.class);
@Bean
UserDetailsService userDetailsService() {
return this.uds;
}
@Bean
AuthenticationProvider authenticationProvider() {
return this.provider;
}
}
@Test
public void enableGlobalMethodSecurityWhenPreAuthorizeThenNoException() throws Exception {
this.spring.register(UsesPreAuthorizeMethodSecurityConfig.class, AuthenticationManagerBeanConfig.class).autowire();
// no exception
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class UsesPreAuthorizeMethodSecurityConfig {
@PreAuthorize("denyAll")
void run() {}
}
@Test
public void enableGlobalMethodSecurityWhenPreAuthorizeThenUsesMethodSecurityService() throws Exception {
this.spring.register(ServicesConfig.class, UsesPreAuthorizeMethodSecurityConfig.class, AuthenticationManagerBeanConfig.class).autowire();
// no exception
}
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
static class UsesServiceMethodSecurityConfig {
@Autowired
Service service;
}
}