@ -1,5 +1,5 @@
/ *
/ *
* Copyright 2002 - 2021 the original author or authors .
* Copyright 2002 - 2022 the original author or authors .
*
*
* Licensed under the Apache License , Version 2 . 0 ( the "License" ) ;
* Licensed under the Apache License , Version 2 . 0 ( the "License" ) ;
* you may not use this file except in compliance with the License .
* you may not use this file except in compliance with the License .
@ -19,6 +19,7 @@ package org.springframework.security.oauth2.client;
import java.time.Clock ;
import java.time.Clock ;
import java.time.Duration ;
import java.time.Duration ;
import java.time.Instant ;
import java.time.Instant ;
import java.util.function.Function ;
import reactor.core.publisher.Mono ;
import reactor.core.publisher.Mono ;
@ -45,6 +46,8 @@ public final class JwtBearerReactiveOAuth2AuthorizedClientProvider implements Re
private ReactiveOAuth2AccessTokenResponseClient < JwtBearerGrantRequest > accessTokenResponseClient = new WebClientReactiveJwtBearerTokenResponseClient ( ) ;
private ReactiveOAuth2AccessTokenResponseClient < JwtBearerGrantRequest > accessTokenResponseClient = new WebClientReactiveJwtBearerTokenResponseClient ( ) ;
private Function < OAuth2AuthorizationContext , Mono < Jwt > > jwtAssertionResolver = this : : resolveJwtAssertion ;
private Duration clockSkew = Duration . ofSeconds ( 60 ) ;
private Duration clockSkew = Duration . ofSeconds ( 60 ) ;
private Clock clock = Clock . systemUTC ( ) ;
private Clock clock = Clock . systemUTC ( ) ;
@ -74,10 +77,7 @@ public final class JwtBearerReactiveOAuth2AuthorizedClientProvider implements Re
// need for re-authorization
// need for re-authorization
return Mono . empty ( ) ;
return Mono . empty ( ) ;
}
}
if ( ! ( context . getPrincipal ( ) . getPrincipal ( ) instanceof Jwt ) ) {
return Mono . empty ( ) ;
}
Jwt jwt = ( Jwt ) context . getPrincipal ( ) . getPrincipal ( ) ;
// As per spec, in section 4.1 Using Assertions as Authorization Grants
// As per spec, in section 4.1 Using Assertions as Authorization Grants
// https://tools.ietf.org/html/rfc7521#section-4.1
// https://tools.ietf.org/html/rfc7521#section-4.1
//
//
@ -90,13 +90,26 @@ public final class JwtBearerReactiveOAuth2AuthorizedClientProvider implements Re
// issued with a reasonably short lifetime. Clients can refresh an
// issued with a reasonably short lifetime. Clients can refresh an
// expired access token by requesting a new one using the same
// expired access token by requesting a new one using the same
// assertion, if it is still valid, or with a new assertion.
// assertion, if it is still valid, or with a new assertion.
return Mono . just ( new JwtBearerGrantRequest ( clientRegistration , jwt ) )
// @formatter:off
return this . jwtAssertionResolver . apply ( context )
. map ( ( jwt ) - > new JwtBearerGrantRequest ( clientRegistration , jwt ) )
. flatMap ( this . accessTokenResponseClient : : getTokenResponse )
. flatMap ( this . accessTokenResponseClient : : getTokenResponse )
. onErrorMap ( OAuth2AuthorizationException . class ,
. onErrorMap ( OAuth2AuthorizationException . class ,
( ex ) - > new ClientAuthorizationException ( ex . getError ( ) , clientRegistration . getRegistrationId ( ) ,
( ex ) - > new ClientAuthorizationException ( ex . getError ( ) , clientRegistration . getRegistrationId ( ) ,
ex ) )
ex ) )
. map ( ( tokenResponse ) - > new OAuth2AuthorizedClient ( clientRegistration , context . getPrincipal ( ) . getName ( ) ,
. map ( ( tokenResponse ) - > new OAuth2AuthorizedClient ( clientRegistration , context . getPrincipal ( ) . getName ( ) ,
tokenResponse . getAccessToken ( ) ) ) ;
tokenResponse . getAccessToken ( ) ) ) ;
// @formatter:on
}
private Mono < Jwt > resolveJwtAssertion ( OAuth2AuthorizationContext context ) {
// @formatter:off
return Mono . just ( context )
. map ( ( ctx ) - > ctx . getPrincipal ( ) . getPrincipal ( ) )
. filter ( ( principal ) - > principal instanceof Jwt )
. cast ( Jwt . class ) ;
// @formatter:on
}
}
private boolean hasTokenExpired ( OAuth2Token token ) {
private boolean hasTokenExpired ( OAuth2Token token ) {
@ -115,6 +128,17 @@ public final class JwtBearerReactiveOAuth2AuthorizedClientProvider implements Re
this . accessTokenResponseClient = accessTokenResponseClient ;
this . accessTokenResponseClient = accessTokenResponseClient ;
}
}
/ * *
* Sets the resolver used for resolving the { @link Jwt } assertion .
* @param jwtAssertionResolver the resolver used for resolving the { @link Jwt }
* assertion
* @since 5 . 7
* /
public void setJwtAssertionResolver ( Function < OAuth2AuthorizationContext , Mono < Jwt > > jwtAssertionResolver ) {
Assert . notNull ( jwtAssertionResolver , "jwtAssertionResolver cannot be null" ) ;
this . jwtAssertionResolver = jwtAssertionResolver ;
}
/ * *
/ * *
* Sets the maximum acceptable clock skew , which is used when checking the
* Sets the maximum acceptable clock skew , which is used when checking the
* { @link OAuth2AuthorizedClient # getAccessToken ( ) access token } expiry . The default is
* { @link OAuth2AuthorizedClient # getAccessToken ( ) access token } expiry . The default is