16
16
17
17
package org .springframework .security .oauth2 .client ;
18
18
19
+ import java .time .Duration ;
20
+ import java .time .Instant ;
21
+
19
22
import org .junit .Before ;
20
23
import org .junit .Test ;
21
24
27
30
import org .springframework .security .oauth2 .client .registration .TestClientRegistrations ;
28
31
import org .springframework .security .oauth2 .core .AuthorizationGrantType ;
29
32
import org .springframework .security .oauth2 .core .ClientAuthenticationMethod ;
33
+ import org .springframework .security .oauth2 .core .OAuth2AccessToken ;
30
34
import org .springframework .security .oauth2 .core .TestOAuth2AccessTokens ;
31
35
import org .springframework .security .oauth2 .core .endpoint .OAuth2AccessTokenResponse ;
32
36
import org .springframework .security .oauth2 .core .endpoint .TestOAuth2AccessTokenResponses ;
@@ -83,6 +87,33 @@ public void setAccessTokenResponseClientWhenClientIsNullThenThrowIllegalArgument
83
87
.withMessage ("accessTokenResponseClient cannot be null" );
84
88
}
85
89
90
+ @ Test
91
+ public void setClockSkewWhenNullThenThrowIllegalArgumentException () {
92
+ // @formatter:off
93
+ assertThatIllegalArgumentException ()
94
+ .isThrownBy (() -> this .authorizedClientProvider .setClockSkew (null ))
95
+ .withMessage ("clockSkew cannot be null" );
96
+ // @formatter:on
97
+ }
98
+
99
+ @ Test
100
+ public void setClockSkewWhenNegativeSecondsThenThrowIllegalArgumentException () {
101
+ // @formatter:off
102
+ assertThatIllegalArgumentException ()
103
+ .isThrownBy (() -> this .authorizedClientProvider .setClockSkew (Duration .ofSeconds (-1 )))
104
+ .withMessage ("clockSkew must be >= 0" );
105
+ // @formatter:on
106
+ }
107
+
108
+ @ Test
109
+ public void setClockWhenNullThenThrowIllegalArgumentException () {
110
+ // @formatter:off
111
+ assertThatIllegalArgumentException ()
112
+ .isThrownBy (() -> this .authorizedClientProvider .setClock (null ))
113
+ .withMessage ("clock cannot be null" );
114
+ // @formatter:on
115
+ }
116
+
86
117
@ Test
87
118
public void authorizeWhenContextIsNullThenThrowIllegalArgumentException () {
88
119
// @formatter:off
@@ -105,7 +136,7 @@ public void authorizeWhenNotJwtBearerThenUnableToAuthorize() {
105
136
}
106
137
107
138
@ Test
108
- public void authorizeWhenJwtBearerAndAuthorizedThenNotAuthorized () {
139
+ public void authorizeWhenJwtBearerAndTokenNotExpiredThenNotReauthorize () {
109
140
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient (this .clientRegistration ,
110
141
this .principal .getName (), TestOAuth2AccessTokens .scopes ("read" , "write" ));
111
142
// @formatter:off
@@ -117,6 +148,55 @@ public void authorizeWhenJwtBearerAndAuthorizedThenNotAuthorized() {
117
148
assertThat (this .authorizedClientProvider .authorize (authorizationContext )).isNull ();
118
149
}
119
150
151
+ @ Test
152
+ public void authorizeWhenJwtBearerAndTokenExpiredThenReauthorize () {
153
+ Instant now = Instant .now ();
154
+ Instant issuedAt = now .minus (Duration .ofMinutes (60 ));
155
+ Instant expiresAt = now .minus (Duration .ofMinutes (30 ));
156
+ OAuth2AccessToken accessToken = new OAuth2AccessToken (OAuth2AccessToken .TokenType .BEARER , "access-token-1234" ,
157
+ issuedAt , expiresAt );
158
+ OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient (this .clientRegistration ,
159
+ this .principal .getName (), accessToken );
160
+ OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses .accessTokenResponse ().build ();
161
+ given (this .accessTokenResponseClient .getTokenResponse (any ())).willReturn (accessTokenResponse );
162
+ // @formatter:off
163
+ OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
164
+ .withAuthorizedClient (authorizedClient )
165
+ .principal (this .principal )
166
+ .build ();
167
+ // @formatter:on
168
+ authorizedClient = this .authorizedClientProvider .authorize (authorizationContext );
169
+ assertThat (authorizedClient .getClientRegistration ()).isSameAs (this .clientRegistration );
170
+ assertThat (authorizedClient .getPrincipalName ()).isEqualTo (this .principal .getName ());
171
+ assertThat (authorizedClient .getAccessToken ()).isEqualTo (accessTokenResponse .getAccessToken ());
172
+ }
173
+
174
+ @ Test
175
+ public void authorizeWhenJwtBearerAndTokenNotExpiredButClockSkewForcesExpiryThenReauthorize () {
176
+ Instant now = Instant .now ();
177
+ Instant issuedAt = now .minus (Duration .ofMinutes (60 ));
178
+ Instant expiresAt = now .plus (Duration .ofMinutes (1 ));
179
+ OAuth2AccessToken expiresInOneMinAccessToken = new OAuth2AccessToken (OAuth2AccessToken .TokenType .BEARER ,
180
+ "access-token-1234" , issuedAt , expiresAt );
181
+ OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient (this .clientRegistration ,
182
+ this .principal .getName (), expiresInOneMinAccessToken );
183
+ // Shorten the lifespan of the access token by 90 seconds, which will ultimately
184
+ // force it to expire on the client
185
+ this .authorizedClientProvider .setClockSkew (Duration .ofSeconds (90 ));
186
+ OAuth2AccessTokenResponse accessTokenResponse = TestOAuth2AccessTokenResponses .accessTokenResponse ().build ();
187
+ given (this .accessTokenResponseClient .getTokenResponse (any ())).willReturn (accessTokenResponse );
188
+ // @formatter:off
189
+ OAuth2AuthorizationContext authorizationContext = OAuth2AuthorizationContext
190
+ .withAuthorizedClient (authorizedClient )
191
+ .principal (this .principal )
192
+ .build ();
193
+ // @formatter:on
194
+ OAuth2AuthorizedClient reauthorizedClient = this .authorizedClientProvider .authorize (authorizationContext );
195
+ assertThat (reauthorizedClient .getClientRegistration ()).isSameAs (this .clientRegistration );
196
+ assertThat (reauthorizedClient .getPrincipalName ()).isEqualTo (this .principal .getName ());
197
+ assertThat (reauthorizedClient .getAccessToken ()).isEqualTo (accessTokenResponse .getAccessToken ());
198
+ }
199
+
120
200
@ Test
121
201
public void authorizeWhenJwtBearerAndNotAuthorizedAndPrincipalNotJwtThenUnableToAuthorize () {
122
202
// @formatter:off
0 commit comments