Skip to content

Commit 505882c

Browse files
ThomasVitalejzheaux
authored andcommitted
Consolidate shared code between JwtDecoders and ReactiveJwtDecoders
Extract duplicated code from JwtDecoders and ReactiveJwtDecoders into a package-private class. Fixes gh-7263
1 parent 742c971 commit 505882c

File tree

3 files changed

+125
-124
lines changed

3 files changed

+125
-124
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright 2002-2019 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+
package org.springframework.security.oauth2.jwt;
17+
18+
import org.springframework.core.ParameterizedTypeReference;
19+
import org.springframework.http.RequestEntity;
20+
import org.springframework.http.ResponseEntity;
21+
import org.springframework.web.client.HttpClientErrorException;
22+
import org.springframework.web.client.RestTemplate;
23+
import org.springframework.web.util.UriComponentsBuilder;
24+
25+
import java.net.URI;
26+
import java.util.Collections;
27+
import java.util.Map;
28+
29+
/**
30+
* Allows resolving configuration from an
31+
* <a href="https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig">OpenID Provider Configuration</a> or
32+
* <a href="https://tools.ietf.org/html/rfc8414#section-3.1">Authorization Server Metadata Request</a> based on provided
33+
* issuer and method invoked.
34+
*
35+
* @author Thomas Vitale
36+
* @since 5.2
37+
*/
38+
class JwtDecoderProviderConfigurationUtils {
39+
private static final String OIDC_METADATA_PATH = "/.well-known/openid-configuration";
40+
private static final String OAUTH_METADATA_PATH = "/.well-known/oauth-authorization-server";
41+
private static final RestTemplate rest = new RestTemplate();
42+
private static final ParameterizedTypeReference<Map<String, Object>> typeReference =
43+
new ParameterizedTypeReference<Map<String, Object>>() {};
44+
45+
static Map<String, Object> getConfigurationForOidcIssuerLocation(String oidcIssuerLocation) {
46+
return getConfiguration(oidcIssuerLocation, oidc(URI.create(oidcIssuerLocation)));
47+
}
48+
49+
static Map<String, Object> getConfigurationForIssuerLocation(String issuer) {
50+
URI uri = URI.create(issuer);
51+
return getConfiguration(issuer, oidc(uri), oidcRfc8414(uri), oauth(uri));
52+
}
53+
54+
static void validateIssuer(Map<String, Object> configuration, String issuer) {
55+
String metadataIssuer = "(unavailable)";
56+
if (configuration.containsKey("issuer")) {
57+
metadataIssuer = configuration.get("issuer").toString();
58+
}
59+
if (!issuer.equals(metadataIssuer)) {
60+
throw new IllegalStateException("The Issuer \"" + metadataIssuer + "\" provided in the configuration did not "
61+
+ "match the requested issuer \"" + issuer + "\"");
62+
}
63+
}
64+
65+
private static Map<String, Object> getConfiguration(String issuer, URI... uris) {
66+
String errorMessage = "Unable to resolve the Configuration with the provided Issuer of " +
67+
"\"" + issuer + "\"";
68+
for (URI uri : uris) {
69+
try {
70+
RequestEntity<Void> request = RequestEntity.get(uri).build();
71+
ResponseEntity<Map<String, Object>> response = rest.exchange(request, typeReference);
72+
return response.getBody();
73+
} catch (RuntimeException e) {
74+
if (!(e instanceof HttpClientErrorException &&
75+
((HttpClientErrorException) e).getStatusCode().is4xxClientError())) {
76+
throw new IllegalArgumentException(errorMessage, e);
77+
}
78+
// else try another endpoint
79+
}
80+
}
81+
throw new IllegalArgumentException(errorMessage);
82+
}
83+
84+
private static URI oidc(URI issuer) {
85+
return UriComponentsBuilder.fromUri(issuer)
86+
.replacePath(issuer.getPath() + OIDC_METADATA_PATH)
87+
.build(Collections.emptyMap());
88+
}
89+
90+
private static URI oidcRfc8414(URI issuer) {
91+
return UriComponentsBuilder.fromUri(issuer)
92+
.replacePath(OIDC_METADATA_PATH + issuer.getPath())
93+
.build(Collections.emptyMap());
94+
}
95+
96+
private static URI oauth(URI issuer) {
97+
return UriComponentsBuilder.fromUri(issuer)
98+
.replacePath(OAUTH_METADATA_PATH + issuer.getPath())
99+
.build(Collections.emptyMap());
100+
}
101+
}

oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/JwtDecoders.java

+6-62
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,10 @@
1515
*/
1616
package org.springframework.security.oauth2.jwt;
1717

18-
import java.net.URI;
19-
import java.util.Collections;
2018
import java.util.Map;
2119

22-
import org.springframework.core.ParameterizedTypeReference;
23-
import org.springframework.http.RequestEntity;
24-
import org.springframework.http.ResponseEntity;
2520
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
2621
import org.springframework.util.Assert;
27-
import org.springframework.web.client.HttpClientErrorException;
28-
import org.springframework.web.client.RestTemplate;
29-
import org.springframework.web.util.UriComponentsBuilder;
3022

3123
import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withJwkSetUri;
3224

@@ -41,11 +33,6 @@
4133
* @since 5.1
4234
*/
4335
public final class JwtDecoders {
44-
private static final String OIDC_METADATA_PATH = "/.well-known/openid-configuration";
45-
private static final String OAUTH_METADATA_PATH = "/.well-known/oauth-authorization-server";
46-
private static final RestTemplate rest = new RestTemplate();
47-
private static final ParameterizedTypeReference<Map<String, Object>> typeReference =
48-
new ParameterizedTypeReference<Map<String, Object>>() {};
4936

5037
/**
5138
* Creates a {@link JwtDecoder} using the provided
@@ -60,7 +47,7 @@ public final class JwtDecoders {
6047
*/
6148
public static JwtDecoder fromOidcIssuerLocation(String oidcIssuerLocation) {
6249
Assert.hasText(oidcIssuerLocation, "oidcIssuerLocation cannot be empty");
63-
Map<String, Object> configuration = getConfiguration(oidcIssuerLocation, oidc(URI.create(oidcIssuerLocation)));
50+
Map<String, Object> configuration = JwtDecoderProviderConfigurationUtils.getConfigurationForOidcIssuerLocation(oidcIssuerLocation);
6451
return withProviderConfiguration(configuration, oidcIssuerLocation);
6552
}
6653

@@ -93,70 +80,27 @@ public static JwtDecoder fromOidcIssuerLocation(String oidcIssuerLocation) {
9380
* Note that the second endpoint is the equivalent of calling
9481
* {@link JwtDecoders#fromOidcIssuerLocation(String)}
9582
*
96-
* @param issuer
83+
* @param issuer the <a href="https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier">Issuer</a>
9784
* @return a {@link JwtDecoder} that was initialized by one of the described endpoints
9885
*/
9986
public static JwtDecoder fromIssuerLocation(String issuer) {
10087
Assert.hasText(issuer, "issuer cannot be empty");
101-
URI uri = URI.create(issuer);
102-
Map<String, Object> configuration = getConfiguration(issuer, oidc(uri), oidcRfc8414(uri), oauth(uri));
88+
Map<String, Object> configuration = JwtDecoderProviderConfigurationUtils.getConfigurationForIssuerLocation(issuer);
10389
return withProviderConfiguration(configuration, issuer);
10490
}
10591

106-
private static URI oidc(URI issuer) {
107-
return UriComponentsBuilder.fromUri(issuer)
108-
.replacePath(issuer.getPath() + OIDC_METADATA_PATH).build(Collections.emptyMap());
109-
}
110-
111-
private static URI oidcRfc8414(URI issuer) {
112-
return UriComponentsBuilder.fromUri(issuer)
113-
.replacePath(OIDC_METADATA_PATH + issuer.getPath()).build(Collections.emptyMap());
114-
}
115-
116-
private static URI oauth(URI issuer) {
117-
return UriComponentsBuilder.fromUri(issuer)
118-
.replacePath(OAUTH_METADATA_PATH + issuer.getPath()).build(Collections.emptyMap());
119-
}
120-
121-
private static Map<String, Object> getConfiguration(String issuer, URI... uris) {
122-
String errorMessage = "Unable to resolve the Configuration with the provided Issuer of " +
123-
"\"" + issuer + "\"";
124-
for (URI uri : uris) {
125-
try {
126-
RequestEntity<Void> request = RequestEntity.get(uri).build();
127-
ResponseEntity<Map<String, Object>> response = rest.exchange(request, typeReference);
128-
return response.getBody();
129-
} catch (RuntimeException e) {
130-
if (!(e instanceof HttpClientErrorException &&
131-
((HttpClientErrorException) e).getStatusCode().is4xxClientError())) {
132-
throw new IllegalArgumentException(errorMessage, e);
133-
}
134-
// else try another endpoint
135-
}
136-
}
137-
throw new IllegalArgumentException(errorMessage);
138-
}
139-
14092
/**
14193
* Validate provided issuer and build {@link JwtDecoder} from
14294
* <a href="https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse">OpenID Provider
14395
* Configuration Response</a> and <a href="https://tools.ietf.org/html/rfc8414#section-3.2">Authorization Server Metadata
14496
* Response</a>.
14597
*
146-
* @param configuration
147-
* @param issuer
98+
* @param configuration the configuration values
99+
* @param issuer the <a href="https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier">Issuer</a>
148100
* @return {@link JwtDecoder}
149101
*/
150102
private static JwtDecoder withProviderConfiguration(Map<String, Object> configuration, String issuer) {
151-
String metadataIssuer = "(unavailable)";
152-
if (configuration.containsKey("issuer")) {
153-
metadataIssuer = configuration.get("issuer").toString();
154-
}
155-
if (!issuer.equals(metadataIssuer)) {
156-
throw new IllegalStateException("The Issuer \"" + metadataIssuer + "\" provided in the configuration did not "
157-
+ "match the requested issuer \"" + issuer + "\"");
158-
}
159-
103+
JwtDecoderProviderConfigurationUtils.validateIssuer(configuration, issuer);
160104
OAuth2TokenValidator<Jwt> jwtValidator = JwtValidators.createDefaultWithIssuer(issuer);
161105
NimbusJwtDecoder jwtDecoder = withJwkSetUri(configuration.get("jwks_uri").toString()).build();
162106
jwtDecoder.setJwtValidator(jwtValidator);

oauth2/oauth2-jose/src/main/java/org/springframework/security/oauth2/jwt/ReactiveJwtDecoders.java

+18-62
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 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.
@@ -15,34 +15,23 @@
1515
*/
1616
package org.springframework.security.oauth2.jwt;
1717

18-
import java.net.URI;
19-
import java.util.Collections;
2018
import java.util.Map;
2119

22-
import org.springframework.core.ParameterizedTypeReference;
23-
import org.springframework.http.RequestEntity;
24-
import org.springframework.http.ResponseEntity;
2520
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
2621
import org.springframework.util.Assert;
27-
import org.springframework.web.client.HttpClientErrorException;
28-
import org.springframework.web.client.RestTemplate;
29-
import org.springframework.web.util.UriComponentsBuilder;
3022

3123
import static org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder.withJwkSetUri;
3224

3325
/**
3426
* Allows creating a {@link ReactiveJwtDecoder} from an
35-
* <a href="https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig">OpenID Provider Configuration</a>.
27+
* <a href="https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig">OpenID Provider Configuration</a> or
28+
* <a href="https://tools.ietf.org/html/rfc8414#section-3.1">Authorization Server Metadata Request</a> based on provided
29+
* issuer and method invoked.
3630
*
3731
* @author Josh Cummings
3832
* @since 5.1
3933
*/
4034
public final class ReactiveJwtDecoders {
41-
private static final String OIDC_METADATA_PATH = "/.well-known/openid-configuration";
42-
private static final String OAUTH_METADATA_PATH = "/.well-known/oauth-authorization-server";
43-
private static final RestTemplate rest = new RestTemplate();
44-
private static final ParameterizedTypeReference<Map<String, Object>> typeReference =
45-
new ParameterizedTypeReference<Map<String, Object>>() {};
4635

4736
/**
4837
* Creates a {@link ReactiveJwtDecoder} using the provided
@@ -57,7 +46,7 @@ public final class ReactiveJwtDecoders {
5746
*/
5847
public static ReactiveJwtDecoder fromOidcIssuerLocation(String oidcIssuerLocation) {
5948
Assert.hasText(oidcIssuerLocation, "oidcIssuerLocation cannot be empty");
60-
Map<String, Object> configuration = getConfiguration(oidcIssuerLocation, oidc(URI.create(oidcIssuerLocation)));
49+
Map<String, Object> configuration = JwtDecoderProviderConfigurationUtils.getConfigurationForOidcIssuerLocation(oidcIssuerLocation);
6150
return withProviderConfiguration(configuration, oidcIssuerLocation);
6251
}
6352

@@ -90,60 +79,27 @@ public static ReactiveJwtDecoder fromOidcIssuerLocation(String oidcIssuerLocatio
9079
* Note that the second endpoint is the equivalent of calling
9180
* {@link ReactiveJwtDecoders#fromOidcIssuerLocation(String)}
9281
*
93-
* @param issuer
82+
* @param issuer the <a href="https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier">Issuer</a>
9483
* @return a {@link ReactiveJwtDecoder} that was initialized by one of the described endpoints
9584
*/
9685
public static ReactiveJwtDecoder fromIssuerLocation(String issuer) {
9786
Assert.hasText(issuer, "issuer cannot be empty");
98-
URI uri = URI.create(issuer);
99-
Map<String, Object> configuration = getConfiguration(issuer, oidc(uri), oidcRfc8414(uri), oauth(uri));
87+
Map<String, Object> configuration = JwtDecoderProviderConfigurationUtils.getConfigurationForIssuerLocation(issuer);
10088
return withProviderConfiguration(configuration, issuer);
10189
}
10290

103-
private static URI oidc(URI issuer) {
104-
return UriComponentsBuilder.fromUri(issuer)
105-
.replacePath(issuer.getPath() + OIDC_METADATA_PATH).build(Collections.emptyMap());
106-
}
107-
108-
private static URI oidcRfc8414(URI issuer) {
109-
return UriComponentsBuilder.fromUri(issuer)
110-
.replacePath(OIDC_METADATA_PATH + issuer.getPath()).build(Collections.emptyMap());
111-
}
112-
113-
private static URI oauth(URI issuer) {
114-
return UriComponentsBuilder.fromUri(issuer)
115-
.replacePath(OAUTH_METADATA_PATH + issuer.getPath()).build(Collections.emptyMap());
116-
}
117-
118-
private static Map<String, Object> getConfiguration(String issuer, URI... uris) {
119-
String errorMessage = "Unable to resolve the Configuration with the provided Issuer of " +
120-
"\"" + issuer + "\"";
121-
for (URI uri : uris) {
122-
try {
123-
RequestEntity<Void> request = RequestEntity.get(uri).build();
124-
ResponseEntity<Map<String, Object>> response = rest.exchange(request, typeReference);
125-
return response.getBody();
126-
} catch (RuntimeException e) {
127-
if (!(e instanceof HttpClientErrorException &&
128-
((HttpClientErrorException) e).getStatusCode().is4xxClientError())) {
129-
throw new IllegalArgumentException(errorMessage, e);
130-
}
131-
// else try another endpoint
132-
}
133-
}
134-
throw new IllegalArgumentException(errorMessage);
135-
}
136-
91+
/**
92+
* Build {@link ReactiveJwtDecoder} from
93+
* <a href="https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse">OpenID Provider
94+
* Configuration Response</a> and <a href="https://tools.ietf.org/html/rfc8414#section-3.2">Authorization Server Metadata
95+
* Response</a>.
96+
*
97+
* @param configuration the configuration values
98+
* @param issuer the <a href="https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier">Issuer</a>
99+
* @return {@link ReactiveJwtDecoder}
100+
*/
137101
private static ReactiveJwtDecoder withProviderConfiguration(Map<String, Object> configuration, String issuer) {
138-
String metadataIssuer = "(unavailable)";
139-
if (configuration.containsKey("issuer")) {
140-
metadataIssuer = configuration.get("issuer").toString();
141-
}
142-
if (!issuer.equals(metadataIssuer)) {
143-
throw new IllegalStateException("The Issuer \"" + metadataIssuer + "\" provided in the configuration did not "
144-
+ "match the requested issuer \"" + issuer + "\"");
145-
}
146-
102+
JwtDecoderProviderConfigurationUtils.validateIssuer(configuration, issuer);
147103
OAuth2TokenValidator<Jwt> jwtValidator = JwtValidators.createDefaultWithIssuer(issuer);
148104
NimbusReactiveJwtDecoder jwtDecoder = withJwkSetUri(configuration.get("jwks_uri").toString()).build();
149105
jwtDecoder.setJwtValidator(jwtValidator);

0 commit comments

Comments
 (0)