From 02d29887fb6c682b3487754bb7a6fedda25008c4 Mon Sep 17 00:00:00 2001 From: Joe Grandja Date: Mon, 11 Jun 2018 14:10:38 -0400 Subject: [PATCH] Associate Refresh Token to OAuth2AuthorizedClient Fixes gh-5416 --- .../oauth2/client/OAuth2AuthorizedClient.java | 30 +++++++++++- ...thorizationCodeAuthenticationProvider.java | 6 +-- ...2AuthorizationCodeAuthenticationToken.java | 29 ++++++++++++ .../OAuth2LoginAuthenticationProvider.java | 5 +- .../OAuth2LoginAuthenticationToken.java | 37 ++++++++++++++- ...th2LoginReactiveAuthenticationManager.java | 6 ++- ...sAuthorizationCodeTokenResponseClient.java | 8 +++- ...eAuthorizationCodeTokenResponseClient.java | 6 +++ ...thorizationCodeAuthenticationProvider.java | 10 ++-- .../OAuth2AuthorizationCodeGrantFilter.java | 3 +- .../web/OAuth2LoginAuthenticationFilter.java | 3 +- ...zationCodeAuthenticationProviderTests.java | 4 ++ ...Auth2LoginAuthenticationProviderTests.java | 6 ++- ...orizationCodeTokenResponseClientTests.java | 4 +- ...orizationCodeTokenResponseClientTests.java | 2 + ...zationCodeAuthenticationProviderTests.java | 7 ++- ...uth2AuthorizationCodeGrantFilterTests.java | 3 ++ .../OAuth2LoginAuthenticationFilterTests.java | 5 +- .../oauth2/core/AuthorizationGrantType.java | 3 +- .../oauth2/core/OAuth2RefreshToken.java | 46 +++++++++++++++++++ .../endpoint/OAuth2AccessTokenResponse.java | 37 ++++++++++++++- .../core/AuthorizationGrantTypeTests.java | 7 ++- .../OAuth2AccessTokenResponseTests.java | 5 +- 23 files changed, 245 insertions(+), 27 deletions(-) create mode 100644 oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/OAuth2RefreshToken.java diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/OAuth2AuthorizedClient.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/OAuth2AuthorizedClient.java index 392a947705..298658324a 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/OAuth2AuthorizedClient.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/OAuth2AuthorizedClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,8 +15,10 @@ */ package org.springframework.security.oauth2.client; +import org.springframework.lang.Nullable; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.security.oauth2.core.OAuth2RefreshToken; import org.springframework.util.Assert; /** @@ -33,11 +35,13 @@ import org.springframework.util.Assert; * @since 5.0 * @see ClientRegistration * @see OAuth2AccessToken + * @see OAuth2RefreshToken */ public class OAuth2AuthorizedClient { private final ClientRegistration clientRegistration; private final String principalName; private final OAuth2AccessToken accessToken; + private final OAuth2RefreshToken refreshToken; /** * Constructs an {@code OAuth2AuthorizedClient} using the provided parameters. @@ -47,12 +51,26 @@ public class OAuth2AuthorizedClient { * @param accessToken the access token credential granted */ public OAuth2AuthorizedClient(ClientRegistration clientRegistration, String principalName, OAuth2AccessToken accessToken) { + this(clientRegistration, principalName, accessToken, null); + } + + /** + * Constructs an {@code OAuth2AuthorizedClient} using the provided parameters. + * + * @param clientRegistration the authorized client's registration + * @param principalName the name of the End-User {@code Principal} (Resource Owner) + * @param accessToken the access token credential granted + * @param refreshToken the refresh token credential granted + */ + public OAuth2AuthorizedClient(ClientRegistration clientRegistration, String principalName, + OAuth2AccessToken accessToken, @Nullable OAuth2RefreshToken refreshToken) { Assert.notNull(clientRegistration, "clientRegistration cannot be null"); Assert.hasText(principalName, "principalName cannot be empty"); Assert.notNull(accessToken, "accessToken cannot be null"); this.clientRegistration = clientRegistration; this.principalName = principalName; this.accessToken = accessToken; + this.refreshToken = refreshToken; } /** @@ -81,4 +99,14 @@ public class OAuth2AuthorizedClient { public OAuth2AccessToken getAccessToken() { return this.accessToken; } + + /** + * Returns the {@link OAuth2RefreshToken refresh token} credential granted. + * + * @since 5.1 + * @return the {@link OAuth2RefreshToken} + */ + public @Nullable OAuth2RefreshToken getRefreshToken() { + return this.refreshToken; + } } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationProvider.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationProvider.java index c202a31f3e..e88fc1e43e 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationProvider.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationProvider.java @@ -20,7 +20,6 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient; import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest; -import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; import org.springframework.util.Assert; @@ -69,13 +68,12 @@ public class OAuth2AuthorizationCodeAuthenticationProvider implements Authentica authorizationCodeAuthentication.getClientRegistration(), authorizationCodeAuthentication.getAuthorizationExchange())); - OAuth2AccessToken accessToken = accessTokenResponse.getAccessToken(); - OAuth2AuthorizationCodeAuthenticationToken authenticationResult = new OAuth2AuthorizationCodeAuthenticationToken( authorizationCodeAuthentication.getClientRegistration(), authorizationCodeAuthentication.getAuthorizationExchange(), - accessToken); + accessTokenResponse.getAccessToken(), + accessTokenResponse.getRefreshToken()); authenticationResult.setDetails(authorizationCodeAuthentication.getDetails()); return authenticationResult; diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationToken.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationToken.java index bbc6d4aca1..969a10a0a8 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationToken.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationToken.java @@ -15,10 +15,12 @@ */ package org.springframework.security.oauth2.client.authentication; +import org.springframework.lang.Nullable; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.SpringSecurityCoreVersion; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.security.oauth2.core.OAuth2RefreshToken; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; import org.springframework.util.Assert; @@ -40,6 +42,7 @@ public class OAuth2AuthorizationCodeAuthenticationToken extends AbstractAuthenti private ClientRegistration clientRegistration; private OAuth2AuthorizationExchange authorizationExchange; private OAuth2AccessToken accessToken; + private OAuth2RefreshToken refreshToken; /** * This constructor should be used when the Authorization Request/Response is complete. @@ -67,9 +70,26 @@ public class OAuth2AuthorizationCodeAuthenticationToken extends AbstractAuthenti public OAuth2AuthorizationCodeAuthenticationToken(ClientRegistration clientRegistration, OAuth2AuthorizationExchange authorizationExchange, OAuth2AccessToken accessToken) { + this(clientRegistration, authorizationExchange, accessToken, null); + } + + /** + * This constructor should be used when the Access Token Request/Response is complete, + * which indicates that the Authorization Code Grant flow has fully completed. + * + * @param clientRegistration the client registration + * @param authorizationExchange the authorization exchange + * @param accessToken the access token credential + * @param refreshToken the refresh token credential + */ + public OAuth2AuthorizationCodeAuthenticationToken(ClientRegistration clientRegistration, + OAuth2AuthorizationExchange authorizationExchange, + OAuth2AccessToken accessToken, + @Nullable OAuth2RefreshToken refreshToken) { this(clientRegistration, authorizationExchange); Assert.notNull(accessToken, "accessToken cannot be null"); this.accessToken = accessToken; + this.refreshToken = refreshToken; this.setAuthenticated(true); } @@ -111,4 +131,13 @@ public class OAuth2AuthorizationCodeAuthenticationToken extends AbstractAuthenti public OAuth2AccessToken getAccessToken() { return this.accessToken; } + + /** + * Returns the {@link OAuth2RefreshToken refresh token}. + * + * @return the {@link OAuth2RefreshToken} + */ + public @Nullable OAuth2RefreshToken getRefreshToken() { + return this.refreshToken; + } } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProvider.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProvider.java index d3c442f334..843424df63 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProvider.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -113,7 +113,8 @@ public class OAuth2LoginAuthenticationProvider implements AuthenticationProvider authorizationCodeAuthentication.getAuthorizationExchange(), oauth2User, mappedAuthorities, - accessToken); + accessToken, + accessTokenResponse.getRefreshToken()); authenticationResult.setDetails(authorizationCodeAuthentication.getDetails()); return authenticationResult; diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationToken.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationToken.java index 0709ac7cd1..32311da81e 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationToken.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationToken.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,11 +15,13 @@ */ package org.springframework.security.oauth2.client.authentication; +import org.springframework.lang.Nullable; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.SpringSecurityCoreVersion; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.security.oauth2.core.OAuth2RefreshToken; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.util.Assert; @@ -46,6 +48,7 @@ public class OAuth2LoginAuthenticationToken extends AbstractAuthenticationToken private ClientRegistration clientRegistration; private OAuth2AuthorizationExchange authorizationExchange; private OAuth2AccessToken accessToken; + private OAuth2RefreshToken refreshToken; /** * This constructor should be used when the Authorization Request/Response is complete. @@ -80,6 +83,27 @@ public class OAuth2LoginAuthenticationToken extends AbstractAuthenticationToken OAuth2User principal, Collection authorities, OAuth2AccessToken accessToken) { + this(clientRegistration, authorizationExchange, principal, authorities, accessToken, null); + } + + /** + * This constructor should be used when the Access Token Request/Response is complete, + * which indicates that the Authorization Code Grant flow has fully completed + * and OAuth 2.0 Login has been achieved. + * + * @param clientRegistration the client registration + * @param authorizationExchange the authorization exchange + * @param principal the user {@code Principal} registered with the OAuth 2.0 Provider + * @param authorities the authorities granted to the user + * @param accessToken the access token credential + * @param refreshToken the refresh token credential + */ + public OAuth2LoginAuthenticationToken(ClientRegistration clientRegistration, + OAuth2AuthorizationExchange authorizationExchange, + OAuth2User principal, + Collection authorities, + OAuth2AccessToken accessToken, + @Nullable OAuth2RefreshToken refreshToken) { super(authorities); Assert.notNull(clientRegistration, "clientRegistration cannot be null"); Assert.notNull(authorizationExchange, "authorizationExchange cannot be null"); @@ -89,6 +113,7 @@ public class OAuth2LoginAuthenticationToken extends AbstractAuthenticationToken this.authorizationExchange = authorizationExchange; this.principal = principal; this.accessToken = accessToken; + this.refreshToken = refreshToken; this.setAuthenticated(true); } @@ -128,4 +153,14 @@ public class OAuth2LoginAuthenticationToken extends AbstractAuthenticationToken public OAuth2AccessToken getAccessToken() { return this.accessToken; } + + /** + * Returns the {@link OAuth2RefreshToken refresh token}. + * + * @since 5.1 + * @return the {@link OAuth2RefreshToken} + */ + public @Nullable OAuth2RefreshToken getRefreshToken() { + return this.refreshToken; + } } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginReactiveAuthenticationManager.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginReactiveAuthenticationManager.java index 8509db1f2f..03aeca3397 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginReactiveAuthenticationManager.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginReactiveAuthenticationManager.java @@ -120,11 +120,13 @@ public class OAuth2LoginReactiveAuthenticationManager implements authorizationCodeAuthentication.getAuthorizationExchange(), oauth2User, mappedAuthorities, - accessToken); + accessToken, + accessTokenResponse.getRefreshToken()); OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient( authenticationResult.getClientRegistration(), authenticationResult.getName(), - authenticationResult.getAccessToken()); + authenticationResult.getAccessToken(), + authenticationResult.getRefreshToken()); OAuth2AuthenticationToken result = new OAuth2AuthenticationToken( authenticationResult.getPrincipal(), authenticationResult.getAuthorities(), diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/NimbusAuthorizationCodeTokenResponseClient.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/NimbusAuthorizationCodeTokenResponseClient.java index ba791b7316..1f1b4ee4c8 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/NimbusAuthorizationCodeTokenResponseClient.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/NimbusAuthorizationCodeTokenResponseClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -138,12 +138,18 @@ public class NimbusAuthorizationCodeTokenResponseClient implements OAuth2AccessT accessTokenResponse.getTokens().getAccessToken().getScope().toStringList()); } + String refreshToken = null; + if (accessTokenResponse.getTokens().getRefreshToken() != null) { + refreshToken = accessTokenResponse.getTokens().getRefreshToken().getValue(); + } + Map additionalParameters = new LinkedHashMap<>(accessTokenResponse.getCustomParameters()); return OAuth2AccessTokenResponse.withToken(accessToken) .tokenType(accessTokenType) .expiresIn(expiresIn) .scopes(scopes) + .refreshToken(refreshToken) .additionalParameters(additionalParameters) .build(); } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/NimbusReactiveAuthorizationCodeTokenResponseClient.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/NimbusReactiveAuthorizationCodeTokenResponseClient.java index cb937ea12d..f92c6cf36f 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/NimbusReactiveAuthorizationCodeTokenResponseClient.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/endpoint/NimbusReactiveAuthorizationCodeTokenResponseClient.java @@ -118,6 +118,11 @@ public class NimbusReactiveAuthorizationCodeTokenResponseClient implements React accessToken.getScope().toStringList()); } + String refreshToken = null; + if (accessTokenResponse.getTokens().getRefreshToken() != null) { + refreshToken = accessTokenResponse.getTokens().getRefreshToken().getValue(); + } + Map additionalParameters = new LinkedHashMap<>( accessTokenResponse.getCustomParameters()); @@ -125,6 +130,7 @@ public class NimbusReactiveAuthorizationCodeTokenResponseClient implements React .tokenType(accessTokenType) .expiresIn(expiresIn) .scopes(scopes) + .refreshToken(refreshToken) .additionalParameters(additionalParameters) .build(); }); diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProvider.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProvider.java index 33f2be8840..ba35276934 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProvider.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,6 @@ import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest; import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; -import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; @@ -142,8 +141,6 @@ public class OidcAuthorizationCodeAuthenticationProvider implements Authenticati authorizationCodeAuthentication.getClientRegistration(), authorizationCodeAuthentication.getAuthorizationExchange())); - OAuth2AccessToken accessToken = accessTokenResponse.getAccessToken(); - ClientRegistration clientRegistration = authorizationCodeAuthentication.getClientRegistration(); if (!accessTokenResponse.getAdditionalParameters().containsKey(OidcParameterNames.ID_TOKEN)) { @@ -161,7 +158,7 @@ public class OidcAuthorizationCodeAuthenticationProvider implements Authenticati this.validateIdToken(idToken, clientRegistration); OidcUser oidcUser = this.userService.loadUser( - new OidcUserRequest(clientRegistration, accessToken, idToken)); + new OidcUserRequest(clientRegistration, accessTokenResponse.getAccessToken(), idToken)); Collection mappedAuthorities = this.authoritiesMapper.mapAuthorities(oidcUser.getAuthorities()); @@ -171,7 +168,8 @@ public class OidcAuthorizationCodeAuthenticationProvider implements Authenticati authorizationCodeAuthentication.getAuthorizationExchange(), oidcUser, mappedAuthorities, - accessToken); + accessTokenResponse.getAccessToken(), + accessTokenResponse.getRefreshToken()); authenticationResult.setDetails(authorizationCodeAuthentication.getDetails()); return authenticationResult; diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationCodeGrantFilter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationCodeGrantFilter.java index 62ce8868a1..eac55375a8 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationCodeGrantFilter.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationCodeGrantFilter.java @@ -198,7 +198,8 @@ public class OAuth2AuthorizationCodeGrantFilter extends OncePerRequestFilter { OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient( authenticationResult.getClientRegistration(), currentAuthentication.getName(), - authenticationResult.getAccessToken()); + authenticationResult.getAccessToken(), + authenticationResult.getRefreshToken()); this.authorizedClientService.saveAuthorizedClient(authorizedClient, currentAuthentication); diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilter.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilter.java index 231b7f5c78..d9a3d9f9bc 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilter.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilter.java @@ -173,7 +173,8 @@ public class OAuth2LoginAuthenticationFilter extends AbstractAuthenticationProce OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient( authenticationResult.getClientRegistration(), oauth2Authentication.getName(), - authenticationResult.getAccessToken()); + authenticationResult.getAccessToken(), + authenticationResult.getRefreshToken()); this.authorizedClientService.saveAuthorizedClient(authorizedClient, oauth2Authentication); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java index ba88b9f570..85176b0d08 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java @@ -27,6 +27,7 @@ import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.OAuth2ErrorCodes; +import org.springframework.security.oauth2.core.OAuth2RefreshToken; import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; @@ -122,8 +123,10 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests { @Test public void authenticateWhenAuthorizationSuccessResponseThenExchangedForAccessToken() { OAuth2AccessToken accessToken = mock(OAuth2AccessToken.class); + OAuth2RefreshToken refreshToken = mock(OAuth2RefreshToken.class); OAuth2AccessTokenResponse accessTokenResponse = mock(OAuth2AccessTokenResponse.class); when(accessTokenResponse.getAccessToken()).thenReturn(accessToken); + when(accessTokenResponse.getRefreshToken()).thenReturn(refreshToken); when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse); OAuth2AuthorizationCodeAuthenticationToken authenticationResult = @@ -137,5 +140,6 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests { assertThat(authenticationResult.getClientRegistration()).isEqualTo(this.clientRegistration); assertThat(authenticationResult.getAuthorizationExchange()).isEqualTo(this.authorizationExchange); assertThat(authenticationResult.getAccessToken()).isEqualTo(accessToken); + assertThat(authenticationResult.getRefreshToken()).isEqualTo(refreshToken); } } diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProviderTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProviderTests.java index 63c54dbf33..668f007f15 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProviderTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationProviderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,6 +35,7 @@ import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.OAuth2ErrorCodes; +import org.springframework.security.oauth2.core.OAuth2RefreshToken; import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; @@ -164,8 +165,10 @@ public class OAuth2LoginAuthenticationProviderTests { @Test public void authenticateWhenLoginSuccessThenReturnAuthentication() { OAuth2AccessToken accessToken = mock(OAuth2AccessToken.class); + OAuth2RefreshToken refreshToken = mock(OAuth2RefreshToken.class); OAuth2AccessTokenResponse accessTokenResponse = mock(OAuth2AccessTokenResponse.class); when(accessTokenResponse.getAccessToken()).thenReturn(accessToken); + when(accessTokenResponse.getRefreshToken()).thenReturn(refreshToken); when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse); OAuth2User principal = mock(OAuth2User.class); @@ -185,6 +188,7 @@ public class OAuth2LoginAuthenticationProviderTests { assertThat(authentication.getClientRegistration()).isEqualTo(this.clientRegistration); assertThat(authentication.getAuthorizationExchange()).isEqualTo(this.authorizationExchange); assertThat(authentication.getAccessToken()).isEqualTo(accessToken); + assertThat(authentication.getRefreshToken()).isEqualTo(refreshToken); } @Test diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/NimbusAuthorizationCodeTokenResponseClientTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/NimbusAuthorizationCodeTokenResponseClientTests.java index 8c63eecb1a..00d3f8b77b 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/NimbusAuthorizationCodeTokenResponseClientTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/NimbusAuthorizationCodeTokenResponseClientTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -91,6 +91,7 @@ public class NimbusAuthorizationCodeTokenResponseClientTests { " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n" + " \"scope\": \"openid profile\",\n" + + " \"refresh_token\": \"refresh-token-1234\",\n" + " \"custom_parameter_1\": \"custom-value-1\",\n" + " \"custom_parameter_2\": \"custom-value-2\"\n" + "}\n"; @@ -115,6 +116,7 @@ public class NimbusAuthorizationCodeTokenResponseClientTests { assertThat(accessTokenResponse.getAccessToken().getTokenType()).isEqualTo(OAuth2AccessToken.TokenType.BEARER); assertThat(accessTokenResponse.getAccessToken().getExpiresAt()).isBetween(expiresAtBefore, expiresAtAfter); assertThat(accessTokenResponse.getAccessToken().getScopes()).containsExactly("openid", "profile"); + assertThat(accessTokenResponse.getRefreshToken().getTokenValue()).isEqualTo("refresh-token-1234"); assertThat(accessTokenResponse.getAdditionalParameters().size()).isEqualTo(2); assertThat(accessTokenResponse.getAdditionalParameters()).containsEntry("custom_parameter_1", "custom-value-1"); assertThat(accessTokenResponse.getAdditionalParameters()).containsEntry("custom_parameter_2", "custom-value-2"); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/NimbusReactiveAuthorizationCodeTokenResponseClientTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/NimbusReactiveAuthorizationCodeTokenResponseClientTests.java index 6f3c93ad24..2fe61e1e61 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/NimbusReactiveAuthorizationCodeTokenResponseClientTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/endpoint/NimbusReactiveAuthorizationCodeTokenResponseClientTests.java @@ -85,6 +85,7 @@ public class NimbusReactiveAuthorizationCodeTokenResponseClientTests { " \"token_type\": \"bearer\",\n" + " \"expires_in\": \"3600\",\n" + " \"scope\": \"openid profile\",\n" + + " \"refresh_token\": \"refresh-token-1234\",\n" + " \"custom_parameter_1\": \"custom-value-1\",\n" + " \"custom_parameter_2\": \"custom-value-2\"\n" + "}\n"; @@ -102,6 +103,7 @@ public class NimbusReactiveAuthorizationCodeTokenResponseClientTests { OAuth2AccessToken.TokenType.BEARER); assertThat(accessTokenResponse.getAccessToken().getExpiresAt()).isBetween(expiresAtBefore, expiresAtAfter); assertThat(accessTokenResponse.getAccessToken().getScopes()).containsExactly("openid", "profile"); + assertThat(accessTokenResponse.getRefreshToken().getTokenValue()).isEqualTo("refresh-token-1234"); assertThat(accessTokenResponse.getAdditionalParameters().size()).isEqualTo(2); assertThat(accessTokenResponse.getAdditionalParameters()).containsEntry("custom_parameter_1", "custom-value-1"); assertThat(accessTokenResponse.getAdditionalParameters()).containsEntry("custom_parameter_2", "custom-value-2"); diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProviderTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProviderTests.java index e963bc818e..6be263b1bd 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProviderTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationProviderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,6 +37,7 @@ import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.OAuth2ErrorCodes; +import org.springframework.security.oauth2.core.OAuth2RefreshToken; import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; @@ -78,6 +79,7 @@ public class OidcAuthorizationCodeAuthenticationProviderTests { private OAuth2AccessTokenResponseClient accessTokenResponseClient; private OAuth2AccessTokenResponse accessTokenResponse; private OAuth2AccessToken accessToken; + private OAuth2RefreshToken refreshToken; private OAuth2UserService userService; private OidcAuthorizationCodeAuthenticationProvider authenticationProvider; @@ -95,6 +97,7 @@ public class OidcAuthorizationCodeAuthenticationProviderTests { this.accessTokenResponseClient = mock(OAuth2AccessTokenResponseClient.class); this.accessTokenResponse = mock(OAuth2AccessTokenResponse.class); this.accessToken = mock(OAuth2AccessToken.class); + this.refreshToken = mock(OAuth2RefreshToken.class); this.userService = mock(OAuth2UserService.class); this.authenticationProvider = PowerMockito.spy( new OidcAuthorizationCodeAuthenticationProvider(this.accessTokenResponseClient, this.userService)); @@ -109,6 +112,7 @@ public class OidcAuthorizationCodeAuthenticationProviderTests { when(this.authorizationRequest.getRedirectUri()).thenReturn("http://example.com"); when(this.authorizationResponse.getRedirectUri()).thenReturn("http://example.com"); when(this.accessTokenResponse.getAccessToken()).thenReturn(this.accessToken); + when(this.accessTokenResponse.getRefreshToken()).thenReturn(this.refreshToken); Map additionalParameters = new HashMap<>(); additionalParameters.put(OidcParameterNames.ID_TOKEN, "id-token"); when(this.accessTokenResponse.getAdditionalParameters()).thenReturn(additionalParameters); @@ -365,6 +369,7 @@ public class OidcAuthorizationCodeAuthenticationProviderTests { assertThat(authentication.getClientRegistration()).isEqualTo(this.clientRegistration); assertThat(authentication.getAuthorizationExchange()).isEqualTo(this.authorizationExchange); assertThat(authentication.getAccessToken()).isEqualTo(this.accessToken); + assertThat(authentication.getRefreshToken()).isEqualTo(this.refreshToken); } @Test diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationCodeGrantFilterTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationCodeGrantFilterTests.java index 6678d6e8b9..3093adc02b 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationCodeGrantFilterTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2AuthorizationCodeGrantFilterTests.java @@ -41,6 +41,7 @@ import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.OAuth2ErrorCodes; +import org.springframework.security.oauth2.core.OAuth2RefreshToken; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; @@ -238,6 +239,7 @@ public class OAuth2AuthorizationCodeGrantFilterTests { assertThat(authorizedClient.getClientRegistration()).isEqualTo(this.registration1); assertThat(authorizedClient.getPrincipalName()).isEqualTo(this.principalName1); assertThat(authorizedClient.getAccessToken()).isNotNull(); + assertThat(authorizedClient.getRefreshToken()).isNotNull(); } @Test @@ -299,6 +301,7 @@ public class OAuth2AuthorizationCodeGrantFilterTests { when(authentication.getClientRegistration()).thenReturn(registration); when(authentication.getAuthorizationExchange()).thenReturn(mock(OAuth2AuthorizationExchange.class)); when(authentication.getAccessToken()).thenReturn(mock(OAuth2AccessToken.class)); + when(authentication.getRefreshToken()).thenReturn(mock(OAuth2RefreshToken.class)); when(this.authenticationManager.authenticate(any(Authentication.class))).thenReturn(authentication); } } diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilterTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilterTests.java index 2b788c8245..9892851d57 100644 --- a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilterTests.java +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/OAuth2LoginAuthenticationFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,6 +40,7 @@ import org.springframework.security.oauth2.core.ClientAuthenticationMethod; import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.security.oauth2.core.OAuth2AuthenticationException; import org.springframework.security.oauth2.core.OAuth2ErrorCodes; +import org.springframework.security.oauth2.core.OAuth2RefreshToken; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; @@ -281,6 +282,7 @@ public class OAuth2LoginAuthenticationFilterTests { assertThat(authorizedClient.getClientRegistration()).isEqualTo(this.registration1); assertThat(authorizedClient.getPrincipalName()).isEqualTo(this.principalName1); assertThat(authorizedClient.getAccessToken()).isNotNull(); + assertThat(authorizedClient.getRefreshToken()).isNotNull(); } @Test @@ -328,6 +330,7 @@ public class OAuth2LoginAuthenticationFilterTests { when(loginAuthentication.getClientRegistration()).thenReturn(registration); when(loginAuthentication.getAuthorizationExchange()).thenReturn(mock(OAuth2AuthorizationExchange.class)); when(loginAuthentication.getAccessToken()).thenReturn(mock(OAuth2AccessToken.class)); + when(loginAuthentication.getRefreshToken()).thenReturn(mock(OAuth2RefreshToken.class)); when(this.authenticationManager.authenticate(any(Authentication.class))).thenReturn(loginAuthentication); } } diff --git a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/AuthorizationGrantType.java b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/AuthorizationGrantType.java index 61c596162e..4e58a2c6f1 100644 --- a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/AuthorizationGrantType.java +++ b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/AuthorizationGrantType.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,6 +37,7 @@ public final class AuthorizationGrantType implements Serializable { private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; public static final AuthorizationGrantType AUTHORIZATION_CODE = new AuthorizationGrantType("authorization_code"); public static final AuthorizationGrantType IMPLICIT = new AuthorizationGrantType("implicit"); + public static final AuthorizationGrantType REFRESH_TOKEN = new AuthorizationGrantType("refresh_token"); private final String value; /** diff --git a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/OAuth2RefreshToken.java b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/OAuth2RefreshToken.java new file mode 100644 index 0000000000..7070c81024 --- /dev/null +++ b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/OAuth2RefreshToken.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.security.oauth2.core; + +import java.time.Instant; + +/** + * An implementation of an {@link AbstractOAuth2Token} representing an OAuth 2.0 Refresh Token. + * + *

+ * A refresh token is a credential that represents an authorization + * granted by the resource owner to the client. + * It is used by the client to obtain a new access token when the current access token + * becomes invalid or expires, or to obtain additional access tokens with identical or narrower scope. + * + * @author Joe Grandja + * @since 5.1 + * @see OAuth2AccessToken + * @see Section 1.5 Refresh Token + */ +public class OAuth2RefreshToken extends AbstractOAuth2Token { + + /** + * Constructs an {@code OAuth2RefreshToken} using the provided parameters. + * + * @param tokenValue the token value + * @param issuedAt the time at which the token was issued + * @param expiresAt the expiration time on or after which the token MUST NOT be accepted + */ + public OAuth2RefreshToken(String tokenValue, Instant issuedAt, Instant expiresAt) { + super(tokenValue, issuedAt, expiresAt); + } +} diff --git a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/OAuth2AccessTokenResponse.java b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/OAuth2AccessTokenResponse.java index 3630ee449c..83015ee58b 100644 --- a/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/OAuth2AccessTokenResponse.java +++ b/oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/OAuth2AccessTokenResponse.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,8 +15,11 @@ */ package org.springframework.security.oauth2.core.endpoint; +import org.springframework.lang.Nullable; import org.springframework.security.oauth2.core.OAuth2AccessToken; +import org.springframework.security.oauth2.core.OAuth2RefreshToken; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; import java.time.Instant; import java.util.Collections; @@ -29,10 +32,12 @@ import java.util.Set; * @author Joe Grandja * @since 5.0 * @see OAuth2AccessToken + * @see OAuth2RefreshToken * @see Section 5.1 Access Token Response */ public final class OAuth2AccessTokenResponse { private OAuth2AccessToken accessToken; + private OAuth2RefreshToken refreshToken; private Map additionalParameters; private OAuth2AccessTokenResponse() { @@ -47,6 +52,16 @@ public final class OAuth2AccessTokenResponse { return this.accessToken; } + /** + * Returns the {@link OAuth2RefreshToken Refresh Token}. + * + * @since 5.1 + * @return the {@link OAuth2RefreshToken} + */ + public @Nullable OAuth2RefreshToken getRefreshToken() { + return this.refreshToken; + } + /** * Returns the additional parameters returned in the response. * @@ -74,6 +89,7 @@ public final class OAuth2AccessTokenResponse { private OAuth2AccessToken.TokenType tokenType; private long expiresIn; private Set scopes; + private String refreshToken; private Map additionalParameters; private Builder(String tokenValue) { @@ -113,6 +129,17 @@ public final class OAuth2AccessTokenResponse { return this; } + /** + * Sets the refresh token associated to the access token. + * + * @param refreshToken the refresh token associated to the access token. + * @return the {@link Builder} + */ + public Builder refreshToken(String refreshToken) { + this.refreshToken = refreshToken; + return this; + } + /** * Sets the additional parameters returned in the response. * @@ -142,6 +169,14 @@ public final class OAuth2AccessTokenResponse { OAuth2AccessTokenResponse accessTokenResponse = new OAuth2AccessTokenResponse(); accessTokenResponse.accessToken = new OAuth2AccessToken( this.tokenType, this.tokenValue, issuedAt, expiresAt, this.scopes); + if (StringUtils.hasText(this.refreshToken)) { + // The Access Token response does not return an expires_in for the Refresh Token, + // therefore, we'll default to +1 second from issuedAt time. + // NOTE: + // The expiry or invalidity of a Refresh Token can only be determined by performing + // the refresh_token grant and if it fails than likely it has expired or has been invalidated. + accessTokenResponse.refreshToken = new OAuth2RefreshToken(this.refreshToken, issuedAt, issuedAt.plusSeconds(1)); + } accessTokenResponse.additionalParameters = Collections.unmodifiableMap( CollectionUtils.isEmpty(this.additionalParameters) ? Collections.emptyMap() : this.additionalParameters); return accessTokenResponse; diff --git a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/AuthorizationGrantTypeTests.java b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/AuthorizationGrantTypeTests.java index dea90e92b1..2d94930c48 100644 --- a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/AuthorizationGrantTypeTests.java +++ b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/AuthorizationGrantTypeTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,4 +40,9 @@ public class AuthorizationGrantTypeTests { public void getValueWhenImplicitGrantTypeThenReturnImplicit() { assertThat(AuthorizationGrantType.IMPLICIT.getValue()).isEqualTo("implicit"); } + + @Test + public void getValueWhenRefreshTokenGrantTypeThenReturnRefreshToken() { + assertThat(AuthorizationGrantType.REFRESH_TOKEN.getValue()).isEqualTo("refresh_token"); + } } diff --git a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/OAuth2AccessTokenResponseTests.java b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/OAuth2AccessTokenResponseTests.java index 2346347aad..cfd5a0dedf 100644 --- a/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/OAuth2AccessTokenResponseTests.java +++ b/oauth2/oauth2-core/src/test/java/org/springframework/security/oauth2/core/endpoint/OAuth2AccessTokenResponseTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,6 +35,7 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class OAuth2AccessTokenResponseTests { private static final String TOKEN_VALUE = "access-token"; + private static final String REFRESH_TOKEN_VALUE = "refresh-token"; private static final long EXPIRES_IN = Instant.now().plusSeconds(5).toEpochMilli(); @Test(expected = IllegalArgumentException.class) @@ -88,6 +89,7 @@ public class OAuth2AccessTokenResponseTests { .tokenType(OAuth2AccessToken.TokenType.BEARER) .expiresIn(expiresAt.toEpochMilli()) .scopes(scopes) + .refreshToken(REFRESH_TOKEN_VALUE) .additionalParameters(additionalParameters) .build(); @@ -97,6 +99,7 @@ public class OAuth2AccessTokenResponseTests { 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); } }