Skip to content

Commit 9c97970

Browse files
committed
Add Jwt Client Authentication support
Closes spring-projectsgh-8175
1 parent 224160f commit 9c97970

File tree

36 files changed

+3388
-433
lines changed

36 files changed

+3388
-433
lines changed

etc/checkstyle/checkstyle-suppressions.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,5 @@
4949
<suppress files="WebSocketMessageBrokerConfigTests\.java" checks="SpringMethodVisibility"/>
5050
<suppress files="WebSecurityConfigurationTests\.java" checks="SpringMethodVisibility"/>
5151
<suppress files="WithSecurityContextTestExecutionListenerTests\.java" checks="SpringMethodVisibility"/>
52+
<suppress files="AbstractOAuth2AuthorizationGrantRequestEntityConverter\.java" checks="SpringMethodVisibility"/>
5253
</suppressions>

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/AbstractOAuth2AuthorizationGrantRequest.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.security.oauth2.client.endpoint;
1818

19+
import org.springframework.security.oauth2.client.registration.ClientRegistration;
1920
import org.springframework.security.oauth2.core.AuthorizationGrantType;
2021
import org.springframework.util.Assert;
2122

@@ -27,20 +28,42 @@
2728
* @author Joe Grandja
2829
* @since 5.0
2930
* @see AuthorizationGrantType
31+
* @see ClientRegistration
3032
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-1.3">Section
3133
* 1.3 Authorization Grant</a>
3234
*/
3335
public abstract class AbstractOAuth2AuthorizationGrantRequest {
3436

3537
private final AuthorizationGrantType authorizationGrantType;
3638

39+
private final ClientRegistration clientRegistration;
40+
3741
/**
3842
* Sub-class constructor.
3943
* @param authorizationGrantType the authorization grant type
44+
* @deprecated Use
45+
* {@link #AbstractOAuth2AuthorizationGrantRequest(AuthorizationGrantType, ClientRegistration)}
46+
* instead
4047
*/
48+
@Deprecated
4149
protected AbstractOAuth2AuthorizationGrantRequest(AuthorizationGrantType authorizationGrantType) {
4250
Assert.notNull(authorizationGrantType, "authorizationGrantType cannot be null");
4351
this.authorizationGrantType = authorizationGrantType;
52+
this.clientRegistration = null;
53+
}
54+
55+
/**
56+
* Sub-class constructor.
57+
* @param authorizationGrantType the authorization grant type
58+
* @param clientRegistration the client registration
59+
* @since 5.5
60+
*/
61+
protected AbstractOAuth2AuthorizationGrantRequest(AuthorizationGrantType authorizationGrantType,
62+
ClientRegistration clientRegistration) {
63+
Assert.notNull(authorizationGrantType, "authorizationGrantType cannot be null");
64+
Assert.notNull(clientRegistration, "clientRegistration cannot be null");
65+
this.authorizationGrantType = authorizationGrantType;
66+
this.clientRegistration = clientRegistration;
4467
}
4568

4669
/**
@@ -51,4 +74,13 @@ public AuthorizationGrantType getGrantType() {
5174
return this.authorizationGrantType;
5275
}
5376

77+
/**
78+
* Returns the {@link ClientRegistration client registration}.
79+
* @return the {@link ClientRegistration}
80+
* @since 5.5
81+
*/
82+
public ClientRegistration getClientRegistration() {
83+
return this.clientRegistration;
84+
}
85+
5486
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
/*
2+
* Copyright 2002-2021 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+
* https://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+
17+
package org.springframework.security.oauth2.client.endpoint;
18+
19+
import java.net.URI;
20+
21+
import org.springframework.core.convert.converter.Converter;
22+
import org.springframework.http.HttpHeaders;
23+
import org.springframework.http.HttpMethod;
24+
import org.springframework.http.RequestEntity;
25+
import org.springframework.util.Assert;
26+
import org.springframework.util.LinkedMultiValueMap;
27+
import org.springframework.util.MultiValueMap;
28+
import org.springframework.web.util.UriComponentsBuilder;
29+
30+
/**
31+
* Base implementation of a {@link Converter} that converts the provided
32+
* {@link AbstractOAuth2AuthorizationGrantRequest} instance to a {@link RequestEntity}
33+
* representation of an OAuth 2.0 Access Token Request for the Authorization Grant.
34+
*
35+
* @param <T> the type of {@link AbstractOAuth2AuthorizationGrantRequest}
36+
* @author Joe Grandja
37+
* @since 5.5
38+
* @see Converter
39+
* @see AbstractOAuth2AuthorizationGrantRequest
40+
* @see RequestEntity
41+
*/
42+
abstract class AbstractOAuth2AuthorizationGrantRequestEntityConverter<T extends AbstractOAuth2AuthorizationGrantRequest>
43+
implements Converter<T, RequestEntity<?>> {
44+
45+
// @formatter:off
46+
private Converter<T, HttpHeaders> headersConverter =
47+
(authorizationGrantRequest) -> OAuth2AuthorizationGrantRequestEntityUtils
48+
.getTokenRequestHeaders(authorizationGrantRequest.getClientRegistration());
49+
// @formatter:on
50+
51+
private Converter<T, MultiValueMap<String, String>> parametersConverter = this::createParameters;
52+
53+
@Override
54+
public RequestEntity<?> convert(T authorizationGrantRequest) {
55+
HttpHeaders headers = getHeadersConverter().convert(authorizationGrantRequest);
56+
MultiValueMap<String, String> parameters = getParametersConverter().convert(authorizationGrantRequest);
57+
URI uri = UriComponentsBuilder
58+
.fromUriString(authorizationGrantRequest.getClientRegistration().getProviderDetails().getTokenUri())
59+
.build().toUri();
60+
return new RequestEntity<>(parameters, headers, HttpMethod.POST, uri);
61+
}
62+
63+
/**
64+
* Returns a {@link MultiValueMap} of the parameters used in the OAuth 2.0 Access
65+
* Token Request body.
66+
* @param authorizationGrantRequest the authorization grant request
67+
* @return a {@link MultiValueMap} of the parameters used in the OAuth 2.0 Access
68+
* Token Request body
69+
*/
70+
abstract MultiValueMap<String, String> createParameters(T authorizationGrantRequest);
71+
72+
/**
73+
* Returns the {@link Converter} used for converting the
74+
* {@link AbstractOAuth2AuthorizationGrantRequest} instance to a {@link HttpHeaders}
75+
* used in the OAuth 2.0 Access Token Request headers.
76+
* @return the {@link Converter} used for converting the
77+
* {@link OAuth2AuthorizationCodeGrantRequest} to {@link HttpHeaders}
78+
*/
79+
final Converter<T, HttpHeaders> getHeadersConverter() {
80+
return this.headersConverter;
81+
}
82+
83+
/**
84+
* Sets the {@link Converter} used for converting the
85+
* {@link AbstractOAuth2AuthorizationGrantRequest} instance to a {@link HttpHeaders}
86+
* used in the OAuth 2.0 Access Token Request headers.
87+
* @param headersConverter the {@link Converter} used for converting the
88+
* {@link OAuth2AuthorizationCodeGrantRequest} to {@link HttpHeaders}
89+
*/
90+
public final void setHeadersConverter(Converter<T, HttpHeaders> headersConverter) {
91+
Assert.notNull(headersConverter, "headersConverter cannot be null");
92+
this.headersConverter = headersConverter;
93+
}
94+
95+
/**
96+
* Add (compose) the provided {@code headersConverter} to the current
97+
* {@link Converter} used for converting the
98+
* {@link AbstractOAuth2AuthorizationGrantRequest} instance to a {@link HttpHeaders}
99+
* used in the OAuth 2.0 Access Token Request headers.
100+
* @param headersConverter the {@link Converter} to add (compose) to the current
101+
* {@link Converter} used for converting the
102+
* {@link OAuth2AuthorizationCodeGrantRequest} to a {@link HttpHeaders}
103+
*/
104+
public final void addHeadersConverter(Converter<T, HttpHeaders> headersConverter) {
105+
Assert.notNull(headersConverter, "headersConverter cannot be null");
106+
Converter<T, HttpHeaders> currentHeadersConverter = this.headersConverter;
107+
this.headersConverter = (authorizationGrantRequest) -> {
108+
// Append headers using a Composite Converter
109+
HttpHeaders headers = currentHeadersConverter.convert(authorizationGrantRequest);
110+
if (headers == null) {
111+
headers = new HttpHeaders();
112+
}
113+
HttpHeaders headersToAdd = headersConverter.convert(authorizationGrantRequest);
114+
if (headersToAdd != null) {
115+
headers.addAll(headersToAdd);
116+
}
117+
return headers;
118+
};
119+
}
120+
121+
/**
122+
* Returns the {@link Converter} used for converting the
123+
* {@link AbstractOAuth2AuthorizationGrantRequest} instance to a {@link MultiValueMap}
124+
* of the parameters used in the OAuth 2.0 Access Token Request body.
125+
* @return the {@link Converter} used for converting the
126+
* {@link OAuth2AuthorizationCodeGrantRequest} to a {@link MultiValueMap} of the
127+
* parameters
128+
*/
129+
final Converter<T, MultiValueMap<String, String>> getParametersConverter() {
130+
return this.parametersConverter;
131+
}
132+
133+
/**
134+
* Sets the {@link Converter} used for converting the
135+
* {@link AbstractOAuth2AuthorizationGrantRequest} instance to a {@link MultiValueMap}
136+
* of the parameters used in the OAuth 2.0 Access Token Request body.
137+
* @param parametersConverter the {@link Converter} used for converting the
138+
* {@link OAuth2AuthorizationCodeGrantRequest} to a {@link MultiValueMap} of the
139+
* parameters
140+
*/
141+
public final void setParametersConverter(Converter<T, MultiValueMap<String, String>> parametersConverter) {
142+
Assert.notNull(parametersConverter, "parametersConverter cannot be null");
143+
this.parametersConverter = parametersConverter;
144+
}
145+
146+
/**
147+
* Add (compose) the provided {@code parametersConverter} to the current
148+
* {@link Converter} used for converting the
149+
* {@link AbstractOAuth2AuthorizationGrantRequest} instance to a {@link MultiValueMap}
150+
* of the parameters used in the OAuth 2.0 Access Token Request body.
151+
* @param parametersConverter the {@link Converter} to add (compose) to the current
152+
* {@link Converter} used for converting the
153+
* {@link OAuth2AuthorizationCodeGrantRequest} to a {@link MultiValueMap} of the
154+
* parameters
155+
*/
156+
public final void addParametersConverter(Converter<T, MultiValueMap<String, String>> parametersConverter) {
157+
Assert.notNull(parametersConverter, "parametersConverter cannot be null");
158+
Converter<T, MultiValueMap<String, String>> currentParametersConverter = this.parametersConverter;
159+
this.parametersConverter = (authorizationGrantRequest) -> {
160+
// Append parameters using a Composite Converter
161+
MultiValueMap<String, String> parameters = currentParametersConverter.convert(authorizationGrantRequest);
162+
if (parameters == null) {
163+
parameters = new LinkedMultiValueMap<>();
164+
}
165+
MultiValueMap<String, String> parametersToAdd = parametersConverter.convert(authorizationGrantRequest);
166+
if (parametersToAdd != null) {
167+
parameters.addAll(parametersToAdd);
168+
}
169+
return parameters;
170+
};
171+
}
172+
173+
}

0 commit comments

Comments
 (0)