Skip to content

Commit af320b4

Browse files
author
Dave Syer
committed
Rationalize some features and merge in customizers from Spring Cloud
1 parent 5468949 commit af320b4

File tree

14 files changed

+502
-161
lines changed

14 files changed

+502
-161
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/client/SpringSecurityOAuth2ClientConfiguration.java

Lines changed: 97 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@
1515
*/
1616
package org.springframework.boot.autoconfigure.security.oauth2.client;
1717

18-
import java.io.IOException;
19-
import java.util.Arrays;
20-
2118
import javax.annotation.PostConstruct;
2219
import javax.annotation.Resource;
2320

@@ -27,6 +24,10 @@
2724
import org.springframework.beans.factory.annotation.Qualifier;
2825
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
2926
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
27+
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
28+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
29+
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication;
30+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
3031
import org.springframework.boot.autoconfigure.security.oauth2.ClientCredentialsProperties;
3132
import org.springframework.boot.context.embedded.FilterRegistrationBean;
3233
import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -35,110 +36,142 @@
3536
import org.springframework.context.annotation.Primary;
3637
import org.springframework.context.annotation.Scope;
3738
import org.springframework.context.annotation.ScopedProxyMode;
38-
import org.springframework.http.HttpHeaders;
39-
import org.springframework.http.HttpRequest;
40-
import org.springframework.http.MediaType;
41-
import org.springframework.http.client.ClientHttpRequestExecution;
42-
import org.springframework.http.client.ClientHttpRequestInterceptor;
43-
import org.springframework.http.client.ClientHttpResponse;
39+
import org.springframework.security.core.Authentication;
40+
import org.springframework.security.core.context.SecurityContextHolder;
4441
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
4542
import org.springframework.security.oauth2.client.OAuth2ClientContext;
46-
import org.springframework.security.oauth2.client.OAuth2RestOperations;
4743
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
4844
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter;
4945
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
5046
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
51-
import org.springframework.security.oauth2.client.token.RequestEnhancer;
52-
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
47+
import org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest;
48+
import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
5349
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
50+
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
5451
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
5552
import org.springframework.security.oauth2.config.annotation.web.configuration.OAuth2ClientConfiguration;
56-
import org.springframework.util.MultiValueMap;
53+
import org.springframework.security.oauth2.provider.OAuth2Authentication;
54+
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
5755

