mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Add auto-config for spring-security-oauth2-resource-server
Closes gh-13787
This commit is contained in:
parent
6a2cb883a5
commit
d6b6a5f81f
@ -553,6 +553,11 @@
|
||||
<artifactId>spring-security-oauth2-client</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-oauth2-resource-server</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.session</groupId>
|
||||
<artifactId>spring-session-core</artifactId>
|
||||
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.resource;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* OAuth 2.0 resource server properties.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "spring.security.oauth2.resource")
|
||||
public class OAuth2ResourceServerProperties {
|
||||
|
||||
private Jwt jwt = new Jwt();
|
||||
|
||||
public Jwt getJwt() {
|
||||
return this.jwt;
|
||||
}
|
||||
|
||||
public void setJwt(Jwt jwt) {
|
||||
this.jwt = jwt;
|
||||
}
|
||||
|
||||
public static class Jwt {
|
||||
|
||||
private Jwk jwk = new Jwk();
|
||||
|
||||
public Jwk getJwk() {
|
||||
return this.jwk;
|
||||
}
|
||||
|
||||
public void setJwk(Jwk jwk) {
|
||||
this.jwk = jwk;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Jwk {
|
||||
|
||||
/**
|
||||
* The URI to get verification keys to verify the JWT token.
|
||||
*/
|
||||
private String setUri;
|
||||
|
||||
public String getSetUri() {
|
||||
return this.setUri;
|
||||
}
|
||||
|
||||
public void setSetUri(String setUri) {
|
||||
this.setUri = setUri;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Support for Spring Security's OAuth 2 resource server.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.resource;
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for OAuth resource server support.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.1.0
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureBefore(SecurityAutoConfiguration.class)
|
||||
@EnableConfigurationProperties(OAuth2ResourceServerProperties.class)
|
||||
@ConditionalOnClass(JwtAuthenticationToken.class)
|
||||
@Import({ OAuth2ResourceServerJwkConfiguration.class,
|
||||
OAuth2ResourceServerWebSecurityConfiguration.class })
|
||||
public class OAuth2ResourceServerAutoConfiguration {
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport;
|
||||
|
||||
/**
|
||||
* Configures a {@link JwtDecoder} when a JWK Set URI is available.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@Configuration
|
||||
class OAuth2ResourceServerJwkConfiguration {
|
||||
|
||||
private final OAuth2ResourceServerProperties properties;
|
||||
|
||||
public OAuth2ResourceServerJwkConfiguration(
|
||||
OAuth2ResourceServerProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "spring.security.oauth2.resource.jwt.jwk.set-uri")
|
||||
@ConditionalOnMissingBean
|
||||
public JwtDecoder jwtDecoder() {
|
||||
return new NimbusJwtDecoderJwkSupport(
|
||||
this.properties.getJwt().getJwk().getSetUri());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
|
||||
/**
|
||||
* {@link WebSecurityConfigurerAdapter} for OAuth2 resource server support.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(WebSecurityConfigurerAdapter.class)
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
class OAuth2ResourceServerWebSecurityConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(JwtDecoder.class)
|
||||
static class OAuth2WebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
||||
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests().anyRequest().authenticated().and().oauth2()
|
||||
.resourceServer().jwt();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for Spring Security's OAuth 2 resource server.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
|
@ -105,6 +105,7 @@ org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.task.TaskExecutorAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
|
||||
|
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.resource.servlet;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoderJwkSupport;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
||||
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link OAuth2ResourceServerAutoConfiguration}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
public class OAuth2ResourceServerAutoConfigurationTests {
|
||||
|
||||
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
|
||||
.withConfiguration(
|
||||
AutoConfigurations.of(OAuth2ResourceServerAutoConfiguration.class))
|
||||
.withUserConfiguration(TestConfig.class);
|
||||
|
||||
@Test
|
||||
public void autoConfigurationShouldConfigureResourceServer() {
|
||||
this.contextRunner.withPropertyValues(
|
||||
"spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com")
|
||||
.run((context) -> {
|
||||
assertThat(context.getBean(JwtDecoder.class))
|
||||
.isInstanceOf(NimbusJwtDecoderJwkSupport.class);
|
||||
assertThat(getBearerTokenFilter(context)).isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void autoConfigurationWhenJwkSetUriNullShouldNotFail() {
|
||||
this.contextRunner
|
||||
.run((context) -> assertThat(getBearerTokenFilter(context)).isNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jwtDecoderBeanIsConditionalOnMissingBean() {
|
||||
this.contextRunner.withPropertyValues(
|
||||
"spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com")
|
||||
.withUserConfiguration(JwtDecoderConfig.class)
|
||||
.run((context) -> assertThat(getBearerTokenFilter(context)).isNotNull());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void autoConfigurationShouldBeConditionalOnJwtAuthenticationTokenClass() {
|
||||
this.contextRunner.withPropertyValues(
|
||||
"spring.security.oauth2.resource.jwt.jwk.set-uri=http://jwk-set-uri.com")
|
||||
.withUserConfiguration(JwtDecoderConfig.class)
|
||||
.withClassLoader(new FilteredClassLoader(JwtAuthenticationToken.class))
|
||||
.run((context) -> assertThat(getBearerTokenFilter(context)).isNull());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Filter getBearerTokenFilter(AssertableWebApplicationContext context) {
|
||||
FilterChainProxy filterChain = (FilterChainProxy) context
|
||||
.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
List<SecurityFilterChain> filterChains = filterChain.getFilterChains();
|
||||
List<Filter> filters = (List<Filter>) ReflectionTestUtils
|
||||
.getField(filterChains.get(0), "filters");
|
||||
return filters.stream()
|
||||
.filter((f) -> f instanceof BearerTokenAuthenticationFilter).findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class TestConfig {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
static class JwtDecoderConfig {
|
||||
|
||||
@Bean
|
||||
public JwtDecoder decoder() {
|
||||
return mock(JwtDecoder.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -529,6 +529,9 @@ content into your application. Rather, pick only the properties that you need.
|
||||
spring.security.oauth2.client.provider.*= # OAuth provider details.
|
||||
spring.security.oauth2.client.registration.*= # OAuth client registrations.
|
||||
|
||||
# SECURITY OAUTH2 RESOURCE SERVER ({sc-spring-boot-autoconfigure}/security/oauth2/resource/OAuth2ResourceServerProperties.{sc-ext}[OAuth2ResourceServerProperties])
|
||||
spring.security.oauth2.resource.jwt.jwk.set-uri.*= # JWK Set URI
|
||||
|
||||
# ----------------------------------------
|
||||
# DATA PROPERTIES
|
||||
# ----------------------------------------
|
||||
|
@ -3276,12 +3276,26 @@ Provider can be configured with the `issuer-uri`:
|
||||
|
||||
|
||||
[[boot-features-security-oauth2-server]]
|
||||
==== Server
|
||||
==== Resource Server
|
||||
If you have `spring-security-oauth2-resource-server` on your classpath, you can take advantage of
|
||||
some auto-configuration to make it easy to set up an OAuth2 Resource Server. This configuration
|
||||
makes use of the properties under `OAuth2ResourceServerProperties`.
|
||||
|
||||
For the OAuth2 Resource Server auto-configuration to kick in, you can
|
||||
provide a bean of type `JwtDecoder` yourself or configure a JWK Set URI as follows:
|
||||
|
||||
[source,properties,indent=0]
|
||||
----
|
||||
spring.security.oauth2.resource.jwt.jwk.set-uri=https://example.com/oauth2/default/v1/keys
|
||||
----
|
||||
|
||||
|
||||
==== Authorization Server
|
||||
Currently, Spring Security does not provide support for implementing an OAuth 2.0
|
||||
Authorization Server or Resource Server. However, this functionality is available from
|
||||
Authorization Server. However, this functionality is available from
|
||||
the https://projects.spring.io/spring-security-oauth/[Spring Security OAuth] project,
|
||||
which will eventually be superseded by Spring Security completely. Until then, you can
|
||||
use the `spring-security-oauth2-autoconfigure` module to easily set up an OAuth 2.0 server;
|
||||
use the `spring-security-oauth2-autoconfigure` module to easily set up an OAuth 2.0 authorization server;
|
||||
see its https://docs.spring.io/spring-security-oauth2-boot[documentation] for instructions.
|
||||
|
||||
|
||||
|
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<!-- Your own application should inherit from spring-boot-starter-parent -->
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-samples</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<artifactId>spring-boot-sample-oauth2-resource-server</artifactId>
|
||||
<name>Spring Boot Sample OAuth2 Resource Server</name>
|
||||
<description>Spring Boot Sample Resource Server</description>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<!-- Compile -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-oauth2-resource-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-oauth2-jose</artifactId>
|
||||
</dependency>
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>mockwebserver</artifactId>
|
||||
<version>3.9.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package sample.oauth2.resource;
|
||||
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.security.oauth2.jwt.Jwt;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class ExampleController {
|
||||
|
||||
@GetMapping("/")
|
||||
public String index(@AuthenticationPrincipal Jwt jwt) {
|
||||
return String.format("Hello, %s!", jwt.getSubject());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package sample.oauth2.resource;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SampleOauth2ResourceServerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SampleOauth2ResourceServerApplication.class);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
spring:
|
||||
security:
|
||||
oauth2:
|
||||
resource:
|
||||
jwt:
|
||||
jwk:
|
||||
# To run the application, replace this with a valid JWK Set URI
|
||||
set-uri: https://example.com/oauth2/default/v1/keys
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2012-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package sample.oauth2.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
public class SampleOauth2ResourceServerApplicationTests {
|
||||
|
||||
private static MockWebServer server = new MockWebServer();
|
||||
|
||||
private static final String VALID_TOKEN = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0Iiwic2NvcGUiOiJtZXNzYWdlOnJlYWQi"
|
||||
+ "LCJleHAiOjQ2ODM4MDUxNDF9.h-j6FKRFdnTdmAueTZCdep45e6DPwqM68ZQ8doIJ1exi9YxAlbWzOwId6Bd0L5YmCmp63gGQgsBUBLzwnZQ8kLUgU"
|
||||
+ "OBEC3UzSWGRqMskCY9_k9pX0iomX6IfF3N0PaYs0WPC4hO1s8wfZQ-6hKQ4KigFi13G9LMLdH58PRMK0pKEvs3gCbHJuEPw-K5ORlpdnleUTQIwIN"
|
||||
+ "afU57cmK3KocTeknPAM_L716sCuSYGvDl6xUTXO7oPdrXhS_EhxLP6KxrpI1uD4Ea_5OWTh7S0Wx5LLDfU6wBG1DowN20d374zepOIEkR-Jnmr_Ql"
|
||||
+ "R44vmRqS5ncrF-1R0EGcPX49U6A";
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() throws Exception {
|
||||
server.start();
|
||||
String url = server.url("/.well-known/jwks.json").toString();
|
||||
server.enqueue(mockResponse());
|
||||
System.setProperty("spring.security.oauth2.resource.jwt.jwk.set-uri", url);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void shutdown() throws IOException {
|
||||
server.shutdown();
|
||||
System.clearProperty("spring.security.oauth2.resource.jwt.jwk.set-uri");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withValidBearerTokenShouldAllowAccess() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setBearerAuth(VALID_TOKEN);
|
||||
HttpEntity<?> request = new HttpEntity<Void>(headers);
|
||||
ResponseEntity<String> entity = this.restTemplate.exchange("/", HttpMethod.GET,
|
||||
request, String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withNoBearerTokenShouldNotAllowAccess() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
HttpEntity<?> request = new HttpEntity<Void>(headers);
|
||||
ResponseEntity<String> entity = this.restTemplate.exchange("/", HttpMethod.GET,
|
||||
request, String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
|
||||
private static MockResponse mockResponse() {
|
||||
String body = "{\"keys\":[{\"p\":\"2p-ViY7DE9ZrdWQb544m0Jp7Cv03YCSljqfim9pD4ALhObX0OrAznOiowTjwBky9JGffMw"
|
||||
+ "DBVSfJSD9TSU7aH2sbbfi0bZLMdekKAuimudXwUqPDxrrg0BCyvCYgLmKjbVT3zcdylWSog93CNTxGDPzauu-oc0XPNKCXnaDpNvE\""
|
||||
+ ",\"kty\":\"RSA\",\"q\":\"sP_QYavrpBvSJ86uoKVGj2AGl78CSsAtpf1ybSY5TwUlorXSdqapRbY69Y271b0aMLzlleUn9ZTBO"
|
||||
+ "1dlKV2_dw_lPADHVia8z3pxL-8sUhIXLsgj4acchMk4c9YX-sFh07xENnyZ-_TXm3llPLuL67HUfBC2eKe800TmCYVWc9U\",\"d\""
|
||||
+ ":\"bn1nFxCQT4KLTHqo8mo9HvHD0cRNRNdWcKNnnEQkCF6tKbt-ILRyQGP8O40axLd7CoNVG9c9p_-g4-2kwCtLJNv_STLtwfpCY7"
|
||||
+ "VN5o6-ZIpfTjiW6duoPrLWq64Hm_4LOBQTiZfUPcLhsuJRHbWqakj-kV_YbUyC2Ocf_dd8IAQcSrAU2SCcDebhDCWwRUFvaa9V5eq0"
|
||||
+ "851S9goaA-AJz-JXyePH6ZFr8JxmWkWxYZ5kdcMD-sm9ZbxE0CaEk32l4fE4hR-L8x2dDtjWA-ahKCZ091z-gV3HWtR2JOjvxoNRjxUo"
|
||||
+ "3UxaGiFJHWNIl0EYUJZu1Cb-5wIlEI7wPx5mwQ\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"one\",\"qi\":\"qS0OK4"
|
||||
+ "8M2CIAA6_4Wdw4EbCaAfcTLf5Oy9t5BOF_PFUKqoSpZ6JsT5H0a_4zkjt-oI969v78OTlvBKbmEyKO-KeytzHBAA5CsLmVcz0THrMSg6o"
|
||||
+ "XZqu66MPnvWoZN9FEN5TklPOvBFm8Bg1QZ3k-YMVaM--DLvhaYR95_mqaz50\",\"dp\":\"Too2NozLGD1XrXyhabZvy1E0EuaVFj0UHQ"
|
||||
+ "PDLSpkZ_2g3BK6Art6T0xmE8RYtmqrKIEIdlI3IliAvyvAx_1D7zWTTRaj-xlZyqJFrnXWL7zj8UxT8PkB-r2E-ILZ3NAi1gxIWezlBTZ8"
|
||||
+ "M6NfObDFmbTc_3tJkN_raISo8z_ziIE\",\"dq\":\"U0yhSkY5yOsa9YcMoigGVBWSJLpNHtbg5NypjHrPv8OhWbkOSq7WvSstBkF"
|
||||
+ "k5AtyFvvfZLMLIkWWxxGzV0t6f1MoxBtttLrYYyCxwihiiGFhLbAdSuZ1wnxcqA9bC7UVECvrQmVTpsMs8UupfHKbQBpZ8OWAqrn"
|
||||
+ "uYNNtG4_4Bt0\",\"n\":\"lygtuZj0lJjqOqIWocF8Bb583QDdq-aaFg8PesOp2-EDda6GqCpL-_NZVOflNGX7XIgjsWHcPsQHs"
|
||||
+ "V9gWuOzSJ0iEuWvtQ6eGBP5M6m7pccLNZfwUse8Cb4Ngx3XiTlyuqM7pv0LPyppZusfEHVEdeelou7Dy9k0OQ_nJTI3b2E1WBoHC5"
|
||||
+ "8CJ453lo4gcBm1efURN3LIVc1V9NQY_ESBKVdwqYyoJPEanURLVGRd6cQKn6YrCbbIRHjqAyqOE-z3KmgDJnPriljfR5XhSGyM9eq"
|
||||
+ "D9Xpy6zu_MAeMJJfSArp857zLPk-Wf5VP9STAcjyfdBIybMKnwBYr2qHMT675hQ\"}]}";
|
||||
return new MockResponse()
|
||||
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.setResponseCode(200).setBody(body);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user