Commit 21be9ef6 authored by Dave Syer's avatar Dave Syer

Merge remote-tracking branch 'origin/1.5.x'

parents 0cfc32e5 fe344df9
...@@ -17,6 +17,9 @@ ...@@ -17,6 +17,9 @@
package org.springframework.boot.autoconfigure.security.oauth2.resource; package org.springframework.boot.autoconfigure.security.oauth2.resource;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.condition.ConditionMessage; import org.springframework.boot.autoconfigure.condition.ConditionMessage;
import org.springframework.boot.autoconfigure.condition.ConditionOutcome; import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
...@@ -45,6 +48,7 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.R ...@@ -45,6 +48,7 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.R
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
...@@ -98,6 +102,36 @@ public class OAuth2ResourceServerConfiguration { ...@@ -98,6 +102,36 @@ public class OAuth2ResourceServerConfiguration {
} }
@Component
public static class ResourceServerFilterChainOrderProcessor
implements BeanPostProcessor {
private ResourceServerProperties resource;
@Autowired
public ResourceServerFilterChainOrderProcessor(
ResourceServerProperties resource) {
this.resource = resource;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof ResourceServerConfiguration) {
ResourceServerConfiguration config = (ResourceServerConfiguration) bean;
config.setOrder(this.resource.getFilterOrder());
}
return bean;
}
}
protected static class ResourceServerCondition extends SpringBootCondition protected static class ResourceServerCondition extends SpringBootCondition
implements ConfigurationCondition { implements ConfigurationCondition {
......
...@@ -23,6 +23,7 @@ import org.springframework.beans.factory.BeanFactory; ...@@ -23,6 +23,7 @@ import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration;
...@@ -77,6 +78,12 @@ public class ResourceServerProperties implements Validator, BeanFactoryAware { ...@@ -77,6 +78,12 @@ public class ResourceServerProperties implements Validator, BeanFactoryAware {
private Jwt jwt = new Jwt(); private Jwt jwt = new Jwt();
/**
* The order of the filter chain used to authenticate tokens. Default puts it after
* the actuator endpoints and before the default HTTP basic filter chain (catchall).
*/
private int filterOrder = SecurityProperties.ACCESS_OVERRIDE_ORDER - 1;
public ResourceServerProperties() { public ResourceServerProperties() {
this(null, null); this(null, null);
} }
...@@ -159,6 +166,14 @@ public class ResourceServerProperties implements Validator, BeanFactoryAware { ...@@ -159,6 +166,14 @@ public class ResourceServerProperties implements Validator, BeanFactoryAware {
return this.clientSecret; return this.clientSecret;
} }
public int getFilterOrder() {
return this.filterOrder;
}
public void setFilterOrder(int filterOrder) {
this.filterOrder = filterOrder;
}
@Override @Override
public boolean supports(Class<?> clazz) { public boolean supports(Class<?> clazz) {
return ResourceServerProperties.class.isAssignableFrom(clazz); return ResourceServerProperties.class.isAssignableFrom(clazz);
......
...@@ -21,11 +21,13 @@ import java.util.Arrays; ...@@ -21,11 +21,13 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import org.junit.Test; import org.junit.Test;
import org.springframework.aop.support.AopUtils; import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration; import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.autoconfigure.security.oauth2.authserver.OAuth2AuthorizationServerConfiguration; 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.method.OAuth2MethodSecurityConfiguration;
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerConfiguration; import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerConfiguration;
...@@ -43,6 +45,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext ...@@ -43,6 +45,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
...@@ -437,6 +440,7 @@ public class OAuth2AutoConfigurationTests { ...@@ -437,6 +440,7 @@ public class OAuth2AutoConfigurationTests {
} }
@Configuration @Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
protected static class TestSecurityConfiguration protected static class TestSecurityConfiguration
extends WebSecurityConfigurerAdapter { extends WebSecurityConfigurerAdapter {
......
<?xml version="1.0" encoding="UTF-8"?> <?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">
<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> <modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId> <artifactId>spring-boot-dependencies</artifactId>
...@@ -2563,4 +2561,4 @@ ...@@ -2563,4 +2561,4 @@
<id>integration-test</id> <id>integration-test</id>
</profile> </profile>
</profiles> </profiles>
</project> </project>
\ No newline at end of file
...@@ -2528,6 +2528,10 @@ WARNING: If you use the `security.oauth2.resource.jwt.key-uri` the authorization ...@@ -2528,6 +2528,10 @@ WARNING: If you use the `security.oauth2.resource.jwt.key-uri` the authorization
needs to be running when your application starts up. It will log a warning if it can't needs to be running when your application starts up. It will log a warning if it can't
find the key, and tell you what to do to fix it. find the key, and tell you what to do to fix it.
OAuth2 resources are protected by a filter chain with order
`security.oauth2.resource.filter-order` and the default is after the
filter protecting the actuator endpoints by default (so actuator
endpoints will stay on HTTP Basic unless you change the order).
[[boot-features-security-oauth2-token-type]] [[boot-features-security-oauth2-token-type]]
......
...@@ -75,6 +75,7 @@ ...@@ -75,6 +75,7 @@
<module>spring-boot-sample-property-validation</module> <module>spring-boot-sample-property-validation</module>
<module>spring-boot-sample-secure</module> <module>spring-boot-sample-secure</module>
<module>spring-boot-sample-secure-oauth2</module> <module>spring-boot-sample-secure-oauth2</module>
<module>spring-boot-sample-secure-oauth2-actuator</module>
<module>spring-boot-sample-secure-oauth2-resource</module> <module>spring-boot-sample-secure-oauth2-resource</module>
<module>spring-boot-sample-servlet</module> <module>spring-boot-sample-servlet</module>
<module>spring-boot-sample-session-redis</module> <module>spring-boot-sample-session-redis</module>
......
...@@ -102,4 +102,4 @@ ...@@ -102,4 +102,4 @@
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
</project> </project>
\ No newline at end of file
<?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>1.5.0.BUILD-SNAPSHOT</version>
</parent>
<artifactId>spring-boot-sample-secure-oauth2-actuator</artifactId>
<name>spring-boot-sample-secure-oauth2-actuator</name>
<description>Spring Boot Security OAuth2 Actuator Sample</description>
<url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<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.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
<!-- Test -->
<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>
/*
* Copyright 2012-2015 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.secure.oauth2.resource;
import java.util.UUID;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@EnableResourceServer
@RestController
public class SampleSecureOAuth2ResourceApplication {
@GetMapping("/")
public Message home() {
return new Message("Hello World");
}
public static void main(String[] args) {
SpringApplication.run(SampleSecureOAuth2ResourceApplication.class, args);
}
}
class Message {
private String id = UUID.randomUUID().toString();
private String value;
public Message(String value) {
this.value = value;
}
public String getId() {
return id;
}
public String getValue() {
return value;
}
}
\ No newline at end of file
server.port=8081
security.basic.enabled=true
security.user.password=password
security.oauth2.resource.id=service
security.oauth2.resource.userInfoUri=http://localhost:8080/user
logging.level.org.springframework.security=DEBUG
/*
* 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 sample.secure.oauth2.resource;
import org.junit.Before;
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.context.SpringBootTest.WebEnvironment;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.util.Base64Utils;
import org.springframework.web.context.WebApplicationContext;
import static org.hamcrest.CoreMatchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
/**
* Series of automated integration tests to verify proper behavior of auto-configured,
* OAuth2-secured system
*
* @author Dave Syer
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SampleSecureOAuth2ResourceApplicationTests {
@Autowired
WebApplicationContext context;
@Autowired
FilterChainProxy filterChain;
private MockMvc mvc;
@Before
public void setUp() {
this.mvc = webAppContextSetup(this.context).addFilters(this.filterChain).build();
SecurityContextHolder.clearContext();
}
@Test
public void homePageSecuredByDefault() throws Exception {
this.mvc.perform(get("/")).andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", containsString("Bearer")))
.andDo(print());
}
@Test
public void healthAvailable() throws Exception {
this.mvc.perform(get("/health")).andExpect(status().isOk()).andDo(print());
}
@Test
public void envSecuredWithBasic() throws Exception {
this.mvc.perform(get("/env")).andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", containsString("Basic")))
.andDo(print());
}
@Test
public void envWithPassword() throws Exception {
this.mvc.perform(get("/env").header("Authorization",
"Basic " + Base64Utils.encodeToString("user:password".getBytes())))
.andExpect(status().isOk()).andDo(print());
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment