@ -16,6 +16,9 @@
@@ -16,6 +16,9 @@
package org.springframework.security.oauth2.client ;
import java.time.Duration ;
import java.time.Instant ;
import org.junit.Before ;
import org.junit.Test ;
@ -27,6 +30,7 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio
@@ -27,6 +30,7 @@ import org.springframework.security.oauth2.client.registration.ClientRegistratio
import org.springframework.security.oauth2.client.registration.TestClientRegistrations ;
import org.springframework.security.oauth2.core.AuthorizationGrantType ;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod ;
import org.springframework.security.oauth2.core.OAuth2AccessToken ;
import org.springframework.security.oauth2.core.TestOAuth2AccessTokens ;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse ;
import org.springframework.security.oauth2.core.endpoint.TestOAuth2AccessTokenResponses ;
@ -83,6 +87,33 @@ public class JwtBearerOAuth2AuthorizedClientProviderTests {
@@ -83,6 +87,33 @@ public class JwtBearerOAuth2AuthorizedClientProviderTests {
. withMessage ( "accessTokenResponseClient cannot be null" ) ;
}
@Test
public void setClockSkewWhenNullThenThrowIllegalArgumentException ( ) {
// @formatter:off
assertThatIllegalArgumentException ( )
. isThrownBy ( ( ) - > this . authorizedClientProvider . setClockSkew ( null ) )
. withMessage ( "clockSkew cannot be null" ) ;
// @formatter:on
}
@Test
public void setClockSkewWhenNegativeSecondsThenThrowIllegalArgumentException ( ) {
// @formatter:off
assertThatIllegalArgumentException ( )
. isThrownBy ( ( ) - > this . authorizedClientProvider . setClockSkew ( Duration . ofSeconds ( - 1 ) ) )
. withMessage ( "clockSkew must be >= 0" ) ;
// @formatter:on
}
@Test
public void setClockWhenNullThenThrowIllegalArgumentException ( ) {
// @formatter:off
assertThatIllegalArgumentException ( )
. isThrownBy ( ( ) - > this . authorizedClientProvider . setClock ( null ) )
. withMessage ( "clock cannot be null" ) ;
// @formatter:on
}
@Test
public void authorizeWhenContextIsNullThenThrowIllegalArgumentException ( ) {
// @formatter:off
@ -105,7 +136,7 @@ public class JwtBearerOAuth2AuthorizedClientProviderTests {
@@ -105,7 +136,7 @@ public class JwtBearerOAuth2AuthorizedClientProviderTests {
}
@Test
public void authorizeWhenJwtBearerAndAuthorizedThenNotAuthorized ( ) {
public void authorizeWhenJwtBearerAndTokenNotExpiredThenNotReauthorize ( ) {
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient ( this . clientRegistration ,
this . principal . getName ( ) , TestOAuth2AccessTokens . scopes ( "read" , "write" ) ) ;
// @formatter:off
@ -117,6 +148,55 @@ public class JwtBearerOAuth2AuthorizedClientProviderTests {
@@ -117,6 +148,55 @@ public class JwtBearerOAuth2AuthorizedClientProviderTests {
assertThat ( this . authorizedClientProvider . authorize ( authorizationContext ) ) . isNull ( ) ;
}
@Test
public void authorizeWhenJwtBearerAndTokenExpiredThenReauthorize ( ) {
Instant now = Instant . now ( ) ;
Instant issuedAt = now . minus ( Duration . ofMinutes ( 60 ) ) ;
Instant expiresAt = now . minus ( Duration . ofMinutes ( 30 ) ) ;
OAuth2AccessToken accessToken = new OAuth2AccessToken ( OAuth2AccessToken . TokenType . BEARER , "access-token-1234" ,
issuedAt , expiresAt ) ;
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient ( this . clientRegistration ,
this . principal . getName ( ) , accessToken ) ;
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses . accessTokenResponse ( ) . build ( ) ;
given ( this . accessTokenResponseClient . getTokenResponse ( any ( ) ) ) . willReturn ( accessTokenResponse ) ;
// @formatter:off
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
. withAuthorizedClient ( authorizedClient )
. principal ( this . principal )
. build ( ) ;
// @formatter:on
authorizedClient = this . authorizedClientProvider . authorize ( authorizationContext ) ;
assertThat ( authorizedClient . getClientRegistration ( ) ) . isSameAs ( this . clientRegistration ) ;
assertThat ( authorizedClient . getPrincipalName ( ) ) . isEqualTo ( this . principal . getName ( ) ) ;
assertThat ( authorizedClient . getAccessToken ( ) ) . isEqualTo ( accessTokenResponse . getAccessToken ( ) ) ;
}
@Test
public void authorizeWhenJwtBearerAndTokenNotExpiredButClockSkewForcesExpiryThenReauthorize ( ) {
Instant now = Instant . now ( ) ;
Instant issuedAt = now . minus ( Duration . ofMinutes ( 60 ) ) ;
Instant expiresAt = now . plus ( Duration . ofMinutes ( 1 ) ) ;
OAuth2AccessToken expiresInOneMinAccessToken = new OAuth2AccessToken ( OAuth2AccessToken . TokenType . BEARER ,
"access-token-1234" , issuedAt , expiresAt ) ;
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient ( this . clientRegistration ,
this . principal . getName ( ) , expiresInOneMinAccessToken ) ;
// Shorten the lifespan of the access token by 90 seconds, which will ultimately
// force it to expire on the client
this . authorizedClientProvider . setClockSkew ( Duration . ofSeconds ( 90 ) ) ;
OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses . accessTokenResponse ( ) . build ( ) ;
given ( this . accessTokenResponseClient . getTokenResponse ( any ( ) ) ) . willReturn ( accessTokenResponse ) ;
// @formatter:off
OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
. withAuthorizedClient ( authorizedClient )
. principal ( this . principal )
. build ( ) ;
// @formatter:on
OAuth2AuthorizedClient reauthorizedClient = this . authorizedClientProvider . authorize ( authorizationContext ) ;
assertThat ( reauthorizedClient . getClientRegistration ( ) ) . isSameAs ( this . clientRegistration ) ;
assertThat ( reauthorizedClient . getPrincipalName ( ) ) . isEqualTo ( this . principal . getName ( ) ) ;
assertThat ( reauthorizedClient . getAccessToken ( ) ) . isEqualTo ( accessTokenResponse . getAccessToken ( ) ) ;
}
@Test
public void authorizeWhenJwtBearerAndNotAuthorizedAndPrincipalNotJwtThenUnableToAuthorize ( ) {
// @formatter:off