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:
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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}]");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user