public static OAuth2AccessTokenResponse.Builder accessTokenResponse() { return OAuth2AccessTokenResponse.withToken("token") .tokenType(OAuth2AccessToken.TokenType.BEARER); } }
@Test public void authenticationWhenOAuth2UserNotFoundThenEmpty() { OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("foo") .tokenType(OAuth2AccessToken.TokenType.BEARER) .build(); when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(Mono.just(accessTokenResponse)); when(this.userService.loadUser(any())).thenReturn(Mono.empty()); assertThat(this.manager.authenticate(loginToken()).block()).isNull(); }
@Test public void authenticationWhenOAuth2UserFoundThenSuccess() { OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("foo") .tokenType(OAuth2AccessToken.TokenType.BEARER) .build(); when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(Mono.just(accessTokenResponse)); DefaultOAuth2User user = new DefaultOAuth2User(AuthorityUtils.createAuthorityList("ROLE_USER"), Collections.singletonMap("user", "rob"), "user"); when(this.userService.loadUser(any())).thenReturn(Mono.just(user)); OAuth2LoginAuthenticationToken result = (OAuth2LoginAuthenticationToken) this.manager.authenticate(loginToken()).block(); assertThat(result.getPrincipal()).isEqualTo(user); assertThat(result.getAuthorities()).containsOnlyElementsOf(user.getAuthorities()); assertThat(result.isAuthenticated()).isTrue(); }
private OAuth2AccessTokenResponse accessTokenSuccessResponse() { Instant expiresAt = Instant.now().plusSeconds(5); Set<String> scopes = new LinkedHashSet<>(Arrays.asList("openid", "profile", "email")); Map<String, Object> additionalParameters = new HashMap<>(); additionalParameters.put("param1", "value1"); additionalParameters.put("param2", "value2"); additionalParameters.put(OidcParameterNames.ID_TOKEN, "id-token"); return OAuth2AccessTokenResponse .withToken("access-token-1234") .tokenType(OAuth2AccessToken.TokenType.BEARER) .expiresIn(expiresAt.getEpochSecond()) .scopes(scopes) .refreshToken("refresh-token-1234") .additionalParameters(additionalParameters) .build(); } }
private OAuth2AccessTokenResponse accessTokenSuccessResponse() { Instant expiresAt = Instant.now().plusSeconds(5); Set<String> scopes = new LinkedHashSet<>(Arrays.asList("scope1", "scope2")); Map<String, Object> additionalParameters = new HashMap<>(); additionalParameters.put("param1", "value1"); additionalParameters.put("param2", "value2"); return OAuth2AccessTokenResponse .withToken("access-token-1234") .tokenType(OAuth2AccessToken.TokenType.BEARER) .expiresIn(expiresAt.getEpochSecond()) .scopes(scopes) .refreshToken("refresh-token-1234") .additionalParameters(additionalParameters) .build(); } }
@Test public void authenticateWhenIdTokenValidationErrorThenOAuth2AuthenticationException() { OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("foo") .tokenType(OAuth2AccessToken.TokenType.BEARER) .additionalParameters(Collections.singletonMap(OidcParameterNames.ID_TOKEN, this.idToken.getTokenValue())) .build(); when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(Mono.just(accessTokenResponse)); when(this.jwtDecoder.decode(any())).thenThrow(new JwtException("ID Token Validation Error")); this.manager.setJwtDecoderFactory(c -> this.jwtDecoder); assertThatThrownBy(() -> this.manager.authenticate(loginToken()).block()) .isInstanceOf(OAuth2AuthenticationException.class) .hasMessageContaining("[invalid_id_token] ID Token Validation Error"); }
@Test public void authenticationWhenOAuth2UserNotFoundThenEmpty() { OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("foo") .tokenType(OAuth2AccessToken.TokenType.BEARER) .additionalParameters(Collections.singletonMap(OidcParameterNames.ID_TOKEN, "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.")) .build(); Map<String, Object> claims = new HashMap<>(); claims.put(IdTokenClaimNames.ISS, "https://issuer.example.com"); claims.put(IdTokenClaimNames.SUB, "rob"); claims.put(IdTokenClaimNames.AUD, Arrays.asList("client-id")); Instant issuedAt = Instant.now(); Instant expiresAt = Instant.from(issuedAt).plusSeconds(3600); Jwt idToken = new Jwt("id-token", issuedAt, expiresAt, claims, claims); when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(Mono.just(accessTokenResponse)); when(this.userService.loadUser(any())).thenReturn(Mono.empty()); when(this.jwtDecoder.decode(any())).thenReturn(Mono.just(idToken)); this.manager.setJwtDecoderFactory(c -> this.jwtDecoder); assertThat(this.manager.authenticate(loginToken()).block()).isNull(); }
@Test public void authenticateWhenTokenSuccessResponseThenAdditionalParametersAddedToUserRequest() { Map<String, Object> additionalParameters = new HashMap<>(); additionalParameters.put("param1", "value1"); additionalParameters.put("param2", "value2"); OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("foo") .tokenType(OAuth2AccessToken.TokenType.BEARER) .additionalParameters(additionalParameters) .build(); when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(Mono.just(accessTokenResponse)); DefaultOAuth2User user = new DefaultOAuth2User(AuthorityUtils.createAuthorityList("ROLE_USER"), Collections.singletonMap("user", "rob"), "user"); ArgumentCaptor<OAuth2UserRequest> userRequestArgCaptor = ArgumentCaptor.forClass(OAuth2UserRequest.class); when(this.userService.loadUser(userRequestArgCaptor.capture())).thenReturn(Mono.just(user)); this.manager.authenticate(loginToken()).block(); assertThat(userRequestArgCaptor.getValue().getAdditionalParameters()) .containsAllEntriesOf(accessTokenResponse.getAdditionalParameters()); }
private static OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> createOauth2AccessTokenResponseClient() { return request -> { Map<String, Object> additionalParameters = new HashMap<>(); if (request.getAuthorizationExchange().getAuthorizationRequest().getScopes().contains("openid")) { additionalParameters.put(OidcParameterNames.ID_TOKEN, "token123"); } return OAuth2AccessTokenResponse.withToken("accessToken123") .tokenType(OAuth2AccessToken.TokenType.BEARER) .additionalParameters(additionalParameters) .build(); }; }
@Test public void writeInternalWhenConversionFailsThenThrowHttpMessageNotWritableException() { Converter tokenResponseParametersConverter = mock(Converter.class); when(tokenResponseParametersConverter.convert(any())).thenThrow(RuntimeException.class); this.messageConverter.setTokenResponseParametersConverter(tokenResponseParametersConverter); OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse .withToken("access-token-1234") .tokenType(OAuth2AccessToken.TokenType.BEARER) .expiresIn(Instant.now().plusSeconds(3600).toEpochMilli()) .build(); MockHttpOutputMessage outputMessage = new MockHttpOutputMessage(); assertThatThrownBy(() -> this.messageConverter.writeInternal(accessTokenResponse, outputMessage)) .isInstanceOf(HttpMessageNotWritableException.class) .hasMessageContaining("An error occurred writing the OAuth 2.0 Access Token Response"); } }
@Test public void authenticationWhenOAuth2UserFoundThenSuccess() { OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("foo") .tokenType(OAuth2AccessToken.TokenType.BEARER) .additionalParameters(Collections.singletonMap(OidcParameterNames.ID_TOKEN, this.idToken.getTokenValue())) .build(); Map<String, Object> claims = new HashMap<>(); claims.put(IdTokenClaimNames.ISS, "https://issuer.example.com"); claims.put(IdTokenClaimNames.SUB, "rob"); claims.put(IdTokenClaimNames.AUD, Arrays.asList("client-id")); Instant issuedAt = Instant.now(); Instant expiresAt = Instant.from(issuedAt).plusSeconds(3600); Jwt idToken = new Jwt("id-token", issuedAt, expiresAt, claims, claims); when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(Mono.just(accessTokenResponse)); DefaultOidcUser user = new DefaultOidcUser(AuthorityUtils.createAuthorityList("ROLE_USER"), this.idToken); when(this.userService.loadUser(any())).thenReturn(Mono.just(user)); when(this.jwtDecoder.decode(any())).thenReturn(Mono.just(idToken)); this.manager.setJwtDecoderFactory(c -> this.jwtDecoder); OAuth2LoginAuthenticationToken result = (OAuth2LoginAuthenticationToken) this.manager.authenticate(loginToken()).block(); assertThat(result.getPrincipal()).isEqualTo(user); assertThat(result.getAuthorities()).containsOnlyElementsOf(user.getAuthorities()); assertThat(result.isAuthenticated()).isTrue(); }
@Test public void buildWhenResponseAndRefreshNullThenRefreshNull() { Instant expiresAt = Instant.now().plusSeconds(5); Set<String> scopes = new LinkedHashSet<>(Arrays.asList("scope1", "scope2")); Map<String, Object> additionalParameters = new HashMap<>(); additionalParameters.put("param1", "value1"); additionalParameters.put("param2", "value2"); OAuth2AccessTokenResponse tokenResponse = OAuth2AccessTokenResponse .withToken(TOKEN_VALUE) .tokenType(OAuth2AccessToken.TokenType.BEARER) .expiresIn(expiresAt.toEpochMilli()) .scopes(scopes) .additionalParameters(additionalParameters) .build(); OAuth2AccessTokenResponse withResponse = OAuth2AccessTokenResponse.withResponse(tokenResponse) .build(); assertThat(withResponse.getRefreshToken()).isNull(); } }
@Test public void authenticationWhenRefreshTokenThenRefreshTokenInAuthorizedClient() { OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("foo") .tokenType(OAuth2AccessToken.TokenType.BEARER) .additionalParameters(Collections.singletonMap(OidcParameterNames.ID_TOKEN, this.idToken.getTokenValue())) .refreshToken("refresh-token") .build(); Map<String, Object> claims = new HashMap<>(); claims.put(IdTokenClaimNames.ISS, "https://issuer.example.com"); claims.put(IdTokenClaimNames.SUB, "rob"); claims.put(IdTokenClaimNames.AUD, Arrays.asList("client-id")); Instant issuedAt = Instant.now(); Instant expiresAt = Instant.from(issuedAt).plusSeconds(3600); Jwt idToken = new Jwt("id-token", issuedAt, expiresAt, claims, claims); when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(Mono.just(accessTokenResponse)); DefaultOidcUser user = new DefaultOidcUser(AuthorityUtils.createAuthorityList("ROLE_USER"), this.idToken); when(this.userService.loadUser(any())).thenReturn(Mono.just(user)); when(this.jwtDecoder.decode(any())).thenReturn(Mono.just(idToken)); this.manager.setJwtDecoderFactory(c -> this.jwtDecoder); OAuth2LoginAuthenticationToken result = (OAuth2LoginAuthenticationToken) this.manager.authenticate(loginToken()).block(); assertThat(result.getPrincipal()).isEqualTo(user); assertThat(result.getAuthorities()).containsOnlyElementsOf(user.getAuthorities()); assertThat(result.isAuthenticated()).isTrue(); assertThat(result.getRefreshToken().getTokenValue()).isNotNull(); }
@Test(expected = IllegalArgumentException.class) public void buildWhenTokenValueIsNullThenThrowIllegalArgumentException() { OAuth2AccessTokenResponse.withToken(null) .tokenType(OAuth2AccessToken.TokenType.BEARER) .expiresIn(EXPIRES_IN) .build(); }
@Test(expected = IllegalArgumentException.class) public void buildWhenTokenTypeIsNullThenThrowIllegalArgumentException() { OAuth2AccessTokenResponse.withToken(TOKEN_VALUE) .tokenType(null) .expiresIn(EXPIRES_IN) .build(); }
@SuppressWarnings("unchecked") @Test public void resolveArgumentWhenAuthorizedClientNotFoundForClientCredentialsClientThenResolvesFromTokenResponseClient() throws Exception { OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> clientCredentialsTokenResponseClient = mock(OAuth2AccessTokenResponseClient.class); this.argumentResolver.setClientCredentialsTokenResponseClient(clientCredentialsTokenResponseClient); OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse .withToken("access-token-1234") .tokenType(OAuth2AccessToken.TokenType.BEARER) .expiresIn(3600) .build(); when(clientCredentialsTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse); when(this.authorizedClientRepository.loadAuthorizedClient(anyString(), any(), any(HttpServletRequest.class))) .thenReturn(null); MethodParameter methodParameter = this.getMethodParameter("clientCredentialsClient", OAuth2AuthorizedClient.class); OAuth2AuthorizedClient authorizedClient = (OAuth2AuthorizedClient) this.argumentResolver.resolveArgument( methodParameter, null, new ServletWebRequest(this.request), null); assertThat(authorizedClient).isNotNull(); assertThat(authorizedClient.getClientRegistration()).isSameAs(this.registration2); assertThat(authorizedClient.getPrincipalName()).isEqualTo(this.principalName); assertThat(authorizedClient.getAccessToken()).isSameAs(accessTokenResponse.getAccessToken()); verify(this.authorizedClientRepository).saveAuthorizedClient( eq(authorizedClient), eq(this.authentication), any(HttpServletRequest.class), eq(null)); }
@Test public void buildWhenAllAttributesProvidedThenAllAttributesAreSet() { Instant expiresAt = Instant.now().plusSeconds(5); Set<String> scopes = new LinkedHashSet<>(Arrays.asList("scope1", "scope2")); Map<String, Object> additionalParameters = new HashMap<>(); additionalParameters.put("param1", "value1"); additionalParameters.put("param2", "value2"); OAuth2AccessTokenResponse tokenResponse = OAuth2AccessTokenResponse .withToken(TOKEN_VALUE) .tokenType(OAuth2AccessToken.TokenType.BEARER) .expiresIn(expiresAt.toEpochMilli()) .scopes(scopes) .refreshToken(REFRESH_TOKEN_VALUE) .additionalParameters(additionalParameters) .build(); assertThat(tokenResponse.getAccessToken()).isNotNull(); assertThat(tokenResponse.getAccessToken().getTokenValue()).isEqualTo(TOKEN_VALUE); assertThat(tokenResponse.getAccessToken().getTokenType()).isEqualTo(OAuth2AccessToken.TokenType.BEARER); assertThat(tokenResponse.getAccessToken().getIssuedAt()).isNotNull(); assertThat(tokenResponse.getAccessToken().getExpiresAt()).isAfterOrEqualTo(expiresAt); assertThat(tokenResponse.getAccessToken().getScopes()).isEqualTo(scopes); assertThat(tokenResponse.getRefreshToken().getTokenValue()).isEqualTo(REFRESH_TOKEN_VALUE); assertThat(tokenResponse.getAdditionalParameters()).isEqualTo(additionalParameters); }
@Test public void buildWhenResponseThenAllAttributesAreSet() { Instant expiresAt = Instant.now().plusSeconds(5); Set<String> scopes = new LinkedHashSet<>(Arrays.asList("scope1", "scope2")); Map<String, Object> additionalParameters = new HashMap<>(); additionalParameters.put("param1", "value1"); additionalParameters.put("param2", "value2"); OAuth2AccessTokenResponse tokenResponse = OAuth2AccessTokenResponse .withToken(TOKEN_VALUE) .tokenType(OAuth2AccessToken.TokenType.BEARER) .expiresIn(expiresAt.toEpochMilli()) .scopes(scopes) .refreshToken(REFRESH_TOKEN_VALUE) .additionalParameters(additionalParameters) .build(); OAuth2AccessTokenResponse withResponse = OAuth2AccessTokenResponse.withResponse(tokenResponse) .build(); assertThat(withResponse.getAccessToken().getTokenValue()).isEqualTo(tokenResponse.getAccessToken().getTokenValue()); assertThat(withResponse.getAccessToken().getTokenType()).isEqualTo(OAuth2AccessToken.TokenType.BEARER); assertThat(withResponse.getAccessToken().getIssuedAt()).isEqualTo(tokenResponse.getAccessToken().getIssuedAt()); assertThat(withResponse.getAccessToken().getExpiresAt()).isEqualTo(tokenResponse.getAccessToken().getExpiresAt()); assertThat(withResponse.getAccessToken().getScopes()).isEqualTo(tokenResponse.getAccessToken().getScopes()); assertThat(withResponse.getRefreshToken().getTokenValue()).isEqualTo(tokenResponse.getRefreshToken().getTokenValue()); assertThat(withResponse.getAdditionalParameters()).isEqualTo(tokenResponse.getAdditionalParameters()); }
@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)); }
@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)); }