@EnableOAuth2*
This commit is contained in:
9
pom.xml
9
pom.xml
@@ -62,6 +62,10 @@
|
|||||||
<version>2.0.3.RELEASE</version>
|
<version>2.0.3.RELEASE</version>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.social</groupId>
|
||||||
|
<artifactId>spring-social-core</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
@@ -82,11 +86,6 @@
|
|||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.ant</groupId>
|
|
||||||
<artifactId>ant-launcher</artifactId>
|
|
||||||
<version>1.9.3</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
@@ -30,17 +30,12 @@ import org.cloudfoundry.community.servicebroker.service.ServiceInstanceService;
|
|||||||
import org.springframework.aop.framework.ProxyFactory;
|
import org.springframework.aop.framework.ProxyFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.ApplicationListener;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.ComponentScan;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.FilterType;
|
|
||||||
import org.springframework.cloud.cloudfoundry.broker.FreeServiceDefinitionFactory;
|
import org.springframework.cloud.cloudfoundry.broker.FreeServiceDefinitionFactory;
|
||||||
import org.springframework.cloud.cloudfoundry.broker.ServiceInstanceBindingRepository;
|
import org.springframework.cloud.cloudfoundry.broker.ServiceInstanceBindingRepository;
|
||||||
import org.springframework.cloud.cloudfoundry.broker.ServiceInstanceRepository;
|
import org.springframework.cloud.cloudfoundry.broker.ServiceInstanceRepository;
|
||||||
@@ -50,6 +45,12 @@ import org.springframework.cloud.cloudfoundry.broker.simple.SimpleServiceInstanc
|
|||||||
import org.springframework.cloud.cloudfoundry.broker.simple.SimpleServiceInstanceService;
|
import org.springframework.cloud.cloudfoundry.broker.simple.SimpleServiceInstanceService;
|
||||||
import org.springframework.cloud.netflix.eureka.advice.PiggybackMethodInterceptor;
|
import org.springframework.cloud.netflix.eureka.advice.PiggybackMethodInterceptor;
|
||||||
import org.springframework.cloud.netflix.eureka.event.EurekaRegistryAvailableEvent;
|
import org.springframework.cloud.netflix.eureka.event.EurekaRegistryAvailableEvent;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationListener;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.FilterType;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
@@ -83,14 +84,14 @@ import com.netflix.eureka.lease.LeaseManager;
|
|||||||
public class ServiceBrokerAutoConfiguration {
|
public class ServiceBrokerAutoConfiguration {
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnMissingClass(name = "com.netflix.eureka.PeerAwareInstanceRegistry")
|
@ConditionalOnMissingBean(EurekaInstanceConfig.class)
|
||||||
@ConditionalOnMissingBean(CatalogService.class)
|
|
||||||
protected static class CatalogConfiguration {
|
protected static class CatalogConfiguration {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private BrokerProperties broker;
|
private BrokerProperties broker;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(CatalogService.class)
|
||||||
public BeanCatalogService catalogService() {
|
public BeanCatalogService catalogService() {
|
||||||
return new BeanCatalogService(catalog());
|
return new BeanCatalogService(catalog());
|
||||||
}
|
}
|
||||||
@@ -143,7 +144,7 @@ public class ServiceBrokerAutoConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnClass(PeerAwareInstanceRegistry.class)
|
@ConditionalOnBean(EurekaInstanceConfig.class)
|
||||||
protected static class EurekaCatalogConfiguration {
|
protected static class EurekaCatalogConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@@ -156,6 +157,7 @@ public class ServiceBrokerAutoConfiguration {
|
|||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnClass(PeerAwareInstanceRegistry.class)
|
@ConditionalOnClass(PeerAwareInstanceRegistry.class)
|
||||||
|
@ConditionalOnBean(EurekaInstanceConfig.class)
|
||||||
protected static class Initializer implements
|
protected static class Initializer implements
|
||||||
ApplicationListener<EurekaRegistryAvailableEvent> {
|
ApplicationListener<EurekaRegistryAvailableEvent> {
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Dave Syer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@ConfigurationProperties("oauth2.resource")
|
||||||
|
@Data
|
||||||
|
public class ResourceServerProperties {
|
||||||
|
|
||||||
|
private String serviceId = "resource";
|
||||||
|
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Value("${vcap.services.${oauth2.resource.serviceId:resource}.credentials.clientId:}")
|
||||||
|
private String clientId;
|
||||||
|
|
||||||
|
@Value("${vcap.services.${oauth2.resource.serviceId:resource}.credentials.clientSecret:}")
|
||||||
|
private String clientSecret;
|
||||||
|
|
||||||
|
@Value("${vcap.services.${oauth2.resource.serviceId:sso}.credentials.userInfoUri:}")
|
||||||
|
private String userInfoUri;
|
||||||
|
|
||||||
|
@Value("${vcap.services.${oauth2.resource.serviceId:sso}.credentials.tokenInfoUri:}")
|
||||||
|
private String tokenInfoUri;
|
||||||
|
|
||||||
|
private boolean preferTokenInfo = true;
|
||||||
|
|
||||||
|
public String getResourceId() {
|
||||||
|
return id==null ? clientId : id;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* 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 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;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||||
|
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.security.oauth2.provider.token.RemoteTokenServices;
|
||||||
|
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
|
||||||
|
import org.springframework.social.connect.support.OAuth2ConnectionFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Dave Syer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableConfigurationProperties(ResourceServerProperties.class)
|
||||||
|
public class ResourceServerTokenServicesConfiguration {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ResourceServerProperties resource;
|
||||||
|
|
||||||
|
@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());
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass(OAuth2ConnectionFactory.class)
|
||||||
|
@ConditionalOnExpression("!${oauth2.resource.preferTokenInfo:${OAUTH2_RESOURCE_PREFERTOKENINFO:true}}")
|
||||||
|
protected static class SocialTokenServicesConfiguration {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ResourceServerProperties sso;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private OAuth2ConnectionFactory<?> connectionFactory;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
@Qualifier("oauth2RestTemplate")
|
||||||
|
private OAuth2RestOperations restTemplate;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnBean(OAuth2ConnectionFactory.class)
|
||||||
|
@ConditionalOnMissingBean(ResourceServerTokenServices.class)
|
||||||
|
public SpringSocialTokenServices socialTokenServices() {
|
||||||
|
return new SpringSocialTokenServices(connectionFactory, sso.getClientId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean({ OAuth2ConnectionFactory.class,
|
||||||
|
ResourceServerTokenServices.class })
|
||||||
|
public UserInfoTokenServices userInfoTokenServices() {
|
||||||
|
return new UserInfoTokenServices(restTemplate, sso.getUserInfoUri(),
|
||||||
|
sso.getClientId());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnMissingClass(name = "org.springframework.social.connect.support.OAuth2ConnectionFactory")
|
||||||
|
@ConditionalOnExpression("!${oauth2.resource.preferTokenInfo:${OAUTH2_RESOURCE_PREFERTOKENINFO:true}}")
|
||||||
|
protected static class UserInfoTokenServicesConfiguration {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ResourceServerProperties sso;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("oauth2RestTemplate")
|
||||||
|
private OAuth2RestOperations restTemplate;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(ResourceServerTokenServices.class)
|
||||||
|
public UserInfoTokenServices userInfoTokenServices() {
|
||||||
|
return new UserInfoTokenServices(restTemplate, sso.getUserInfoUri(),
|
||||||
|
sso.getClientId());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* 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 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.authority.AuthorityUtils;
|
||||||
|
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.social.connect.Connection;
|
||||||
|
import org.springframework.social.connect.UserProfile;
|
||||||
|
import org.springframework.social.connect.support.OAuth2ConnectionFactory;
|
||||||
|
import org.springframework.social.oauth2.AccessGrant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Dave Syer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SpringSocialTokenServices implements ResourceServerTokenServices {
|
||||||
|
|
||||||
|
protected final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
|
private OAuth2ConnectionFactory<?> connectionFactory;
|
||||||
|
|
||||||
|
private String clientId;
|
||||||
|
|
||||||
|
public SpringSocialTokenServices(OAuth2ConnectionFactory<?> connectionFactory,
|
||||||
|
String clientId) {
|
||||||
|
this.connectionFactory = connectionFactory;
|
||||||
|
this.clientId = clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OAuth2Authentication loadAuthentication(String accessToken)
|
||||||
|
throws AuthenticationException, InvalidTokenException {
|
||||||
|
|
||||||
|
Connection<?> connection = connectionFactory.createConnection(new AccessGrant(
|
||||||
|
accessToken));
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OAuth2AccessToken readAccessToken(String accessToken) {
|
||||||
|
throw new UnsupportedOperationException("Not supported: read access token");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* 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.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.authority.AuthorityUtils;
|
||||||
|
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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
this.userInfoEndpointUrl = userInfoEndpointUrl;
|
||||||
|
this.clientId = clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OAuth2Authentication loadAuthentication(String accessToken)
|
||||||
|
throws AuthenticationException, InvalidTokenException {
|
||||||
|
|
||||||
|
Map<String, Object> map = getMap(userInfoEndpointUrl);
|
||||||
|
|
||||||
|
if (map.containsKey("error")) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object getPrincipal(Map<String, Object> map) {
|
||||||
|
String[] keys = new String[] { "user", "username", "userid", "user_id",
|
||||||
|
"login", "id" };
|
||||||
|
for (String key : keys) {
|
||||||
|
if (map.containsKey(key)) {
|
||||||
|
return map.get(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OAuth2AccessToken readAccessToken(String accessToken) {
|
||||||
|
throw new UnsupportedOperationException("Not supported: read access token");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> getMap(String path) {
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
Map map = restTemplate.getForEntity(path, Map.class).getBody();
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> result = map;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,11 +31,11 @@ import com.netflix.zuul.ZuulFilter;
|
|||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnClass({ ZuulFilter.class, EnableOAuth2Client.class, SecurityProperties.class })
|
@ConditionalOnClass({ ZuulFilter.class, EnableOAuth2Client.class, SecurityProperties.class })
|
||||||
@ConditionalOnWebApplication
|
@ConditionalOnWebApplication
|
||||||
public class CloudfoundryProxyConfiguration {
|
public class OAuth2ProxyAutoConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public CloudfoundryTokenFilter cloudfoundryTokenFilter() {
|
public OAuth2TokenFilter cloudfoundryTokenFilter() {
|
||||||
return new CloudfoundryTokenFilter();
|
return new OAuth2TokenFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@ import org.springframework.security.oauth2.provider.authentication.OAuth2Authent
|
|||||||
import com.netflix.zuul.ZuulFilter;
|
import com.netflix.zuul.ZuulFilter;
|
||||||
import com.netflix.zuul.context.RequestContext;
|
import com.netflix.zuul.context.RequestContext;
|
||||||
|
|
||||||
public class CloudfoundryTokenFilter extends ZuulFilter {
|
public class OAuth2TokenFilter extends ZuulFilter {
|
||||||
|
|
||||||
private static final String ACCESS_TOKEN = "ACCESS_TOKEN";
|
private static final String ACCESS_TOKEN = "ACCESS_TOKEN";
|
||||||
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.resource;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.validation.Errors;
|
|
||||||
import org.springframework.validation.Validator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Dave Syer
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@ConfigurationProperties("cloudfoundry.resource")
|
|
||||||
@Data
|
|
||||||
public class CloudfoundryResourceProperties implements Validator {
|
|
||||||
|
|
||||||
private String serviceId = "resource";
|
|
||||||
|
|
||||||
private String id;
|
|
||||||
|
|
||||||
@Value("${vcap.services.${cloudfoundry.resource.serviceId:resource}.credentials.clientId:}")
|
|
||||||
private String clientId;
|
|
||||||
|
|
||||||
@Value("${vcap.services.${cloudfoundry.resource.serviceId:resource}.credentials.clientSecret:}")
|
|
||||||
private String clientSecret;
|
|
||||||
|
|
||||||
@Value("${vcap.services.${cloudfoundry.resource.serviceId:resource}.credentials.tokenInfoUri:}")
|
|
||||||
private String tokenInfoUri;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supports(Class<?> clazz) {
|
|
||||||
return CloudfoundryResourceProperties.class.isAssignableFrom(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void validate(Object target, Errors errors) {
|
|
||||||
CloudfoundryResourceProperties resource = (CloudfoundryResourceProperties) target;
|
|
||||||
if (StringUtils.hasText(resource.getClientId())) {
|
|
||||||
if (!StringUtils.hasText(resource.getTokenInfoUri())) {
|
|
||||||
errors.rejectValue("tokenInfoUri", "missing.tokenInfoUri", "Missing tokenInfoUri");
|
|
||||||
}
|
|
||||||
if (!StringUtils.hasText(resource.getClientSecret())) {
|
|
||||||
errors.rejectValue("clientSecret", "missing.clientSecret", "Missing clientSecret");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getResourceId() {
|
|
||||||
return id==null ? clientId : id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -30,7 +30,7 @@ import org.springframework.context.annotation.Import;
|
|||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Documented
|
@Documented
|
||||||
@Import(CloudfoundryResourceConfiguration.class)
|
@Import(OAuth2ResourceConfiguration.class)
|
||||||
public @interface EnableCloudfoundryResource {
|
public @interface EnableOAuth2Resource {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -24,17 +24,17 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
|||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.cloud.cloudfoundry.oauth2.ResourceServerProperties;
|
||||||
|
import org.springframework.cloud.cloudfoundry.oauth2.ResourceServerTokenServicesConfiguration;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
|
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
|
||||||
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration;
|
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration;
|
||||||
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurer;
|
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurer;
|
||||||
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
|
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
|
||||||
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
|
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
|
||||||
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
|
|
||||||
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
|
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,40 +42,28 @@ import org.springframework.util.ClassUtils;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnExpression("'${cloudfoundry.resource.clientId:${vcap.services.resource.credentials.clientId:}}'!=''")
|
@ConditionalOnExpression("'${oauth2.resource.clientId:${vcap.services.resource.credentials.clientId:}}'!=''")
|
||||||
@ConditionalOnClass({ EnableResourceServer.class, SecurityProperties.class })
|
@ConditionalOnClass({ EnableResourceServer.class, SecurityProperties.class })
|
||||||
@ConditionalOnWebApplication
|
@ConditionalOnWebApplication
|
||||||
@EnableResourceServer
|
@EnableResourceServer
|
||||||
@EnableConfigurationProperties(CloudfoundryResourceProperties.class)
|
@Import(ResourceServerTokenServicesConfiguration.class)
|
||||||
public class CloudfoundryResourceConfiguration {
|
public class OAuth2ResourceConfiguration {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private CloudfoundryResourceProperties resource;
|
private ResourceServerProperties resource;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(ResourceServerConfigurer.class)
|
@ConditionalOnMissingBean(ResourceServerConfigurer.class)
|
||||||
public ResourceServerConfigurer resourceServer() {
|
public ResourceServerConfigurer resourceServer() {
|
||||||
return new ResourceSecurityConfigurer(resource);
|
return new ResourceSecurityConfigurer(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean(ResourceServerTokenServices.class)
|
|
||||||
public ResourceServerTokenServices tokenServices() {
|
|
||||||
RemoteTokenServices services = new RemoteTokenServices();
|
|
||||||
services.setCheckTokenEndpointUrl(resource.getTokenInfoUri());
|
|
||||||
services.setClientId(resource.getClientId());
|
|
||||||
services.setClientSecret(resource.getClientSecret());
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected static class ResourceSecurityConfigurer extends ResourceServerConfigurerAdapter {
|
protected static class ResourceSecurityConfigurer extends ResourceServerConfigurerAdapter {
|
||||||
|
|
||||||
private CloudfoundryResourceProperties resource;
|
private ResourceServerProperties resource;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ResourceSecurityConfigurer(CloudfoundryResourceProperties resource) {
|
public ResourceSecurityConfigurer(ResourceServerProperties resource) {
|
||||||
this.resource = resource;
|
this.resource = resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,8 +21,6 @@ import java.lang.annotation.Retention;
|
|||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Import;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*
|
*
|
||||||
@@ -30,7 +28,7 @@ import org.springframework.context.annotation.Import;
|
|||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Documented
|
@Documented
|
||||||
@Import(CloudfoundrySsoConfiguration.class)
|
@EnableOAuth2Sso
|
||||||
public @interface EnableCloudfoundrySso {
|
public @interface EnableCloudfoundrySso {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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.sso;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Dave Syer
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
@Import(OAuth2SsoConfiguration.class)
|
||||||
|
public @interface EnableOAuth2Sso {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
package org.springframework.cloud.cloudfoundry.sso;
|
package org.springframework.cloud.cloudfoundry.sso;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -32,11 +33,19 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat
|
|||||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||||
import org.springframework.boot.context.embedded.FilterRegistrationBean;
|
import org.springframework.boot.context.embedded.FilterRegistrationBean;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
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.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.context.annotation.ScopedProxyMode;
|
import org.springframework.context.annotation.ScopedProxyMode;
|
||||||
import org.springframework.core.Ordered;
|
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.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
|
||||||
@@ -49,30 +58,33 @@ import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticat
|
|||||||
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter;
|
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter;
|
||||||
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
|
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
|
||||||
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
|
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.client.token.grant.code.AuthorizationCodeResourceDetails;
|
||||||
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
|
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
|
||||||
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
|
|
||||||
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
|
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
|
||||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
||||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||||
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
|
import org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnExpression("'${cloudfoundry.sso.clientId:${vcap.services.sso.credentials.clientId:}}'!=''")
|
@ConditionalOnExpression("'${oauth2.sso.clientId:${vcap.services.sso.credentials.clientId:}}'!=''")
|
||||||
@ConditionalOnClass({ EnableOAuth2Client.class, SecurityProperties.class })
|
@ConditionalOnClass({ EnableOAuth2Client.class, SecurityProperties.class })
|
||||||
@ConditionalOnWebApplication
|
@ConditionalOnWebApplication
|
||||||
@EnableOAuth2Client
|
@EnableOAuth2Client
|
||||||
@EnableConfigurationProperties(CloudfoundrySsoProperties.class)
|
@EnableConfigurationProperties(OAuth2SsoProperties.class)
|
||||||
public class CloudfoundrySsoConfiguration {
|
@Import(ResourceServerTokenServicesConfiguration.class)
|
||||||
|
public class OAuth2SsoConfiguration {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private CloudfoundrySsoProperties sso;
|
private OAuth2SsoProperties sso;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
@Qualifier("accessTokenRequest")
|
@Qualifier("accessTokenRequest")
|
||||||
@@ -88,19 +100,42 @@ public class CloudfoundrySsoConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public OAuth2ProtectedResourceDetails remote() {
|
public OAuth2ProtectedResourceDetails oauth2RemoteResource() {
|
||||||
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
|
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
|
||||||
// set up resource details, OAuth2 URLs etc.
|
// set up resource details, OAuth2 URLs etc.
|
||||||
details.setClientId(sso.getClientId());
|
details.setClientId(sso.getClientId());
|
||||||
details.setClientSecret(sso.getClientSecret());
|
details.setClientSecret(sso.getClientSecret());
|
||||||
details.setAccessTokenUri(sso.getTokenUri());
|
details.setAccessTokenUri(sso.getTokenUri());
|
||||||
details.setUserAuthorizationUri(sso.getAuthorizationUri());
|
details.setUserAuthorizationUri(sso.getAuthorizationUri());
|
||||||
|
details.setClientAuthenticationScheme(sso.getAuthenticationScheme());
|
||||||
return details;
|
return details;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public OAuth2RestOperations restTemplate() {
|
public OAuth2RestOperations oauth2RestTemplate() {
|
||||||
return new OAuth2RestTemplate(remote(), oauth2ClientContext());
|
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
|
@Bean
|
||||||
@@ -117,12 +152,16 @@ public class CloudfoundrySsoConfiguration {
|
|||||||
private OAuth2ProtectedResourceDetails remote;
|
private OAuth2ProtectedResourceDetails remote;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private CloudfoundrySsoProperties sso;
|
private OAuth2SsoProperties sso;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
|
private ResourceServerTokenServices tokenServices;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("oauth2RestTemplate")
|
||||||
private OAuth2RestOperations restTemplate;
|
private OAuth2RestOperations restTemplate;
|
||||||
|
|
||||||
private List<CloudfoundrySsoConfigurer> configurers = Collections.emptyList();
|
private List<OAuth2SsoConfigurer> configurers = Collections.emptyList();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getOrder() {
|
public int getOrder() {
|
||||||
@@ -139,7 +178,7 @@ public class CloudfoundrySsoConfiguration {
|
|||||||
* @param configurers the configurers to set
|
* @param configurers the configurers to set
|
||||||
*/
|
*/
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
public void setConfigurers(List<CloudfoundrySsoConfigurer> configurers) {
|
public void setConfigurers(List<OAuth2SsoConfigurer> configurers) {
|
||||||
this.configurers = configurers;
|
this.configurers = configurers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +188,7 @@ public class CloudfoundrySsoConfiguration {
|
|||||||
http.addFilterAfter(cloudfoundrySsoFilter(),
|
http.addFilterAfter(cloudfoundrySsoFilter(),
|
||||||
AbstractPreAuthenticatedProcessingFilter.class);
|
AbstractPreAuthenticatedProcessingFilter.class);
|
||||||
|
|
||||||
for (CloudfoundrySsoConfigurer configurer : configurers) {
|
for (OAuth2SsoConfigurer configurer : configurers) {
|
||||||
// Delegates can add authorizeRequests() here
|
// Delegates can add authorizeRequests() here
|
||||||
configurer.configure(http);
|
configurer.configure(http);
|
||||||
}
|
}
|
||||||
@@ -165,7 +204,8 @@ public class CloudfoundrySsoConfiguration {
|
|||||||
requests.anyRequest().authenticated();
|
requests.anyRequest().authenticated();
|
||||||
}
|
}
|
||||||
|
|
||||||
http.logout().logoutRequestMatcher(new AntPathRequestMatcher(sso.getLogoutPath()))
|
http.logout()
|
||||||
|
.logoutRequestMatcher(new AntPathRequestMatcher(sso.getLogoutPath()))
|
||||||
.addLogoutHandler(logoutHandler());
|
.addLogoutHandler(logoutHandler());
|
||||||
http.exceptionHandling().authenticationEntryPoint(
|
http.exceptionHandling().authenticationEntryPoint(
|
||||||
new LoginUrlAuthenticationEntryPoint(sso.getLoginPath()));
|
new LoginUrlAuthenticationEntryPoint(sso.getLoginPath()));
|
||||||
@@ -176,18 +216,10 @@ public class CloudfoundrySsoConfiguration {
|
|||||||
OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter(
|
OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter(
|
||||||
sso.getLoginPath());
|
sso.getLoginPath());
|
||||||
filter.setRestTemplate(restTemplate);
|
filter.setRestTemplate(restTemplate);
|
||||||
filter.setTokenServices(tokenServices());
|
filter.setTokenServices(tokenServices);
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourceServerTokenServices tokenServices() {
|
|
||||||
RemoteTokenServices services = new RemoteTokenServices();
|
|
||||||
services.setCheckTokenEndpointUrl(sso.getTokenInfoUri());
|
|
||||||
services.setClientId(sso.getClientId());
|
|
||||||
services.setClientSecret(sso.getClientSecret());
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
|
|
||||||
private LogoutHandler logoutHandler() {
|
private LogoutHandler logoutHandler() {
|
||||||
LogoutHandler handler = new LogoutHandler() {
|
LogoutHandler handler = new LogoutHandler() {
|
||||||
@Override
|
@Override
|
||||||
@@ -21,7 +21,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public interface CloudfoundrySsoConfigurer {
|
public interface OAuth2SsoConfigurer {
|
||||||
|
|
||||||
void configure(HttpSecurity http);
|
void configure(HttpSecurity http);
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class CloudfoundrySsoConfigurerAdapter implements CloudfoundrySsoConfigurer {
|
public class OAuth2SsoConfigurerAdapter implements OAuth2SsoConfigurer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(HttpSecurity http) {
|
public void configure(HttpSecurity http) {
|
||||||
@@ -19,6 +19,7 @@ import lombok.Data;
|
|||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.security.oauth2.common.AuthenticationScheme;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.validation.Errors;
|
import org.springframework.validation.Errors;
|
||||||
import org.springframework.validation.Validator;
|
import org.springframework.validation.Validator;
|
||||||
@@ -27,34 +28,33 @@ import org.springframework.validation.Validator;
|
|||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ConfigurationProperties("cloudfoundry.sso")
|
@ConfigurationProperties("oauth2.sso")
|
||||||
@Data
|
@Data
|
||||||
public class CloudfoundrySsoProperties implements Validator {
|
public class OAuth2SsoProperties implements Validator {
|
||||||
|
|
||||||
private String serviceId = "sso";
|
private String serviceId = "sso";
|
||||||
|
|
||||||
private String logoutPath = "/logout";
|
private String logoutPath = "/logout";
|
||||||
|
|
||||||
|
@Value("${vcap.services.${oauth2.sso.serviceId:sso}.credentials.logoutUri:}")
|
||||||
|
private String logoutUri;
|
||||||
|
|
||||||
private String loginPath = "/login";
|
private String loginPath = "/login";
|
||||||
|
|
||||||
@Value("${vcap.services.${cloudfoundry.sso.serviceId:sso}.credentials.tokenUri:}")
|
@Value("${vcap.services.${oauth2.sso.serviceId:sso}.credentials.tokenUri:}")
|
||||||
private String tokenUri;
|
private String tokenUri;
|
||||||
|
|
||||||
@Value("${vcap.services.${cloudfoundry.sso.serviceId:sso}.credentials.userInfoUri:}")
|
@Value("${vcap.services.${oauth2.sso.serviceId:sso}.credentials.authorizationUri:}")
|
||||||
private String userInfoUri;
|
|
||||||
|
|
||||||
@Value("${vcap.services.${cloudfoundry.sso.serviceId:sso}.credentials.tokenInfoUri:}")
|
|
||||||
private String tokenInfoUri;
|
|
||||||
|
|
||||||
@Value("${vcap.services.${cloudfoundry.sso.serviceId:sso}.credentials.authorizationUri:}")
|
|
||||||
private String authorizationUri;
|
private String authorizationUri;
|
||||||
|
|
||||||
@Value("${vcap.services.${cloudfoundry.sso.serviceId:sso}.credentials.clientId:}")
|
@Value("${vcap.services.${oauth2.sso.serviceId:sso}.credentials.clientId:}")
|
||||||
private String clientId;
|
private String clientId;
|
||||||
|
|
||||||
@Value("${vcap.services.${cloudfoundry.sso.serviceId:sso}.credentials.clientSecret:}")
|
@Value("${vcap.services.${oauth2.sso.serviceId:sso}.credentials.clientSecret:}")
|
||||||
private String clientSecret;
|
private String clientSecret;
|
||||||
|
|
||||||
|
private AuthenticationScheme authenticationScheme = AuthenticationScheme.header;
|
||||||
|
|
||||||
private Home home = new Home();
|
private Home home = new Home();
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@@ -63,27 +63,19 @@ public class CloudfoundrySsoProperties implements Validator {
|
|||||||
private boolean secure = true;
|
private boolean secure = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTokenInfoUri() {
|
|
||||||
return StringUtils.hasText(tokenInfoUri) ? tokenInfoUri : tokenUri.replace(
|
|
||||||
"/oauth/token", "/check_token");
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUserInfoUri() {
|
|
||||||
return tokenUri.replace("/oauth/token", "/user_info");
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLogoutUri(String redirectUrl) {
|
public String getLogoutUri(String redirectUrl) {
|
||||||
return tokenUri.replace("/oauth/token", "/logout.do?redirect=" + redirectUrl);
|
return logoutUri != null ? logoutUri : tokenUri.replace("/oauth/token",
|
||||||
|
"/logout.do?redirect=" + redirectUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supports(Class<?> clazz) {
|
public boolean supports(Class<?> clazz) {
|
||||||
return CloudfoundrySsoProperties.class.isAssignableFrom(clazz);
|
return OAuth2SsoProperties.class.isAssignableFrom(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validate(Object target, Errors errors) {
|
public void validate(Object target, Errors errors) {
|
||||||
CloudfoundrySsoProperties sso = (CloudfoundrySsoProperties) target;
|
OAuth2SsoProperties sso = (OAuth2SsoProperties) target;
|
||||||
if (StringUtils.hasText(sso.getClientId())) {
|
if (StringUtils.hasText(sso.getClientId())) {
|
||||||
if (!StringUtils.hasText(sso.getAuthorizationUri())) {
|
if (!StringUtils.hasText(sso.getAuthorizationUri())) {
|
||||||
errors.rejectValue("authorizeUri", "missing.authorizeUri",
|
errors.rejectValue("authorizeUri", "missing.authorizeUri",
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
org.springframework.cloud.cloudfoundry.broker.configuration.ServiceBrokerAutoConfiguration,\
|
org.springframework.cloud.cloudfoundry.broker.configuration.ServiceBrokerAutoConfiguration,\
|
||||||
org.springframework.cloud.cloudfoundry.proxy.CloudfoundryProxyConfiguration
|
org.springframework.cloud.cloudfoundry.proxy.OAuth2ProxyAutoConfiguration
|
||||||
@@ -15,15 +15,25 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.cloud.cloudfoundry.broker.sample;
|
package org.springframework.cloud.cloudfoundry.broker.sample;
|
||||||
|
|
||||||
|
import java.security.Principal;
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.cloud.cloudfoundry.sso.EnableCloudfoundrySso;
|
import org.springframework.cloud.cloudfoundry.sso.EnableOAuth2Sso;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableAutoConfiguration
|
@EnableAutoConfiguration
|
||||||
@EnableCloudfoundrySso
|
@EnableOAuth2Sso
|
||||||
|
@RestController
|
||||||
public class Application {
|
public class Application {
|
||||||
|
|
||||||
|
@RequestMapping("/")
|
||||||
|
public Principal home(Principal principal) {
|
||||||
|
return principal;
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(Application.class, args);
|
SpringApplication.run(Application.class, args);
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
debug: true
|
debug: true
|
||||||
server:
|
server:
|
||||||
port: 8787
|
port: 8080
|
||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: eureka
|
name: eureka
|
||||||
management:
|
management:
|
||||||
context-path: /admin
|
context-path: /admin
|
||||||
cloudfoundry:
|
eureka:
|
||||||
|
server:
|
||||||
|
enabled: false
|
||||||
|
oauth2:
|
||||||
sso:
|
sso:
|
||||||
tokenUri: http://localhost:8080/uaa/oauth/token
|
tokenUri: http://localhost:8080/uaa/oauth/token
|
||||||
authorizationUri: http://localhost:8080/uaa/oauth/authorize
|
authorizationUri: http://localhost:8080/uaa/oauth/authorize
|
||||||
@@ -16,12 +19,19 @@ logging:
|
|||||||
level:
|
level:
|
||||||
com.netflix.discovery: 'OFF'
|
com.netflix.discovery: 'OFF'
|
||||||
org.springframework.security: DEBUG
|
org.springframework.security: DEBUG
|
||||||
eureka:
|
|
||||||
server:
|
---
|
||||||
waitTimeInMsWhenSyncEmpty: 1000
|
spring:
|
||||||
client:
|
profiles: github
|
||||||
serviceUrl:
|
oauth2:
|
||||||
defaultZone: http://localhost:8787/v2/
|
sso:
|
||||||
default.defaultZone: http://localhost:8787/v2/
|
tokenUri: https://github.com/login/oauth/access_token
|
||||||
registerWithEureka: false
|
authorizationUri: https://github.com/login/oauth/authorize
|
||||||
fetchRegistry: false
|
clientId: bd1c0a783ccdd1c9b9e4
|
||||||
|
clientSecret: 1a9030fbca47a5b2c28e92f19050bb77824b5ad1
|
||||||
|
authenticationScheme: form
|
||||||
|
resource:
|
||||||
|
clientId: ${oauth2.sso.clientId}
|
||||||
|
userInfoUri: https://api.github.com/user
|
||||||
|
preferTokenInfo: false
|
||||||
|
|
||||||
Reference in New Issue
Block a user