private Builder(OAuth2AccessTokenResponse response) { OAuth2AccessToken accessToken = response.getAccessToken(); this.tokenValue = accessToken.getTokenValue(); this.tokenType = accessToken.getTokenType(); this.expiresAt = accessToken.getExpiresAt(); this.issuedAt = accessToken.getIssuedAt(); this.scopes = accessToken.getScopes(); this.refreshToken = response.getRefreshToken() == null ? null : response.getRefreshToken().getTokenValue(); this.additionalParameters = response.getAdditionalParameters(); }
OAuth2AccessToken newAccessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "new-token", Instant.now(), Instant accessTokenExpiresAt = issuedAt.plus(Duration.ofHours(1)); OAuth2AccessToken accessToken = new OAuth2AccessToken(this.accessToken.getTokenType(), this.accessToken.getTokenValue(), issuedAt, accessTokenExpiresAt);
@Test public void oauth2AccessTokenResponseWhenValidThenCreated() throws Exception { BodyExtractor<Mono<OAuth2AccessTokenResponse>, ReactiveHttpInputMessage> extractor = OAuth2BodyExtractors .oauth2AccessTokenResponse(); MockClientHttpResponse response = new MockClientHttpResponse(HttpStatus.OK); response.getHeaders().setContentType(MediaType.APPLICATION_JSON); response.setBody("{\n" + " \"access_token\":\"2YotnFZFEjr1zCsicMWpAA\",\n" + " \"token_type\":\"Bearer\",\n" + " \"expires_in\":3600,\n" + " \"refresh_token\":\"tGzv3JOkF0XG5Qx2TlKWIA\",\n" + " \"example_parameter\":\"example_value\"\n" + " }"); Instant now = Instant.now(); OAuth2AccessTokenResponse result = extractor.extract(response, this.context).block(); assertThat(result.getAccessToken().getTokenValue()).isEqualTo("2YotnFZFEjr1zCsicMWpAA"); assertThat(result.getAccessToken().getTokenType()).isEqualTo(OAuth2AccessToken.TokenType.BEARER); assertThat(result.getAccessToken().getExpiresAt()).isBetween(now.plusSeconds(3600), now.plusSeconds(3600 + 2)); assertThat(result.getRefreshToken().getTokenValue()).isEqualTo("tGzv3JOkF0XG5Qx2TlKWIA"); assertThat(result.getAdditionalParameters()).containsEntry("example_parameter", "example_value"); }
@Test public void buildWhenExpiresInIsNegativeThenExpiresAtOneSecondAfterIssueAt() { OAuth2AccessTokenResponse tokenResponse = OAuth2AccessTokenResponse .withToken(TOKEN_VALUE) .tokenType(OAuth2AccessToken.TokenType.BEARER) .expiresIn(-1L) .build(); assertThat(tokenResponse.getAccessToken().getExpiresAt()).isEqualTo( tokenResponse.getAccessToken().getIssuedAt().plusSeconds(1)); }
@Override public Object getCredentials() { return this.accessToken != null ? this.accessToken.getTokenValue() : this.authorizationExchange.getAuthorizationResponse().getCode(); }
@Override public OAuth2AccessTokenResponse getTokenResponse(OAuth2ClientCredentialsGrantRequest clientCredentialsGrantRequest) { Assert.notNull(clientCredentialsGrantRequest, "clientCredentialsGrantRequest cannot be null"); RequestEntity<?> request = this.requestEntityConverter.convert(clientCredentialsGrantRequest); ResponseEntity<OAuth2AccessTokenResponse> response; try { response = this.restOperations.exchange(request, OAuth2AccessTokenResponse.class); } catch (RestClientException ex) { OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE, "An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(), null); throw new OAuth2AuthorizationException(oauth2Error, ex); } OAuth2AccessTokenResponse tokenResponse = response.getBody(); if (CollectionUtils.isEmpty(tokenResponse.getAccessToken().getScopes())) { // As per spec, in Section 5.1 Successful Access Token Response // https://tools.ietf.org/html/rfc6749#section-5.1 // If AccessTokenResponse.scope is empty, then default to the scope // originally requested by the client in the Token Request tokenResponse = OAuth2AccessTokenResponse.withResponse(tokenResponse) .scopes(clientCredentialsGrantRequest.getClientRegistration().getScopes()) .build(); } return tokenResponse; }
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken(accessToken.getTokenValue()) .tokenType(accessToken.getTokenType()) .scopes(accessToken.getScopes()) .additionalParameters(additionalParameters) .build();
/** * Builds a new {@link OAuth2AccessTokenResponse}. * * @return a {@link OAuth2AccessTokenResponse} */ public OAuth2AccessTokenResponse build() { Instant issuedAt = getIssuedAt(); Instant expiresAt = getExpiresAt(); OAuth2AccessTokenResponse accessTokenResponse = new OAuth2AccessTokenResponse(); accessTokenResponse.accessToken = new OAuth2AccessToken( this.tokenType, this.tokenValue, issuedAt, expiresAt, this.scopes); if (StringUtils.hasText(this.refreshToken)) { accessTokenResponse.refreshToken = new OAuth2RefreshToken(this.refreshToken, issuedAt); } accessTokenResponse.additionalParameters = Collections.unmodifiableMap( CollectionUtils.isEmpty(this.additionalParameters) ? Collections.emptyMap() : this.additionalParameters); return accessTokenResponse; }
private boolean hasTokenExpired(OAuth2AuthorizedClient authorizedClient) { Instant now = this.clock.instant(); Instant expiresAt = authorizedClient.getAccessToken().getExpiresAt(); if (now.isAfter(expiresAt.minus(this.accessTokenExpiresSkew))) { return true; } return false; }
@Test public void filterWhenClientRegistrationIdAndServerWebExchangeFromContextThenServerWebExchangeFromContext() { OAuth2RefreshToken refreshToken = new OAuth2RefreshToken("refresh-token", this.accessToken.getIssuedAt()); OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration, "principalName", this.accessToken, refreshToken); when(this.authorizedClientRepository.loadAuthorizedClient(any(), any(), any())).thenReturn(Mono.just(authorizedClient)); when(this.clientRegistrationRepository.findByRegistrationId(any())).thenReturn(Mono.just(this.registration)); ClientRequest request = ClientRequest.create(GET, URI.create("https://example.com")) .attributes(clientRegistrationId(this.registration.getRegistrationId())) .build(); this.function.filter(request, this.exchange) .subscriberContext(serverWebExchange()) .block(); verify(this.authorizedClientRepository).loadAuthorizedClient(eq(this.registration.getRegistrationId()), any(), eq(this.serverWebExchange)); }
private ClientRequest bearer(ClientRequest request, OAuth2AuthorizedClient authorizedClient) { return ClientRequest.from(request) .headers(headers -> headers.setBearerAuth(authorizedClient.getAccessToken().getTokenValue())) .build(); }
@Override public OAuth2AccessTokenResponse getTokenResponse(OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) { Assert.notNull(authorizationCodeGrantRequest, "authorizationCodeGrantRequest cannot be null"); RequestEntity<?> request = this.requestEntityConverter.convert(authorizationCodeGrantRequest); ResponseEntity<OAuth2AccessTokenResponse> response; try { response = this.restOperations.exchange(request, OAuth2AccessTokenResponse.class); } catch (RestClientException ex) { OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE, "An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(), null); throw new OAuth2AuthorizationException(oauth2Error, ex); } OAuth2AccessTokenResponse tokenResponse = response.getBody(); if (CollectionUtils.isEmpty(tokenResponse.getAccessToken().getScopes())) { // As per spec, in Section 5.1 Successful Access Token Response // https://tools.ietf.org/html/rfc6749#section-5.1 // If AccessTokenResponse.scope is empty, then default to the scope // originally requested by the client in the Token Request tokenResponse = OAuth2AccessTokenResponse.withResponse(tokenResponse) .scopes(authorizationCodeGrantRequest.getClientRegistration().getScopes()) .build(); } return tokenResponse; }
@Test // gh-6087 public void oauth2AccessTokenResponseWhenMultipleAttributeTypesThenCreated() throws Exception { BodyExtractor<Mono<OAuth2AccessTokenResponse>, ReactiveHttpInputMessage> extractor = OAuth2BodyExtractors .oauth2AccessTokenResponse(); MockClientHttpResponse response = new MockClientHttpResponse(HttpStatus.OK); response.getHeaders().setContentType(MediaType.APPLICATION_JSON); response.setBody("{\n" + " \"access_token\":\"2YotnFZFEjr1zCsicMWpAA\",\n" + " \"token_type\":\"Bearer\",\n" + " \"expires_in\":3600,\n" + " \"refresh_token\":\"tGzv3JOkF0XG5Qx2TlKWIA\",\n" + " \"subjson\":{}, \n" + " \"list\":[] \n" + " }"); Instant now = Instant.now(); OAuth2AccessTokenResponse result = extractor.extract(response, this.context).block(); assertThat(result.getAccessToken().getTokenValue()).isEqualTo("2YotnFZFEjr1zCsicMWpAA"); assertThat(result.getAccessToken().getTokenType()).isEqualTo(OAuth2AccessToken.TokenType.BEARER); assertThat(result.getAccessToken().getExpiresAt()).isBetween(now.plusSeconds(3600), now.plusSeconds(3600 + 2)); assertThat(result.getRefreshToken().getTokenValue()).isEqualTo("tGzv3JOkF0XG5Qx2TlKWIA"); assertThat(result.getAdditionalParameters().get("subjson")).isInstanceOfAny(Map.class); assertThat(result.getAdditionalParameters().get("list")).isInstanceOfAny(List.class); } }
public static OAuth2AccessToken scopes(String... scopes) { return new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, "scopes", Instant.now(), Instant.now().plus(Duration.ofDays(1)), new HashSet<>(Arrays.asList(scopes))); } }
@Test public void buildWhenExpiresInIsZeroThenExpiresAtOneSecondAfterIssueAt() { OAuth2AccessTokenResponse tokenResponse = OAuth2AccessTokenResponse .withToken(TOKEN_VALUE) .tokenType(OAuth2AccessToken.TokenType.BEARER) .expiresIn(0) .build(); assertThat(tokenResponse.getAccessToken().getExpiresAt()).isEqualTo( tokenResponse.getAccessToken().getIssuedAt().plusSeconds(1)); }
private boolean hasTokenExpired(OAuth2AuthorizedClient authorizedClient) { Instant now = this.clock.instant(); Instant expiresAt = authorizedClient.getAccessToken().getExpiresAt(); if (now.isAfter(expiresAt.minus(this.accessTokenExpiresSkew))) { return true; } return false; }
@Test public void filterWhenDefaultClientRegistrationIdThenAuthorizedClientResolved() { this.function.setDefaultClientRegistrationId(this.registration.getRegistrationId()); OAuth2RefreshToken refreshToken = new OAuth2RefreshToken("refresh-token", this.accessToken.getIssuedAt()); OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(this.registration, "principalName", this.accessToken, refreshToken); when(this.authorizedClientRepository.loadAuthorizedClient(any(), any(), any())).thenReturn(Mono.just(authorizedClient)); when(this.clientRegistrationRepository.findByRegistrationId(any())).thenReturn(Mono.just(this.registration)); ClientRequest request = ClientRequest.create(GET, URI.create("https://example.com")) .build(); this.function.filter(request, this.exchange).block(); List<ClientRequest> requests = this.exchange.getRequests(); assertThat(requests).hasSize(1); ClientRequest request0 = requests.get(0); assertThat(request0.headers().getFirst(HttpHeaders.AUTHORIZATION)).isEqualTo("Bearer token-0"); assertThat(request0.url().toASCIIString()).isEqualTo("https://example.com"); assertThat(request0.method()).isEqualTo(HttpMethod.GET); assertThat(getBody(request0)).isEmpty(); }
@Test public void constructorWhenAllParametersProvidedAndValidThenCreated() { OAuth2AccessToken accessToken = new OAuth2AccessToken( TOKEN_TYPE, TOKEN_VALUE, ISSUED_AT, EXPIRES_AT, SCOPES); assertThat(accessToken.getTokenType()).isEqualTo(TOKEN_TYPE); assertThat(accessToken.getTokenValue()).isEqualTo(TOKEN_VALUE); assertThat(accessToken.getIssuedAt()).isEqualTo(ISSUED_AT); assertThat(accessToken.getExpiresAt()).isEqualTo(EXPIRES_AT); assertThat(accessToken.getScopes()).isEqualTo(SCOPES); }
private ClientRequest bearer(ClientRequest request, OAuth2AuthorizedClient authorizedClient) { return ClientRequest.from(request) .headers(headers -> headers.setBearerAuth(authorizedClient.getAccessToken().getTokenValue())) .build(); }
Instant accessTokenExpiresAt = issuedAt.plus(Duration.ofHours(1)); this.accessToken = new OAuth2AccessToken(this.accessToken.getTokenType(), this.accessToken.getTokenValue(), issuedAt, accessTokenExpiresAt);