Polish OAuth SSO
This commit is contained in:
@@ -102,4 +102,15 @@ public class ConditionOutcome {
|
||||
public String toString() {
|
||||
return (this.message == null ? "" : this.message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the inverse of the specified condition outcome.
|
||||
* @param outcome the outcome to inverse
|
||||
* @return the inverse of the condition outcome
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public static ConditionOutcome inverse(ConditionOutcome outcome) {
|
||||
return new ConditionOutcome(!outcome.isMatch(), outcome.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,16 +18,12 @@ package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.ClassMetadata;
|
||||
import org.springframework.core.type.MethodMetadata;
|
||||
import org.springframework.core.type.StandardAnnotationMetadata;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -41,18 +37,6 @@ import org.springframework.util.StringUtils;
|
||||
public abstract class SpringBootCondition implements Condition {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
public static boolean evaluateForClass(Class<?> annotated, ConditionContext context) {
|
||||
Conditional conditional = AnnotationUtils.findAnnotation(annotated, Conditional.class);
|
||||
StandardAnnotationMetadata metadata = new StandardAnnotationMetadata(annotated);
|
||||
for (Class<? extends Condition> type : conditional.value()) {
|
||||
Condition condition = BeanUtils.instantiateClass(type);
|
||||
if (condition.matches(context, metadata)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-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.
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -26,26 +27,27 @@ import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
|
||||
|
||||
/**
|
||||
* AuthenticationEntryPoint that sends a 401 and Parameterized by the value of the
|
||||
* WWW-Authenticate header. Like the {@link BasicAuthenticationEntryPoint} but more
|
||||
* AuthenticationEntryPoint that sends a 401 and Parameterized by the value of the {@coe
|
||||
* WWW-Authenticate} header. Like the {@link BasicAuthenticationEntryPoint} but more
|
||||
* flexible.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class Http401AuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||
|
||||
private final String authenticateHeader;
|
||||
private final String headerValue;
|
||||
|
||||
public Http401AuthenticationEntryPoint(String authenticateHeader) {
|
||||
this.authenticateHeader = authenticateHeader;
|
||||
public Http401AuthenticationEntryPoint(String headerValue) {
|
||||
this.headerValue = headerValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException authException) throws IOException, ServletException {
|
||||
response.setHeader("WWW-Authenticate", authenticateHeader);
|
||||
response.setHeader("WWW-Authenticate", this.headerValue);
|
||||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
|
||||
authException.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -20,13 +20,14 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.authserver.SpringSecurityOAuth2AuthorizationServerConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2RestOperationsConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.method.OAuth2MethodSecurityConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
|
||||
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -37,16 +38,16 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.R
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
/**
|
||||
* Spring Security OAuth2 top level auto-configuration beans
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Spring Security OAuth2.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ OAuth2AccessToken.class, WebMvcConfigurerAdapter.class })
|
||||
@Import({ SpringSecurityOAuth2AuthorizationServerConfiguration.class,
|
||||
OAuth2MethodSecurityConfiguration.class,
|
||||
OAuth2ResourceServerConfiguration.class,
|
||||
OAuth2MethodSecurityConfiguration.class, OAuth2ResourceServerConfiguration.class,
|
||||
OAuth2RestOperationsConfiguration.class })
|
||||
@AutoConfigureBefore(WebMvcAutoConfiguration.class)
|
||||
@EnableConfigurationProperties(OAuth2ClientProperties.class)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -21,7 +21,10 @@ import java.util.UUID;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Configuration properties for OAuth2 Client.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@ConfigurationProperties("spring.oauth2.client")
|
||||
public class OAuth2ClientProperties {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -47,12 +47,13 @@ import org.springframework.security.oauth2.provider.client.BaseClientDetails;
|
||||
import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||
|
||||
/**
|
||||
* Auto-configure a Spring Security OAuth2 authorization server. Back off if another
|
||||
* Configuration for a Spring Security OAuth2 authorization server. Back off if another
|
||||
* {@link AuthorizationServerConfigurer} already exists or if authorization server is not
|
||||
* enabled.
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(EnableAuthorizationServer.class)
|
||||
@@ -62,6 +63,9 @@ import org.springframework.security.oauth2.provider.token.TokenStore;
|
||||
public class SpringSecurityOAuth2AuthorizationServerConfiguration extends
|
||||
AuthorizationServerConfigurerAdapter {
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(SpringSecurityOAuth2AuthorizationServerConfiguration.class);
|
||||
|
||||
@Autowired
|
||||
private BaseClientDetails details;
|
||||
|
||||
@@ -70,13 +74,10 @@ public class SpringSecurityOAuth2AuthorizationServerConfiguration extends
|
||||
|
||||
@Autowired(required = false)
|
||||
private TokenStore tokenStore;
|
||||
|
||||
|
||||
@Configuration
|
||||
protected static class ClientDetailsLogger {
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(SpringSecurityOAuth2AuthorizationServerConfiguration.class);
|
||||
|
||||
@Autowired
|
||||
private OAuth2ClientProperties credentials;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* 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.
|
||||
@@ -28,21 +28,22 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
|
||||
|
||||
/**
|
||||
* Configuration for OAuth2 Single Sign On (SSO). If there is an existing
|
||||
* Enable OAuth2 Single Sign On (SSO). If there is an existing
|
||||
* {@link WebSecurityConfigurerAdapter} provided by the user and annotated with
|
||||
* <code>@EnableOAuth2Sso</code>, it is enhanced by adding an authentication filter and an
|
||||
* authentication entry point. If the user only has <code>@EnableOAuth2Sso</code> but not
|
||||
* on a WebSecurityConfigurerAdapter then one is added with all paths secured and with an
|
||||
* order that puts it ahead of the default HTTP Basic security chain in Spring Boot.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* {@code @EnableOAuth2Sso}, it is enhanced by adding an authentication filter and an
|
||||
* authentication entry point. If the user only has {@code @EnableOAuth2Sso} but not on a
|
||||
* WebSecurityConfigurerAdapter then one is added with all paths secured and with an order
|
||||
* that puts it ahead of the default HTTP Basic security chain in Spring Boot.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@EnableOAuth2Client
|
||||
@Import({ OAuth2SsoDefaultConfiguration.class, OAuth2SsoCustomConfiguration.class, ResourceServerTokenServicesConfiguration.class })
|
||||
@Import({ OAuth2SsoDefaultConfiguration.class, OAuth2SsoCustomConfiguration.class,
|
||||
ResourceServerTokenServicesConfiguration.class })
|
||||
public @interface EnableOAuth2Sso {
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -49,8 +50,10 @@ import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* Configuration for OAuth2 Single Sign On REST operations.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(EnableOAuth2Client.class)
|
||||
@@ -109,7 +112,7 @@ public class OAuth2RestOperationsConfiguration {
|
||||
@Bean
|
||||
@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
|
||||
public OAuth2ClientContext oauth2ClientContext() {
|
||||
return new DefaultOAuth2ClientContext(accessTokenRequest);
|
||||
return new DefaultOAuth2ClientContext(this.accessTokenRequest);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* 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.
|
||||
@@ -44,9 +44,8 @@ import org.springframework.util.ReflectionUtils;
|
||||
* {@link WebSecurityConfigurerAdapter} provided by the user and annotated with
|
||||
* <code>@EnableOAuth2Sso</code>. The user-provided configuration is enhanced by adding an
|
||||
* authentication filter and an authentication entry point.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Configuration
|
||||
@Conditional(WebSecurityEnhancerCondition.class)
|
||||
@@ -64,7 +63,8 @@ public class OAuth2SsoCustomConfiguration implements ImportAware, BeanPostProces
|
||||
|
||||
@Override
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
configType = ClassUtils.resolveClassName(importMetadata.getClassName(), null);
|
||||
this.configType = ClassUtils
|
||||
.resolveClassName(importMetadata.getClassName(), null);
|
||||
|
||||
}
|
||||
|
||||
@@ -77,11 +77,11 @@ public class OAuth2SsoCustomConfiguration implements ImportAware, BeanPostProces
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
if (configType.isAssignableFrom(bean.getClass())
|
||||
if (this.configType.isAssignableFrom(bean.getClass())
|
||||
&& bean instanceof WebSecurityConfigurerAdapter) {
|
||||
ProxyFactory factory = new ProxyFactory();
|
||||
factory.setTarget(bean);
|
||||
factory.addAdvice(new SsoSecurityAdapter(beanFactory));
|
||||
factory.addAdvice(new SsoSecurityAdapter(this.beanFactory));
|
||||
bean = factory.getProxy();
|
||||
}
|
||||
return bean;
|
||||
@@ -92,7 +92,7 @@ public class OAuth2SsoCustomConfiguration implements ImportAware, BeanPostProces
|
||||
private SsoSecurityConfigurer configurer;
|
||||
|
||||
public SsoSecurityAdapter(BeanFactory beanFactory) {
|
||||
configurer = new SsoSecurityConfigurer(beanFactory);
|
||||
this.configurer = new SsoSecurityConfigurer(beanFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,8 +102,8 @@ public class OAuth2SsoCustomConfiguration implements ImportAware, BeanPostProces
|
||||
WebSecurityConfigurerAdapter.class, "getHttp");
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
HttpSecurity http = (HttpSecurity) ReflectionUtils.invokeMethod(method,
|
||||
(WebSecurityConfigurerAdapter) invocation.getThis());
|
||||
configurer.configure(http);
|
||||
invocation.getThis());
|
||||
this.configurer.configure(http);
|
||||
}
|
||||
return invocation.proceed();
|
||||
}
|
||||
@@ -127,6 +127,7 @@ public class OAuth2SsoCustomConfiguration implements ImportAware, BeanPostProces
|
||||
return ConditionOutcome
|
||||
.noMatch("found no @EnableOAuth2Sso on a WebSecurityConfigurerAdapter");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* 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.
|
||||
@@ -32,12 +32,13 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* If the user only has <code>@EnableOAuth2Sso</code> but not on a
|
||||
* WebSecurityConfigurerAdapter then one is added with all paths secured and with an order
|
||||
* that puts it ahead of the default HTTP Basic security chain in Spring Boot.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* Configuration for OAuth2 Single Sign On (SSO). If the user only has
|
||||
* {@code @EnableOAuth2Sso} but not on a {@code WebSecurityConfigurerAdapter} then one is
|
||||
* added with all paths secured and with an order that puts it ahead of the default HTTP
|
||||
* Basic security chain in Spring Boot.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(OAuth2SsoProperties.class)
|
||||
@@ -57,13 +58,13 @@ public class OAuth2SsoDefaultConfiguration {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.antMatcher("/**").authorizeRequests().anyRequest().authenticated();
|
||||
new SsoSecurityConfigurer(beanFactory).configure(http);
|
||||
new SsoSecurityConfigurer(this.beanFactory).configure(http);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
if (sso.getFilterOrder() != null) {
|
||||
return sso.getFilterOrder();
|
||||
if (this.sso.getFilterOrder() != null) {
|
||||
return this.sso.getFilterOrder();
|
||||
}
|
||||
if (ClassUtils
|
||||
.isPresent(
|
||||
@@ -80,6 +81,7 @@ public class OAuth2SsoDefaultConfiguration {
|
||||
}
|
||||
|
||||
private static class NeedsWebSecurityCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
@@ -95,6 +97,7 @@ public class OAuth2SsoDefaultConfiguration {
|
||||
return ConditionOutcome
|
||||
.match("found no @EnableOAuth2Sso on a WebSecurityConfigurerAdapter");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -13,13 +13,16 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.client;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* Configuration properties for OAuth2 Single Sign On (SSO).
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@ConfigurationProperties("spring.oauth2.sso")
|
||||
public class OAuth2SsoProperties {
|
||||
@@ -39,7 +42,7 @@ public class OAuth2SsoProperties {
|
||||
private Integer filterOrder;
|
||||
|
||||
public String getLoginPath() {
|
||||
return loginPath;
|
||||
return this.loginPath;
|
||||
}
|
||||
|
||||
public void setLoginPath(String loginPath) {
|
||||
@@ -47,7 +50,7 @@ public class OAuth2SsoProperties {
|
||||
}
|
||||
|
||||
public Integer getFilterOrder() {
|
||||
return filterOrder;
|
||||
return this.filterOrder;
|
||||
}
|
||||
|
||||
public void setFilterOrder(Integer filterOrder) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* 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.
|
||||
@@ -36,7 +36,7 @@ class SsoSecurityConfigurer {
|
||||
}
|
||||
|
||||
public void configure(HttpSecurity http) throws Exception {
|
||||
OAuth2SsoProperties sso = beanFactory.getBean(OAuth2SsoProperties.class);
|
||||
OAuth2SsoProperties sso = this.beanFactory.getBean(OAuth2SsoProperties.class);
|
||||
// Delay the processing of the filter until we know the
|
||||
// SessionAuthenticationStrategy is available:
|
||||
http.apply(new OAuth2ClientAuthenticationConfigurer(oauth2SsoFilter(sso)));
|
||||
@@ -46,9 +46,9 @@ class SsoSecurityConfigurer {
|
||||
|
||||
private OAuth2ClientAuthenticationProcessingFilter oauth2SsoFilter(
|
||||
OAuth2SsoProperties sso) {
|
||||
OAuth2RestOperations restTemplate = beanFactory
|
||||
OAuth2RestOperations restTemplate = this.beanFactory
|
||||
.getBean(OAuth2RestOperations.class);
|
||||
ResourceServerTokenServices tokenServices = beanFactory
|
||||
ResourceServerTokenServices tokenServices = this.beanFactory
|
||||
.getBean(ResourceServerTokenServices.class);
|
||||
OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter(
|
||||
sso.getLoginPath());
|
||||
@@ -59,6 +59,7 @@ class SsoSecurityConfigurer {
|
||||
|
||||
private static class OAuth2ClientAuthenticationConfigurer extends
|
||||
SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
|
||||
|
||||
private OAuth2ClientAuthenticationProcessingFilter filter;
|
||||
|
||||
public OAuth2ClientAuthenticationConfigurer(
|
||||
@@ -68,12 +69,13 @@ class SsoSecurityConfigurer {
|
||||
|
||||
@Override
|
||||
public void configure(HttpSecurity builder) throws Exception {
|
||||
OAuth2ClientAuthenticationProcessingFilter ssoFilter = filter;
|
||||
OAuth2ClientAuthenticationProcessingFilter ssoFilter = this.filter;
|
||||
ssoFilter.setSessionAuthenticationStrategy(builder
|
||||
.getSharedObject(SessionAuthenticationStrategy.class));
|
||||
builder.addFilterAfter(ssoFilter,
|
||||
AbstractPreAuthenticatedProcessingFilter.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -30,22 +30,22 @@ import org.springframework.security.oauth2.provider.expression.OAuth2MethodSecur
|
||||
|
||||
/**
|
||||
* Auto-configure an expression handler for method-level security (if the user already has
|
||||
* <code>@EnableGlobalMethodSecurity</code>).
|
||||
* {@code @EnableGlobalMethodSecurity}).
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass({ OAuth2AccessToken.class })
|
||||
@ConditionalOnBean(GlobalMethodSecurityConfiguration.class)
|
||||
public class OAuth2MethodSecurityConfiguration implements
|
||||
BeanFactoryPostProcessor {
|
||||
public class OAuth2MethodSecurityConfiguration implements BeanFactoryPostProcessor {
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
|
||||
throws BeansException {
|
||||
beanFactory
|
||||
.addBeanPostProcessor(new OAuth2ExpressionHandlerInjectionPostProcessor());
|
||||
OAuth2ExpressionHandlerInjectionPostProcessor processor = new OAuth2ExpressionHandlerInjectionPostProcessor();
|
||||
beanFactory.addBeanPostProcessor(processor);
|
||||
}
|
||||
|
||||
private static class OAuth2ExpressionHandlerInjectionPostProcessor implements
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
* 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.
|
||||
@@ -13,12 +13,24 @@
|
||||
* 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.security.oauth2.provider.token.store.JwtAccessTokenConverter;
|
||||
|
||||
/**
|
||||
* Callback interface that can be used to provide additional configuration to the
|
||||
* {@link JwtAccessTokenConverter}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public interface JwtAccessTokenConverterConfigurer {
|
||||
|
||||
/**
|
||||
* Configure the {@link JwtAccessTokenConverter}.
|
||||
* @param converter the converter to configure
|
||||
*/
|
||||
void configure(JwtAccessTokenConverter converter);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.resource;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
@@ -27,13 +28,16 @@ import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerConfiguration.ResourceServerCondition;
|
||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ConfigurationCondition;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
import org.springframework.core.type.StandardAnnotationMetadata;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
|
||||
@@ -50,6 +54,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@Configuration
|
||||
@Conditional(ResourceServerCondition.class)
|
||||
@@ -91,10 +96,13 @@ public class OAuth2ResourceServerConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnBean(AuthorizationServerEndpointsConfiguration.class)
|
||||
protected static class ResourceServerCondition extends SpringBootCondition implements
|
||||
ConfigurationCondition {
|
||||
|
||||
private static final String AUTHORIZATION_ANNOTATION = "org.springframework."
|
||||
+ "security.oauth2.config.annotation.web.configuration."
|
||||
+ "AuthorizationServerEndpointsConfiguration";
|
||||
|
||||
@Override
|
||||
public ConfigurationPhase getConfigurationPhase() {
|
||||
return ConfigurationPhase.REGISTER_BEAN;
|
||||
@@ -104,31 +112,48 @@ public class OAuth2ResourceServerConfiguration {
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
Environment environment = context.getEnvironment();
|
||||
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(environment);
|
||||
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(environment,
|
||||
"spring.oauth2.resource.");
|
||||
String client = environment
|
||||
.resolvePlaceholders("${spring.oauth2.client.clientId:}");
|
||||
if (StringUtils.hasText(client)) {
|
||||
return ConditionOutcome.match("found client id");
|
||||
}
|
||||
if (!resolver.getSubProperties("spring.oauth2.resource.jwt").isEmpty()) {
|
||||
if (!resolver.getSubProperties("jwt").isEmpty()) {
|
||||
return ConditionOutcome.match("found JWT resource configuration");
|
||||
}
|
||||
if (StringUtils.hasText(resolver
|
||||
.getProperty("spring.oauth2.resource.userInfoUri"))) {
|
||||
return ConditionOutcome
|
||||
.match("found UserInfo URI resource configuration");
|
||||
if (StringUtils.hasText(resolver.getProperty("user-info-uri"))) {
|
||||
return ConditionOutcome.match("found UserInfo "
|
||||
+ "URI resource configuration");
|
||||
}
|
||||
if (ClassUtils
|
||||
.isPresent(
|
||||
"org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration",
|
||||
null)) {
|
||||
if (SpringBootCondition.evaluateForClass(ResourceServerCondition.class, context)) {
|
||||
return ConditionOutcome
|
||||
.match("found authorization server endpoints configuration");
|
||||
if (ClassUtils.isPresent(AUTHORIZATION_ANNOTATION, null)) {
|
||||
if (AuthorizationServerEndpointsConfigurationBeanCondition
|
||||
.matches(context)) {
|
||||
return ConditionOutcome.match("found authorization "
|
||||
+ "server endpoints configuration");
|
||||
}
|
||||
}
|
||||
return ConditionOutcome
|
||||
.noMatch("found neither client id nor JWT resource nor authorization server");
|
||||
return ConditionOutcome.noMatch("found neither client id nor "
|
||||
+ "JWT resource nor authorization server");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnBean(AuthorizationServerEndpointsConfiguration.class)
|
||||
private static class AuthorizationServerEndpointsConfigurationBeanCondition {
|
||||
|
||||
public static boolean matches(ConditionContext context) {
|
||||
Class<AuthorizationServerEndpointsConfigurationBeanCondition> type = AuthorizationServerEndpointsConfigurationBeanCondition.class;
|
||||
Conditional conditional = AnnotationUtils.findAnnotation(type,
|
||||
Conditional.class);
|
||||
StandardAnnotationMetadata metadata = new StandardAnnotationMetadata(type);
|
||||
for (Class<? extends Condition> conditionType : conditional.value()) {
|
||||
Condition condition = BeanUtils.instantiateClass(conditionType);
|
||||
if (condition.matches(context, metadata)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -30,8 +30,10 @@ import org.springframework.validation.Validator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* Configuration properties for OAuth2 Resources.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@ConfigurationProperties("spring.oauth2.resource")
|
||||
public class ResourceServerProperties implements Validator, BeanFactoryAware {
|
||||
@@ -71,7 +73,7 @@ public class ResourceServerProperties implements Validator, BeanFactoryAware {
|
||||
* The token type to send when using the userInfoUri.
|
||||
*/
|
||||
private String tokenType = DefaultOAuth2AccessToken.BEARER_TYPE;
|
||||
|
||||
|
||||
private Jwt jwt = new Jwt();
|
||||
|
||||
public ResourceServerProperties() {
|
||||
@@ -133,7 +135,7 @@ public class ResourceServerProperties implements Validator, BeanFactoryAware {
|
||||
}
|
||||
|
||||
public String getTokenType() {
|
||||
return tokenType;
|
||||
return this.tokenType;
|
||||
}
|
||||
|
||||
public void setTokenType(String tokenType) {
|
||||
@@ -187,7 +189,8 @@ public class ResourceServerProperties implements Validator, BeanFactoryAware {
|
||||
}
|
||||
if (!StringUtils.hasText(resource.getUserInfoUri())) {
|
||||
errors.rejectValue("tokenInfoUri", "missing.tokenInfoUri",
|
||||
"Missing tokenInfoUri and userInfoUri and there is no JWT verifier key");
|
||||
"Missing tokenInfoUri and userInfoUri and there is no "
|
||||
+ "JWT verifier key");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.resource;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -31,11 +32,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.OrderComparator;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
@@ -71,8 +72,10 @@ import org.springframework.web.client.ResourceAccessException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* Configuration for an OAuth2 resource server.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(AuthorizationServerEndpointsConfiguration.class)
|
||||
@@ -88,10 +91,10 @@ public class ResourceServerTokenServicesConfiguration {
|
||||
|
||||
static {
|
||||
DEFAULT_RESOURCE_DETAILS.setClientId("<N/A>");
|
||||
DEFAULT_RESOURCE_DETAILS
|
||||
.setUserAuthorizationUri("Not a URI because there is no client");
|
||||
DEFAULT_RESOURCE_DETAILS
|
||||
.setAccessTokenUri("Not a URI because there is no client");
|
||||
DEFAULT_RESOURCE_DETAILS.setUserAuthorizationUri("Not a URI "
|
||||
+ "because there is no client");
|
||||
DEFAULT_RESOURCE_DETAILS.setAccessTokenUri("Not a URI "
|
||||
+ "because there is no client");
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
@@ -106,52 +109,37 @@ public class ResourceServerTokenServicesConfiguration {
|
||||
|
||||
@Bean(name = "userInfoRestTemplate")
|
||||
public OAuth2RestTemplate userInfoRestTemplate() {
|
||||
OAuth2RestTemplate template;
|
||||
if (details == null) {
|
||||
details = DEFAULT_RESOURCE_DETAILS;
|
||||
}
|
||||
if (oauth2ClientContext == null) {
|
||||
template = new OAuth2RestTemplate(details);
|
||||
}
|
||||
else {
|
||||
template = new OAuth2RestTemplate(details, oauth2ClientContext);
|
||||
if (this.details == null) {
|
||||
this.details = DEFAULT_RESOURCE_DETAILS;
|
||||
}
|
||||
OAuth2RestTemplate template = getTemplate();
|
||||
template.setInterceptors(Arrays
|
||||
.<ClientHttpRequestInterceptor> asList(new ClientHttpRequestInterceptor() {
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request,
|
||||
byte[] body, ClientHttpRequestExecution execution)
|
||||
throws IOException {
|
||||
request.getHeaders().setAccept(
|
||||
Arrays.asList(MediaType.APPLICATION_JSON));
|
||||
return execution.execute(request, body);
|
||||
}
|
||||
}));
|
||||
.<ClientHttpRequestInterceptor> asList(new AcceptJsonRequestInterceptor()));
|
||||
AuthorizationCodeAccessTokenProvider accessTokenProvider = new AuthorizationCodeAccessTokenProvider();
|
||||
accessTokenProvider.setTokenRequestEnhancer(new RequestEnhancer() {
|
||||
@Override
|
||||
public void enhance(AccessTokenRequest request,
|
||||
OAuth2ProtectedResourceDetails resource,
|
||||
MultiValueMap<String, String> form, HttpHeaders headers) {
|
||||
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
|
||||
}
|
||||
});
|
||||
accessTokenProvider.setTokenRequestEnhancer(new AcceptJsonRequestEnhancer());
|
||||
template.setAccessTokenProvider(accessTokenProvider);
|
||||
OrderComparator.sort(customizers);
|
||||
for (UserInfoRestTemplateCustomizer customizer : customizers) {
|
||||
AnnotationAwareOrderComparator.sort(this.customizers);
|
||||
for (UserInfoRestTemplateCustomizer customizer : this.customizers) {
|
||||
customizer.customize(template);
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
private OAuth2RestTemplate getTemplate() {
|
||||
if (this.oauth2ClientContext == null) {
|
||||
return new OAuth2RestTemplate(this.details);
|
||||
}
|
||||
return new OAuth2RestTemplate(this.details, this.oauth2ClientContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Conditional(NotJwtToken.class)
|
||||
@Conditional(NotJwtTokenCondition.class)
|
||||
protected static class RemoteTokenServicesConfiguration {
|
||||
|
||||
@Configuration
|
||||
@Conditional(TokenInfo.class)
|
||||
@Conditional(TokenInfoCondition.class)
|
||||
protected static class TokenInfoServicesConfiguration {
|
||||
|
||||
@Autowired
|
||||
@@ -170,7 +158,7 @@ public class ResourceServerTokenServicesConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(OAuth2ConnectionFactory.class)
|
||||
@Conditional(NotTokenInfo.class)
|
||||
@Conditional(NotTokenInfoCondition.class)
|
||||
protected static class SocialTokenServicesConfiguration {
|
||||
|
||||
@Autowired
|
||||
@@ -197,8 +185,8 @@ public class ResourceServerTokenServicesConfiguration {
|
||||
public ResourceServerTokenServices userInfoTokenServices() {
|
||||
UserInfoTokenServices services = new UserInfoTokenServices(
|
||||
this.sso.getUserInfoUri(), this.sso.getClientId());
|
||||
services.setTokenType(sso.getTokenType());
|
||||
services.setRestTemplate(restTemplate);
|
||||
services.setTokenType(this.sso.getTokenType());
|
||||
services.setRestTemplate(this.restTemplate);
|
||||
return services;
|
||||
}
|
||||
|
||||
@@ -206,7 +194,7 @@ public class ResourceServerTokenServicesConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnMissingClass("org.springframework.social.connect.support.OAuth2ConnectionFactory")
|
||||
@Conditional(NotTokenInfo.class)
|
||||
@Conditional(NotTokenInfoCondition.class)
|
||||
protected static class UserInfoTokenServicesConfiguration {
|
||||
|
||||
@Autowired
|
||||
@@ -221,8 +209,8 @@ public class ResourceServerTokenServicesConfiguration {
|
||||
public ResourceServerTokenServices userInfoTokenServices() {
|
||||
UserInfoTokenServices services = new UserInfoTokenServices(
|
||||
this.sso.getUserInfoUri(), this.sso.getClientId());
|
||||
services.setRestTemplate(restTemplate);
|
||||
services.setTokenType(sso.getTokenType());
|
||||
services.setRestTemplate(this.restTemplate);
|
||||
services.setTokenType(this.sso.getTokenType());
|
||||
return services;
|
||||
}
|
||||
|
||||
@@ -231,7 +219,7 @@ public class ResourceServerTokenServicesConfiguration {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Conditional(JwtToken.class)
|
||||
@Conditional(JwtTokenCondition.class)
|
||||
protected static class JwtTokenServicesConfiguration {
|
||||
|
||||
private RestTemplate keyUriRestTemplate = new RestTemplate();
|
||||
@@ -262,22 +250,11 @@ public class ResourceServerTokenServicesConfiguration {
|
||||
String keyValue = this.resource.getJwt().getKeyValue();
|
||||
if (!StringUtils.hasText(keyValue)) {
|
||||
try {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
if (resource.getClientId() != null
|
||||
&& resource.getClientSecret() != null) {
|
||||
byte[] token = Base64
|
||||
.encode((resource.getClientId() + ":" + resource
|
||||
.getClientSecret()).getBytes());
|
||||
headers.add("Authorization", "Basic " + new String(token));
|
||||
}
|
||||
HttpEntity<Void> requestEntity = new HttpEntity<Void>(headers);
|
||||
keyValue = (String) keyUriRestTemplate
|
||||
.exchange(resource.getJwt().getKeyUri(), HttpMethod.GET,
|
||||
requestEntity, Map.class).getBody().get("value");
|
||||
keyValue = getKeyFromServer();
|
||||
}
|
||||
catch (ResourceAccessException e) {
|
||||
// ignore
|
||||
logger.warn("Failed to fetch token key (you may need to refresh when the auth server is back)");
|
||||
catch (ResourceAccessException ex) {
|
||||
logger.warn("Failed to fetch token key (you may need to refresh "
|
||||
+ "when the auth server is back)");
|
||||
}
|
||||
}
|
||||
if (StringUtils.hasText(keyValue) && !keyValue.startsWith("-----BEGIN")) {
|
||||
@@ -286,52 +263,68 @@ public class ResourceServerTokenServicesConfiguration {
|
||||
if (keyValue != null) {
|
||||
converter.setVerifierKey(keyValue);
|
||||
}
|
||||
AnnotationAwareOrderComparator.sort(configurers);
|
||||
for (JwtAccessTokenConverterConfigurer configurer : configurers) {
|
||||
AnnotationAwareOrderComparator.sort(this.configurers);
|
||||
for (JwtAccessTokenConverterConfigurer configurer : this.configurers) {
|
||||
configurer.configure(converter);
|
||||
}
|
||||
return converter;
|
||||
}
|
||||
|
||||
private String getKeyFromServer() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
String username = this.resource.getClientId();
|
||||
String password = this.resource.getClientSecret();
|
||||
if (username != null && password != null) {
|
||||
byte[] token = Base64.encode((username + ":" + password).getBytes());
|
||||
headers.add("Authorization", "Basic " + new String(token));
|
||||
}
|
||||
HttpEntity<Void> request = new HttpEntity<Void>(headers);
|
||||
String url = this.resource.getJwt().getKeyUri();
|
||||
return (String) this.keyUriRestTemplate
|
||||
.exchange(url, HttpMethod.GET, request, Map.class).getBody()
|
||||
.get("value");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class TokenInfo extends SpringBootCondition {
|
||||
private static class TokenInfoCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
Environment environment = context.getEnvironment();
|
||||
boolean preferTokenInfo = environment
|
||||
.resolvePlaceholders(
|
||||
"${spring.oauth2.resource.preferTokenInfo:${OAUTH2_RESOURCE_PREFERTOKENINFO:true}}")
|
||||
.equals("true");
|
||||
boolean hasTokenInfo = !environment.resolvePlaceholders(
|
||||
"${spring.oauth2.resource.tokenInfoUri:}").equals("");
|
||||
boolean hasUserInfo = !environment.resolvePlaceholders(
|
||||
"${spring.oauth2.resource.userInfoUri:}").equals("");
|
||||
if (!hasUserInfo) {
|
||||
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(environment,
|
||||
"spring.oauth2.resource.");
|
||||
Boolean preferTokenInfo = resolver.getProperty("prefer-token-info",
|
||||
Boolean.class);
|
||||
if (preferTokenInfo == null) {
|
||||
preferTokenInfo = environment.resolvePlaceholders(
|
||||
"${OAUTH2_RESOURCE_PREFERTOKENINFO:true}").equals("true");
|
||||
}
|
||||
String tokenInfoUri = resolver.getProperty("token-info-uri");
|
||||
String userInfoUri = resolver.getProperty("user-info-uri");
|
||||
if (!StringUtils.hasLength(userInfoUri)) {
|
||||
return ConditionOutcome.match("No user info provided");
|
||||
}
|
||||
if (hasTokenInfo) {
|
||||
if (preferTokenInfo) {
|
||||
return ConditionOutcome
|
||||
.match("Token info endpoint is preferred and user info provided");
|
||||
}
|
||||
if (StringUtils.hasLength(tokenInfoUri) && preferTokenInfo) {
|
||||
return ConditionOutcome.match("Token info endpoint "
|
||||
+ "is preferred and user info provided");
|
||||
}
|
||||
return ConditionOutcome.noMatch("Token info endpoint is not provided");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class JwtToken extends SpringBootCondition {
|
||||
private static class JwtTokenCondition extends SpringBootCondition {
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
if (StringUtils.hasText(context.getEnvironment().getProperty(
|
||||
"spring.oauth2.resource.jwt.keyValue"))
|
||||
|| StringUtils.hasText(context.getEnvironment().getProperty(
|
||||
"spring.oauth2.resource.jwt.keyUri"))) {
|
||||
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
|
||||
context.getEnvironment(), "spring.oauth2.resource.jwt.");
|
||||
String keyValue = resolver.getProperty("key-value");
|
||||
String keyUri = resolver.getProperty("key-uri");
|
||||
if (StringUtils.hasText(keyValue) || StringUtils.hasText(keyUri)) {
|
||||
return ConditionOutcome.match("public key is provided");
|
||||
}
|
||||
return ConditionOutcome.noMatch("public key is not provided");
|
||||
@@ -339,35 +332,53 @@ public class ResourceServerTokenServicesConfiguration {
|
||||
|
||||
}
|
||||
|
||||
private static class NotTokenInfo extends SpringBootCondition {
|
||||
private static class NotTokenInfoCondition extends SpringBootCondition {
|
||||
|
||||
private TokenInfo opposite = new TokenInfo();
|
||||
private TokenInfoCondition tokenInfoCondition = new TokenInfoCondition();
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionOutcome outcome = this.opposite.getMatchOutcome(context, metadata);
|
||||
if (outcome.isMatch()) {
|
||||
return ConditionOutcome.noMatch(outcome.getMessage());
|
||||
}
|
||||
return ConditionOutcome.match(outcome.getMessage());
|
||||
return ConditionOutcome.inverse(this.tokenInfoCondition.getMatchOutcome(
|
||||
context, metadata));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class NotJwtToken extends SpringBootCondition {
|
||||
private static class NotJwtTokenCondition extends SpringBootCondition {
|
||||
|
||||
private JwtToken opposite = new JwtToken();
|
||||
private JwtTokenCondition jwtTokenCondition = new JwtTokenCondition();
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||
AnnotatedTypeMetadata metadata) {
|
||||
ConditionOutcome outcome = this.opposite.getMatchOutcome(context, metadata);
|
||||
if (outcome.isMatch()) {
|
||||
return ConditionOutcome.noMatch(outcome.getMessage());
|
||||
}
|
||||
return ConditionOutcome.match(outcome.getMessage());
|
||||
return ConditionOutcome.inverse(this.jwtTokenCondition.getMatchOutcome(
|
||||
context, metadata));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class AcceptJsonRequestInterceptor implements
|
||||
ClientHttpRequestInterceptor {
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
|
||||
return execution.execute(request, body);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class AcceptJsonRequestEnhancer implements RequestEnhancer {
|
||||
|
||||
@Override
|
||||
public void enhance(AccessTokenRequest request,
|
||||
OAuth2ProtectedResourceDetails resource,
|
||||
MultiValueMap<String, String> form, HttpHeaders headers) {
|
||||
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -13,12 +13,16 @@
|
||||
* 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.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.oauth2.common.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
|
||||
@@ -31,16 +35,18 @@ import org.springframework.social.connect.support.OAuth2ConnectionFactory;
|
||||
import org.springframework.social.oauth2.AccessGrant;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* {@link ResourceServerTokenServices} backed by Spring Social.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class SpringSocialTokenServices implements ResourceServerTokenServices {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private OAuth2ConnectionFactory<?> connectionFactory;
|
||||
private final OAuth2ConnectionFactory<?> connectionFactory;
|
||||
|
||||
private String clientId;
|
||||
private final String clientId;
|
||||
|
||||
public SpringSocialTokenServices(OAuth2ConnectionFactory<?> connectionFactory,
|
||||
String clientId) {
|
||||
@@ -51,21 +57,20 @@ public class SpringSocialTokenServices implements ResourceServerTokenServices {
|
||||
@Override
|
||||
public OAuth2Authentication loadAuthentication(String accessToken)
|
||||
throws AuthenticationException, InvalidTokenException {
|
||||
|
||||
Connection<?> connection = connectionFactory.createConnection(new AccessGrant(
|
||||
accessToken));
|
||||
AccessGrant accessGrant = new AccessGrant(accessToken);
|
||||
Connection<?> connection = this.connectionFactory.createConnection(accessGrant);
|
||||
UserProfile user = connection.fetchUserProfile();
|
||||
return extractAuthentication(user);
|
||||
}
|
||||
|
||||
private OAuth2Authentication extractAuthentication(UserProfile user) {
|
||||
UsernamePasswordAuthenticationToken principal = new UsernamePasswordAuthenticationToken(
|
||||
user.getUsername(), "N/A",
|
||||
AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"));
|
||||
principal.setDetails(user);
|
||||
OAuth2Request request = new OAuth2Request(null, clientId, null, true, null, null,
|
||||
null, null, null);
|
||||
return new OAuth2Authentication(request, principal);
|
||||
String principal = user.getUsername();
|
||||
List<GrantedAuthority> authorities = AuthorityUtils
|
||||
.commaSeparatedStringToAuthorityList("ROLE_USER");
|
||||
OAuth2Request request = new OAuth2Request(null, this.clientId, null, true, null,
|
||||
null, null, null, null);
|
||||
return new OAuth2Authentication(request, new UsernamePasswordAuthenticationToken(
|
||||
principal, "N/A", authorities));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,4 +78,4 @@ public class SpringSocialTokenServices implements ResourceServerTokenServices {
|
||||
throw new UnsupportedOperationException("Not supported: read access token");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
* 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.
|
||||
@@ -25,15 +25,15 @@ import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
* authenticator (which is how the token gets attached to outgoing requests). The rest
|
||||
* template that is being customized here is <i>only</i> used internally to carry out
|
||||
* authentication (in the SSO or Resource Server use cases).
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public interface UserInfoRestTemplateCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the rest template before it is initialized.
|
||||
*
|
||||
*
|
||||
* @param template the rest template
|
||||
*/
|
||||
void customize(OAuth2RestTemplate template);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -13,14 +13,17 @@
|
||||
* 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 java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.AuthorityUtils;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestOperations;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
@@ -32,13 +35,22 @@ import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Request;
|
||||
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
|
||||
|
||||
/**
|
||||
* {@link ResourceServerTokenServices} that uses a user info REST service.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class UserInfoTokenServices implements ResourceServerTokenServices {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private String userInfoEndpointUrl;
|
||||
private static final String[] PRINCIPAL_KEYS = new String[] { "user", "username",
|
||||
"userid", "user_id", "login", "id", "name" };
|
||||
|
||||
private String clientId;
|
||||
private final String userInfoEndpointUrl;
|
||||
|
||||
private final String clientId;
|
||||
|
||||
private OAuth2RestOperations restTemplate;
|
||||
|
||||
@@ -48,7 +60,7 @@ public class UserInfoTokenServices implements ResourceServerTokenServices {
|
||||
this.userInfoEndpointUrl = userInfoEndpointUrl;
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
|
||||
public void setTokenType(String tokenType) {
|
||||
this.tokenType = tokenType;
|
||||
}
|
||||
@@ -60,31 +72,28 @@ public class UserInfoTokenServices implements ResourceServerTokenServices {
|
||||
@Override
|
||||
public OAuth2Authentication loadAuthentication(String accessToken)
|
||||
throws AuthenticationException, InvalidTokenException {
|
||||
|
||||
Map<String, Object> map = getMap(userInfoEndpointUrl, accessToken);
|
||||
|
||||
Map<String, Object> map = getMap(this.userInfoEndpointUrl, accessToken);
|
||||
if (map.containsKey("error")) {
|
||||
logger.debug("userinfo returned error: " + map.get("error"));
|
||||
this.logger.debug("userinfo returned error: " + map.get("error"));
|
||||
throw new InvalidTokenException(accessToken);
|
||||
}
|
||||
|
||||
return extractAuthentication(map);
|
||||
}
|
||||
|
||||
private OAuth2Authentication extractAuthentication(Map<String, Object> map) {
|
||||
UsernamePasswordAuthenticationToken user = new UsernamePasswordAuthenticationToken(
|
||||
getPrincipal(map), "N/A",
|
||||
AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"));
|
||||
user.setDetails(map);
|
||||
OAuth2Request request = new OAuth2Request(null, clientId, null, true, null, null,
|
||||
null, null, null);
|
||||
return new OAuth2Authentication(request, user);
|
||||
Object principal = getPrincipal(map);
|
||||
List<GrantedAuthority> authorities = AuthorityUtils
|
||||
.commaSeparatedStringToAuthorityList("ROLE_USER");
|
||||
OAuth2Request request = new OAuth2Request(null, this.clientId, null, true, null,
|
||||
null, null, null, null);
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
principal, "N/A", authorities);
|
||||
token.setDetails(map);
|
||||
return new OAuth2Authentication(request, token);
|
||||
}
|
||||
|
||||
private Object getPrincipal(Map<String, Object> map) {
|
||||
String[] keys = new String[] { "user", "username", "userid", "user_id", "login",
|
||||
"id", "name" };
|
||||
for (String key : keys) {
|
||||
for (String key : PRINCIPAL_KEYS) {
|
||||
if (map.containsKey(key)) {
|
||||
return map.get(key);
|
||||
}
|
||||
@@ -97,22 +106,19 @@ public class UserInfoTokenServices implements ResourceServerTokenServices {
|
||||
throw new UnsupportedOperationException("Not supported: read access token");
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
private Map<String, Object> getMap(String path, String accessToken) {
|
||||
logger.info("Getting user info from: " + path);
|
||||
this.logger.info("Getting user info from: " + path);
|
||||
OAuth2RestOperations restTemplate = this.restTemplate;
|
||||
if (restTemplate == null) {
|
||||
BaseOAuth2ProtectedResourceDetails resource = new BaseOAuth2ProtectedResourceDetails();
|
||||
resource.setClientId(clientId);
|
||||
resource.setClientId(this.clientId);
|
||||
restTemplate = new OAuth2RestTemplate(resource);
|
||||
}
|
||||
DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(accessToken);
|
||||
token.setTokenType(tokenType);
|
||||
token.setTokenType(this.tokenType);
|
||||
restTemplate.getOAuth2ClientContext().setAccessToken(token);
|
||||
@SuppressWarnings("rawtypes")
|
||||
Map map = restTemplate.getForEntity(path, Map.class).getBody();
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> result = map;
|
||||
return result;
|
||||
return restTemplate.getForEntity(path, Map.class).getBody();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -16,10 +16,6 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.oauth2;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -30,8 +26,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.authserver.SpringSecurityOAuth2AuthorizationServerConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.method.OAuth2MethodSecurityConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
|
||||
import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration;
|
||||
@@ -93,6 +89,9 @@ import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* Verify Spring Security OAuth2 auto-configuration secures end points properly, accepts
|
||||
* environmental overrides, and also backs off in the presence of other
|
||||
@@ -103,6 +102,10 @@ import com.fasterxml.jackson.databind.JsonNode;
|
||||
*/
|
||||
public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
|
||||
private static final Class<?> RESOURCE_SERVER_CONFIG = OAuth2ResourceServerConfiguration.class;
|
||||
|
||||
private static final Class<?> AUTHORIZATION_SERVER_CONFIG = SpringSecurityOAuth2AuthorizationServerConfiguration.class;
|
||||
|
||||
private AnnotationConfigEmbeddedWebApplicationContext context;
|
||||
|
||||
@Test
|
||||
@@ -111,11 +114,9 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
this.context.register(AuthorizationAndResourceServerConfiguration.class,
|
||||
MinimalSecureWebApplication.class);
|
||||
this.context.refresh();
|
||||
|
||||
this.context.getBean(SpringSecurityOAuth2AuthorizationServerConfiguration.class);
|
||||
this.context.getBean(OAuth2ResourceServerConfiguration.class);
|
||||
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);
|
||||
@@ -125,15 +126,11 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
.getBean(ClientDetailsService.class);
|
||||
ClientDetails clientDetails = clientDetailsService.loadClientByClientId(config
|
||||
.getClientId());
|
||||
|
||||
assertThat(AopUtils.isJdkDynamicProxy(clientDetailsService), is(true));
|
||||
assertThat(AopUtils.isJdkDynamicProxy(clientDetailsService), equalTo(true));
|
||||
assertThat(AopUtils.getTargetClass(clientDetailsService).getName(),
|
||||
is(ClientDetailsService.class.getName()));
|
||||
|
||||
assertThat(handler instanceof ApprovalStoreUserApprovalHandler, is(true));
|
||||
|
||||
equalTo(ClientDetailsService.class.getName()));
|
||||
assertThat(handler instanceof ApprovalStoreUserApprovalHandler, equalTo(true));
|
||||
assertThat(clientDetails, equalTo(config));
|
||||
|
||||
verifyAuthentication(config);
|
||||
}
|
||||
|
||||
@@ -146,12 +143,9 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
this.context.register(AuthorizationAndResourceServerConfiguration.class,
|
||||
MinimalSecureWebApplication.class);
|
||||
this.context.refresh();
|
||||
|
||||
ClientDetails config = this.context.getBean(ClientDetails.class);
|
||||
|
||||
assertThat(config.getClientId(), is("myclientid"));
|
||||
assertThat(config.getClientSecret(), is("mysecret"));
|
||||
|
||||
assertThat(config.getClientId(), equalTo("myclientid"));
|
||||
assertThat(config.getClientSecret(), equalTo("mysecret"));
|
||||
verifyAuthentication(config);
|
||||
}
|
||||
|
||||
@@ -161,16 +155,8 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
this.context.register(AuthorizationServerConfiguration.class,
|
||||
MinimalSecureWebApplication.class);
|
||||
this.context.refresh();
|
||||
|
||||
assertThat(
|
||||
this.context
|
||||
.getBeanNamesForType(OAuth2ResourceServerConfiguration.class).length,
|
||||
is(0));
|
||||
|
||||
assertThat(
|
||||
this.context
|
||||
.getBeanNamesForType(SpringSecurityOAuth2AuthorizationServerConfiguration.class).length,
|
||||
is(1));
|
||||
assertThat(countBeans(RESOURCE_SERVER_CONFIG), equalTo(0));
|
||||
assertThat(countBeans(AUTHORIZATION_SERVER_CONFIG), equalTo(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -181,21 +167,10 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
EnvironmentTestUtils.addEnvironment(this.context,
|
||||
"spring.oauth2.resource.jwt.keyValue:DEADBEEF");
|
||||
this.context.refresh();
|
||||
|
||||
assertThat(
|
||||
this.context
|
||||
.getBeanNamesForType(OAuth2ResourceServerConfiguration.class).length,
|
||||
is(1));
|
||||
|
||||
assertThat(
|
||||
this.context
|
||||
.getBeanNamesForType(SpringSecurityOAuth2AuthorizationServerConfiguration.class).length,
|
||||
is(0));
|
||||
|
||||
assertThat(this.context.getBeanNamesForType(UserApprovalHandler.class).length,
|
||||
is(0));
|
||||
assertThat(this.context.getBeanNamesForType(DefaultTokenServices.class).length,
|
||||
is(1));
|
||||
assertThat(countBeans(RESOURCE_SERVER_CONFIG), equalTo(1));
|
||||
assertThat(countBeans(AUTHORIZATION_SERVER_CONFIG), equalTo(0));
|
||||
assertThat(countBeans(UserApprovalHandler.class), equalTo(0));
|
||||
assertThat(countBeans(DefaultTokenServices.class), equalTo(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -204,24 +179,11 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
this.context.register(AuthorizationAndResourceServerConfiguration.class,
|
||||
CustomResourceServer.class, MinimalSecureWebApplication.class);
|
||||
this.context.refresh();
|
||||
|
||||
ClientDetails config = this.context.getBean(ClientDetails.class);
|
||||
|
||||
assertThat(
|
||||
this.context
|
||||
.getBeanNamesForType(SpringSecurityOAuth2AuthorizationServerConfiguration.class).length,
|
||||
is(1));
|
||||
|
||||
assertThat(this.context.getBeanNamesForType(CustomResourceServer.class).length,
|
||||
is(1));
|
||||
|
||||
assertThat(
|
||||
this.context
|
||||
.getBeanNamesForType(OAuth2ResourceServerConfiguration.class).length,
|
||||
is(1));
|
||||
|
||||
assertThat(countBeans(AUTHORIZATION_SERVER_CONFIG), equalTo(1));
|
||||
assertThat(countBeans(CustomResourceServer.class), equalTo(1));
|
||||
assertThat(countBeans(RESOURCE_SERVER_CONFIG), equalTo(1));
|
||||
verifyAuthentication(config);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -232,7 +194,6 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
this.context.register(AuthorizationAndResourceServerConfiguration.class,
|
||||
CustomAuthorizationServer.class, MinimalSecureWebApplication.class);
|
||||
this.context.refresh();
|
||||
|
||||
BaseClientDetails config = new BaseClientDetails();
|
||||
config.setClientId("client");
|
||||
config.setClientSecret("secret");
|
||||
@@ -240,17 +201,8 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
config.setAuthorizedGrantTypes(Arrays.asList("password"));
|
||||
config.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList("USER"));
|
||||
config.setScope(Arrays.asList("read"));
|
||||
|
||||
assertThat(
|
||||
this.context
|
||||
.getBeanNamesForType(SpringSecurityOAuth2AuthorizationServerConfiguration.class).length,
|
||||
is(0));
|
||||
|
||||
assertThat(
|
||||
this.context
|
||||
.getBeanNamesForType(OAuth2ResourceServerConfiguration.class).length,
|
||||
is(1));
|
||||
|
||||
assertThat(countBeans(AUTHORIZATION_SERVER_CONFIG), equalTo(0));
|
||||
assertThat(countBeans(RESOURCE_SERVER_CONFIG), equalTo(1));
|
||||
verifyAuthentication(config);
|
||||
}
|
||||
|
||||
@@ -260,20 +212,15 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
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(), is(1));
|
||||
assertThat(sources.size(), equalTo(1));
|
||||
assertThat(sources.get(0).getClass().getName(),
|
||||
is(PrePostAnnotationSecurityMetadataSource.class.getName()));
|
||||
|
||||
equalTo(PrePostAnnotationSecurityMetadataSource.class.getName()));
|
||||
verifyAuthentication(config);
|
||||
}
|
||||
|
||||
@@ -283,20 +230,15 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
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(), is(1));
|
||||
assertThat(sources.size(), equalTo(1));
|
||||
assertThat(sources.get(0).getClass().getName(),
|
||||
is(SecuredAnnotationSecurityMetadataSource.class.getName()));
|
||||
|
||||
equalTo(SecuredAnnotationSecurityMetadataSource.class.getName()));
|
||||
verifyAuthentication(config, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@@ -306,20 +248,15 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
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(), is(1));
|
||||
assertThat(sources.size(), equalTo(1));
|
||||
assertThat(sources.get(0).getClass().getName(),
|
||||
is(Jsr250MethodSecurityMetadataSource.class.getName()));
|
||||
|
||||
equalTo(Jsr250MethodSecurityMetadataSource.class.getName()));
|
||||
verifyAuthentication(config, HttpStatus.OK);
|
||||
}
|
||||
|
||||
@@ -329,20 +266,18 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
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(), is(1));
|
||||
assertThat(sources.size(), equalTo(1));
|
||||
assertThat(sources.get(0).getClass().getName(),
|
||||
is(PrePostAnnotationSecurityMetadataSource.class.getName()));
|
||||
equalTo(PrePostAnnotationSecurityMetadataSource.class.getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the oauth service, get a token, and then attempt some operations using
|
||||
* it.
|
||||
*
|
||||
* @param config
|
||||
*/
|
||||
private void verifyAuthentication(ClientDetails config) {
|
||||
@@ -352,60 +287,66 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
private void verifyAuthentication(ClientDetails config, HttpStatus finalStatus) {
|
||||
String baseUrl = "http://localhost:"
|
||||
+ this.context.getEmbeddedServletContainer().getPort();
|
||||
|
||||
RestTemplate rest = new TestRestTemplate();
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
// First, verify the web endpoint can't be reached
|
||||
ResponseEntity<String> entity = rest.exchange(new RequestEntity<Void>(headers,
|
||||
HttpMethod.GET, URI.create(baseUrl + "/secured")), String.class);
|
||||
assertThat(entity.getStatusCode(), is(HttpStatus.UNAUTHORIZED));
|
||||
|
||||
assertEndpointUnauthorized(baseUrl, rest);
|
||||
// Since we can't reach it, need to collect an authorization token
|
||||
String base64Creds = new String(
|
||||
Base64.encode((config.getClientId() + ":" + config.getClientSecret())
|
||||
.getBytes()));
|
||||
headers.set("Authorization", "Basic " + base64Creds);
|
||||
HttpHeaders headers = getHeaders(config);
|
||||
String url = baseUrl + "/oauth/token";
|
||||
JsonNode tokenResponse = rest.postForObject(url,
|
||||
new HttpEntity<MultiValueMap<String, Object>>(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, equalTo("bearer"));
|
||||
assertThat(scope, equalTo("\"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(), equalTo(HttpStatus.OK));
|
||||
assertThat(securedResponse.getBody(), equalTo("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(), equalTo(finalStatus));
|
||||
}
|
||||
|
||||
private HttpHeaders getHeaders(ClientDetails config) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
String token = new String(Base64.encode((config.getClientId() + ":" + config
|
||||
.getClientSecret()).getBytes()));
|
||||
headers.set("Authorization", "Basic " + token);
|
||||
return headers;
|
||||
}
|
||||
|
||||
private MultiValueMap<String, Object> getBody() {
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<String, Object>();
|
||||
body.set("grant_type", "password");
|
||||
body.set("username", "foo");
|
||||
body.set("password", "bar");
|
||||
body.set("scope", "read");
|
||||
return body;
|
||||
}
|
||||
|
||||
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<MultiValueMap<String, Object>>(
|
||||
body, headers);
|
||||
private void assertEndpointUnauthorized(String baseUrl, RestTemplate rest) {
|
||||
URI uri = URI.create(baseUrl + "/secured");
|
||||
ResponseEntity<String> entity = rest.exchange(new RequestEntity<Void>(
|
||||
HttpMethod.GET, uri), String.class);
|
||||
assertThat(entity.getStatusCode(), equalTo(HttpStatus.UNAUTHORIZED));
|
||||
}
|
||||
|
||||
JsonNode response = rest.postForObject(baseUrl + "/oauth/token", request,
|
||||
JsonNode.class);
|
||||
String authorizationToken = response.findValue("access_token").asText();
|
||||
String tokenType = response.findValue("token_type").asText();
|
||||
String scope = response.findValues("scope").get(0).toString();
|
||||
assertThat(tokenType, is("bearer"));
|
||||
assertThat(scope, is("\"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(), is(HttpStatus.OK));
|
||||
assertThat(securedResponse.getBody(),
|
||||
is("You reached an endpoint secured by Spring Security OAuth2"));
|
||||
|
||||
entity = rest.exchange(
|
||||
new RequestEntity<Void>(headers, HttpMethod.POST, URI.create(baseUrl
|
||||
+ "/securedSave")), String.class);
|
||||
assertThat(entity.getStatusCode(), is(finalStatus));
|
||||
private int countBeans(Class<?> type) {
|
||||
return this.context.getBeanNamesForType(type).length;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import({ UseFreePortEmbeddedContainerConfiguration.class,
|
||||
SecurityAutoConfiguration.class, ServerPropertiesAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class,
|
||||
OAuth2AutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class })
|
||||
DispatcherServletAutoConfiguration.class, OAuth2AutoConfiguration.class,
|
||||
WebMvcAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class })
|
||||
protected static class MinimalSecureWebApplication {
|
||||
|
||||
}
|
||||
@@ -428,6 +369,7 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
TestWebApp testWebApp() {
|
||||
return new TestWebApp();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@@ -436,6 +378,7 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
protected static class AuthorizationAndResourceServerConfiguration extends
|
||||
TestSecurityConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@@ -443,6 +386,7 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
@EnableResourceServer
|
||||
@EnableGlobalMethodSecurity(securedEnabled = true)
|
||||
protected static class SecuredEnabledConfiguration extends TestSecurityConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@@ -450,17 +394,20 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
@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
|
||||
@@ -477,14 +424,17 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
public String secureSave() {
|
||||
return "You reached an endpoint secured by Spring Security OAuth2";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class UseFreePortEmbeddedContainerConfiguration {
|
||||
|
||||
@Bean
|
||||
TomcatEmbeddedServletContainerFactory containerFactory() {
|
||||
return new TomcatEmbeddedServletContainerFactory(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@@ -544,14 +494,18 @@ public class SpringSecurityOAuth2AutoConfigurationTests {
|
||||
endpoints.tokenStore(tokenStore()).authenticationManager(
|
||||
this.authenticationManager);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
protected static class CustomMethodSecurity extends GlobalMethodSecurityConfiguration {
|
||||
|
||||
@Override
|
||||
protected MethodSecurityExpressionHandler createExpressionHandler() {
|
||||
return new OAuth2MethodSecurityExpressionHandler();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -13,9 +13,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.resource;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.resource;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -23,30 +22,34 @@ import org.junit.Test;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* Tests for {@link ResourceServerProperties}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class ResourceServerPropertiesTests {
|
||||
|
||||
private ResourceServerProperties properties = new ResourceServerProperties("client", "secret");
|
||||
private ResourceServerProperties properties = new ResourceServerProperties("client",
|
||||
"secret");
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void json() throws Exception {
|
||||
properties.getJwt().setKeyUri("http://example.com/token_key");
|
||||
this.properties.getJwt().setKeyUri("http://example.com/token_key");
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
String json = mapper.writeValueAsString(properties);
|
||||
@SuppressWarnings("unchecked")
|
||||
String json = mapper.writeValueAsString(this.properties);
|
||||
Map<String, Object> value = mapper.readValue(json, Map.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> jwt = (Map<String, Object>) value.get("jwt");
|
||||
assertNotNull("Wrong json: " + json, jwt.get("keyUri"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tokenKeyDerived() throws Exception {
|
||||
properties.setUserInfoUri("http://example.com/userinfo");
|
||||
assertNotNull("Wrong properties: " + properties, properties.getJwt().getKeyUri());
|
||||
this.properties.setUserInfoUri("http://example.com/userinfo");
|
||||
assertNotNull("Wrong properties: " + this.properties, this.properties.getJwt()
|
||||
.getKeyUri());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -13,11 +13,11 @@
|
||||
* 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.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.security.oauth2.OAuth2ClientProperties;
|
||||
@@ -38,13 +38,23 @@ import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
|
||||
import org.springframework.social.connect.ConnectionFactoryLocator;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* Tests for {@link ResourceServerTokenServicesConfiguration}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
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();
|
||||
@@ -112,7 +122,7 @@ public class ResourceServerTokenServicesConfigurationTests {
|
||||
@Test
|
||||
public void asymmetricJwt() {
|
||||
EnvironmentTestUtils.addEnvironment(this.environment,
|
||||
"spring.oauth2.resource.jwt.keyValue=" + publicKey);
|
||||
"spring.oauth2.resource.jwt.keyValue=" + PUBLIC_KEY);
|
||||
this.context = new SpringApplicationBuilder(ResourceConfiguration.class)
|
||||
.environment(this.environment).web(false).run();
|
||||
DefaultTokenServices services = this.context.getBean(DefaultTokenServices.class);
|
||||
@@ -141,6 +151,7 @@ public class ResourceServerTokenServicesConfigurationTests {
|
||||
PropertyPlaceholderAutoConfiguration.class })
|
||||
@EnableConfigurationProperties(OAuth2ClientProperties.class)
|
||||
protected static class ResourceConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@@ -154,18 +165,17 @@ public class ResourceServerTokenServicesConfigurationTests {
|
||||
return new ResourceServerProperties(this.credentials.getClientId(),
|
||||
this.credentials.getClientSecret());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Import({ FacebookAutoConfiguration.class, SocialWebAutoConfiguration.class })
|
||||
protected static class SocialResourceConfiguration extends ResourceConfiguration {
|
||||
|
||||
@Bean
|
||||
public EmbeddedServletContainerFactory embeddedServletContainerFactory() {
|
||||
return Mockito.mock(EmbeddedServletContainerFactory.class);
|
||||
return mock(EmbeddedServletContainerFactory.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static String publicKey = "-----BEGIN PUBLIC KEY-----\n"
|
||||
+ "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnGp/Q5lh0P8nPL21oMMrt2RrkT9AW5jgYwLfSUnJVc9G6uR3cXRRDCjHqWU5WYwivcF180A6CWp/ireQFFBNowgc5XaA0kPpzEtgsA5YsNX7iSnUibB004iBTfU9hZ2Rbsc8cWqynT0RyN4TP1RYVSeVKvMQk4GT1r7JCEC+TNu1ELmbNwMQyzKjsfBXyIOCFU/E94ktvsTZUHF4Oq44DBylCDsS1k7/sfZC2G5EU7Oz0mhG8+Uz6MSEQHtoIi6mc8u64Rwi3Z3tscuWG2ShtsUFuNSAFNkY7LkLn+/hxLCu2bNISMaESa8dG22CIMuIeRLVcAmEWEWH5EEforTg+QIDAQAB\n"
|
||||
+ "-----END PUBLIC KEY-----";
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -15,14 +15,11 @@
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.resource;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.oauth2.client.OAuth2ClientContext;
|
||||
@@ -30,42 +27,51 @@ import org.springframework.security.oauth2.client.OAuth2RestOperations;
|
||||
import org.springframework.security.oauth2.client.resource.BaseOAuth2ProtectedResourceDetails;
|
||||
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* Tests for {@link UserInfoTokenServices}.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class UserInfoTokenServicesTests {
|
||||
|
||||
private UserInfoTokenServices services = new UserInfoTokenServices(
|
||||
"http://example.com", "foo");
|
||||
|
||||
private BaseOAuth2ProtectedResourceDetails resource = new BaseOAuth2ProtectedResourceDetails();
|
||||
private OAuth2RestOperations template = Mockito.mock(OAuth2RestOperations.class);
|
||||
|
||||
private OAuth2RestOperations template = mock(OAuth2RestOperations.class);
|
||||
|
||||
private Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
|
||||
@Before
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void init() {
|
||||
resource.setClientId("foo");
|
||||
Mockito.when(
|
||||
template.getForEntity(Mockito.any(String.class), Mockito.any(Class.class)))
|
||||
.thenReturn(new ResponseEntity<Map>(map, HttpStatus.OK));
|
||||
Mockito.when(template.getAccessToken()).thenReturn(new DefaultOAuth2AccessToken("FOO"));
|
||||
Mockito.when(template.getResource()).thenReturn(resource);
|
||||
Mockito.when(template.getOAuth2ClientContext()).thenReturn(
|
||||
Mockito.mock(OAuth2ClientContext.class));
|
||||
this.resource.setClientId("foo");
|
||||
given(this.template.getForEntity(any(String.class), any(Class.class)))
|
||||
.willReturn(new ResponseEntity<Map>(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() {
|
||||
services.setRestTemplate(template);
|
||||
assertEquals("unknown", services.loadAuthentication("FOO").getName());
|
||||
this.services.setRestTemplate(this.template);
|
||||
assertEquals("unknown", this.services.loadAuthentication("FOO").getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userId() {
|
||||
map.put("userid", "spencer");
|
||||
services.setRestTemplate(template);
|
||||
assertEquals("spencer", services.loadAuthentication("FOO").getName());
|
||||
this.map.put("userid", "spencer");
|
||||
this.services.setRestTemplate(this.template);
|
||||
assertEquals("spencer", this.services.loadAuthentication("FOO").getName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2012-2014 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.
|
||||
@@ -13,11 +13,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.sso;
|
||||
|
||||
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;
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.sso;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
@@ -39,9 +36,14 @@ 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;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* Tests for {@link OAuth2AutoConfiguration} with basic configuration.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = TestConfiguration.class)
|
||||
@@ -64,12 +66,13 @@ public class BasicOAuth2SsoConfigurationTests {
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
mvc = MockMvcBuilders.webAppContextSetup(context).addFilters(filter).build();
|
||||
this.mvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.addFilters(this.filter).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void homePageIsSecure() throws Exception {
|
||||
mvc.perform(get("/")).andExpect(status().isFound())
|
||||
this.mvc.perform(get("/")).andExpect(status().isFound())
|
||||
.andExpect(header().string("location", "http://localhost/login"));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -13,13 +13,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.sso;
|
||||
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
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;
|
||||
package org.springframework.boot.autoconfigure.security.oauth2.sso;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
@@ -45,9 +40,16 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* Tests for {@link OAuth2AutoConfiguration} with custom configuration.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = TestConfiguration.class)
|
||||
@@ -70,24 +72,25 @@ public class CustomOAuth2SsoConfigurationTests {
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
mvc = MockMvcBuilders.webAppContextSetup(context).addFilters(filter).build();
|
||||
this.mvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.addFilters(this.filter).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void homePageIsBasicAuth() throws Exception {
|
||||
mvc.perform(get("/")).andExpect(status().isUnauthorized())
|
||||
this.mvc.perform(get("/")).andExpect(status().isUnauthorized())
|
||||
.andExpect(header().string("WWW-Authenticate", startsWith("Basic")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uiPageIsSecure() throws Exception {
|
||||
mvc.perform(get("/ui/")).andExpect(status().isFound())
|
||||
this.mvc.perform(get("/ui/")).andExpect(status().isFound())
|
||||
.andExpect(header().string("location", "http://localhost/login"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void uiTestPageIsAccessible() throws Exception {
|
||||
mvc.perform(get("/ui/test")).andExpect(status().isOk())
|
||||
this.mvc.perform(get("/ui/test")).andExpect(status().isOk())
|
||||
.andExpect(content().string("test"));
|
||||
}
|
||||
|
||||
@@ -112,6 +115,7 @@ public class CustomOAuth2SsoConfigurationTests {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 the original author or authors.
|
||||
* 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.
|
||||
@@ -40,8 +40,8 @@ import org.springframework.context.annotation.Import;
|
||||
@Import({ EmbeddedServletContainerAutoConfiguration.class,
|
||||
ServerPropertiesAutoConfiguration.class,
|
||||
DispatcherServletAutoConfiguration.class, WebMvcAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class,
|
||||
ErrorMvcAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class,
|
||||
SecurityAutoConfiguration.class }) @interface MinimalSecureWebConfiguration {
|
||||
HttpMessageConvertersAutoConfiguration.class, ErrorMvcAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class, SecurityAutoConfiguration.class })
|
||||
public @interface MinimalSecureWebConfiguration {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -28,28 +28,30 @@ import org.springframework.boot.cli.compiler.DependencyCustomizer;
|
||||
*
|
||||
* @author Greg Turnquist
|
||||
* @author Dave Syer
|
||||
* @since 1.3.0
|
||||
*/
|
||||
public class SpringSecurityOAuth2CompilerAutoConfiguration extends CompilerAutoConfiguration {
|
||||
public class SpringSecurityOAuth2CompilerAutoConfiguration extends
|
||||
CompilerAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean matches(ClassNode classNode) {
|
||||
return AstUtils.hasAtLeastOneAnnotation(classNode,
|
||||
"EnableAuthorizationServer", "EnableResourceServer", "EnableOAuth2Client", "EnableOAuth2Sso");
|
||||
return AstUtils.hasAtLeastOneAnnotation(classNode, "EnableAuthorizationServer",
|
||||
"EnableResourceServer", "EnableOAuth2Client", "EnableOAuth2Sso");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyDependencies(DependencyCustomizer dependencies) throws CompilationFailedException {
|
||||
dependencies.add("spring-security-oauth2").add("spring-boot-starter-web")
|
||||
.add("spring-boot-starter-security");
|
||||
public void applyDependencies(DependencyCustomizer dependencies)
|
||||
throws CompilationFailedException {
|
||||
dependencies.add("spring-security-oauth2", "spring-boot-starter-web",
|
||||
"spring-boot-starter-security");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyImports(ImportCustomizer imports) throws CompilationFailedException {
|
||||
imports
|
||||
.addImports(
|
||||
"org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso")
|
||||
.addStarImports(
|
||||
"org.springframework.security.oauth2.config.annotation.web.configuration",
|
||||
"org.springframework.security.access.prepost");
|
||||
imports.addImports("org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso");
|
||||
imports.addStarImports(
|
||||
"org.springframework.security.oauth2.config.annotation.web.configuration",
|
||||
"org.springframework.security.access.prepost");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -16,11 +16,6 @@
|
||||
|
||||
package org.springframework.boot.cli;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
|
||||
@@ -28,6 +23,11 @@ import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Integration tests to exercise the samples.
|
||||
*
|
||||
@@ -72,8 +72,10 @@ public class SampleIntegrationTests {
|
||||
@Test
|
||||
public void oauth2Sample() throws Exception {
|
||||
String output = this.cli.run("oauth2.groovy");
|
||||
assertTrue("Wrong output: " + output, output.contains("spring.oauth2.client.clientId"));
|
||||
assertTrue("Wrong output: " + output, output.contains("spring.oauth2.client.secret ="));
|
||||
assertTrue("Wrong output: " + output,
|
||||
output.contains("spring.oauth2.client.clientId"));
|
||||
assertTrue("Wrong output: " + output,
|
||||
output.contains("spring.oauth2.client.secret ="));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -13,13 +13,15 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package sample;
|
||||
|
||||
package sample.secure.oauth2;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import java.util.Date;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
@@ -33,18 +35,24 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Flight {
|
||||
|
||||
@Id @GeneratedValue(strategy = GenerationType.AUTO)
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private String origin;
|
||||
|
||||
private String destination;
|
||||
|
||||
private String airline;
|
||||
|
||||
private String flightNumber;
|
||||
|
||||
private Date date;
|
||||
|
||||
private String traveler;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
@@ -52,7 +60,7 @@ public class Flight {
|
||||
}
|
||||
|
||||
public String getOrigin() {
|
||||
return origin;
|
||||
return this.origin;
|
||||
}
|
||||
|
||||
public void setOrigin(String origin) {
|
||||
@@ -60,7 +68,7 @@ public class Flight {
|
||||
}
|
||||
|
||||
public String getDestination() {
|
||||
return destination;
|
||||
return this.destination;
|
||||
}
|
||||
|
||||
public void setDestination(String destination) {
|
||||
@@ -68,7 +76,7 @@ public class Flight {
|
||||
}
|
||||
|
||||
public String getAirline() {
|
||||
return airline;
|
||||
return this.airline;
|
||||
}
|
||||
|
||||
public void setAirline(String airline) {
|
||||
@@ -76,7 +84,7 @@ public class Flight {
|
||||
}
|
||||
|
||||
public String getFlightNumber() {
|
||||
return flightNumber;
|
||||
return this.flightNumber;
|
||||
}
|
||||
|
||||
public void setFlightNumber(String flightNumber) {
|
||||
@@ -84,7 +92,7 @@ public class Flight {
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return date;
|
||||
return this.date;
|
||||
}
|
||||
|
||||
public void setDate(Date date) {
|
||||
@@ -92,10 +100,11 @@ public class Flight {
|
||||
}
|
||||
|
||||
public String getTraveler() {
|
||||
return traveler;
|
||||
return this.traveler;
|
||||
}
|
||||
|
||||
public void setTraveler(String traveler) {
|
||||
this.traveler = traveler;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -13,7 +13,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package sample;
|
||||
|
||||
package sample.secure.oauth2;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
@@ -26,15 +27,16 @@ import org.springframework.security.access.prepost.PreAuthorize;
|
||||
*/
|
||||
public interface FlightRepository extends CrudRepository<Flight, Long> {
|
||||
|
||||
@PreAuthorize("#oauth2.hasScope('read')")
|
||||
@Override
|
||||
@PreAuthorize("#oauth2.hasScope('read')")
|
||||
Iterable<Flight> findAll();
|
||||
|
||||
@PreAuthorize("#oauth2.hasScope('read')")
|
||||
@Override
|
||||
@PreAuthorize("#oauth2.hasScope('read')")
|
||||
Flight findOne(Long aLong);
|
||||
|
||||
@PreAuthorize("#oauth2.hasScope('write')")
|
||||
@Override
|
||||
@PreAuthorize("#oauth2.hasScope('write')")
|
||||
<S extends Flight> S save(S entity);
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2014 the original author or authors.
|
||||
* 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.
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package sample;
|
||||
package sample.secure.oauth2;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
@@ -21,14 +21,11 @@ import org.springframework.security.config.annotation.method.configuration.Enabl
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
|
||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
|
||||
|
||||
// @formatter:off
|
||||
/**
|
||||
* After you launch the app, you can seek a bearer token like this:
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* curl localhost:8080/oauth/token -d "grant_type=password&scope=read&username=greg&password=turnquist" -u foo:bar
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* <ul>
|
||||
@@ -91,16 +88,14 @@ import org.springframework.security.oauth2.config.annotation.web.configuration.E
|
||||
* @author Craig Walls
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
// @formatter:on
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableAuthorizationServer
|
||||
@EnableResourceServer
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public class Application {
|
||||
public class SampleSecureOAuth2Application {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
SpringApplication.run(SampleSecureOAuth2Application.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +1,4 @@
|
||||
package sample;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
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;
|
||||
package sample.secure.oauth2;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -28,8 +19,20 @@ import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import sample.secure.oauth2.SampleSecureOAuth2Application;
|
||||
import sample.secure.oauth2.Flight;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
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
|
||||
@@ -38,12 +41,13 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@WebAppConfiguration
|
||||
@SpringApplicationConfiguration(classes = Application.class)
|
||||
@SpringApplicationConfiguration(classes = SampleSecureOAuth2Application.class)
|
||||
@IntegrationTest("server.port:0")
|
||||
public class ApplicationTests {
|
||||
public class SampleSecureOAuth2ApplicationTests {
|
||||
|
||||
@Autowired
|
||||
WebApplicationContext context;
|
||||
|
||||
@Autowired
|
||||
FilterChainProxy filterChain;
|
||||
|
||||
@@ -53,85 +57,51 @@ public class ApplicationTests {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
this.mvc = webAppContextSetup(this.context).addFilters(this.filterChain).build();
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void everythingIsSecuredByDefault() throws Exception {
|
||||
|
||||
this.mvc.perform(get("/").//
|
||||
accept(MediaTypes.HAL_JSON)).// /
|
||||
andExpect(status().isUnauthorized()).//
|
||||
andDo(print());
|
||||
|
||||
this.mvc.perform(get("/flights").//
|
||||
accept(MediaTypes.HAL_JSON)).// /
|
||||
andExpect(status().isUnauthorized()).//
|
||||
andDo(print());
|
||||
|
||||
this.mvc.perform(get("/flights/1").//
|
||||
accept(MediaTypes.HAL_JSON)).// /
|
||||
andExpect(status().isUnauthorized()).//
|
||||
andDo(print());
|
||||
|
||||
this.mvc.perform(get("/alps").//
|
||||
accept(MediaTypes.HAL_JSON)).// /
|
||||
andExpect(status().isUnauthorized()).//
|
||||
andDo(print());
|
||||
this.mvc.perform(get("/").accept(MediaTypes.HAL_JSON))
|
||||
.andExpect(status().isUnauthorized()).andDo(print());
|
||||
this.mvc.perform(get("/flights").accept(MediaTypes.HAL_JSON))
|
||||
.andExpect(status().isUnauthorized()).andDo(print());
|
||||
this.mvc.perform(get("/flights/1").accept(MediaTypes.HAL_JSON))
|
||||
.andExpect(status().isUnauthorized()).andDo(print());
|
||||
this.mvc.perform(get("/alps").accept(MediaTypes.HAL_JSON))
|
||||
.andExpect(status().isUnauthorized()).andDo(print());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
// TODO: maybe show mixed basic + token auth on different resources?
|
||||
public void accessingRootUriPossibleWithUserAccount() throws Exception {
|
||||
|
||||
String header = "Basic " + new String(Base64.encode("greg:turnquist".getBytes()));
|
||||
this.mvc.perform(
|
||||
get("/").//
|
||||
accept(MediaTypes.HAL_JSON).//
|
||||
header("Authorization",
|
||||
"Basic "
|
||||
+ new String(Base64.encode("greg:turnquist"
|
||||
.getBytes()))))
|
||||
.//
|
||||
andExpect(header().string("Content-Type", MediaTypes.HAL_JSON.toString()))
|
||||
.//
|
||||
andExpect(status().isOk()).//
|
||||
andDo(print());
|
||||
get("/").accept(MediaTypes.HAL_JSON).header("Authorization", header))
|
||||
.andExpect(
|
||||
header().string("Content-Type", MediaTypes.HAL_JSON.toString()))
|
||||
.andExpect(status().isOk()).andDo(print());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useAppSecretsPlusUserAccountToGetBearerToken() throws Exception {
|
||||
|
||||
// @formatter:off
|
||||
String header = "Basic " + new String(Base64.encode("foo:bar".getBytes()));
|
||||
MvcResult result = this.mvc
|
||||
.perform(
|
||||
post("/oauth/token").
|
||||
header("Authorization",
|
||||
"Basic " + new String(Base64.encode("foo:bar".getBytes()))).
|
||||
param("grant_type", "password").
|
||||
param("scope", "read").
|
||||
param("username", "greg").
|
||||
param("password", "turnquist")).
|
||||
andExpect(status().isOk()).
|
||||
andDo(print()).
|
||||
andReturn();
|
||||
// @formatter:on
|
||||
|
||||
post("/oauth/token").header("Authorization", header)
|
||||
.param("grant_type", "password").param("scope", "read")
|
||||
.param("username", "greg").param("password", "turnquist"))
|
||||
.andExpect(status().isOk()).andDo(print()).andReturn();
|
||||
Object accessToken = this.objectMapper.readValue(
|
||||
result.getResponse().getContentAsString(), Map.class).get("access_token");
|
||||
|
||||
MvcResult flightsAction = this.mvc
|
||||
.perform(get("/flights/1").//
|
||||
accept(MediaTypes.HAL_JSON).//
|
||||
header("Authorization", "Bearer " + accessToken))
|
||||
.//
|
||||
andExpect(header().string("Content-Type", MediaTypes.HAL_JSON.toString()))
|
||||
.//
|
||||
andExpect(status().isOk()).//
|
||||
andDo(print()).//
|
||||
andReturn();
|
||||
.perform(
|
||||
get("/flights/1").accept(MediaTypes.HAL_JSON).header(
|
||||
"Authorization", "Bearer " + accessToken))
|
||||
.andExpect(
|
||||
header().string("Content-Type", MediaTypes.HAL_JSON.toString()))
|
||||
.andExpect(status().isOk()).andDo(print()).andReturn();
|
||||
|
||||
Flight flight = this.objectMapper.readValue(flightsAction.getResponse()
|
||||
.getContentAsString(), Flight.class);
|
||||
Reference in New Issue
Block a user