Skip to content

Commit 2d4f07f

Browse files
Introduced custom WebClient and RestOperations to ReactiveJwtDecords and JwtDecoders
Signed-off-by: Thiago Locatelli <[email protected]>
1 parent 6f1232c commit 2d4f07f

File tree

2 files changed

+136
-12
lines changed

2 files changed

+136
-12
lines changed

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

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
2222
import org.springframework.util.Assert;
23+
import org.springframework.web.client.RestOperations;
2324

2425
/**
2526
* Allows creating a {@link JwtDecoder} from an <a href=
@@ -52,10 +53,29 @@ private JwtDecoders() {
5253
*/
5354
@SuppressWarnings("unchecked")
5455
public static <T extends JwtDecoder> T fromOidcIssuerLocation(String oidcIssuerLocation) {
56+
return fromOidcIssuerLocation(oidcIssuerLocation, null);
57+
}
58+
59+
/**
60+
* Creates a {@link JwtDecoder} using the provided <a href=
61+
* "https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier">Issuer</a>
62+
* by making an <a href=
63+
* "https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest">OpenID
64+
* Provider Configuration Request</a> and using the values in the <a href=
65+
* "https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse">OpenID
66+
* Provider Configuration Response</a> to initialize the {@link JwtDecoder}.
67+
* @param oidcIssuerLocation the <a href=
68+
* "https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier">Issuer</a>
69+
* @param restOperations customized {@link RestOperations}
70+
* @return a {@link JwtDecoder} that was initialized by the OpenID Provider
71+
* Configuration.
72+
*/
73+
public static <T extends JwtDecoder> T fromOidcIssuerLocation(String oidcIssuerLocation,
74+
RestOperations restOperations) {
5575
Assert.hasText(oidcIssuerLocation, "oidcIssuerLocation cannot be empty");
5676
Map<String, Object> configuration = JwtDecoderProviderConfigurationUtils
5777
.getConfigurationForOidcIssuerLocation(oidcIssuerLocation);
58-
return (T) withProviderConfiguration(configuration, oidcIssuerLocation);
78+
return (T) withProviderConfiguration(configuration, oidcIssuerLocation, restOperations);
5979
}
6080

