20
20
21
21
import org .springframework .security .oauth2 .core .OAuth2TokenValidator ;
22
22
import org .springframework .util .Assert ;
23
+ import org .springframework .web .client .RestOperations ;
23
24
24
25
/**
25
26
* Allows creating a {@link JwtDecoder} from an <a href=
@@ -52,10 +53,29 @@ private JwtDecoders() {
52
53
*/
53
54
@ SuppressWarnings ("unchecked" )
54
55
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 ) {
55
75
Assert .hasText (oidcIssuerLocation , "oidcIssuerLocation cannot be empty" );
56
76
Map <String , Object > configuration = JwtDecoderProviderConfigurationUtils
57
77
.getConfigurationForOidcIssuerLocation (oidcIssuerLocation );
58
- return (T ) withProviderConfiguration (configuration , oidcIssuerLocation );
78
+ return (T ) withProviderConfiguration (configuration , oidcIssuerLocation , restOperations );
59
79
}
60
80
61
81
/**
@@ -88,8 +108,46 @@ public static <T extends JwtDecoder> T fromOidcIssuerLocation(String oidcIssuerL
88
108
*/
89
109
@ SuppressWarnings ("unchecked" )
90
110
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 ) {
91
145
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 ();
93
151
OAuth2TokenValidator <Jwt > jwtValidator = JwtValidators .createDefaultWithIssuer (issuer );
94
152
jwtDecoder .setJwtValidator (jwtValidator );
95
153
return (T ) jwtDecoder ;
@@ -104,15 +162,20 @@ public static <T extends JwtDecoder> T fromIssuerLocation(String issuer) {
104
162
* @param configuration the configuration values
105
163
* @param issuer the <a href=
106
164
* "https://openid.net/specs/openid-connect-core-1_0.html#IssuerIdentifier">Issuer</a>
165
+ * @param restOperations customized {@link RestOperations}
107
166
* @return {@link JwtDecoder}
108
167
*/
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 ) {
110
170
JwtDecoderProviderConfigurationUtils .validateIssuer (configuration , issuer );
111
171
OAuth2TokenValidator <Jwt > jwtValidator = JwtValidators .createDefaultWithIssuer (issuer );
112
172
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 ();
116
179
jwtDecoder .setJwtValidator (jwtValidator );
117
180
return jwtDecoder ;
118
181
}
0 commit comments