Skip to content

Commit

Permalink
Rationalize some features and merge in customizers from Spring Cloud
Browse files Browse the repository at this point in the history
  • Loading branch information
dsyer committed May 26, 2015
1 parent 5468949 commit af320b4
Show file tree
Hide file tree
Showing 14 changed files with 502 additions and 161 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@
*/
package org.springframework.boot.autoconfigure.security.oauth2.client;

import java.io.IOException;
import java.util.Arrays;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

Expand All @@ -27,6 +24,10 @@
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.ConditionalOnNotWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.security.oauth2.ClientCredentialsProperties;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
Expand All @@ -35,110 +36,142 @@
import org.springframework.context.annotation.Primary;
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.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
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.DefaultAccessTokenRequest;
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
import org.springframework.security.oauth2.config.annotation.web.configuration.OAuth2ClientConfiguration;
import org.springframework.util.MultiValueMap;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;

/**
* @author Dave Syer
*
*/
@Configuration
@ConditionalOnClass(EnableOAuth2Client.class)
@ConditionalOnBean(OAuth2ClientConfiguration.class)
@ConditionalOnExpression("'${spring.oauth2.client.clientId:}'!=''")
public class SpringSecurityOAuth2ClientConfiguration {

private static final Log logger = LogFactory
.getLog(SpringSecurityOAuth2ClientConfiguration.class);

@Autowired
private ClientCredentialsProperties credentials;

@PostConstruct
public void init() {
String prefix = "spring.oauth2.client";
boolean defaultSecret = this.credentials.isDefaultSecret();
logger.info(String.format(
"Initialized OAuth2 Client\n\n%s.clientId = %s\n%s.secret = %s\n\n",
prefix, this.credentials.getClientId(), prefix,
defaultSecret ? this.credentials.getClientSecret() : "****"));
}

@Bean
@Primary
public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext oauth2ClientContext,
OAuth2ProtectedResourceDetails details) {
OAuth2RestTemplate template = new OAuth2RestTemplate(details, oauth2ClientContext);
return template;
}

@Configuration
public static class ClientAuthenticationFilterConfiguration {
protected abstract static class BaseConfiguration {

@Resource
@Qualifier("accessTokenRequest")
private AccessTokenRequest accessTokenRequest;

@Autowired
private ClientCredentialsProperties credentials;

@PostConstruct
public void init() {
String prefix = "spring.oauth2.client";
boolean defaultSecret = this.credentials.isDefaultSecret();
logger.info(String.format(
"Initialized OAuth2 Client\n\n%s.clientId = %s\n%s.secret = %s\n\n",
prefix, this.credentials.getClientId(), prefix,
defaultSecret ? this.credentials.getClientSecret() : "****"));
@Bean
@ConfigurationProperties("spring.oauth2.client")
@Primary
public AuthorizationCodeResourceDetails oauth2RemoteResource() {
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
return details;
}

}

@Configuration
@ConditionalOnNotWebApplication
protected static class SingletonScopedConfiguration {

@Bean
@ConfigurationProperties("spring.oauth2.client")
@Primary
public AuthorizationCodeResourceDetails authorizationCodeResourceDetails() {
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
details.setClientSecret(this.credentials.getClientSecret());
details.setClientId(this.credentials.getClientId());
public ClientCredentialsResourceDetails oauth2RemoteResource() {
ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails();
return details;
}

@Bean
public OAuth2ClientContext oauth2ClientContext() {
return new DefaultOAuth2ClientContext(new DefaultAccessTokenRequest());
}

}

@Configuration
@ConditionalOnBean(OAuth2ClientConfiguration.class)
@ConditionalOnWebApplication
protected static class SessionScopedConfiguration extends BaseConfiguration {

@Resource
@Qualifier("accessTokenRequest")
protected AccessTokenRequest accessTokenRequest;

@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
public OAuth2ClientContext oauth2ClientContext() {
return new DefaultOAuth2ClientContext(accessTokenRequest);
}

@Bean
public FilterRegistrationBean oauth2ClientFilterRegistration(
OAuth2ClientContextFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(filter);
registration.setOrder(0);
registration.setOrder(-100);
return registration;
}

@Bean
public OAuth2RestOperations authorizationCodeRestTemplate(
AuthorizationCodeResourceDetails oauth2RemoteResource) {
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;
}
}

/*
* When the authentication is per cookie but the stored token is an oauth2 one, we can
* pass that on to a client that wants to call downstream. We don't even need an
* OAuth2ClientContextFilter until we need to refresh the access token. To handle
* refresh tokens you need to <code>@EnableOAuth2Client</code>
*/
@Configuration
@ConditionalOnMissingBean(OAuth2ClientConfiguration.class)
@ConditionalOnWebApplication
protected static class RequestScopedConfiguration extends BaseConfiguration {

@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
public OAuth2ClientContext oauth2ClientContext() {
return new DefaultOAuth2ClientContext(this.accessTokenRequest);
DefaultOAuth2ClientContext context = new DefaultOAuth2ClientContext(
new DefaultAccessTokenRequest());
Authentication principal = SecurityContextHolder.getContext()
.getAuthentication();
if (principal instanceof OAuth2Authentication) {
OAuth2Authentication authentication = (OAuth2Authentication) principal;
Object details = authentication.getDetails();
if (details instanceof OAuth2AuthenticationDetails) {
OAuth2AuthenticationDetails oauthsDetails = (OAuth2AuthenticationDetails) details;
String token = oauthsDetails.getTokenValue();
context.setAccessToken(new DefaultOAuth2AccessToken(token));
}
}
return context;
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.security.oauth2.resource;

import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

public interface JwtAccessTokenConverterConfigurer {

void configure(JwtAccessTokenConverter converter);

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
Expand Down Expand Up @@ -66,6 +67,11 @@ public class ResourceServerProperties implements Validator, BeanFactoryAware {
*/
private boolean preferTokenInfo = true;

/**
* The token type to send when using the userInfoUri.
*/
private String tokenType = DefaultOAuth2AccessToken.BEARER_TYPE;

private Jwt jwt = new Jwt();

public ResourceServerProperties() {
Expand Down Expand Up @@ -126,6 +132,14 @@ public void setPreferTokenInfo(boolean preferTokenInfo) {
this.preferTokenInfo = preferTokenInfo;
}

public String getTokenType() {
return tokenType;
}

public void setTokenType(String tokenType) {
this.tokenType = tokenType;
}

public Jwt getJwt() {
return this.jwt;
}
Expand Down
Loading

0 comments on commit af320b4

Please sign in to comment.