6181
/**
@@ -88,8 +108,46 @@ public static <T extends JwtDecoder> T fromOidcIssuerLocation(String oidcIssuerL
88108
*/
89109
@SuppressWarnings("unchecked")
90110
public static <T extends JwtDecoder> T fromIssuerLocation(String issuer) {
111+
return fromIssuerLocation(issuer, null);
112+
}
113+
114+
/**
115+
* Creates a {@link JwtDecoder} using the provided <a href=
116+
* "https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier">Issuer</a>
117+
* by querying three different discovery endpoints serially, using the values in the
118+
* first successful response to initialize. If an endpoint returns anything other than
119+
* a 200 or a 4xx, the method will exit without attempting subsequent endpoints.
120+
*
121+
* The three endpoints are computed as follows, given that the {@code issuer} is
122+
* composed of a {@code host} and a {@code path}:
123+
*
124+
* <ol>
125+
* <li>{@code host/.well-known/openid-configuration/path}, as defined in
126+
* <a href="https://tools.ietf.org/html/rfc8414#section-5">RFC 8414's Compatibility
127+
* Notes</a>.</li>
128+
* <li>{@code issuer/.well-known/openid-configuration}, as defined in <a href=
129+
* "https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest">
130+
* OpenID Provider Configuration</a>.</li>
131+
* <li>{@code host/.well-known/oauth-authorization-server/path}, as defined in
132+
* <a href="https://tools.ietf.org/html/rfc8414#section-3.1">Authorization Server
133+
* Metadata Request</a>.</li>
134+
* </ol>
135+
*
136+
* Note that the second endpoint is the equivalent of calling
137+
* {@link JwtDecoders#fromOidcIssuerLocation(String)}
138+
* @param issuer the <a href=
139+
* "https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier">Issuer</a>
140+
* @param restOperations customized {@link RestOperations}
141+
* @return a {@link JwtDecoder} that was initialized by one of the described endpoints
142+
*/
143+
@SuppressWarnings("unchecked")
144+
public static <T extends JwtDecoder> T fromIssuerLocation(String issuer, RestOperations restOperations) {
91145
Assert.hasText(issuer, "issuer cannot be empty");
92-
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withIssuerLocation(issuer).build();
146+
NimbusJwtDecoder.JwkSetUriJwtDecoderBuilder builder = NimbusJwtDecoder.withIssuerLocation(issuer);
147+
if (restOperations != null) {
148+
builder = builder.restOperations(restOperations);
149+
}
150+
NimbusJwtDecoder jwtDecoder = builder.build();
93151
OAuth2TokenValidator<Jwt> jwtValidator = JwtValidators.createDefaultWithIssuer(issuer);
94152
jwtDecoder.setJwtValidator(jwtValidator);
95153
return (T) jwtDecoder;
@@ -104,15 +162,20 @@ public static <T extends JwtDecoder> T fromIssuerLocation(String issuer) {
104162
* @param configuration the configuration values
105163
* @param issuer the <a href=
106164
* "https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier">Issuer</a>
165+
* @param restOperations customized {@link RestOperations}
107166
* @return {@link JwtDecoder}
108167
*/
109-
private static JwtDecoder withProviderConfiguration(Map<String, Object> configuration, String issuer) {
168+
private static JwtDecoder withProviderConfiguration(Map<String, Object> configuration, String issuer,
169+
RestOperations restOperations) {
110170
JwtDecoderProviderConfigurationUtils.validateIssuer(configuration, issuer);
111171
OAuth2TokenValidator<Jwt> jwtValidator = JwtValidators.createDefaultWithIssuer(issuer);
112172
String jwkSetUri = configuration.get("jwks_uri").toString();
113-
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri)
114-
.jwtProcessorCustomizer(JwtDecoderProviderConfigurationUtils::addJWSAlgorithms)
115-
.build();
173+
NimbusJwtDecoder.JwkSetUriJwtDecoderBuilder builder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri)
174+
.jwtProcessorCustomizer(JwtDecoderProviderConfigurationUtils::addJWSAlgorithms);
175+
if (restOperations != null) {
176+
builder = builder.restOperations(restOperations);
177+
}
178+
NimbusJwtDecoder jwtDecoder = builder.build();
116179
jwtDecoder.setJwtValidator(jwtValidator);
117180
return jwtDecoder;
118181
}

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

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
2222
import org.springframework.util.Assert;
23+
import org.springframework.web.reactive.function.client.WebClient;
2324

2425
/**
2526
* Allows creating a {@link ReactiveJwtDecoder} from an <a href=
@@ -51,10 +52,29 @@ private ReactiveJwtDecoders() {
5152
*/
5253
@SuppressWarnings("unchecked")
5354
public static <T extends ReactiveJwtDecoder> T fromOidcIssuerLocation(String oidcIssuerLocation) {
55+
return fromOidcIssuerLocation(oidcIssuerLocation, null);
56+
}
57+
58+
/**
59+
* Creates a {@link ReactiveJwtDecoder} using the provided <a href=
60+
* "https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier">Issuer</a>
61+
* by making an <a href=
62+
* "https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest">OpenID
63+
* Provider Configuration Request</a> and using the values in the <a href=
64+
* "https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse">OpenID
65+
* Provider Configuration Response</a> to initialize the {@link ReactiveJwtDecoder}.
66+
* @param oidcIssuerLocation the <a href=
67+
* "https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier">Issuer</a>
68+
* @param webClient customized {@link WebClient}
69+
* @return a {@link ReactiveJwtDecoder} that was initialized by the OpenID Provider
70+
* Configuration.
71+
*/
72+
public static <T extends ReactiveJwtDecoder> T fromOidcIssuerLocation(String oidcIssuerLocation,
73+
WebClient webClient) {
5474
Assert.hasText(oidcIssuerLocation, "oidcIssuerLocation cannot be empty");
5575
Map<String, Object> configuration = JwtDecoderProviderConfigurationUtils
5676
.getConfigurationForOidcIssuerLocation(oidcIssuerLocation);
57-
return (T) withProviderConfiguration(configuration, oidcIssuerLocation);
77+
return (T) withProviderConfiguration(configuration, oidcIssuerLocation, webClient);
5878
}
5979

6080
/**
@@ -88,10 +108,45 @@ public static <T extends ReactiveJwtDecoder> T fromOidcIssuerLocation(String oid
88108
*/
89109
@SuppressWarnings("unchecked")
90110
public static <T extends ReactiveJwtDecoder> T fromIssuerLocation(String issuer) {
111+
return fromIssuerLocation(issuer, null);
112+
}
113+
114+
/**
115+
* Creates a {@link ReactiveJwtDecoder} using the provided <a href=
116+
* "https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier">Issuer</a>
117+
* by querying three different discovery endpoints serially, using the values in the
118+
* first successful response to initialize. If an endpoint returns anything other than
119+
* a 200 or a 4xx, the method will exit without attempting subsequent endpoints.
120+
*
121+
* The three endpoints are computed as follows, given that the {@code issuer} is
122+
* composed of a {@code host} and a {@code path}:
123+
*
124+
* <ol>
125+
* <li>{@code host/.well-known/openid-configuration/path}, as defined in
126+
* <a href="https://tools.ietf.org/html/rfc8414#section-5">RFC 8414's Compatibility
127+
* Notes</a>.</li>
128+
* <li>{@code issuer/.well-known/openid-configuration}, as defined in <a href=
129+
* "https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest">
130+
* OpenID Provider Configuration</a>.</li>
131+
* <li>{@code host/.well-known/oauth-authorization-server/path}, as defined in
132+
* <a href="https://tools.ietf.org/html/rfc8414#section-3.1">Authorization Server
133+
* Metadata Request</a>.</li>
134+
* </ol>
135+
*
136+
* Note that the second endpoint is the equivalent of calling
137+
* {@link ReactiveJwtDecoders#fromOidcIssuerLocation(String)}
138+
* @param issuer the <a href=
139+
* "https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier">Issuer</a>
140+
* @param webClient customized {@link WebClient}
141+
* @return a {@link ReactiveJwtDecoder} that was initialized by one of the described
142+
* endpoints
143+
*/
144+
@SuppressWarnings("unchecked")
145+
public static <T extends ReactiveJwtDecoder> T fromIssuerLocation(String issuer, WebClient webClient) {
91146
Assert.hasText(issuer, "issuer cannot be empty");
92147
Map<String, Object> configuration = JwtDecoderProviderConfigurationUtils
93148
.getConfigurationForIssuerLocation(issuer);
94-
return (T) withProviderConfiguration(configuration, issuer);
149+
return (T) withProviderConfiguration(configuration, issuer, webClient);
95150
}
96151

97152
/**
@@ -103,15 +158,21 @@ public static <T extends ReactiveJwtDecoder> T fromIssuerLocation(String issuer)
103158
* @param configuration the configuration values
104159
* @param issuer the <a href=
105160
* "https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier">Issuer</a>
161+
* @param webClient customized {@link WebClient}
106162
* @return {@link ReactiveJwtDecoder}
107163
*/
108-
private static ReactiveJwtDecoder withProviderConfiguration(Map<String, Object> configuration, String issuer) {
164+
private static ReactiveJwtDecoder withProviderConfiguration(Map<String, Object> configuration, String issuer,
165+
WebClient webClient) {
109166
JwtDecoderProviderConfigurationUtils.validateIssuer(configuration, issuer);
110167
OAuth2TokenValidator<Jwt> jwtValidator = JwtValidators.createDefaultWithIssuer(issuer);
111168
String jwkSetUri = configuration.get("jwks_uri").toString();
112-
NimbusReactiveJwtDecoder jwtDecoder = NimbusReactiveJwtDecoder.withJwkSetUri(jwkSetUri)
113-
.jwtProcessorCustomizer(ReactiveJwtDecoderProviderConfigurationUtils::addJWSAlgorithms)
114-
.build();
169+
NimbusReactiveJwtDecoder.JwkSetUriReactiveJwtDecoderBuilder builder = NimbusReactiveJwtDecoder
170+
.withJwkSetUri(jwkSetUri)
171+
.jwtProcessorCustomizer(ReactiveJwtDecoderProviderConfigurationUtils::addJWSAlgorithms);
172+
if (webClient != null) {
173+
builder = builder.webClient(webClient);
174+
}
175+
NimbusReactiveJwtDecoder jwtDecoder = builder.build();
115176
jwtDecoder.setJwtValidator(jwtValidator);
116177
return jwtDecoder;
117178
}

0 commit comments

Comments
 (0)