5856
/**
5957
* @author Dave Syer
6058
*
6159
*/
6260
@Configuration
6361
@ConditionalOnClass(EnableOAuth2Client.class)
64-
@ConditionalOnBean(OAuth2ClientConfiguration.class)
62+
@ConditionalOnExpression("'${spring.oauth2.client.clientId:}'!=''")
6563
public class SpringSecurityOAuth2ClientConfiguration {
6664

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

68+
@Autowired
69+
private ClientCredentialsProperties credentials;
70+
71+
@PostConstruct
72+
public void init() {
73+
String prefix = "spring.oauth2.client";
74+
boolean defaultSecret = this.credentials.isDefaultSecret();
75+
logger.info(String.format(
76+
"Initialized OAuth2 Client\n\n%s.clientId = %s\n%s.secret = %s\n\n",
77+
prefix, this.credentials.getClientId(), prefix,
78+
defaultSecret ? this.credentials.getClientSecret() : "****"));
79+
}
80+
81+
@Bean
82+
@Primary
83+
public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext oauth2ClientContext,
84+
OAuth2ProtectedResourceDetails details) {
85+
OAuth2RestTemplate template = new OAuth2RestTemplate(details, oauth2ClientContext);
86+
return template;
87+
}
88+
7089
@Configuration
71-
public static class ClientAuthenticationFilterConfiguration {
90+
protected abstract static class BaseConfiguration {
7291

73-
@Resource
74-
@Qualifier("accessTokenRequest")
75-
private AccessTokenRequest accessTokenRequest;
76-
77-
@Autowired
78-
private ClientCredentialsProperties credentials;
79-
80-
@PostConstruct
81-
public void init() {
82-
String prefix = "spring.oauth2.client";
83-
boolean defaultSecret = this.credentials.isDefaultSecret();
84-
logger.info(String.format(
85-
"Initialized OAuth2 Client\n\n%s.clientId = %s\n%s.secret = %s\n\n",
86-
prefix, this.credentials.getClientId(), prefix,
87-
defaultSecret ? this.credentials.getClientSecret() : "****"));
92+
@Bean
93+
@ConfigurationProperties("spring.oauth2.client")
94+
@Primary
95+
public AuthorizationCodeResourceDetails oauth2RemoteResource() {
96+
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
97+
return details;
8898
}
8999

100+
}
101+
102+
@Configuration
103+
@ConditionalOnNotWebApplication
104+
protected static class SingletonScopedConfiguration {
105+
90106
@Bean
91107
@ConfigurationProperties("spring.oauth2.client")
92108
@Primary
93-
public AuthorizationCodeResourceDetails authorizationCodeResourceDetails() {
94-
AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
95-
details.setClientSecret(this.credentials.getClientSecret());
96-
details.setClientId(this.credentials.getClientId());
109+
public ClientCredentialsResourceDetails oauth2RemoteResource() {
110+
ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails();
97111
return details;
98112
}
99113

114+
@Bean
115+
public OAuth2ClientContext oauth2ClientContext() {
116+
return new DefaultOAuth2ClientContext(new DefaultAccessTokenRequest());
117+
}
118+
119+
}
120+
121+
@Configuration
122+
@ConditionalOnBean(OAuth2ClientConfiguration.class)
123+
@ConditionalOnWebApplication
124+
protected static class SessionScopedConfiguration extends BaseConfiguration {
125+
126+
@Resource
127+
@Qualifier("accessTokenRequest")
128+
protected AccessTokenRequest accessTokenRequest;
129+
130+
@Bean
131+
@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
132+
public OAuth2ClientContext oauth2ClientContext() {
133+
return new DefaultOAuth2ClientContext(accessTokenRequest);
134+
}
135+
100136
@Bean
101137
public FilterRegistrationBean oauth2ClientFilterRegistration(
102138
OAuth2ClientContextFilter filter) {
103139
FilterRegistrationBean registration = new FilterRegistrationBean();
104140
registration.setFilter(filter);
105-
registration.setOrder(0);
141+
registration.setOrder(-100);
106142
return registration;
107143
}
108144

109-
@Bean
110-
public OAuth2RestOperations authorizationCodeRestTemplate(
111-
AuthorizationCodeResourceDetails oauth2RemoteResource) {
112-
OAuth2RestTemplate template = new OAuth2RestTemplate(oauth2RemoteResource,
113-
oauth2ClientContext());
114-
template.setInterceptors(Arrays
115-
.<ClientHttpRequestInterceptor> asList(new ClientHttpRequestInterceptor() {
116-
@Override
117-
public ClientHttpResponse intercept(HttpRequest request,
118-
byte[] body, ClientHttpRequestExecution execution)
119-
throws IOException {
120-
request.getHeaders().setAccept(
121-
Arrays.asList(MediaType.APPLICATION_JSON));
122-
return execution.execute(request, body);
123-
}
124-
}));
125-
AuthorizationCodeAccessTokenProvider accessTokenProvider = new AuthorizationCodeAccessTokenProvider();
126-
accessTokenProvider.setTokenRequestEnhancer(new RequestEnhancer() {
127-
@Override
128-
public void enhance(AccessTokenRequest request,
129-
OAuth2ProtectedResourceDetails resource,
130-
MultiValueMap<String, String> form, HttpHeaders headers) {
131-
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
132-
}
133-
});
134-
template.setAccessTokenProvider(accessTokenProvider);
135-
return template;
136-
}
145+
}
146+
147+
/*
148+
* When the authentication is per cookie but the stored token is an oauth2 one, we can
149+
* pass that on to a client that wants to call downstream. We don't even need an
150+
* OAuth2ClientContextFilter until we need to refresh the access token. To handle
151+
* refresh tokens you need to <code>@EnableOAuth2Client</code>
152+
*/
153+
@Configuration
154+
@ConditionalOnMissingBean(OAuth2ClientConfiguration.class)
155+
@ConditionalOnWebApplication
156+
protected static class RequestScopedConfiguration extends BaseConfiguration {
137157

138158
@Bean
139159
@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
140160
public OAuth2ClientContext oauth2ClientContext() {
141-
return new DefaultOAuth2ClientContext(this.accessTokenRequest);
161+
DefaultOAuth2ClientContext context = new DefaultOAuth2ClientContext(
162+
new DefaultAccessTokenRequest());
163+
Authentication principal = SecurityContextHolder.getContext()
164+
.getAuthentication();
165+
if (principal instanceof OAuth2Authentication) {
166+
OAuth2Authentication authentication = (OAuth2Authentication) principal;
167+
Object details = authentication.getDetails();
168+
if (details instanceof OAuth2AuthenticationDetails) {
169+
OAuth2AuthenticationDetails oauthsDetails = (OAuth2AuthenticationDetails) details;
170+
String token = oauthsDetails.getTokenValue();
171+
context.setAccessToken(new DefaultOAuth2AccessToken(token));
172+
}
173+
}
174+
return context;
142175
}
143176

144177
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2013-2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.boot.autoconfigure.security.oauth2.resource;
17+
18+
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
19+
20+
public interface JwtAccessTokenConverterConfigurer {
21+
22+
void configure(JwtAccessTokenConverter converter);
23+
24+
}

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/ResourceServerProperties.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.springframework.beans.factory.BeanFactoryUtils;
2222
import org.springframework.beans.factory.ListableBeanFactory;
2323
import org.springframework.boot.context.properties.ConfigurationProperties;
24+
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
2425
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration;
2526
import org.springframework.util.StringUtils;
2627
import org.springframework.validation.Errors;
@@ -66,6 +67,11 @@ public class ResourceServerProperties implements Validator, BeanFactoryAware {
6667
*/
6768
private boolean preferTokenInfo = true;
6869

70+
/**
71+
* The token type to send when using the userInfoUri.
72+
*/
73+
private String tokenType = DefaultOAuth2AccessToken.BEARER_TYPE;
74+
6975
private Jwt jwt = new Jwt();
7076

7177
public ResourceServerProperties() {
@@ -126,6 +132,14 @@ public void setPreferTokenInfo(boolean preferTokenInfo) {
126132
this.preferTokenInfo = preferTokenInfo;
127133
}
128134

135+
public String getTokenType() {
136+
return tokenType;
137+
}
138+
139+
public void setTokenType(String tokenType) {
140+
this.tokenType = tokenType;
141+
}
142+
129143
public Jwt getJwt() {
130144
return this.jwt;
131145
}

0 commit comments

Comments
 (0)