Extract OAuth2ClientProperties

This commit is contained in:
Dave Syer
2014-09-02 19:35:46 +01:00
parent c42a0dfc78
commit 7ca40861eb
9 changed files with 317 additions and 246 deletions

View File

@@ -65,6 +65,7 @@
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>

View File

@@ -0,0 +1,120 @@
/*
* Copyright 2013-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.cloudfoundry.oauth2;
import java.io.IOException;
import java.util.Arrays;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.RequestEnhancer;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
import org.springframework.util.MultiValueMap;
/**
* @author Dave Syer
*
*/
@Configuration
@EnableOAuth2Client
@EnableConfigurationProperties(OAuth2ClientProperties.class)
public class ClientConfiguration {
@Autowired
private OAuth2ClientProperties sso;
@Resource
@Qualifier("accessTokenRequest")
private AccessTokenRequest accessTokenRequest;
@Bean
public FilterRegistrationBean oauth2ClientFilterRegistration(
OAuth2ClientContextFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(filter);
registration.setOrder(0);
return registration;
}
@Bean
public OAuth2ProtectedResourceDetails oauth2RemoteResource() {
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
// set up resource details, OAuth2 URLs etc.
details.setClientId(sso.getClientId());
details.setClientSecret(sso.getClientSecret());
details.setAccessTokenUri(sso.getTokenUri());
details.setUserAuthorizationUri(sso.getAuthorizationUri());
details.setClientAuthenticationScheme(sso.getAuthenticationScheme());
return details;
}
@Bean
public OAuth2RestOperations oauth2RestTemplate() {
OAuth2RestTemplate template = new OAuth2RestTemplate(oauth2RemoteResource(),
oauth2ClientContext());
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);
}
}));
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));
}
});
template.setAccessTokenProvider(accessTokenProvider);
return template;
}
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
public OAuth2ClientContext oauth2ClientContext() {
return new DefaultOAuth2ClientContext(accessTokenRequest);
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2013-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.cloudfoundry.oauth2;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.security.oauth2.common.AuthenticationScheme;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
/**
* @author Dave Syer
*
*/
@ConfigurationProperties("oauth2.client")
@Data
public class OAuth2ClientProperties implements Validator {
@Value("${vcap.services.${oauth2.sso.serviceId:sso}.credentials.tokenUri:${vcap.services.${oauth2.resource.serviceId:resource}.credentials.tokenUri:}}")
private String tokenUri;
@Value("${vcap.services.${oauth2.sso.serviceId:sso}.credentials.authorizationUri:${vcap.services.${oauth2.resource.serviceId:resource}.credentials.authorizationUri:}}")
private String authorizationUri;
@Value("${vcap.services.${oauth2.sso.serviceId:sso}.credentials.clientId:${vcap.services.${oauth2.resource.serviceId:resource}.credentials.clientId:}}")
private String clientId;
@Value("${vcap.services.${oauth2.sso.serviceId:sso}.credentials.clientSecret:${vcap.services.${oauth2.resource.serviceId:resource}.credentials.clientSecret:}}")
private String clientSecret;
private AuthenticationScheme authenticationScheme = AuthenticationScheme.header;
@Override
public boolean supports(Class<?> clazz) {
return OAuth2ClientProperties.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
OAuth2ClientProperties sso = (OAuth2ClientProperties) target;
if (StringUtils.hasText(sso.getClientId())) {
if (!StringUtils.hasText(sso.getAuthorizationUri())) {
errors.rejectValue("authorizeUri", "missing.authorizeUri",
"Missing authorizeUri");
}
if (!StringUtils.hasText(sso.getTokenUri())) {
errors.rejectValue("tokenUri", "missing.tokenUri", "Missing tokenUri");
}
if (!StringUtils.hasText(sso.getClientSecret())) {
errors.rejectValue("clientSecret", "missing.clientSecret",
"Missing clientSecret");
}
}
}
}

View File

@@ -16,7 +16,9 @@
package org.springframework.cloud.cloudfoundry.oauth2;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.StringUtils;
@@ -29,19 +31,16 @@ import org.springframework.validation.Validator;
*/
@ConfigurationProperties("oauth2.resource")
@Data
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ResourceServerProperties implements Validator {
private final OAuth2ClientProperties client;
private String serviceId = "resource";
@Value("${vcap.services.${oauth2.resource.serviceId:resource}.credentials.id:}")
private String id;
@Value("${vcap.services.${oauth2.resource.serviceId:resource}.credentials.clientId:${vcap.services.${oauth2.sso.serviceId:sso}.credentials.clientId:}}")
private String clientId;
@Value("${vcap.services.${oauth2.resource.serviceId:resource}.credentials.clientSecret:${vcap.services.${oauth2.sso.serviceId:sso}.credentials.clientSecret:}}")
private String clientSecret;
@Value("${vcap.services.${oauth2.resource.serviceId:resource}.credentials.userInfoUri:${vcap.services.${oauth2.sso.serviceId:sso}.credentials.userInfoUri:}}")
private String userInfoUri;
@@ -51,7 +50,7 @@ public class ResourceServerProperties implements Validator {
private boolean preferTokenInfo = true;
public String getResourceId() {
return !StringUtils.hasText(id) ? clientId : id;
return id;
}
@Override
@@ -62,8 +61,8 @@ public class ResourceServerProperties implements Validator {
@Override
public void validate(Object target, Errors errors) {
ResourceServerProperties resource = (ResourceServerProperties) target;
if (StringUtils.hasText(resource.getClientId())) {
if (!StringUtils.hasText(resource.getClientSecret())) {
if (StringUtils.hasText(client.getClientId())) {
if (!StringUtils.hasText(client.getClientSecret())) {
if (!StringUtils.hasText(resource.getUserInfoUri())) {
errors.rejectValue("userInfoUri", "missing.userInfoUri",
"Missing userInfoUri (no client secret available)");

View File

@@ -16,7 +16,6 @@
package org.springframework.cloud.cloudfoundry.oauth2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
@@ -25,7 +24,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClas
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.context.annotation.Import;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.social.connect.support.OAuth2ConnectionFactory;
@@ -36,19 +35,23 @@ import org.springframework.social.connect.support.OAuth2ConnectionFactory;
*/
@Configuration
@EnableConfigurationProperties(ResourceServerProperties.class)
@Import(ClientConfiguration.class)
public class ResourceServerTokenServicesConfiguration {
@Autowired
private ResourceServerProperties resource;
@Autowired
private OAuth2ClientProperties client;
@Bean
@ConditionalOnMissingBean(ResourceServerTokenServices.class)
@ConditionalOnExpression("${oauth2.resource.preferTokenInfo:${OAUTH2_RESOURCE_PREFERTOKENINFO:true}}")
protected RemoteTokenServices remoteTokenServices() {
RemoteTokenServices services = new RemoteTokenServices();
services.setCheckTokenEndpointUrl(resource.getTokenInfoUri());
services.setClientId(resource.getClientId());
services.setClientSecret(resource.getClientSecret());
services.setClientId(client.getClientId());
services.setClientSecret(client.getClientSecret());
return services;
}
@@ -60,26 +63,24 @@ public class ResourceServerTokenServicesConfiguration {
@Autowired
private ResourceServerProperties sso;
@Autowired(required = false)
private OAuth2ConnectionFactory<?> connectionFactory;
@Autowired
private OAuth2ClientProperties client;
@Autowired(required = false)
@Qualifier("oauth2RestTemplate")
private OAuth2RestOperations restTemplate;
private OAuth2ConnectionFactory<?> connectionFactory;
@Bean
@ConditionalOnBean(OAuth2ConnectionFactory.class)
@ConditionalOnMissingBean(ResourceServerTokenServices.class)
public SpringSocialTokenServices socialTokenServices() {
return new SpringSocialTokenServices(connectionFactory, sso.getClientId());
return new SpringSocialTokenServices(connectionFactory, client.getClientId());
}
@Bean
@ConditionalOnMissingBean({ OAuth2ConnectionFactory.class,
ResourceServerTokenServices.class })
public UserInfoTokenServices userInfoTokenServices() {
return new UserInfoTokenServices(restTemplate, sso.getUserInfoUri(),
sso.getClientId());
return new UserInfoTokenServices(sso.getUserInfoUri(), client.getClientId());
}
}
@@ -93,14 +94,12 @@ public class ResourceServerTokenServicesConfiguration {
private ResourceServerProperties sso;
@Autowired
@Qualifier("oauth2RestTemplate")
private OAuth2RestOperations restTemplate;
private OAuth2ClientProperties client;
@Bean
@ConditionalOnMissingBean(ResourceServerTokenServices.class)
public UserInfoTokenServices userInfoTokenServices() {
return new UserInfoTokenServices(restTemplate, sso.getUserInfoUri(),
sso.getClientId());
return new UserInfoTokenServices(sso.getUserInfoUri(), client.getClientId());
}
}

View File

@@ -22,12 +22,14 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.BaseOAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.web.client.RestOperations;
/**
* @author Dave Syer
@@ -37,15 +39,11 @@ public class UserInfoTokenServices implements ResourceServerTokenServices {
protected final Log logger = LogFactory.getLog(getClass());
private RestOperations restTemplate;
private String userInfoEndpointUrl;
private String clientId;
public UserInfoTokenServices(RestOperations restTemplate,
String userInfoEndpointUrl, String clientId) {
this.restTemplate = restTemplate;
public UserInfoTokenServices(String userInfoEndpointUrl, String clientId) {
this.userInfoEndpointUrl = userInfoEndpointUrl;
this.clientId = clientId;
}
@@ -54,7 +52,7 @@ public class UserInfoTokenServices implements ResourceServerTokenServices {
public OAuth2Authentication loadAuthentication(String accessToken)
throws AuthenticationException, InvalidTokenException {
Map<String, Object> map = getMap(userInfoEndpointUrl);
Map<String, Object> map = getMap(userInfoEndpointUrl, accessToken);
if (map.containsKey("error")) {
logger.debug("userinfo returned error: " + map.get("error"));
@@ -90,11 +88,17 @@ public class UserInfoTokenServices implements ResourceServerTokenServices {
throw new UnsupportedOperationException("Not supported: read access token");
}
private Map<String, Object> getMap(String path) {
private Map<String, Object> getMap(String path, String accessToken) {
logger.info("Getting user info from :" + path);
BaseOAuth2ProtectedResourceDetails resource = new BaseOAuth2ProtectedResourceDetails();
resource.setClientId(clientId);
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resource);
restTemplate.getOAuth2ClientContext().setAccessToken(new DefaultOAuth2AccessToken(accessToken));
@SuppressWarnings("rawtypes")
Map map = restTemplate.getForEntity(path, Map.class).getBody();
@SuppressWarnings("unchecked")
Map<String, Object> result = map;
return result;
}
}

View File

@@ -42,7 +42,7 @@ import org.springframework.util.ClassUtils;
*
*/
@Configuration
@ConditionalOnExpression("'${oauth2.resource.clientId:${vcap.services.resource.credentials.clientId:}}'!=''")
@ConditionalOnExpression("'${oauth2.client.clientId:${vcap.services.resource.credentials.clientId:}}'!=''")
@ConditionalOnClass({ EnableResourceServer.class, SecurityProperties.class })
@ConditionalOnWebApplication
@EnableResourceServer

View File

@@ -16,11 +16,9 @@
package org.springframework.cloud.cloudfoundry.sso;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -31,214 +29,126 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.cloudfoundry.oauth2.ResourceServerTokenServicesConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter;
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.RequestEnhancer;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.ClassUtils;
import org.springframework.util.MultiValueMap;
/**
* @author Dave Syer
*
*/
@Configuration
@ConditionalOnExpression("'${oauth2.sso.clientId:${vcap.services.sso.credentials.clientId:}}'!=''")
@ConditionalOnClass({ EnableOAuth2Client.class, SecurityProperties.class })
@ConditionalOnExpression("'${oauth2.client.clientId:${vcap.services.sso.credentials.clientId:}}'!=''")
@ConditionalOnClass({ ResourceServerTokenServices.class, SecurityProperties.class })
@ConditionalOnWebApplication
@EnableOAuth2Client
@EnableConfigurationProperties(OAuth2SsoProperties.class)
@Import(ResourceServerTokenServicesConfiguration.class)
public class OAuth2SsoConfiguration {
public class OAuth2SsoConfiguration extends WebSecurityConfigurerAdapter implements Ordered {
@Autowired
private OAuth2ProtectedResourceDetails remote;
@Autowired
private OAuth2SsoProperties sso;
@Resource
@Qualifier("accessTokenRequest")
private AccessTokenRequest accessTokenRequest;
@Autowired
private ResourceServerTokenServices tokenServices;
@Bean
public FilterRegistrationBean oauth2ClientFilterRegistration(
OAuth2ClientContextFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(filter);
registration.setOrder(0);
return registration;
@Autowired
@Qualifier("oauth2RestTemplate")
private OAuth2RestOperations restTemplate;
private List<OAuth2SsoConfigurer> configurers = Collections.emptyList();
@Override
public int getOrder() {
if (ClassUtils
.isPresent(
"org.springframework.boot.actuate.autoconfigure.ManagementServerProperties",
null)) {
return ManagementServerProperties.ACCESS_OVERRIDE_ORDER;
}
return SecurityProperties.ACCESS_OVERRIDE_ORDER;
}
@Bean
public OAuth2ProtectedResourceDetails oauth2RemoteResource() {
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
// set up resource details, OAuth2 URLs etc.
details.setClientId(sso.getClientId());
details.setClientSecret(sso.getClientSecret());
details.setAccessTokenUri(sso.getTokenUri());
details.setUserAuthorizationUri(sso.getAuthorizationUri());
details.setClientAuthenticationScheme(sso.getAuthenticationScheme());
return details;
/**
* @param configurers the configurers to set
*/
@Autowired(required = false)
public void setConfigurers(List<OAuth2SsoConfigurer> configurers) {
this.configurers = configurers;
}
@Bean
public OAuth2RestOperations oauth2RestTemplate() {
OAuth2RestTemplate template = new OAuth2RestTemplate(oauth2RemoteResource(),
oauth2ClientContext());
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);
}
}));
AuthorizationCodeAccessTokenProvider accessTokenProvider = new AuthorizationCodeAccessTokenProvider();
accessTokenProvider.setTokenRequestEnhancer(new RequestEnhancer() {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterAfter(cloudfoundrySsoFilter(),
AbstractPreAuthenticatedProcessingFilter.class);
for (OAuth2SsoConfigurer configurer : configurers) {
// Delegates can add authorizeRequests() here
configurer.configure(http);
}
if (configurers.isEmpty()) {
// Add anyRequest() last as a fall back. Spring Security would replace an
// existing anyRequest() matcher with this one, so to avoid that we only
// add it if the user hasn't configured anything.
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry requests = http
.antMatcher("/**").authorizeRequests();
if (!sso.getHome().isSecure()) {
requests.antMatchers(sso.getHome().getPath()).permitAll();
}
requests.anyRequest().authenticated();
}
http.logout()
.logoutRequestMatcher(new AntPathRequestMatcher(sso.getLogoutPath()))
.addLogoutHandler(logoutHandler()).permitAll();
http.exceptionHandling().authenticationEntryPoint(
new LoginUrlAuthenticationEntryPoint(sso.getLoginPath()));
}
protected OAuth2ClientAuthenticationProcessingFilter cloudfoundrySsoFilter() {
OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter(
sso.getLoginPath());
filter.setRestTemplate(restTemplate);
filter.setTokenServices(tokenServices);
return filter;
}
private LogoutHandler logoutHandler() {
LogoutHandler handler = new LogoutHandler() {
@Override
public void enhance(AccessTokenRequest request,
OAuth2ProtectedResourceDetails resource,
MultiValueMap<String, String> form, HttpHeaders headers) {
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
}
});
template.setAccessTokenProvider(accessTokenProvider);
return template;
}
@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
public OAuth2ClientContext oauth2ClientContext() {
return new DefaultOAuth2ClientContext(accessTokenRequest);
}
@Configuration
protected static class SsoSecurityConfigurer extends WebSecurityConfigurerAdapter
implements Ordered {
@Autowired
private OAuth2ProtectedResourceDetails remote;
@Autowired
private OAuth2SsoProperties sso;
@Autowired
private ResourceServerTokenServices tokenServices;
@Autowired
@Qualifier("oauth2RestTemplate")
private OAuth2RestOperations restTemplate;
private List<OAuth2SsoConfigurer> configurers = Collections.emptyList();
@Override
public int getOrder() {
if (ClassUtils
.isPresent(
"org.springframework.boot.actuate.autoconfigure.ManagementServerProperties",
null)) {
return ManagementServerProperties.ACCESS_OVERRIDE_ORDER;
}
return SecurityProperties.ACCESS_OVERRIDE_ORDER;
}
/**
* @param configurers the configurers to set
*/
@Autowired(required = false)
public void setConfigurers(List<OAuth2SsoConfigurer> configurers) {
this.configurers = configurers;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterAfter(cloudfoundrySsoFilter(),
AbstractPreAuthenticatedProcessingFilter.class);
for (OAuth2SsoConfigurer configurer : configurers) {
// Delegates can add authorizeRequests() here
configurer.configure(http);
}
if (configurers.isEmpty()) {
// Add anyRequest() last as a fall back. Spring Security would replace an
// existing anyRequest() matcher with this one, so to avoid that we only
// add it if the user hasn't configured anything.
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry requests = http
.antMatcher("/**").authorizeRequests();
if (!sso.getHome().isSecure()) {
requests.antMatchers(sso.getHome().getPath()).permitAll();
public void logout(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) {
restTemplate.getOAuth2ClientContext().setAccessToken(null);
String redirect = request.getRequestURL().toString()
.replace(sso.getLogoutPath(), sso.getHome().getPath());
try {
response.sendRedirect(sso.getLogoutUri(redirect));
}
requests.anyRequest().authenticated();
}
http.logout()
.logoutRequestMatcher(new AntPathRequestMatcher(sso.getLogoutPath()))
.addLogoutHandler(logoutHandler()).permitAll();
http.exceptionHandling().authenticationEntryPoint(
new LoginUrlAuthenticationEntryPoint(sso.getLoginPath()));
}
protected OAuth2ClientAuthenticationProcessingFilter cloudfoundrySsoFilter() {
OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter(
sso.getLoginPath());
filter.setRestTemplate(restTemplate);
filter.setTokenServices(tokenServices);
return filter;
}
private LogoutHandler logoutHandler() {
LogoutHandler handler = new LogoutHandler() {
@Override
public void logout(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) {
restTemplate.getOAuth2ClientContext().setAccessToken(null);
String redirect = request.getRequestURL().toString()
.replace(sso.getLogoutPath(), sso.getHome().getPath());
try {
response.sendRedirect(sso.getLogoutUri(redirect));
}
catch (IOException e) {
throw new IllegalStateException("Cannot logout remote server", e);
}
catch (IOException e) {
throw new IllegalStateException("Cannot logout remote server", e);
}
};
return handler;
}
}
};
return handler;
}
}

View File

@@ -16,13 +16,13 @@
package org.springframework.cloud.cloudfoundry.sso;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.security.oauth2.common.AuthenticationScheme;
import org.springframework.cloud.cloudfoundry.oauth2.OAuth2ClientProperties;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
/**
* @author Dave Syer
@@ -30,7 +30,10 @@ import org.springframework.validation.Validator;
*/
@ConfigurationProperties("oauth2.sso")
@Data
public class OAuth2SsoProperties implements Validator {
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class OAuth2SsoProperties {
private final OAuth2ClientProperties client;
private String serviceId = "sso";
@@ -41,20 +44,6 @@ public class OAuth2SsoProperties implements Validator {
private String loginPath = "/login";
@Value("${vcap.services.${oauth2.sso.serviceId:sso}.credentials.tokenUri:}")
private String tokenUri;
@Value("${vcap.services.${oauth2.sso.serviceId:sso}.credentials.authorizationUri:}")
private String authorizationUri;
@Value("${vcap.services.${oauth2.sso.serviceId:sso}.credentials.clientId:}")
private String clientId;
@Value("${vcap.services.${oauth2.sso.serviceId:sso}.credentials.clientSecret:}")
private String clientSecret;
private AuthenticationScheme authenticationScheme = AuthenticationScheme.header;
private Home home = new Home();
@Data
@@ -64,31 +53,8 @@ public class OAuth2SsoProperties implements Validator {
}
public String getLogoutUri(String redirectUrl) {
return StringUtils.hasText(logoutUri) ? logoutUri : tokenUri.replace("/oauth/token",
return StringUtils.hasText(logoutUri) ? logoutUri : client.getTokenUri().replace("/oauth/token",
"/logout.do?redirect=" + redirectUrl);
}
@Override
public boolean supports(Class<?> clazz) {
return OAuth2SsoProperties.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
OAuth2SsoProperties sso = (OAuth2SsoProperties) target;
if (StringUtils.hasText(sso.getClientId())) {
if (!StringUtils.hasText(sso.getAuthorizationUri())) {
errors.rejectValue("authorizeUri", "missing.authorizeUri",
"Missing authorizeUri");
}
if (!StringUtils.hasText(sso.getTokenUri())) {
errors.rejectValue("tokenUri", "missing.tokenUri", "Missing tokenUri");
}
if (!StringUtils.hasText(sso.getClientSecret())) {
errors.rejectValue("clientSecret", "missing.clientSecret",
"Missing clientSecret");
}
}
}
}