Remove Spring Security OAuth Auto-Configuration

This commit removes auto-configuration support for Spring Security
OAuth, paving the way for the introduction of auto-configuration for
Spring Security 5's new OAuth-related features.

Closes gh-10255
This commit is contained in:
Andy Wilkinson
2017-09-21 10:30:34 +01:00
parent a0fee6fe3b
commit e9147c2f20
79 changed files with 2 additions and 6877 deletions

View File

@@ -1,683 +0,0 @@
/*
* Copyright 2012-2017 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.boot.autoconfigure.security.oauth2;
import java.net.URI;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import com.fasterxml.jackson.databind.JsonNode;
import org.junit.Test;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.authserver.OAuth2AuthorizationServerConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.method.OAuth2MethodSecurityConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.ApplicationContext;
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.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource;
import org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource;
import org.springframework.security.access.method.MethodSecurityMetadataSource;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdvice;
import org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.ApprovalStoreUserApprovalHandler;
import org.springframework.security.oauth2.provider.approval.TokenApprovalStore;
import org.springframework.security.oauth2.provider.approval.UserApprovalHandler;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.security.oauth2.provider.client.InMemoryClientDetailsService;
import org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint;
import org.springframework.security.oauth2.provider.expression.OAuth2MethodSecurityExpressionHandler;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Verify Spring Security OAuth2 auto-configuration secures end points properly, accepts
* environmental overrides, and also backs off in the presence of other
* resource/authorization components.
*
* @author Greg Turnquist
* @author Dave Syer
*/
public class OAuth2AutoConfigurationTests {
private static final Class<?> RESOURCE_SERVER_CONFIG = OAuth2ResourceServerConfiguration.class;
private static final Class<?> AUTHORIZATION_SERVER_CONFIG = OAuth2AuthorizationServerConfiguration.class;
private AnnotationConfigServletWebServerApplicationContext context;
@Test
public void testDefaultConfiguration() {
this.context = new AnnotationConfigServletWebServerApplicationContext();
this.context.register(AuthorizationAndResourceServerConfiguration.class,
MinimalSecureWebApplication.class);
this.context.refresh();
this.context.getBean(AUTHORIZATION_SERVER_CONFIG);
this.context.getBean(RESOURCE_SERVER_CONFIG);
this.context.getBean(OAuth2MethodSecurityConfiguration.class);
ClientDetails config = this.context.getBean(BaseClientDetails.class);
AuthorizationEndpoint endpoint = this.context
.getBean(AuthorizationEndpoint.class);
UserApprovalHandler handler = (UserApprovalHandler) ReflectionTestUtils
.getField(endpoint, "userApprovalHandler");
ClientDetailsService clientDetailsService = this.context
.getBean(ClientDetailsService.class);
ClientDetails clientDetails = clientDetailsService
.loadClientByClientId(config.getClientId());
assertThat(AopUtils.isJdkDynamicProxy(clientDetailsService)).isTrue();
assertThat(AopUtils.getTargetClass(clientDetailsService).getName())
.isEqualTo(InMemoryClientDetailsService.class.getName());
assertThat(handler).isInstanceOf(ApprovalStoreUserApprovalHandler.class);
assertThat(clientDetails).isEqualTo(config);
verifyAuthentication(config);
assertThat(this.context.getBeanNamesForType(OAuth2RestOperations.class))
.isEmpty();
}
@Test
public void methodSecurityExpressionHandlerIsConfiguredWithRoleHierarchyFromTheContext() {
this.context = new AnnotationConfigServletWebServerApplicationContext();
this.context.register(RoleHierarchyConfiguration.class,
AuthorizationAndResourceServerConfiguration.class,
MinimalSecureWebApplication.class);
this.context.refresh();
PreInvocationAuthorizationAdvice advice = this.context
.getBean(PreInvocationAuthorizationAdvice.class);
MethodSecurityExpressionHandler expressionHandler = (MethodSecurityExpressionHandler) ReflectionTestUtils
.getField(advice, "expressionHandler");
RoleHierarchy roleHierarchy = (RoleHierarchy) ReflectionTestUtils
.getField(expressionHandler, "roleHierarchy");
assertThat(roleHierarchy).isSameAs(this.context.getBean(RoleHierarchy.class));
}
@Test
public void methodSecurityExpressionHandlerIsConfiguredWithPermissionEvaluatorFromTheContext() {
this.context = new AnnotationConfigServletWebServerApplicationContext();
this.context.register(PermissionEvaluatorConfiguration.class,
AuthorizationAndResourceServerConfiguration.class,
MinimalSecureWebApplication.class);
this.context.refresh();
PreInvocationAuthorizationAdvice advice = this.context
.getBean(PreInvocationAuthorizationAdvice.class);
MethodSecurityExpressionHandler expressionHandler = (MethodSecurityExpressionHandler) ReflectionTestUtils
.getField(advice, "expressionHandler");
PermissionEvaluator permissionEvaluator = (PermissionEvaluator) ReflectionTestUtils
.getField(expressionHandler, "permissionEvaluator");
assertThat(permissionEvaluator)
.isSameAs(this.context.getBean(PermissionEvaluator.class));
}
@Test
public void testEnvironmentalOverrides() {
this.context = new AnnotationConfigServletWebServerApplicationContext();
TestPropertyValues
.of("security.oauth2.client.clientId:myclientid",
"security.oauth2.client.clientSecret:mysecret",
"security.oauth2.client.autoApproveScopes:read,write",
"security.oauth2.client.accessTokenValiditySeconds:40",
"security.oauth2.client.refreshTokenValiditySeconds:80")
.applyTo(this.context);
this.context.register(AuthorizationAndResourceServerConfiguration.class,
MinimalSecureWebApplication.class);
this.context.refresh();
ClientDetails config = this.context.getBean(ClientDetails.class);
assertThat(config.getClientId()).isEqualTo("myclientid");
assertThat(config.getClientSecret()).isEqualTo("mysecret");
assertThat(config.isAutoApprove("read")).isTrue();
assertThat(config.isAutoApprove("write")).isTrue();
assertThat(config.isAutoApprove("foo")).isFalse();
assertThat(config.getAccessTokenValiditySeconds()).isEqualTo(40);
assertThat(config.getRefreshTokenValiditySeconds()).isEqualTo(80);
verifyAuthentication(config);
}
@Test
public void testDisablingResourceServer() {
this.context = new AnnotationConfigServletWebServerApplicationContext();
this.context.register(AuthorizationServerConfiguration.class,
MinimalSecureWebApplication.class);
this.context.refresh();
assertThat(countBeans(RESOURCE_SERVER_CONFIG)).isEqualTo(0);
assertThat(countBeans(AUTHORIZATION_SERVER_CONFIG)).isEqualTo(1);
}
@Test
public void testClientIsNotResourceServer() {
this.context = new AnnotationConfigServletWebServerApplicationContext();
this.context.register(ClientConfiguration.class,
MinimalSecureWebApplication.class);
this.context.refresh();
assertThat(countBeans(RESOURCE_SERVER_CONFIG)).isEqualTo(0);
assertThat(countBeans(AUTHORIZATION_SERVER_CONFIG)).isEqualTo(0);
// Scoped target and proxy:
assertThat(countBeans(OAuth2ClientContext.class)).isEqualTo(2);
}
@Test
public void testCanUseClientCredentials() {
this.context = new AnnotationConfigServletWebServerApplicationContext();
this.context.register(TestSecurityConfiguration.class,
MinimalSecureWebApplication.class);
TestPropertyValues
.of("security.oauth2.client.clientId=client",
"security.oauth2.client.grantType=client_credentials")
.applyTo(this.context);
ConfigurationPropertySources.attach(this.context.getEnvironment());
this.context.refresh();
OAuth2ClientContext bean = this.context.getBean(OAuth2ClientContext.class);
assertThat(bean.getAccessTokenRequest()).isNotNull();
assertThat(countBeans(ClientCredentialsResourceDetails.class)).isEqualTo(1);
assertThat(countBeans(OAuth2ClientContext.class)).isEqualTo(1);
}
@Test
public void testCanUseClientCredentialsWithEnableOAuth2Client() {
this.context = new AnnotationConfigServletWebServerApplicationContext();
this.context.register(ClientConfiguration.class,
MinimalSecureWebApplication.class);
TestPropertyValues
.of("security.oauth2.client.clientId=client",
"security.oauth2.client.grantType=client_credentials")
.applyTo(this.context);
ConfigurationPropertySources.attach(this.context.getEnvironment());
this.context.refresh();
// The primary context is fine (not session scoped):
OAuth2ClientContext bean = this.context.getBean(OAuth2ClientContext.class);
assertThat(bean.getAccessTokenRequest()).isNotNull();
assertThat(countBeans(ClientCredentialsResourceDetails.class)).isEqualTo(1);
// Kind of a bug (should ideally be 1), but the cause is in Spring OAuth2 (there
// is no need for the extra session-scoped bean). What this test proves is that
// even if the user screws up and does @EnableOAuth2Client for client credentials,
// it will still just about work (because of the @Primary annotation on the
// Boot-created instance of OAuth2ClientContext).
assertThat(countBeans(OAuth2ClientContext.class)).isEqualTo(2);
}
@Test
public void testClientIsNotAuthCode() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(MinimalSecureNonWebApplication.class);
TestPropertyValues.of("security.oauth2.client.clientId=client").applyTo(context);
context.refresh();
assertThat(countBeans(context, ClientCredentialsResourceDetails.class))
.isEqualTo(1);
context.close();
}
@Test
public void testDisablingAuthorizationServer() {
this.context = new AnnotationConfigServletWebServerApplicationContext();
this.context.register(ResourceServerConfiguration.class,
MinimalSecureWebApplication.class);
TestPropertyValues.of("security.oauth2.resource.jwt.keyValue:DEADBEEF")
.applyTo(this.context);
ConfigurationPropertySources.attach(this.context.getEnvironment());
this.context.refresh();
assertThat(countBeans(RESOURCE_SERVER_CONFIG)).isEqualTo(1);
assertThat(countBeans(AUTHORIZATION_SERVER_CONFIG)).isEqualTo(0);
assertThat(countBeans(UserApprovalHandler.class)).isEqualTo(0);
assertThat(countBeans(DefaultTokenServices.class)).isEqualTo(1);
}
@Test
public void testResourceServerOverride() {
this.context = new AnnotationConfigServletWebServerApplicationContext();
this.context.register(AuthorizationAndResourceServerConfiguration.class,
CustomResourceServer.class, MinimalSecureWebApplication.class);
this.context.refresh();
ClientDetails config = this.context.getBean(ClientDetails.class);
assertThat(countBeans(AUTHORIZATION_SERVER_CONFIG)).isEqualTo(1);
assertThat(countBeans(CustomResourceServer.class)).isEqualTo(1);
assertThat(countBeans(RESOURCE_SERVER_CONFIG)).isEqualTo(1);
verifyAuthentication(config);
}
@Test
public void testAuthorizationServerOverride() {
this.context = new AnnotationConfigServletWebServerApplicationContext();
TestPropertyValues.of("security.oauth2.resourceId:resource-id")
.applyTo(this.context);
this.context.register(AuthorizationAndResourceServerConfiguration.class,
CustomAuthorizationServer.class, MinimalSecureWebApplication.class);
this.context.refresh();
BaseClientDetails config = new BaseClientDetails();
config.setClientId("client");
config.setClientSecret("secret");
config.setResourceIds(Arrays.asList("resource-id"));
config.setAuthorizedGrantTypes(Arrays.asList("password"));
config.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList("USER"));
config.setScope(Arrays.asList("read"));
assertThat(countBeans(AUTHORIZATION_SERVER_CONFIG)).isEqualTo(0);
assertThat(countBeans(RESOURCE_SERVER_CONFIG)).isEqualTo(1);
verifyAuthentication(config);
}
@Test
public void testDefaultPrePostSecurityAnnotations() {
this.context = new AnnotationConfigServletWebServerApplicationContext();
this.context.register(AuthorizationAndResourceServerConfiguration.class,
MinimalSecureWebApplication.class);
this.context.refresh();
this.context.getBean(OAuth2MethodSecurityConfiguration.class);
ClientDetails config = this.context.getBean(ClientDetails.class);
DelegatingMethodSecurityMetadataSource source = this.context
.getBean(DelegatingMethodSecurityMetadataSource.class);
List<MethodSecurityMetadataSource> sources = source
.getMethodSecurityMetadataSources();
assertThat(sources.size()).isEqualTo(1);
assertThat(sources.get(0).getClass().getName())
.isEqualTo(PrePostAnnotationSecurityMetadataSource.class.getName());
verifyAuthentication(config);
}
@Test
public void testClassicSecurityAnnotationOverride() {
this.context = new AnnotationConfigServletWebServerApplicationContext();
this.context.register(SecuredEnabledConfiguration.class,
MinimalSecureWebApplication.class);
this.context.refresh();
this.context.getBean(OAuth2MethodSecurityConfiguration.class);
ClientDetails config = this.context.getBean(ClientDetails.class);
DelegatingMethodSecurityMetadataSource source = this.context
.getBean(DelegatingMethodSecurityMetadataSource.class);
List<MethodSecurityMetadataSource> sources = source
.getMethodSecurityMetadataSources();
assertThat(sources.size()).isEqualTo(1);
assertThat(sources.get(0).getClass().getName())
.isEqualTo(SecuredAnnotationSecurityMetadataSource.class.getName());
verifyAuthentication(config, HttpStatus.OK);
}
@Test
public void testJsr250SecurityAnnotationOverride() {
this.context = new AnnotationConfigServletWebServerApplicationContext();
this.context.register(Jsr250EnabledConfiguration.class,
MinimalSecureWebApplication.class);
this.context.refresh();
this.context.getBean(OAuth2MethodSecurityConfiguration.class);
ClientDetails config = this.context.getBean(ClientDetails.class);
DelegatingMethodSecurityMetadataSource source = this.context
.getBean(DelegatingMethodSecurityMetadataSource.class);
List<MethodSecurityMetadataSource> sources = source
.getMethodSecurityMetadataSources();
assertThat(sources.size()).isEqualTo(1);
assertThat(sources.get(0).getClass().getName())
.isEqualTo(Jsr250MethodSecurityMetadataSource.class.getName());
verifyAuthentication(config, HttpStatus.OK);
}
@Test
public void testMethodSecurityBackingOff() {
this.context = new AnnotationConfigServletWebServerApplicationContext();
this.context.register(CustomMethodSecurity.class, TestSecurityConfiguration.class,
MinimalSecureWebApplication.class);
this.context.refresh();
DelegatingMethodSecurityMetadataSource source = this.context
.getBean(DelegatingMethodSecurityMetadataSource.class);
List<MethodSecurityMetadataSource> sources = source
.getMethodSecurityMetadataSources();
assertThat(sources.size()).isEqualTo(1);
assertThat(sources.get(0).getClass().getName())
.isEqualTo(PrePostAnnotationSecurityMetadataSource.class.getName());
}
@Test
public void resourceServerConditionWhenJwkConfigurationPresentShouldMatch()
throws Exception {
this.context = new AnnotationConfigServletWebServerApplicationContext();
TestPropertyValues
.of("security.oauth2.resource.jwk.key-set-uri:http://my-auth-server/token_keys")
.applyTo(this.context);
this.context.register(ResourceServerConfiguration.class,
MinimalSecureWebApplication.class);
this.context.refresh();
assertThat(countBeans(RESOURCE_SERVER_CONFIG)).isEqualTo(1);
}
/**
* Connect to the oauth service, get a token, and then attempt some operations using
* it.
* @param config the client details.
*/
private void verifyAuthentication(ClientDetails config) {
verifyAuthentication(config, HttpStatus.FORBIDDEN);
}
private void verifyAuthentication(ClientDetails config, HttpStatus finalStatus) {
String baseUrl = "http://localhost:" + this.context.getWebServer().getPort();
TestRestTemplate rest = new TestRestTemplate();
// First, verify the web endpoint can't be reached
assertEndpointUnauthorized(baseUrl, rest);
// Since we can't reach it, need to collect an authorization token
HttpHeaders headers = getHeaders(config);
String url = baseUrl + "/oauth/token";
JsonNode tokenResponse = rest.postForObject(url,
new HttpEntity<>(getBody(), headers), JsonNode.class);
String authorizationToken = tokenResponse.findValue("access_token").asText();
String tokenType = tokenResponse.findValue("token_type").asText();
String scope = tokenResponse.findValues("scope").get(0).toString();
assertThat(tokenType).isEqualTo("bearer");
assertThat(scope).isEqualTo("\"read\"");
// Now we should be able to see that endpoint.
headers.set("Authorization", "BEARER " + authorizationToken);
ResponseEntity<String> securedResponse = rest
.exchange(new RequestEntity<Void>(headers, HttpMethod.GET,
URI.create(baseUrl + "/securedFind")), String.class);
assertThat(securedResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(securedResponse.getBody()).isEqualTo(
"You reached an endpoint " + "secured by Spring Security OAuth2");
ResponseEntity<String> entity = rest.exchange(new RequestEntity<Void>(headers,
HttpMethod.POST, URI.create(baseUrl + "/securedSave")), String.class);
assertThat(entity.getStatusCode()).isEqualTo(finalStatus);
}
private HttpHeaders getHeaders(ClientDetails config) {
HttpHeaders headers = new HttpHeaders();
String token = new String(Base64.getEncoder().encode(
(config.getClientId() + ":" + config.getClientSecret()).getBytes()));
headers.set("Authorization", "Basic " + token);
return headers;
}
private MultiValueMap<String, Object> getBody() {
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.set("grant_type", "password");
body.set("username", "foo");
body.set("password", "bar");
body.set("scope", "read");
return body;
}
private void assertEndpointUnauthorized(String baseUrl, TestRestTemplate rest) {
URI uri = URI.create(baseUrl + "/secured");
ResponseEntity<String> entity = rest
.exchange(new RequestEntity<Void>(HttpMethod.GET, uri), String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
}
private int countBeans(Class<?> type) {
return countBeans(this.context, type);
}
private int countBeans(ApplicationContext context, Class<?> type) {
return context.getBeanNamesForType(type).length;
}
@Configuration
@Import({ UseFreePortEmbeddedContainerConfiguration.class,
SecurityAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
OAuth2AutoConfiguration.class, WebMvcAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class })
protected static class MinimalSecureWebApplication {
}
@Configuration
@Import({ SecurityAutoConfiguration.class, OAuth2AutoConfiguration.class })
protected static class MinimalSecureNonWebApplication {
}
@Configuration
protected static class TestSecurityConfiguration
extends WebSecurityConfigurerAdapter {
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("foo").password("bar").roles("USER");
}
@Bean
TestWebApp testWebApp() {
return new TestWebApp();
}
}
@Configuration
@EnableOAuth2Client
protected static class ClientConfiguration extends TestSecurityConfiguration {
}
@Configuration
@EnableAuthorizationServer
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
protected static class AuthorizationAndResourceServerConfiguration
extends TestSecurityConfiguration {
}
@Configuration
@EnableAuthorizationServer
@EnableResourceServer
@EnableGlobalMethodSecurity(securedEnabled = true)
protected static class SecuredEnabledConfiguration extends TestSecurityConfiguration {
}
@Configuration
@EnableAuthorizationServer
@EnableResourceServer
@EnableGlobalMethodSecurity(jsr250Enabled = true)
protected static class Jsr250EnabledConfiguration extends TestSecurityConfiguration {
}
@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration
extends TestSecurityConfiguration {
}
@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends TestSecurityConfiguration {
}
@RestController
protected static class TestWebApp {
@GetMapping("/securedFind")
@PreAuthorize("#oauth2.hasScope('read')")
public String secureFind() {
return "You reached an endpoint secured by Spring Security OAuth2";
}
@PostMapping("/securedSave")
@PreAuthorize("#oauth2.hasScope('write')")
public String secureSave() {
return "You reached an endpoint secured by Spring Security OAuth2";
}
}
@Configuration
protected static class UseFreePortEmbeddedContainerConfiguration {
@Bean
TomcatServletWebServerFactory webServerFactory() {
return new TomcatServletWebServerFactory(0);
}
}
@Configuration
@EnableResourceServer
protected static class CustomResourceServer extends ResourceServerConfigurerAdapter {
private final ResourceServerProperties config;
protected CustomResourceServer(ResourceServerProperties config) {
this.config = config;
}
@Override
public void configure(ResourceServerSecurityConfigurer resources)
throws Exception {
if (this.config.getId() != null) {
resources.resourceId(this.config.getId());
}
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().httpBasic().and()
.csrf().disable();
}
}
@Configuration
@EnableAuthorizationServer
protected static class CustomAuthorizationServer
extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
protected CustomAuthorizationServer(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Bean
public ApprovalStore approvalStore(final TokenStore tokenStore) {
TokenApprovalStore approvalStore = new TokenApprovalStore();
approvalStore.setTokenStore(tokenStore);
return approvalStore;
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("client").secret("secret")
.resourceIds("resource-id").authorizedGrantTypes("password")
.authorities("USER").scopes("read")
.redirectUris("http://localhost:8080");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.tokenStore(tokenStore())
.authenticationManager(this.authenticationManager);
}
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
protected static class CustomMethodSecurity
extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
@Configuration
protected static class RoleHierarchyConfiguration {
@Bean
public RoleHierarchy roleHierarchy() {
return mock(RoleHierarchy.class);
}
}
@Configuration
protected static class PermissionEvaluatorConfiguration {
@Bean
public PermissionEvaluator permissionEvaluator() {
return mock(PermissionEvaluator.class);
}
}
}

View File

@@ -1,137 +0,0 @@
/*
* Copyright 2012-2017 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.boot.autoconfigure.security.oauth2.client;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.autoconfigure.web.servlet.MockServletWebServerFactory;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
import org.springframework.security.oauth2.config.annotation.web.configuration.OAuth2ClientConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link OAuth2RestOperationsConfiguration}.
*
* @author Madhura Bhave
*/
public class OAuth2RestOperationsConfigurationTests {
private ConfigurableApplicationContext context;
private ConfigurableEnvironment environment = new StandardEnvironment();
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void clientCredentialsWithClientId() throws Exception {
TestPropertyValues.of("security.oauth2.client.client-id=acme")
.applyTo(this.environment);
initializeContext(OAuth2RestOperationsConfiguration.class, true);
assertThat(this.context.getBean(OAuth2RestOperationsConfiguration.class))
.isNotNull();
assertThat(this.context.getBean(ClientCredentialsResourceDetails.class))
.isNotNull();
}
@Test
public void clientCredentialsWithNoClientId() throws Exception {
initializeContext(OAuth2RestOperationsConfiguration.class, true);
assertThat(this.context.getBean(OAuth2RestOperationsConfiguration.class))
.isNotNull();
assertThat(this.context.getBean(ClientCredentialsResourceDetails.class))
.isNotNull();
}
@Test
public void requestScopedWithClientId() throws Exception {
TestPropertyValues.of("security.oauth2.client.client-id=acme")
.applyTo(this.environment);
initializeContext(ConfigForRequestScopedConfiguration.class, false);
assertThat(this.context.containsBean("oauth2ClientContext")).isTrue();
}
@Test
public void requestScopedWithNoClientId() throws Exception {
initializeContext(ConfigForRequestScopedConfiguration.class, false);
this.thrown.expect(NoSuchBeanDefinitionException.class);
this.context.getBean(DefaultOAuth2ClientContext.class);
}
@Test
public void sessionScopedWithClientId() throws Exception {
TestPropertyValues.of("security.oauth2.client.client-id=acme")
.applyTo(this.environment);
initializeContext(ConfigForSessionScopedConfiguration.class, false);
assertThat(this.context.containsBean("oauth2ClientContext")).isTrue();
}
@Test
public void sessionScopedWithNoClientId() throws Exception {
initializeContext(ConfigForSessionScopedConfiguration.class, false);
this.thrown.expect(NoSuchBeanDefinitionException.class);
this.context.getBean(DefaultOAuth2ClientContext.class);
}
private void initializeContext(Class<?> configuration, boolean clientCredentials) {
this.context = new SpringApplicationBuilder(configuration)
.environment(this.environment).web(clientCredentials
? WebApplicationType.NONE : WebApplicationType.SERVLET)
.run();
}
@Configuration
@Import({ OAuth2RestOperationsConfiguration.class })
protected static class WebApplicationConfiguration {
@Bean
public MockServletWebServerFactory webServerFactory() {
return new MockServletWebServerFactory();
}
}
@Configuration
@Import({ SecurityProperties.class, OAuth2ClientConfiguration.class,
OAuth2RestOperationsConfiguration.class })
protected static class ConfigForSessionScopedConfiguration
extends WebApplicationConfiguration {
}
@Configuration
protected static class ConfigForRequestScopedConfiguration
extends WebApplicationConfiguration {
}
}

View File

@@ -1,104 +0,0 @@
/*
* Copyright 2012-2017 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.boot.autoconfigure.security.oauth2.resource;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link FixedAuthoritiesExtractor}.
*
* @author Dave Syer
*/
public class FixedAuthoritiesExtractorTests {
private FixedAuthoritiesExtractor extractor = new FixedAuthoritiesExtractor();
private Map<String, Object> map = new LinkedHashMap<>();
@Test
public void authorities() {
this.map.put("authorities", "ROLE_ADMIN");
assertThat(this.extractor.extractAuthorities(this.map).toString())
.isEqualTo("[ROLE_ADMIN]");
}
@Test
public void authoritiesCommaSeparated() {
this.map.put("authorities", "ROLE_USER,ROLE_ADMIN");
assertThat(this.extractor.extractAuthorities(this.map).toString())
.isEqualTo("[ROLE_USER, ROLE_ADMIN]");
}
@Test
public void authoritiesArray() {
this.map.put("authorities", new String[] { "ROLE_USER", "ROLE_ADMIN" });
assertThat(this.extractor.extractAuthorities(this.map).toString())
.isEqualTo("[ROLE_USER, ROLE_ADMIN]");
}
@Test
public void authoritiesList() {
this.map.put("authorities", Arrays.asList("ROLE_USER", "ROLE_ADMIN"));
assertThat(this.extractor.extractAuthorities(this.map).toString())
.isEqualTo("[ROLE_USER, ROLE_ADMIN]");
}
@Test
public void authoritiesAsListOfMaps() {
this.map.put("authorities",
Arrays.asList(Collections.singletonMap("authority", "ROLE_ADMIN")));
assertThat(this.extractor.extractAuthorities(this.map).toString())
.isEqualTo("[ROLE_ADMIN]");
}
@Test
public void authoritiesAsListOfMapsWithStandardKey() {
Map<String, String> map = new LinkedHashMap<>();
map.put("role", "ROLE_ADMIN");
map.put("extra", "value");
this.map.put("authorities", Arrays.asList(map));
assertThat(this.extractor.extractAuthorities(this.map).toString())
.isEqualTo("[ROLE_ADMIN]");
}
@Test
public void authoritiesAsListOfMapsWithNonStandardKey() {
this.map.put("authorities",
Arrays.asList(Collections.singletonMap("any", "ROLE_ADMIN")));
assertThat(this.extractor.extractAuthorities(this.map).toString())
.isEqualTo("[ROLE_ADMIN]");
}
@Test
public void authoritiesAsListOfMapsWithMultipleNonStandardKeys() {
Map<String, String> map = new HashMap<>();
map.put("any", "ROLE_ADMIN");
map.put("foo", "bar");
this.map.put("authorities", Arrays.asList(map));
assertThat(this.extractor.extractAuthorities(this.map).toString())
.isEqualTo("[{foo=bar, any=ROLE_ADMIN}]");
}
}

View File

@@ -1,105 +0,0 @@
/*
* Copyright 2012-2017 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.boot.autoconfigure.security.oauth2.resource;
import java.util.List;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link OAuth2ResourceServerConfiguration} when there are multiple
* {@link ResourceServerConfiguration} beans.
*
* @author Dave Syer
*/
public class MultipleResourceServerConfigurationTests {
private AnnotationConfigWebApplicationContext context;
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void orderIsUnchangedWhenThereAreMultipleResourceServerConfigurations() {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(DoubleResourceConfiguration.class);
TestPropertyValues.of("security.oauth2.resource.tokenInfoUri:http://example.com",
"security.oauth2.client.clientId=acme").applyTo(this.context);
this.context.refresh();
assertThat(this.context
.getBean("adminResources", ResourceServerConfiguration.class).getOrder())
.isEqualTo(3);
assertThat(this.context
.getBean("otherResources", ResourceServerConfiguration.class).getOrder())
.isEqualTo(4);
}
@ImportAutoConfiguration({ OAuth2AutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
@EnableWebSecurity
@Configuration
protected static class DoubleResourceConfiguration {
@Bean
protected ResourceServerConfiguration adminResources() {
ResourceServerConfiguration resource = new ResourceServerConfiguration() {
// Switch off the Spring Boot @Autowired configurers
@Override
public void setConfigurers(List<ResourceServerConfigurer> configurers) {
super.setConfigurers(configurers);
}
};
resource.setOrder(3);
return resource;
}
@Bean
protected ResourceServerConfiguration otherResources() {
ResourceServerConfiguration resource = new ResourceServerConfiguration() {
// Switch off the Spring Boot @Autowired configurers
@Override
public void setConfigurers(List<ResourceServerConfigurer> configurers) {
super.setConfigurers(configurers);
}
};
resource.setOrder(4);
return resource;
}
}
}

View File

@@ -1,224 +0,0 @@
/*
* Copyright 2012-2017 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.boot.autoconfigure.security.oauth2.resource;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.context.support.StaticWebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyZeroInteractions;
/**
* Tests for {@link ResourceServerProperties}.
*
* @author Dave Syer
* @author Vedran Pavic
* @author Madhura Bhave
*/
public class ResourceServerPropertiesTests {
private ResourceServerProperties properties = new ResourceServerProperties("client",
"secret");
private Errors errors = mock(Errors.class);
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
@SuppressWarnings("unchecked")
public void json() throws Exception {
this.properties.getJwt().setKeyUri("http://example.com/token_key");
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(this.properties);
Map<String, Object> value = mapper.readValue(json, Map.class);
Map<String, Object> jwt = (Map<String, Object>) value.get("jwt");
assertThat(jwt.get("keyUri")).isNotNull();
}
@Test
public void validateWhenClientIdNullShouldNotFail() throws Exception {
this.properties = new ResourceServerProperties(null, "secret");
setListableBeanFactory();
this.properties.validate();
verifyZeroInteractions(this.errors);
}
@Test
public void validateWhenBothJwtAndJwkKeyUrisPresentShouldFail() throws Exception {
this.properties.getJwk().setKeySetUri("http://my-auth-server/token_keys");
this.properties.getJwt().setKeyUri("http://my-auth-server/token_key");
setListableBeanFactory();
this.thrown.expect(IllegalStateException.class);
this.thrown.expect(getMatcher("Only one of jwt.keyUri (or jwt.keyValue) "
+ "and jwk.keySetUri should be configured.", null));
this.properties.validate();
}
@Test
public void validateWhenBothJwtKeyValueAndJwkKeyUriPresentShouldFail()
throws Exception {
this.properties.getJwk().setKeySetUri("http://my-auth-server/token_keys");
this.properties.getJwt().setKeyValue("my-key");
setListableBeanFactory();
this.thrown.expect(IllegalStateException.class);
this.thrown.expect(getMatcher("Only one of jwt.keyUri (or jwt.keyValue) "
+ "and jwk.keySetUri should be configured.", null));
this.properties.validate();
}
@Test
public void validateWhenJwkKeySetUriProvidedShouldSucceed() throws Exception {
this.properties.getJwk().setKeySetUri("http://my-auth-server/token_keys");
setListableBeanFactory();
this.properties.validate();
verifyZeroInteractions(this.errors);
}
@Test
public void validateWhenKeyValuePresentShouldSucceed() throws Exception {
this.properties.getJwt().setKeyValue("my-key");
setListableBeanFactory();
this.properties.validate();
verifyZeroInteractions(this.errors);
}
@Test
public void validateWhenKeysUriOrValuePresentAndUserInfoAbsentShouldNotFail()
throws Exception {
this.properties = new ResourceServerProperties("client", "");
this.properties.getJwk().setKeySetUri("http://my-auth-server/token_keys");
setListableBeanFactory();
this.properties.validate();
verifyZeroInteractions(this.errors);
}
@Test
public void validateWhenKeyConfigAbsentAndInfoUrisNotConfiguredShouldFail()
throws Exception {
setListableBeanFactory();
this.thrown.expect(IllegalStateException.class);
this.thrown.expect(getMatcher("Missing tokenInfoUri and userInfoUri and there"
+ " is no JWT verifier key", "tokenInfoUri"));
this.properties.validate();
}
@Test
public void validateWhenTokenUriConfiguredShouldNotFail() throws Exception {
this.properties.setTokenInfoUri("http://my-auth-server/userinfo");
setListableBeanFactory();
this.properties.validate();
verifyZeroInteractions(this.errors);
}
@Test
public void validateWhenUserInfoUriConfiguredShouldNotFail() throws Exception {
this.properties.setUserInfoUri("http://my-auth-server/userinfo");
setListableBeanFactory();
this.properties.validate();
verifyZeroInteractions(this.errors);
}
@Test
public void validateWhenTokenUriPreferredAndClientSecretAbsentShouldFail()
throws Exception {
this.properties = new ResourceServerProperties("client", "");
this.properties.setTokenInfoUri("http://my-auth-server/check_token");
this.properties.setUserInfoUri("http://my-auth-server/userinfo");
setListableBeanFactory();
this.thrown.expect(IllegalStateException.class);
this.thrown.expect(getMatcher("Missing client secret", "clientSecret"));
this.properties.validate();
}
@Test
public void validateWhenTokenUriAbsentAndClientSecretAbsentShouldNotFail()
throws Exception {
this.properties = new ResourceServerProperties("client", "");
this.properties.setUserInfoUri("http://my-auth-server/userinfo");
setListableBeanFactory();
this.properties.validate();
verifyZeroInteractions(this.errors);
}
@Test
public void validateWhenTokenUriNotPreferredAndClientSecretAbsentShouldNotFail()
throws Exception {
this.properties = new ResourceServerProperties("client", "");
this.properties.setPreferTokenInfo(false);
this.properties.setTokenInfoUri("http://my-auth-server/check_token");
this.properties.setUserInfoUri("http://my-auth-server/userinfo");
setListableBeanFactory();
this.properties.validate();
verifyZeroInteractions(this.errors);
}
private void setListableBeanFactory() {
ListableBeanFactory beanFactory = new StaticWebApplicationContext() {
@Override
public String[] getBeanNamesForType(Class<?> type,
boolean includeNonSingletons, boolean allowEagerInit) {
if (type.isAssignableFrom(
ResourceServerTokenServicesConfiguration.class)) {
return new String[] { "ResourceServerTokenServicesConfiguration" };
}
return new String[0];
}
};
this.properties.setBeanFactory(beanFactory);
}
private BaseMatcher<BindException> getMatcher(String message, String field) {
return new BaseMatcher<BindException>() {
@Override
public void describeTo(Description description) {
}
@Override
public boolean matches(Object item) {
BindException ex = (BindException) ((Exception) item).getCause();
ObjectError error = ex.getAllErrors().get(0);
boolean messageMatches = message.equals(error.getDefaultMessage());
if (field == null) {
return messageMatches;
}
String fieldErrors = ((FieldError) error).getField();
return messageMatches && fieldErrors.equals(field);
}
};
}
}

View File

@@ -1,417 +0,0 @@
/*
* Copyright 2012-2017 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.boot.autoconfigure.security.oauth2.resource;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.OAuth2ClientProperties;
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2RestOperationsConfiguration;
import org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration;
import org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.MockServletWebServerFactory;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.mock.http.client.MockClientHttpResponse;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.jwk.JwkTokenStore;
import org.springframework.social.connect.ConnectionFactoryLocator;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link ResourceServerTokenServicesConfiguration}.
*
* @author Dave Syer
* @author Madhura Bhave
* @author Eddú Meléndez
*/
public class ResourceServerTokenServicesConfigurationTests {
private static String PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\n"
+ "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnGp/Q5lh0P8nPL21oMMrt2RrkT9"
+ "AW5jgYwLfSUnJVc9G6uR3cXRRDCjHqWU5WYwivcF180A6CWp/ireQFFBNowgc5XaA0kPpzE"
+ "tgsA5YsNX7iSnUibB004iBTfU9hZ2Rbsc8cWqynT0RyN4TP1RYVSeVKvMQk4GT1r7JCEC+T"
+ "Nu1ELmbNwMQyzKjsfBXyIOCFU/E94ktvsTZUHF4Oq44DBylCDsS1k7/sfZC2G5EU7Oz0mhG"
+ "8+Uz6MSEQHtoIi6mc8u64Rwi3Z3tscuWG2ShtsUFuNSAFNkY7LkLn+/hxLCu2bNISMaESa8"
+ "dG22CIMuIeRLVcAmEWEWH5EEforTg+QIDAQAB\n-----END PUBLIC KEY-----";
private ConfigurableApplicationContext context;
private ConfigurableEnvironment environment = new StandardEnvironment();
@Rule
public ExpectedException thrown = ExpectedException.none();
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void useRemoteTokenServices() {
TestPropertyValues.of("security.oauth2.resource.tokenInfoUri:http://example.com")
.applyTo(this.environment);
this.context = new SpringApplicationBuilder(ResourceConfiguration.class)
.environment(this.environment).web(WebApplicationType.NONE).run();
RemoteTokenServices services = this.context.getBean(RemoteTokenServices.class);
assertThat(services).isNotNull();
}
@Test
public void switchToUserInfo() {
TestPropertyValues.of("security.oauth2.resource.userInfoUri:http://example.com")
.applyTo(this.environment);
this.context = new SpringApplicationBuilder(ResourceConfiguration.class)
.environment(this.environment).web(WebApplicationType.NONE).run();
UserInfoTokenServices services = this.context
.getBean(UserInfoTokenServices.class);
assertThat(services).isNotNull();
}
@Test
public void userInfoWithAuthorities() {
TestPropertyValues.of("security.oauth2.resource.userInfoUri:http://example.com")
.applyTo(this.environment);
this.context = new SpringApplicationBuilder(AuthoritiesConfiguration.class)
.environment(this.environment).web(WebApplicationType.NONE).run();
UserInfoTokenServices services = this.context
.getBean(UserInfoTokenServices.class);
assertThat(services).isNotNull();
assertThat(services).extracting("authoritiesExtractor")
.containsExactly(this.context.getBean(AuthoritiesExtractor.class));
}
@Test
public void userInfoWithPrincipal() {
TestPropertyValues.of("security.oauth2.resource.userInfoUri:http://example.com")
.applyTo(this.environment);
this.context = new SpringApplicationBuilder(PrincipalConfiguration.class)
.environment(this.environment).web(WebApplicationType.NONE).run();
UserInfoTokenServices services = this.context
.getBean(UserInfoTokenServices.class);
assertThat(services).isNotNull();
assertThat(services).extracting("principalExtractor")
.containsExactly(this.context.getBean(PrincipalExtractor.class));
}
@Test
public void userInfoWithClient() {
TestPropertyValues.of("security.oauth2.client.client-id=acme",
"security.oauth2.resource.userInfoUri:http://example.com",
"server.port=-1", "debug=true").applyTo(this.environment);
this.context = new SpringApplicationBuilder(ResourceNoClientConfiguration.class)
.environment(this.environment).web(WebApplicationType.SERVLET).run();
BeanDefinition bean = ((BeanDefinitionRegistry) this.context)
.getBeanDefinition("scopedTarget.oauth2ClientContext");
assertThat(bean.getScope()).isEqualTo("request");
}
@Test
public void preferUserInfo() {
TestPropertyValues
.of("security.oauth2.resource.userInfoUri:http://example.com",
"security.oauth2.resource.tokenInfoUri:http://example.com",
"security.oauth2.resource.preferTokenInfo:false")
.applyTo(this.environment);
this.context = new SpringApplicationBuilder(ResourceConfiguration.class)
.environment(this.environment).web(WebApplicationType.NONE).run();
UserInfoTokenServices services = this.context
.getBean(UserInfoTokenServices.class);
assertThat(services).isNotNull();
}
@Test
public void userInfoWithCustomizer() {
TestPropertyValues
.of("security.oauth2.resource.userInfoUri:http://example.com",
"security.oauth2.resource.tokenInfoUri:http://example.com",
"security.oauth2.resource.preferTokenInfo:false")
.applyTo(this.environment);
this.context = new SpringApplicationBuilder(ResourceConfiguration.class,
Customizer.class).environment(this.environment)
.web(WebApplicationType.NONE).run();
UserInfoTokenServices services = this.context
.getBean(UserInfoTokenServices.class);
assertThat(services).isNotNull();
}
@Test
public void switchToJwt() {
TestPropertyValues.of("security.oauth2.resource.jwt.keyValue=FOOBAR")
.applyTo(this.environment);
this.context = new SpringApplicationBuilder(ResourceConfiguration.class)
.environment(this.environment).web(WebApplicationType.NONE).run();
DefaultTokenServices services = this.context.getBean(DefaultTokenServices.class);
assertThat(services).isNotNull();
this.thrown.expect(NoSuchBeanDefinitionException.class);
this.context.getBean(RemoteTokenServices.class);
}
@Test
public void asymmetricJwt() {
TestPropertyValues.of("security.oauth2.resource.jwt.keyValue=" + PUBLIC_KEY)
.applyTo(this.environment);
this.context = new SpringApplicationBuilder(ResourceConfiguration.class)
.environment(this.environment).web(WebApplicationType.NONE).run();
DefaultTokenServices services = this.context.getBean(DefaultTokenServices.class);
assertThat(services).isNotNull();
}
@Test
public void jwkConfiguration() throws Exception {
TestPropertyValues
.of("security.oauth2.resource.jwk.key-set-uri=http://my-auth-server/token_keys")
.applyTo(this.environment);
this.context = new SpringApplicationBuilder(ResourceConfiguration.class)
.environment(this.environment).web(WebApplicationType.NONE).run();
DefaultTokenServices services = this.context.getBean(DefaultTokenServices.class);
assertThat(services).isNotNull();
this.thrown.expect(NoSuchBeanDefinitionException.class);
this.context.getBean(RemoteTokenServices.class);
}
@Test
public void springSocialUserInfo() {
TestPropertyValues
.of("security.oauth2.resource.userInfoUri:http://example.com",
"spring.social.facebook.app-id=foo",
"spring.social.facebook.app-secret=bar")
.applyTo(this.environment);
this.context = new SpringApplicationBuilder(SocialResourceConfiguration.class)
.environment(this.environment).web(WebApplicationType.SERVLET).run();
ConnectionFactoryLocator connectionFactory = this.context
.getBean(ConnectionFactoryLocator.class);
assertThat(connectionFactory).isNotNull();
SpringSocialTokenServices services = this.context
.getBean(SpringSocialTokenServices.class);
assertThat(services).isNotNull();
}
@Test
public void customUserInfoRestTemplateFactory() {
TestPropertyValues.of("security.oauth2.resource.userInfoUri:http://example.com")
.applyTo(this.environment);
this.context = new SpringApplicationBuilder(
CustomUserInfoRestTemplateFactory.class, ResourceConfiguration.class)
.environment(this.environment).web(WebApplicationType.NONE).run();
assertThat(this.context.getBeansOfType(UserInfoRestTemplateFactory.class))
.hasSize(1);
assertThat(this.context.getBean(UserInfoRestTemplateFactory.class))
.isInstanceOf(CustomUserInfoRestTemplateFactory.class);
}
@Test
public void jwtAccessTokenConverterIsConfiguredWhenKeyUriIsProvided() {
TestPropertyValues
.of("security.oauth2.resource.jwt.key-uri=http://localhost:12345/banana")
.applyTo(this.environment);
this.context = new SpringApplicationBuilder(ResourceConfiguration.class,
JwtAccessTokenConverterRestTemplateCustomizerConfiguration.class)
.environment(this.environment).web(WebApplicationType.NONE).run();
assertThat(this.context.getBeansOfType(JwtAccessTokenConverter.class)).hasSize(1);
}
@Test
public void jwkTokenStoreShouldBeConditionalOnMissingBean() throws Exception {
TestPropertyValues
.of("security.oauth2.resource.jwk.key-set-uri=http://my-auth-server/token_keys")
.applyTo(this.environment);
this.context = new SpringApplicationBuilder(JwkTokenStoreConfiguration.class,
ResourceConfiguration.class).environment(this.environment)
.web(WebApplicationType.NONE).run();
assertThat(this.context.getBeansOfType(JwkTokenStore.class)).hasSize(1);
}
@Test
public void jwtTokenStoreShouldBeConditionalOnMissingBean() throws Exception {
TestPropertyValues.of("security.oauth2.resource.jwt.keyValue=" + PUBLIC_KEY)
.applyTo(this.environment);
this.context = new SpringApplicationBuilder(JwtTokenStoreConfiguration.class,
ResourceConfiguration.class).environment(this.environment)
.web(WebApplicationType.NONE).run();
assertThat(this.context.getBeansOfType(JwtTokenStore.class)).hasSize(1);
}
@Configuration
@Import({ ResourceServerTokenServicesConfiguration.class,
ResourceServerPropertiesConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
@EnableConfigurationProperties(OAuth2ClientProperties.class)
protected static class ResourceConfiguration {
}
@Configuration
protected static class AuthoritiesConfiguration extends ResourceConfiguration {
@Bean
AuthoritiesExtractor authoritiesExtractor() {
return (map) -> AuthorityUtils
.commaSeparatedStringToAuthorityList("ROLE_ADMIN");
}
}
@Configuration
protected static class PrincipalConfiguration extends ResourceConfiguration {
@Bean
PrincipalExtractor principalExtractor() {
return (map) -> "boot";
}
}
@Import({ OAuth2RestOperationsConfiguration.class })
protected static class ResourceNoClientConfiguration extends ResourceConfiguration {
@Bean
public MockServletWebServerFactory webServerFactory() {
return new MockServletWebServerFactory();
}
}
@Configuration
protected static class ResourceServerPropertiesConfiguration {
private OAuth2ClientProperties credentials;
public ResourceServerPropertiesConfiguration(OAuth2ClientProperties credentials) {
this.credentials = credentials;
}
@Bean
public ResourceServerProperties resourceServerProperties() {
return new ResourceServerProperties(this.credentials.getClientId(),
this.credentials.getClientSecret());
}
}
@Import({ FacebookAutoConfiguration.class, SocialWebAutoConfiguration.class })
protected static class SocialResourceConfiguration extends ResourceConfiguration {
@Bean
public ServletWebServerFactory webServerFactory() {
return mock(ServletWebServerFactory.class);
}
}
@Component
protected static class Customizer implements UserInfoRestTemplateCustomizer {
@Override
public void customize(OAuth2RestTemplate template) {
template.getInterceptors()
.add((request, body, execution) -> execution.execute(request, body));
}
}
@Component
protected static class CustomUserInfoRestTemplateFactory
implements UserInfoRestTemplateFactory {
private final OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(
new AuthorizationCodeResourceDetails());
@Override
public OAuth2RestTemplate getUserInfoRestTemplate() {
return this.restTemplate;
}
}
@Configuration
static class JwtAccessTokenConverterRestTemplateCustomizerConfiguration {
@Bean
public JwtAccessTokenConverterRestTemplateCustomizer restTemplateCustomizer() {
return new MockRestCallCustomizer();
}
}
@Configuration
static class JwtTokenStoreConfiguration {
@Bean
public TokenStore tokenStore(JwtAccessTokenConverter jwtTokenEnhancer) {
return new JwtTokenStore(jwtTokenEnhancer);
}
}
@Configuration
static class JwkTokenStoreConfiguration {
@Bean
public TokenStore tokenStore() {
return new JwkTokenStore("http://my.key-set.uri");
}
}
private static class MockRestCallCustomizer
implements JwtAccessTokenConverterRestTemplateCustomizer {
@Override
public void customize(RestTemplate template) {
template.getInterceptors().add((request, body, execution) -> {
String payload = "{\"value\":\"FOO\"}";
MockClientHttpResponse response = new MockClientHttpResponse(
payload.getBytes(), HttpStatus.OK);
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
return response;
});
}
}
}

View File

@@ -1,150 +0,0 @@
/*
* Copyright 2012-2017 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.boot.autoconfigure.security.oauth2.resource;
import java.util.Date;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.common.DefaultExpiringOAuth2RefreshToken;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link UserInfoTokenServices}.
*
* @author Dave Syer
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {
"security.oauth2.resource.userInfoUri:http://example.com",
"security.oauth2.client.clientId=foo" })
@DirtiesContext
public class UserInfoTokenServicesRefreshTokenTests {
@Rule
public ExpectedException expected = ExpectedException.none();
@LocalServerPort
private int port;
private UserInfoTokenServices services;
@Before
public void init() {
this.services = new UserInfoTokenServices(
"http://localhost:" + this.port + "/user", "foo");
}
@Test
public void sunnyDay() {
assertThat(this.services.loadAuthentication("FOO").getName()).isEqualTo("me");
}
@Test
public void withRestTemplate() {
OAuth2ProtectedResourceDetails resource = new AuthorizationCodeResourceDetails();
OAuth2ClientContext context = new DefaultOAuth2ClientContext();
DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken("FOO");
token.setRefreshToken(new DefaultExpiringOAuth2RefreshToken("BAR", new Date(0L)));
context.setAccessToken(token);
this.services.setRestTemplate(new OAuth2RestTemplate(resource, context));
assertThat(this.services.loadAuthentication("FOO").getName()).isEqualTo("me");
assertThat(context.getAccessToken().getValue()).isEqualTo("FOO");
// The refresh token is still intact
assertThat(context.getAccessToken().getRefreshToken())
.isEqualTo(token.getRefreshToken());
}
@Test
public void withRestTemplateChangesState() {
OAuth2ProtectedResourceDetails resource = new AuthorizationCodeResourceDetails();
OAuth2ClientContext context = new DefaultOAuth2ClientContext();
context.setAccessToken(new DefaultOAuth2AccessToken("FOO"));
this.services.setRestTemplate(new OAuth2RestTemplate(resource, context));
assertThat(this.services.loadAuthentication("BAR").getName()).isEqualTo("me");
assertThat(context.getAccessToken().getValue()).isEqualTo("BAR");
}
@Configuration
@Import({ ServletWebServerFactoryAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
@RestController
protected static class Application {
@RequestMapping("/user")
public User user(@RequestHeader("Authorization") String authorization) {
if (authorization.endsWith("EXPIRED")) {
throw new InvalidTokenException("Expired");
}
return new User();
}
@ExceptionHandler(InvalidTokenException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public void expired() {
}
}
public static class User {
private String userid = "me";
public String getUserid() {
return this.userid;
}
public void setUserid(String userid) {
this.userid = userid;
}
}
}

View File

@@ -1,100 +0,0 @@
/*
* Copyright 2012-2017 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.boot.autoconfigure.security.oauth2.resource;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.client.resource.BaseOAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link UserInfoTokenServices}.
*
* @author Dave Syer
*/
public class UserInfoTokenServicesTests {
@Rule
public ExpectedException expected = ExpectedException.none();
private UserInfoTokenServices services = new UserInfoTokenServices(
"http://example.com", "foo");
private BaseOAuth2ProtectedResourceDetails resource = new BaseOAuth2ProtectedResourceDetails();
private OAuth2RestOperations template = mock(OAuth2RestOperations.class);
private Map<String, Object> map = new LinkedHashMap<>();
@Before
public void init() {
this.resource.setClientId("foo");
given(this.template.getForEntity(any(String.class), eq(Map.class)))
.willReturn(new ResponseEntity<>(this.map, HttpStatus.OK));
given(this.template.getAccessToken())
.willReturn(new DefaultOAuth2AccessToken("FOO"));
given(this.template.getResource()).willReturn(this.resource);
given(this.template.getOAuth2ClientContext())
.willReturn(mock(OAuth2ClientContext.class));
}
@Test
public void sunnyDay() {
this.services.setRestTemplate(this.template);
assertThat(this.services.loadAuthentication("FOO").getName())
.isEqualTo("unknown");
}
@Test
public void badToken() {
this.services.setRestTemplate(this.template);
given(this.template.getForEntity(any(String.class), eq(Map.class)))
.willThrow(new UserRedirectRequiredException("foo:bar",
Collections.<String, String>emptyMap()));
this.expected.expect(InvalidTokenException.class);
assertThat(this.services.loadAuthentication("FOO").getName())
.isEqualTo("unknown");
}
@Test
public void userId() {
this.map.put("userid", "spencer");
this.services.setRestTemplate(this.template);
assertThat(this.services.loadAuthentication("FOO").getName())
.isEqualTo("spencer");
}
}

View File

@@ -1,93 +0,0 @@
/*
* Copyright 2012-2016 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.boot.autoconfigure.security.oauth2.sso;
import javax.servlet.Filter;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Tests for {@link OAuth2AutoConfiguration} with basic configuration.
*
* @author Dave Syer
*/
@RunWith(SpringRunner.class)
@DirtiesContext
@SpringBootTest
@TestPropertySource(properties = { "security.oauth2.client.clientId=client",
"security.oauth2.client.clientSecret=secret",
"security.oauth2.client.userAuthorizationUri=http://example.com/oauth/authorize",
"security.oauth2.client.accessTokenUri=http://example.com/oauth/token",
"security.oauth2.resource.jwt.keyValue=SSSSHHH" })
public class BasicOAuth2SsoConfigurationTests {
@Autowired
private WebApplicationContext context;
@Autowired
@Qualifier("springSecurityFilterChain")
private Filter filter;
private MockMvc mvc;
@Before
public void init() {
this.mvc = MockMvcBuilders.webAppContextSetup(this.context)
.addFilters(this.filter).build();
}
@Test
public void homePageIsSecure() throws Exception {
this.mvc.perform(get("/")).andExpect(status().isFound())
.andExpect(header().string("location", "http://localhost/login"));
}
@Test
public void homePageSends401ToXhr() throws Exception {
this.mvc.perform(get("/").header("X-Requested-With", "XMLHttpRequest"))
.andExpect(status().isUnauthorized());
}
@Configuration
@Import(OAuth2AutoConfiguration.class)
@EnableOAuth2Sso
@MinimalSecureWebConfiguration
protected static class TestConfiguration {
}
}

View File

@@ -1,120 +0,0 @@
/*
* Copyright 2012-2017 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.boot.autoconfigure.security.oauth2.sso;
import javax.servlet.Filter;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Tests for {@link OAuth2AutoConfiguration} with custom configuration.
*
* @author Dave Syer
*/
@RunWith(SpringRunner.class)
@DirtiesContext
@SpringBootTest
@TestPropertySource(properties = { "security.oauth2.client.clientId=client",
"security.oauth2.client.clientSecret=secret",
"security.oauth2.client.authorizationUri=http://example.com/oauth/authorize",
"security.oauth2.client.tokenUri=http://example.com/oauth/token",
"security.oauth2.resource.jwt.keyValue=SSSSHHH" })
public class CustomOAuth2SsoConfigurationTests {
@Autowired
private WebApplicationContext context;
@Autowired
@Qualifier("springSecurityFilterChain")
private Filter filter;
private MockMvc mvc;
@Before
public void init() {
this.mvc = MockMvcBuilders.webAppContextSetup(this.context)
.addFilters(this.filter).build();
}
@Test
public void uiPageIsSecure() throws Exception {
this.mvc.perform(get("/ui/")).andExpect(status().isFound())
.andExpect(header().string("location", "http://localhost/login"));
}
@Test
public void uiPageSends401ToXhr() throws Exception {
this.mvc.perform(get("/ui/").header("X-Requested-With", "XMLHttpRequest"))
.andExpect(status().isUnauthorized());
}
@Test
public void uiTestPageIsAccessible() throws Exception {
this.mvc.perform(get("/ui/test")).andExpect(status().isOk())
.andExpect(content().string("test"));
}
@Configuration
@EnableOAuth2Sso
@Import(OAuth2AutoConfiguration.class)
@MinimalSecureWebConfiguration
protected static class TestConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/ui/**").authorizeRequests().antMatchers("/ui/test")
.permitAll().anyRequest().authenticated();
}
@RestController
public static class TestController {
@RequestMapping("/ui/test")
public String test() {
return "test";
}
}
}
}

View File

@@ -1,116 +0,0 @@
/*
* Copyright 2012-2017 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.boot.autoconfigure.security.oauth2.sso;
import javax.servlet.Filter;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Tests for {@link OAuth2AutoConfiguration} with custom configuration.
*
* @author Dave Syer
*/
@RunWith(SpringRunner.class)
@DirtiesContext
@SpringBootTest
@TestPropertySource(properties = { "security.oauth2.client.clientId=client",
"security.oauth2.client.clientSecret=secret",
"security.oauth2.client.authorizationUri=http://example.com/oauth/authorize",
"security.oauth2.client.tokenUri=http://example.com/oauth/token",
"security.oauth2.resource.jwt.keyValue=SSSSHHH" })
public class CustomOAuth2SsoWithAuthenticationEntryPointConfigurationTests {
@Autowired
private WebApplicationContext context;
@Autowired
@Qualifier("springSecurityFilterChain")
private Filter filter;
private MockMvc mvc;
@Before
public void init() {
this.mvc = MockMvcBuilders.webAppContextSetup(this.context)
.addFilters(this.filter).build();
}
@Test
public void uiPageIsSecure() throws Exception {
this.mvc.perform(get("/ui/")).andExpect(status().isUnauthorized());
}
@Test
public void uiTestPageIsAccessible() throws Exception {
this.mvc.perform(get("/ui/test")).andExpect(status().isOk())
.andExpect(content().string("test"));
}
@Configuration
@EnableOAuth2Sso
@Import(OAuth2AutoConfiguration.class)
@MinimalSecureWebConfiguration
protected static class TestConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/ui/**").authorizeRequests().antMatchers("/ui/test")
.permitAll().anyRequest().authenticated().and().exceptionHandling()
.authenticationEntryPoint(
new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
}
@RestController
public static class TestController {
@RequestMapping("/ui/test")
public String test() {
return "test";
}
}
}
}

View File

@@ -1,83 +0,0 @@
/*
* Copyright 2012-2016 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.boot.autoconfigure.security.oauth2.sso;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.client.RestTemplate;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyZeroInteractions;
/**
* Test to validate that a custom {@link RestTemplate} can be defined with OAuth2 SSO.
*
* @author Stephane Nicoll
*/
@RunWith(SpringRunner.class)
@DirtiesContext
@SpringBootTest
@TestPropertySource(properties = { "security.oauth2.client.clientId=client",
"security.oauth2.client.clientSecret=secret",
"security.oauth2.client.userAuthorizationUri=http://example.com/oauth/authorize",
"security.oauth2.client.accessTokenUri=http://example.com/oauth/token",
"security.oauth2.resource.jwt.keyValue=SSSSHHH" })
public class CustomRestTemplateBasicOAuth2SsoConfigurationTests {
@Autowired
private ApplicationContext applicationContext;
@Autowired
private ObjectProvider<RestTemplate> restTemplate;
@Test
public void customRestTemplateCanBePrimary() {
RestTemplate restTemplate = this.restTemplate.getIfAvailable();
verifyZeroInteractions(restTemplate);
assertThat(this.applicationContext.getBeansOfType(RestTemplate.class)).hasSize(1);
}
@Configuration
@Import(OAuth2AutoConfiguration.class)
@EnableOAuth2Sso
@MinimalSecureWebConfiguration
protected static class TestConfiguration {
@Bean
@Primary
public RestTemplate myRestTemplate() {
return mock(RestTemplate.class);
}
}
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright 2012-2017 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.boot.autoconfigure.security.oauth2.sso;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({ ServletWebServerFactoryAutoConfiguration.class,
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, ErrorMvcAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, SecurityAutoConfiguration.class })
public @interface MinimalSecureWebConfiguration {
}