2424import org .springframework .security .config .annotation .web .HttpSecurityBuilder ;
2525import org .springframework .security .config .annotation .web .configurers .AbstractHttpConfigurer ;
2626import org .springframework .security .config .annotation .web .configurers .ExceptionHandlingConfigurer ;
27+ import org .springframework .security .crypto .key .AsymmetricKey ;
28+ import org .springframework .security .crypto .key .CryptoKey ;
2729import org .springframework .security .crypto .key .CryptoKeySource ;
30+ import org .springframework .security .crypto .key .SymmetricKey ;
2831import org .springframework .security .oauth2 .jose .jws .NimbusJwsEncoder ;
32+ import org .springframework .security .oauth2 .jwt .JwtDecoder ;
33+ import org .springframework .security .oauth2 .jwt .NimbusJwtDecoder ;
2934import org .springframework .security .oauth2 .server .authorization .InMemoryOAuth2AuthorizationService ;
3035import org .springframework .security .oauth2 .server .authorization .OAuth2AuthorizationService ;
3136import org .springframework .security .oauth2 .server .authorization .authentication .OAuth2AuthorizationCodeAuthenticationProvider ;
3237import org .springframework .security .oauth2 .server .authorization .authentication .OAuth2ClientAuthenticationProvider ;
3338import org .springframework .security .oauth2 .server .authorization .authentication .OAuth2ClientCredentialsAuthenticationProvider ;
3439import org .springframework .security .oauth2 .server .authorization .authentication .OAuth2RefreshTokenAuthenticationProvider ;
40+ import org .springframework .security .oauth2 .server .authorization .authentication .OAuth2TokenIntrospectionAuthenticationProvider ;
3541import org .springframework .security .oauth2 .server .authorization .authentication .OAuth2TokenRevocationAuthenticationProvider ;
3642import org .springframework .security .oauth2 .server .authorization .client .RegisteredClientRepository ;
3743import org .springframework .security .oauth2 .server .authorization .config .ProviderSettings ;
3844import org .springframework .security .oauth2 .server .authorization .web .JwkSetEndpointFilter ;
3945import org .springframework .security .oauth2 .server .authorization .web .OAuth2AuthorizationEndpointFilter ;
4046import org .springframework .security .oauth2 .server .authorization .web .OAuth2ClientAuthenticationFilter ;
4147import org .springframework .security .oauth2 .server .authorization .web .OAuth2TokenEndpointFilter ;
48+ import org .springframework .security .oauth2 .server .authorization .web .OAuth2TokenIntrospectionEndpointFilter ;
4249import org .springframework .security .oauth2 .server .authorization .web .OAuth2TokenRevocationEndpointFilter ;
4350import org .springframework .security .oauth2 .server .authorization .web .OidcProviderConfigurationEndpointFilter ;
4451import org .springframework .security .web .AuthenticationEntryPoint ;
5562import org .springframework .util .StringUtils ;
5663
5764import java .net .URI ;
65+ import java .security .Key ;
66+ import java .security .interfaces .RSAPublicKey ;
67+ import java .util .ArrayList ;
5868import java .util .Arrays ;
69+ import java .util .Collection ;
5970import java .util .LinkedHashMap ;
6071import java .util .List ;
6172import java .util .Map ;
6576 *
6677 * @author Joe Grandja
6778 * @author Daniel Garnier-Moiroux
79+ * @author Gerardo Roza
6880 * @since 0.0.1
6981 * @see AbstractHttpConfigurer
7082 * @see RegisteredClientRepository
7183 * @see OAuth2AuthorizationService
7284 * @see OAuth2AuthorizationEndpointFilter
7385 * @see OAuth2TokenEndpointFilter
86+ * @see OAuth2TokenIntrospectionEndpointFilter
7487 * @see OAuth2TokenRevocationEndpointFilter
7588 * @see JwkSetEndpointFilter
7689 * @see OidcProviderConfigurationEndpointFilter
@@ -88,6 +101,8 @@ public final class OAuth2AuthorizationServerConfigurer<B extends HttpSecurityBui
88101 HttpMethod .POST .name ()));
89102 private final RequestMatcher tokenEndpointMatcher = new AntPathRequestMatcher (
90103 OAuth2TokenEndpointFilter .DEFAULT_TOKEN_ENDPOINT_URI , HttpMethod .POST .name ());
104+ private final RequestMatcher tokenIntrospectionMatcher = new AntPathRequestMatcher (
105+ OAuth2TokenIntrospectionEndpointFilter .DEFAULT_TOKEN_INTROSPECTION_ENDPOINT_URI , HttpMethod .POST .name ());
91106 private final RequestMatcher tokenRevocationEndpointMatcher = new AntPathRequestMatcher (
92107 OAuth2TokenRevocationEndpointFilter .DEFAULT_TOKEN_REVOCATION_ENDPOINT_URI , HttpMethod .POST .name ());
93108 private final RequestMatcher jwkSetEndpointMatcher = new AntPathRequestMatcher (
@@ -152,7 +167,7 @@ public List<RequestMatcher> getEndpointMatchers() {
152167 // TODO Initialize matchers using URI's from ProviderSettings
153168 return Arrays .asList (this .authorizationEndpointMatcher , this .tokenEndpointMatcher ,
154169 this .tokenRevocationEndpointMatcher , this .jwkSetEndpointMatcher ,
155- this .oidcProviderConfigurationEndpointMatcher );
170+ this .oidcProviderConfigurationEndpointMatcher , this . tokenIntrospectionMatcher );
156171 }
157172
158173 @ Override
@@ -192,11 +207,17 @@ public void init(B builder) {
192207 getAuthorizationService (builder ));
193208 builder .authenticationProvider (postProcess (tokenRevocationAuthenticationProvider ));
194209
210+ OAuth2TokenIntrospectionAuthenticationProvider tokenIntrospectionAuthenticationProvider =
211+ new OAuth2TokenIntrospectionAuthenticationProvider (
212+ getAuthorizationService (builder ), getJwtDecoders (builder ));
213+ builder .authenticationProvider (postProcess (tokenIntrospectionAuthenticationProvider ));
214+
195215 ExceptionHandlingConfigurer <B > exceptionHandling = builder .getConfigurer (ExceptionHandlingConfigurer .class );
196216 if (exceptionHandling != null ) {
197217 LinkedHashMap <RequestMatcher , AuthenticationEntryPoint > entryPoints = new LinkedHashMap <>();
198218 entryPoints .put (
199- new OrRequestMatcher (this .tokenEndpointMatcher , this .tokenRevocationEndpointMatcher ),
219+ new OrRequestMatcher (this .tokenEndpointMatcher , this .tokenRevocationEndpointMatcher ,
220+ this .tokenIntrospectionMatcher ),
200221 new HttpStatusEntryPoint (HttpStatus .UNAUTHORIZED ));
201222 DelegatingAuthenticationEntryPoint authenticationEntryPoint =
202223 new DelegatingAuthenticationEntryPoint (entryPoints );
@@ -229,7 +250,8 @@ public void configure(B builder) {
229250 OAuth2ClientAuthenticationFilter clientAuthenticationFilter =
230251 new OAuth2ClientAuthenticationFilter (
231252 authenticationManager ,
232- new OrRequestMatcher (this .tokenEndpointMatcher , this .tokenRevocationEndpointMatcher ));
253+ new OrRequestMatcher (this .tokenEndpointMatcher , this .tokenRevocationEndpointMatcher ,
254+ this .tokenIntrospectionMatcher ));
233255 builder .addFilterAfter (postProcess (clientAuthenticationFilter ), AbstractPreAuthenticatedProcessingFilter .class );
234256
235257 OAuth2AuthorizationEndpointFilter authorizationEndpointFilter =
@@ -251,6 +273,12 @@ public void configure(B builder) {
251273 authenticationManager ,
252274 providerSettings .tokenRevocationEndpoint ());
253275 builder .addFilterAfter (postProcess (tokenRevocationEndpointFilter ), OAuth2TokenEndpointFilter .class );
276+
277+ OAuth2TokenIntrospectionEndpointFilter tokenIntrospectionEndpointFilter =
278+ new OAuth2TokenIntrospectionEndpointFilter (
279+ authenticationManager ,
280+ providerSettings .tokenIntrospectionEndpoint ());
281+ builder .addFilterAfter (postProcess (tokenIntrospectionEndpointFilter ), OAuth2TokenEndpointFilter .class );
254282 }
255283
256284 private static <B extends HttpSecurityBuilder <B >> RegisteredClientRepository getRegisteredClientRepository (B builder ) {
@@ -278,6 +306,20 @@ private static <B extends HttpSecurityBuilder<B>> OAuth2AuthorizationService get
278306 return authorizationService ;
279307 }
280308
309+ private static <B extends HttpSecurityBuilder <B >> Collection <JwtDecoder > getJwtDecoders (B builder ) {
310+ Collection <JwtDecoder > jwtDecoders = new ArrayList <>();
311+ for (CryptoKey <? extends Key > cryptoKey : getKeySource (builder ).getKeys ()) {
312+ if (AsymmetricKey .class .isAssignableFrom (cryptoKey .getClass ())
313+ && RSAPublicKey .class .isAssignableFrom (((AsymmetricKey ) cryptoKey ).getPublicKey ().getClass ())) {
314+ jwtDecoders .add (NimbusJwtDecoder
315+ .withPublicKey ((RSAPublicKey ) ((AsymmetricKey ) cryptoKey ).getPublicKey ()).build ());
316+ } else if (SymmetricKey .class .isAssignableFrom (cryptoKey .getClass ())) {
317+ jwtDecoders .add (NimbusJwtDecoder .withSecretKey (((SymmetricKey ) cryptoKey ).getKey ()).build ());
318+ }
319+ }
320+ return jwtDecoders ;
321+ }
322+
281323 private static <B extends HttpSecurityBuilder <B >> OAuth2AuthorizationService getAuthorizationServiceBean (B builder ) {
282324 Map <String , OAuth2AuthorizationService > authorizationServiceMap = BeanFactoryUtils .beansOfTypeIncludingAncestors (
283325 builder .getSharedObject (ApplicationContext .class ), OAuth2AuthorizationService .class );
0 commit comments