Associate Refresh Token to OAuth2AuthorizedClient
Fixes gh-5416
This commit is contained in:
parent
1137f3b46d
commit
02d29887fb
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -15,8 +15,10 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.security.oauth2.client;
|
package org.springframework.security.oauth2.client;
|
||||||
|
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,11 +35,13 @@ import org.springframework.util.Assert;
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
* @see ClientRegistration
|
* @see ClientRegistration
|
||||||
* @see OAuth2AccessToken
|
* @see OAuth2AccessToken
|
||||||
|
* @see OAuth2RefreshToken
|
||||||
*/
|
*/
|
||||||
public class OAuth2AuthorizedClient {
|
public class OAuth2AuthorizedClient {
|
||||||
private final ClientRegistration clientRegistration;
|
private final ClientRegistration clientRegistration;
|
||||||
private final String principalName;
|
private final String principalName;
|
||||||
private final OAuth2AccessToken accessToken;
|
private final OAuth2AccessToken accessToken;
|
||||||
|
private final OAuth2RefreshToken refreshToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an {@code OAuth2AuthorizedClient} using the provided parameters.
|
* Constructs an {@code OAuth2AuthorizedClient} using the provided parameters.
|
||||||
|
@ -47,12 +51,26 @@ public class OAuth2AuthorizedClient {
|
||||||
* @param accessToken the access token credential granted
|
* @param accessToken the access token credential granted
|
||||||
*/
|
*/
|
||||||
public OAuth2AuthorizedClient(ClientRegistration clientRegistration, String principalName, OAuth2AccessToken accessToken) {
|
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.notNull(clientRegistration, "clientRegistration cannot be null");
|
||||||
Assert.hasText(principalName, "principalName cannot be empty");
|
Assert.hasText(principalName, "principalName cannot be empty");
|
||||||
Assert.notNull(accessToken, "accessToken cannot be null");
|
Assert.notNull(accessToken, "accessToken cannot be null");
|
||||||
this.clientRegistration = clientRegistration;
|
this.clientRegistration = clientRegistration;
|
||||||
this.principalName = principalName;
|
this.principalName = principalName;
|
||||||
this.accessToken = accessToken;
|
this.accessToken = accessToken;
|
||||||
|
this.refreshToken = refreshToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -81,4 +99,14 @@ public class OAuth2AuthorizedClient {
|
||||||
public OAuth2AccessToken getAccessToken() {
|
public OAuth2AccessToken getAccessToken() {
|
||||||
return this.accessToken;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@ import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
|
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
|
||||||
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
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.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
@ -69,13 +68,12 @@ public class OAuth2AuthorizationCodeAuthenticationProvider implements Authentica
|
||||||
authorizationCodeAuthentication.getClientRegistration(),
|
authorizationCodeAuthentication.getClientRegistration(),
|
||||||
authorizationCodeAuthentication.getAuthorizationExchange()));
|
authorizationCodeAuthentication.getAuthorizationExchange()));
|
||||||
|
|
||||||
OAuth2AccessToken accessToken = accessTokenResponse.getAccessToken();
|
|
||||||
|
|
||||||
OAuth2AuthorizationCodeAuthenticationToken authenticationResult =
|
OAuth2AuthorizationCodeAuthenticationToken authenticationResult =
|
||||||
new OAuth2AuthorizationCodeAuthenticationToken(
|
new OAuth2AuthorizationCodeAuthenticationToken(
|
||||||
authorizationCodeAuthentication.getClientRegistration(),
|
authorizationCodeAuthentication.getClientRegistration(),
|
||||||
authorizationCodeAuthentication.getAuthorizationExchange(),
|
authorizationCodeAuthentication.getAuthorizationExchange(),
|
||||||
accessToken);
|
accessTokenResponse.getAccessToken(),
|
||||||
|
accessTokenResponse.getRefreshToken());
|
||||||
authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
|
authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
|
||||||
|
|
||||||
return authenticationResult;
|
return authenticationResult;
|
||||||
|
|
|
@ -15,10 +15,12 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.security.oauth2.client.authentication;
|
package org.springframework.security.oauth2.client.authentication;
|
||||||
|
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
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.endpoint.OAuth2AuthorizationExchange;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
@ -40,6 +42,7 @@ public class OAuth2AuthorizationCodeAuthenticationToken extends AbstractAuthenti
|
||||||
private ClientRegistration clientRegistration;
|
private ClientRegistration clientRegistration;
|
||||||
private OAuth2AuthorizationExchange authorizationExchange;
|
private OAuth2AuthorizationExchange authorizationExchange;
|
||||||
private OAuth2AccessToken accessToken;
|
private OAuth2AccessToken accessToken;
|
||||||
|
private OAuth2RefreshToken refreshToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor should be used when the Authorization Request/Response is complete.
|
* 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,
|
public OAuth2AuthorizationCodeAuthenticationToken(ClientRegistration clientRegistration,
|
||||||
OAuth2AuthorizationExchange authorizationExchange,
|
OAuth2AuthorizationExchange authorizationExchange,
|
||||||
OAuth2AccessToken accessToken) {
|
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);
|
this(clientRegistration, authorizationExchange);
|
||||||
Assert.notNull(accessToken, "accessToken cannot be null");
|
Assert.notNull(accessToken, "accessToken cannot be null");
|
||||||
this.accessToken = accessToken;
|
this.accessToken = accessToken;
|
||||||
|
this.refreshToken = refreshToken;
|
||||||
this.setAuthenticated(true);
|
this.setAuthenticated(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,4 +131,13 @@ public class OAuth2AuthorizationCodeAuthenticationToken extends AbstractAuthenti
|
||||||
public OAuth2AccessToken getAccessToken() {
|
public OAuth2AccessToken getAccessToken() {
|
||||||
return this.accessToken;
|
return this.accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link OAuth2RefreshToken refresh token}.
|
||||||
|
*
|
||||||
|
* @return the {@link OAuth2RefreshToken}
|
||||||
|
*/
|
||||||
|
public @Nullable OAuth2RefreshToken getRefreshToken() {
|
||||||
|
return this.refreshToken;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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(),
|
authorizationCodeAuthentication.getAuthorizationExchange(),
|
||||||
oauth2User,
|
oauth2User,
|
||||||
mappedAuthorities,
|
mappedAuthorities,
|
||||||
accessToken);
|
accessToken,
|
||||||
|
accessTokenResponse.getRefreshToken());
|
||||||
authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
|
authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
|
||||||
|
|
||||||
return authenticationResult;
|
return authenticationResult;
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
package org.springframework.security.oauth2.client.authentication;
|
||||||
|
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.SpringSecurityCoreVersion;
|
import org.springframework.security.core.SpringSecurityCoreVersion;
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
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.endpoint.OAuth2AuthorizationExchange;
|
||||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
@ -46,6 +48,7 @@ public class OAuth2LoginAuthenticationToken extends AbstractAuthenticationToken
|
||||||
private ClientRegistration clientRegistration;
|
private ClientRegistration clientRegistration;
|
||||||
private OAuth2AuthorizationExchange authorizationExchange;
|
private OAuth2AuthorizationExchange authorizationExchange;
|
||||||
private OAuth2AccessToken accessToken;
|
private OAuth2AccessToken accessToken;
|
||||||
|
private OAuth2RefreshToken refreshToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This constructor should be used when the Authorization Request/Response is complete.
|
* This constructor should be used when the Authorization Request/Response is complete.
|
||||||
|
@ -80,6 +83,27 @@ public class OAuth2LoginAuthenticationToken extends AbstractAuthenticationToken
|
||||||
OAuth2User principal,
|
OAuth2User principal,
|
||||||
Collection<? extends GrantedAuthority> authorities,
|
Collection<? extends GrantedAuthority> authorities,
|
||||||
OAuth2AccessToken accessToken) {
|
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<? extends GrantedAuthority> authorities,
|
||||||
|
OAuth2AccessToken accessToken,
|
||||||
|
@Nullable OAuth2RefreshToken refreshToken) {
|
||||||
super(authorities);
|
super(authorities);
|
||||||
Assert.notNull(clientRegistration, "clientRegistration cannot be null");
|
Assert.notNull(clientRegistration, "clientRegistration cannot be null");
|
||||||
Assert.notNull(authorizationExchange, "authorizationExchange cannot be null");
|
Assert.notNull(authorizationExchange, "authorizationExchange cannot be null");
|
||||||
|
@ -89,6 +113,7 @@ public class OAuth2LoginAuthenticationToken extends AbstractAuthenticationToken
|
||||||
this.authorizationExchange = authorizationExchange;
|
this.authorizationExchange = authorizationExchange;
|
||||||
this.principal = principal;
|
this.principal = principal;
|
||||||
this.accessToken = accessToken;
|
this.accessToken = accessToken;
|
||||||
|
this.refreshToken = refreshToken;
|
||||||
this.setAuthenticated(true);
|
this.setAuthenticated(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,4 +153,14 @@ public class OAuth2LoginAuthenticationToken extends AbstractAuthenticationToken
|
||||||
public OAuth2AccessToken getAccessToken() {
|
public OAuth2AccessToken getAccessToken() {
|
||||||
return this.accessToken;
|
return this.accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link OAuth2RefreshToken refresh token}.
|
||||||
|
*
|
||||||
|
* @since 5.1
|
||||||
|
* @return the {@link OAuth2RefreshToken}
|
||||||
|
*/
|
||||||
|
public @Nullable OAuth2RefreshToken getRefreshToken() {
|
||||||
|
return this.refreshToken;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,11 +120,13 @@ public class OAuth2LoginReactiveAuthenticationManager implements
|
||||||
authorizationCodeAuthentication.getAuthorizationExchange(),
|
authorizationCodeAuthentication.getAuthorizationExchange(),
|
||||||
oauth2User,
|
oauth2User,
|
||||||
mappedAuthorities,
|
mappedAuthorities,
|
||||||
accessToken);
|
accessToken,
|
||||||
|
accessTokenResponse.getRefreshToken());
|
||||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
|
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
|
||||||
authenticationResult.getClientRegistration(),
|
authenticationResult.getClientRegistration(),
|
||||||
authenticationResult.getName(),
|
authenticationResult.getName(),
|
||||||
authenticationResult.getAccessToken());
|
authenticationResult.getAccessToken(),
|
||||||
|
authenticationResult.getRefreshToken());
|
||||||
OAuth2AuthenticationToken result = new OAuth2AuthenticationToken(
|
OAuth2AuthenticationToken result = new OAuth2AuthenticationToken(
|
||||||
authenticationResult.getPrincipal(),
|
authenticationResult.getPrincipal(),
|
||||||
authenticationResult.getAuthorities(),
|
authenticationResult.getAuthorities(),
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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());
|
accessTokenResponse.getTokens().getAccessToken().getScope().toStringList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String refreshToken = null;
|
||||||
|
if (accessTokenResponse.getTokens().getRefreshToken() != null) {
|
||||||
|
refreshToken = accessTokenResponse.getTokens().getRefreshToken().getValue();
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, Object> additionalParameters = new LinkedHashMap<>(accessTokenResponse.getCustomParameters());
|
Map<String, Object> additionalParameters = new LinkedHashMap<>(accessTokenResponse.getCustomParameters());
|
||||||
|
|
||||||
return OAuth2AccessTokenResponse.withToken(accessToken)
|
return OAuth2AccessTokenResponse.withToken(accessToken)
|
||||||
.tokenType(accessTokenType)
|
.tokenType(accessTokenType)
|
||||||
.expiresIn(expiresIn)
|
.expiresIn(expiresIn)
|
||||||
.scopes(scopes)
|
.scopes(scopes)
|
||||||
|
.refreshToken(refreshToken)
|
||||||
.additionalParameters(additionalParameters)
|
.additionalParameters(additionalParameters)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,6 +118,11 @@ public class NimbusReactiveAuthorizationCodeTokenResponseClient implements React
|
||||||
accessToken.getScope().toStringList());
|
accessToken.getScope().toStringList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String refreshToken = null;
|
||||||
|
if (accessTokenResponse.getTokens().getRefreshToken() != null) {
|
||||||
|
refreshToken = accessTokenResponse.getTokens().getRefreshToken().getValue();
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, Object> additionalParameters = new LinkedHashMap<>(
|
Map<String, Object> additionalParameters = new LinkedHashMap<>(
|
||||||
accessTokenResponse.getCustomParameters());
|
accessTokenResponse.getCustomParameters());
|
||||||
|
|
||||||
|
@ -125,6 +130,7 @@ public class NimbusReactiveAuthorizationCodeTokenResponseClient implements React
|
||||||
.tokenType(accessTokenType)
|
.tokenType(accessTokenType)
|
||||||
.expiresIn(expiresIn)
|
.expiresIn(expiresIn)
|
||||||
.scopes(scopes)
|
.scopes(scopes)
|
||||||
|
.refreshToken(refreshToken)
|
||||||
.additionalParameters(additionalParameters)
|
.additionalParameters(additionalParameters)
|
||||||
.build();
|
.build();
|
||||||
});
|
});
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.oidc.userinfo.OidcUserService;
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||||
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
|
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.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
||||||
|
@ -142,8 +141,6 @@ public class OidcAuthorizationCodeAuthenticationProvider implements Authenticati
|
||||||
authorizationCodeAuthentication.getClientRegistration(),
|
authorizationCodeAuthentication.getClientRegistration(),
|
||||||
authorizationCodeAuthentication.getAuthorizationExchange()));
|
authorizationCodeAuthentication.getAuthorizationExchange()));
|
||||||
|
|
||||||
OAuth2AccessToken accessToken = accessTokenResponse.getAccessToken();
|
|
||||||
|
|
||||||
ClientRegistration clientRegistration = authorizationCodeAuthentication.getClientRegistration();
|
ClientRegistration clientRegistration = authorizationCodeAuthentication.getClientRegistration();
|
||||||
|
|
||||||
if (!accessTokenResponse.getAdditionalParameters().containsKey(OidcParameterNames.ID_TOKEN)) {
|
if (!accessTokenResponse.getAdditionalParameters().containsKey(OidcParameterNames.ID_TOKEN)) {
|
||||||
|
@ -161,7 +158,7 @@ public class OidcAuthorizationCodeAuthenticationProvider implements Authenticati
|
||||||
this.validateIdToken(idToken, clientRegistration);
|
this.validateIdToken(idToken, clientRegistration);
|
||||||
|
|
||||||
OidcUser oidcUser = this.userService.loadUser(
|
OidcUser oidcUser = this.userService.loadUser(
|
||||||
new OidcUserRequest(clientRegistration, accessToken, idToken));
|
new OidcUserRequest(clientRegistration, accessTokenResponse.getAccessToken(), idToken));
|
||||||
|
|
||||||
Collection<? extends GrantedAuthority> mappedAuthorities =
|
Collection<? extends GrantedAuthority> mappedAuthorities =
|
||||||
this.authoritiesMapper.mapAuthorities(oidcUser.getAuthorities());
|
this.authoritiesMapper.mapAuthorities(oidcUser.getAuthorities());
|
||||||
|
@ -171,7 +168,8 @@ public class OidcAuthorizationCodeAuthenticationProvider implements Authenticati
|
||||||
authorizationCodeAuthentication.getAuthorizationExchange(),
|
authorizationCodeAuthentication.getAuthorizationExchange(),
|
||||||
oidcUser,
|
oidcUser,
|
||||||
mappedAuthorities,
|
mappedAuthorities,
|
||||||
accessToken);
|
accessTokenResponse.getAccessToken(),
|
||||||
|
accessTokenResponse.getRefreshToken());
|
||||||
authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
|
authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
|
||||||
|
|
||||||
return authenticationResult;
|
return authenticationResult;
|
||||||
|
|
|
@ -198,7 +198,8 @@ public class OAuth2AuthorizationCodeGrantFilter extends OncePerRequestFilter {
|
||||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
|
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
|
||||||
authenticationResult.getClientRegistration(),
|
authenticationResult.getClientRegistration(),
|
||||||
currentAuthentication.getName(),
|
currentAuthentication.getName(),
|
||||||
authenticationResult.getAccessToken());
|
authenticationResult.getAccessToken(),
|
||||||
|
authenticationResult.getRefreshToken());
|
||||||
|
|
||||||
this.authorizedClientService.saveAuthorizedClient(authorizedClient, currentAuthentication);
|
this.authorizedClientService.saveAuthorizedClient(authorizedClient, currentAuthentication);
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,8 @@ public class OAuth2LoginAuthenticationFilter extends AbstractAuthenticationProce
|
||||||
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
|
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
|
||||||
authenticationResult.getClientRegistration(),
|
authenticationResult.getClientRegistration(),
|
||||||
oauth2Authentication.getName(),
|
oauth2Authentication.getName(),
|
||||||
authenticationResult.getAccessToken());
|
authenticationResult.getAccessToken(),
|
||||||
|
authenticationResult.getRefreshToken());
|
||||||
|
|
||||||
this.authorizedClientService.saveAuthorizedClient(authorizedClient, oauth2Authentication);
|
this.authorizedClientService.saveAuthorizedClient(authorizedClient, oauth2Authentication);
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
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.OAuth2AccessTokenResponse;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
||||||
|
@ -122,8 +123,10 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests {
|
||||||
@Test
|
@Test
|
||||||
public void authenticateWhenAuthorizationSuccessResponseThenExchangedForAccessToken() {
|
public void authenticateWhenAuthorizationSuccessResponseThenExchangedForAccessToken() {
|
||||||
OAuth2AccessToken accessToken = mock(OAuth2AccessToken.class);
|
OAuth2AccessToken accessToken = mock(OAuth2AccessToken.class);
|
||||||
|
OAuth2RefreshToken refreshToken = mock(OAuth2RefreshToken.class);
|
||||||
OAuth2AccessTokenResponse accessTokenResponse = mock(OAuth2AccessTokenResponse.class);
|
OAuth2AccessTokenResponse accessTokenResponse = mock(OAuth2AccessTokenResponse.class);
|
||||||
when(accessTokenResponse.getAccessToken()).thenReturn(accessToken);
|
when(accessTokenResponse.getAccessToken()).thenReturn(accessToken);
|
||||||
|
when(accessTokenResponse.getRefreshToken()).thenReturn(refreshToken);
|
||||||
when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
|
when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
|
||||||
|
|
||||||
OAuth2AuthorizationCodeAuthenticationToken authenticationResult =
|
OAuth2AuthorizationCodeAuthenticationToken authenticationResult =
|
||||||
|
@ -137,5 +140,6 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests {
|
||||||
assertThat(authenticationResult.getClientRegistration()).isEqualTo(this.clientRegistration);
|
assertThat(authenticationResult.getClientRegistration()).isEqualTo(this.clientRegistration);
|
||||||
assertThat(authenticationResult.getAuthorizationExchange()).isEqualTo(this.authorizationExchange);
|
assertThat(authenticationResult.getAuthorizationExchange()).isEqualTo(this.authorizationExchange);
|
||||||
assertThat(authenticationResult.getAccessToken()).isEqualTo(accessToken);
|
assertThat(authenticationResult.getAccessToken()).isEqualTo(accessToken);
|
||||||
|
assertThat(authenticationResult.getRefreshToken()).isEqualTo(refreshToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
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.OAuth2AccessTokenResponse;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
||||||
|
@ -164,8 +165,10 @@ public class OAuth2LoginAuthenticationProviderTests {
|
||||||
@Test
|
@Test
|
||||||
public void authenticateWhenLoginSuccessThenReturnAuthentication() {
|
public void authenticateWhenLoginSuccessThenReturnAuthentication() {
|
||||||
OAuth2AccessToken accessToken = mock(OAuth2AccessToken.class);
|
OAuth2AccessToken accessToken = mock(OAuth2AccessToken.class);
|
||||||
|
OAuth2RefreshToken refreshToken = mock(OAuth2RefreshToken.class);
|
||||||
OAuth2AccessTokenResponse accessTokenResponse = mock(OAuth2AccessTokenResponse.class);
|
OAuth2AccessTokenResponse accessTokenResponse = mock(OAuth2AccessTokenResponse.class);
|
||||||
when(accessTokenResponse.getAccessToken()).thenReturn(accessToken);
|
when(accessTokenResponse.getAccessToken()).thenReturn(accessToken);
|
||||||
|
when(accessTokenResponse.getRefreshToken()).thenReturn(refreshToken);
|
||||||
when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
|
when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
|
||||||
|
|
||||||
OAuth2User principal = mock(OAuth2User.class);
|
OAuth2User principal = mock(OAuth2User.class);
|
||||||
|
@ -185,6 +188,7 @@ public class OAuth2LoginAuthenticationProviderTests {
|
||||||
assertThat(authentication.getClientRegistration()).isEqualTo(this.clientRegistration);
|
assertThat(authentication.getClientRegistration()).isEqualTo(this.clientRegistration);
|
||||||
assertThat(authentication.getAuthorizationExchange()).isEqualTo(this.authorizationExchange);
|
assertThat(authentication.getAuthorizationExchange()).isEqualTo(this.authorizationExchange);
|
||||||
assertThat(authentication.getAccessToken()).isEqualTo(accessToken);
|
assertThat(authentication.getAccessToken()).isEqualTo(accessToken);
|
||||||
|
assertThat(authentication.getRefreshToken()).isEqualTo(refreshToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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" +
|
" \"token_type\": \"bearer\",\n" +
|
||||||
" \"expires_in\": \"3600\",\n" +
|
" \"expires_in\": \"3600\",\n" +
|
||||||
" \"scope\": \"openid profile\",\n" +
|
" \"scope\": \"openid profile\",\n" +
|
||||||
|
" \"refresh_token\": \"refresh-token-1234\",\n" +
|
||||||
" \"custom_parameter_1\": \"custom-value-1\",\n" +
|
" \"custom_parameter_1\": \"custom-value-1\",\n" +
|
||||||
" \"custom_parameter_2\": \"custom-value-2\"\n" +
|
" \"custom_parameter_2\": \"custom-value-2\"\n" +
|
||||||
"}\n";
|
"}\n";
|
||||||
|
@ -115,6 +116,7 @@ public class NimbusAuthorizationCodeTokenResponseClientTests {
|
||||||
assertThat(accessTokenResponse.getAccessToken().getTokenType()).isEqualTo(OAuth2AccessToken.TokenType.BEARER);
|
assertThat(accessTokenResponse.getAccessToken().getTokenType()).isEqualTo(OAuth2AccessToken.TokenType.BEARER);
|
||||||
assertThat(accessTokenResponse.getAccessToken().getExpiresAt()).isBetween(expiresAtBefore, expiresAtAfter);
|
assertThat(accessTokenResponse.getAccessToken().getExpiresAt()).isBetween(expiresAtBefore, expiresAtAfter);
|
||||||
assertThat(accessTokenResponse.getAccessToken().getScopes()).containsExactly("openid", "profile");
|
assertThat(accessTokenResponse.getAccessToken().getScopes()).containsExactly("openid", "profile");
|
||||||
|
assertThat(accessTokenResponse.getRefreshToken().getTokenValue()).isEqualTo("refresh-token-1234");
|
||||||
assertThat(accessTokenResponse.getAdditionalParameters().size()).isEqualTo(2);
|
assertThat(accessTokenResponse.getAdditionalParameters().size()).isEqualTo(2);
|
||||||
assertThat(accessTokenResponse.getAdditionalParameters()).containsEntry("custom_parameter_1", "custom-value-1");
|
assertThat(accessTokenResponse.getAdditionalParameters()).containsEntry("custom_parameter_1", "custom-value-1");
|
||||||
assertThat(accessTokenResponse.getAdditionalParameters()).containsEntry("custom_parameter_2", "custom-value-2");
|
assertThat(accessTokenResponse.getAdditionalParameters()).containsEntry("custom_parameter_2", "custom-value-2");
|
||||||
|
|
|
@ -85,6 +85,7 @@ public class NimbusReactiveAuthorizationCodeTokenResponseClientTests {
|
||||||
" \"token_type\": \"bearer\",\n" +
|
" \"token_type\": \"bearer\",\n" +
|
||||||
" \"expires_in\": \"3600\",\n" +
|
" \"expires_in\": \"3600\",\n" +
|
||||||
" \"scope\": \"openid profile\",\n" +
|
" \"scope\": \"openid profile\",\n" +
|
||||||
|
" \"refresh_token\": \"refresh-token-1234\",\n" +
|
||||||
" \"custom_parameter_1\": \"custom-value-1\",\n" +
|
" \"custom_parameter_1\": \"custom-value-1\",\n" +
|
||||||
" \"custom_parameter_2\": \"custom-value-2\"\n" +
|
" \"custom_parameter_2\": \"custom-value-2\"\n" +
|
||||||
"}\n";
|
"}\n";
|
||||||
|
@ -102,6 +103,7 @@ public class NimbusReactiveAuthorizationCodeTokenResponseClientTests {
|
||||||
OAuth2AccessToken.TokenType.BEARER);
|
OAuth2AccessToken.TokenType.BEARER);
|
||||||
assertThat(accessTokenResponse.getAccessToken().getExpiresAt()).isBetween(expiresAtBefore, expiresAtAfter);
|
assertThat(accessTokenResponse.getAccessToken().getExpiresAt()).isBetween(expiresAtBefore, expiresAtAfter);
|
||||||
assertThat(accessTokenResponse.getAccessToken().getScopes()).containsExactly("openid", "profile");
|
assertThat(accessTokenResponse.getAccessToken().getScopes()).containsExactly("openid", "profile");
|
||||||
|
assertThat(accessTokenResponse.getRefreshToken().getTokenValue()).isEqualTo("refresh-token-1234");
|
||||||
assertThat(accessTokenResponse.getAdditionalParameters().size()).isEqualTo(2);
|
assertThat(accessTokenResponse.getAdditionalParameters().size()).isEqualTo(2);
|
||||||
assertThat(accessTokenResponse.getAdditionalParameters()).containsEntry("custom_parameter_1", "custom-value-1");
|
assertThat(accessTokenResponse.getAdditionalParameters()).containsEntry("custom_parameter_1", "custom-value-1");
|
||||||
assertThat(accessTokenResponse.getAdditionalParameters()).containsEntry("custom_parameter_2", "custom-value-2");
|
assertThat(accessTokenResponse.getAdditionalParameters()).containsEntry("custom_parameter_2", "custom-value-2");
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
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.OAuth2AccessTokenResponse;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
||||||
|
@ -78,6 +79,7 @@ public class OidcAuthorizationCodeAuthenticationProviderTests {
|
||||||
private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient;
|
private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient;
|
||||||
private OAuth2AccessTokenResponse accessTokenResponse;
|
private OAuth2AccessTokenResponse accessTokenResponse;
|
||||||
private OAuth2AccessToken accessToken;
|
private OAuth2AccessToken accessToken;
|
||||||
|
private OAuth2RefreshToken refreshToken;
|
||||||
private OAuth2UserService<OidcUserRequest, OidcUser> userService;
|
private OAuth2UserService<OidcUserRequest, OidcUser> userService;
|
||||||
private OidcAuthorizationCodeAuthenticationProvider authenticationProvider;
|
private OidcAuthorizationCodeAuthenticationProvider authenticationProvider;
|
||||||
|
|
||||||
|
@ -95,6 +97,7 @@ public class OidcAuthorizationCodeAuthenticationProviderTests {
|
||||||
this.accessTokenResponseClient = mock(OAuth2AccessTokenResponseClient.class);
|
this.accessTokenResponseClient = mock(OAuth2AccessTokenResponseClient.class);
|
||||||
this.accessTokenResponse = mock(OAuth2AccessTokenResponse.class);
|
this.accessTokenResponse = mock(OAuth2AccessTokenResponse.class);
|
||||||
this.accessToken = mock(OAuth2AccessToken.class);
|
this.accessToken = mock(OAuth2AccessToken.class);
|
||||||
|
this.refreshToken = mock(OAuth2RefreshToken.class);
|
||||||
this.userService = mock(OAuth2UserService.class);
|
this.userService = mock(OAuth2UserService.class);
|
||||||
this.authenticationProvider = PowerMockito.spy(
|
this.authenticationProvider = PowerMockito.spy(
|
||||||
new OidcAuthorizationCodeAuthenticationProvider(this.accessTokenResponseClient, this.userService));
|
new OidcAuthorizationCodeAuthenticationProvider(this.accessTokenResponseClient, this.userService));
|
||||||
|
@ -109,6 +112,7 @@ public class OidcAuthorizationCodeAuthenticationProviderTests {
|
||||||
when(this.authorizationRequest.getRedirectUri()).thenReturn("http://example.com");
|
when(this.authorizationRequest.getRedirectUri()).thenReturn("http://example.com");
|
||||||
when(this.authorizationResponse.getRedirectUri()).thenReturn("http://example.com");
|
when(this.authorizationResponse.getRedirectUri()).thenReturn("http://example.com");
|
||||||
when(this.accessTokenResponse.getAccessToken()).thenReturn(this.accessToken);
|
when(this.accessTokenResponse.getAccessToken()).thenReturn(this.accessToken);
|
||||||
|
when(this.accessTokenResponse.getRefreshToken()).thenReturn(this.refreshToken);
|
||||||
Map<String, Object> additionalParameters = new HashMap<>();
|
Map<String, Object> additionalParameters = new HashMap<>();
|
||||||
additionalParameters.put(OidcParameterNames.ID_TOKEN, "id-token");
|
additionalParameters.put(OidcParameterNames.ID_TOKEN, "id-token");
|
||||||
when(this.accessTokenResponse.getAdditionalParameters()).thenReturn(additionalParameters);
|
when(this.accessTokenResponse.getAdditionalParameters()).thenReturn(additionalParameters);
|
||||||
|
@ -365,6 +369,7 @@ public class OidcAuthorizationCodeAuthenticationProviderTests {
|
||||||
assertThat(authentication.getClientRegistration()).isEqualTo(this.clientRegistration);
|
assertThat(authentication.getClientRegistration()).isEqualTo(this.clientRegistration);
|
||||||
assertThat(authentication.getAuthorizationExchange()).isEqualTo(this.authorizationExchange);
|
assertThat(authentication.getAuthorizationExchange()).isEqualTo(this.authorizationExchange);
|
||||||
assertThat(authentication.getAccessToken()).isEqualTo(this.accessToken);
|
assertThat(authentication.getAccessToken()).isEqualTo(this.accessToken);
|
||||||
|
assertThat(authentication.getRefreshToken()).isEqualTo(this.refreshToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -41,6 +41,7 @@ import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
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.OAuth2AuthorizationExchange;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||||
|
@ -238,6 +239,7 @@ public class OAuth2AuthorizationCodeGrantFilterTests {
|
||||||
assertThat(authorizedClient.getClientRegistration()).isEqualTo(this.registration1);
|
assertThat(authorizedClient.getClientRegistration()).isEqualTo(this.registration1);
|
||||||
assertThat(authorizedClient.getPrincipalName()).isEqualTo(this.principalName1);
|
assertThat(authorizedClient.getPrincipalName()).isEqualTo(this.principalName1);
|
||||||
assertThat(authorizedClient.getAccessToken()).isNotNull();
|
assertThat(authorizedClient.getAccessToken()).isNotNull();
|
||||||
|
assertThat(authorizedClient.getRefreshToken()).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -299,6 +301,7 @@ public class OAuth2AuthorizationCodeGrantFilterTests {
|
||||||
when(authentication.getClientRegistration()).thenReturn(registration);
|
when(authentication.getClientRegistration()).thenReturn(registration);
|
||||||
when(authentication.getAuthorizationExchange()).thenReturn(mock(OAuth2AuthorizationExchange.class));
|
when(authentication.getAuthorizationExchange()).thenReturn(mock(OAuth2AuthorizationExchange.class));
|
||||||
when(authentication.getAccessToken()).thenReturn(mock(OAuth2AccessToken.class));
|
when(authentication.getAccessToken()).thenReturn(mock(OAuth2AccessToken.class));
|
||||||
|
when(authentication.getRefreshToken()).thenReturn(mock(OAuth2RefreshToken.class));
|
||||||
when(this.authenticationManager.authenticate(any(Authentication.class))).thenReturn(authentication);
|
when(this.authenticationManager.authenticate(any(Authentication.class))).thenReturn(authentication);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.OAuth2AccessToken;
|
||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
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.OAuth2AuthorizationExchange;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||||
|
@ -281,6 +282,7 @@ public class OAuth2LoginAuthenticationFilterTests {
|
||||||
assertThat(authorizedClient.getClientRegistration()).isEqualTo(this.registration1);
|
assertThat(authorizedClient.getClientRegistration()).isEqualTo(this.registration1);
|
||||||
assertThat(authorizedClient.getPrincipalName()).isEqualTo(this.principalName1);
|
assertThat(authorizedClient.getPrincipalName()).isEqualTo(this.principalName1);
|
||||||
assertThat(authorizedClient.getAccessToken()).isNotNull();
|
assertThat(authorizedClient.getAccessToken()).isNotNull();
|
||||||
|
assertThat(authorizedClient.getRefreshToken()).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -328,6 +330,7 @@ public class OAuth2LoginAuthenticationFilterTests {
|
||||||
when(loginAuthentication.getClientRegistration()).thenReturn(registration);
|
when(loginAuthentication.getClientRegistration()).thenReturn(registration);
|
||||||
when(loginAuthentication.getAuthorizationExchange()).thenReturn(mock(OAuth2AuthorizationExchange.class));
|
when(loginAuthentication.getAuthorizationExchange()).thenReturn(mock(OAuth2AuthorizationExchange.class));
|
||||||
when(loginAuthentication.getAccessToken()).thenReturn(mock(OAuth2AccessToken.class));
|
when(loginAuthentication.getAccessToken()).thenReturn(mock(OAuth2AccessToken.class));
|
||||||
|
when(loginAuthentication.getRefreshToken()).thenReturn(mock(OAuth2RefreshToken.class));
|
||||||
when(this.authenticationManager.authenticate(any(Authentication.class))).thenReturn(loginAuthentication);
|
when(this.authenticationManager.authenticate(any(Authentication.class))).thenReturn(loginAuthentication);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
|
||||||
public static final AuthorizationGrantType AUTHORIZATION_CODE = new AuthorizationGrantType("authorization_code");
|
public static final AuthorizationGrantType AUTHORIZATION_CODE = new AuthorizationGrantType("authorization_code");
|
||||||
public static final AuthorizationGrantType IMPLICIT = new AuthorizationGrantType("implicit");
|
public static final AuthorizationGrantType IMPLICIT = new AuthorizationGrantType("implicit");
|
||||||
|
public static final AuthorizationGrantType REFRESH_TOKEN = new AuthorizationGrantType("refresh_token");
|
||||||
private final String value;
|
private final String value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* 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 <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-1.5">Section 1.5 Refresh Token</a>
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
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.OAuth2AccessToken;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -29,10 +32,12 @@ import java.util.Set;
|
||||||
* @author Joe Grandja
|
* @author Joe Grandja
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
* @see OAuth2AccessToken
|
* @see OAuth2AccessToken
|
||||||
|
* @see OAuth2RefreshToken
|
||||||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-5.1">Section 5.1 Access Token Response</a>
|
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-5.1">Section 5.1 Access Token Response</a>
|
||||||
*/
|
*/
|
||||||
public final class OAuth2AccessTokenResponse {
|
public final class OAuth2AccessTokenResponse {
|
||||||
private OAuth2AccessToken accessToken;
|
private OAuth2AccessToken accessToken;
|
||||||
|
private OAuth2RefreshToken refreshToken;
|
||||||
private Map<String, Object> additionalParameters;
|
private Map<String, Object> additionalParameters;
|
||||||
|
|
||||||
private OAuth2AccessTokenResponse() {
|
private OAuth2AccessTokenResponse() {
|
||||||
|
@ -47,6 +52,16 @@ public final class OAuth2AccessTokenResponse {
|
||||||
return this.accessToken;
|
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.
|
* Returns the additional parameters returned in the response.
|
||||||
*
|
*
|
||||||
|
@ -74,6 +89,7 @@ public final class OAuth2AccessTokenResponse {
|
||||||
private OAuth2AccessToken.TokenType tokenType;
|
private OAuth2AccessToken.TokenType tokenType;
|
||||||
private long expiresIn;
|
private long expiresIn;
|
||||||
private Set<String> scopes;
|
private Set<String> scopes;
|
||||||
|
private String refreshToken;
|
||||||
private Map<String, Object> additionalParameters;
|
private Map<String, Object> additionalParameters;
|
||||||
|
|
||||||
private Builder(String tokenValue) {
|
private Builder(String tokenValue) {
|
||||||
|
@ -113,6 +129,17 @@ public final class OAuth2AccessTokenResponse {
|
||||||
return this;
|
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.
|
* Sets the additional parameters returned in the response.
|
||||||
*
|
*
|
||||||
|
@ -142,6 +169,14 @@ public final class OAuth2AccessTokenResponse {
|
||||||
OAuth2AccessTokenResponse accessTokenResponse = new OAuth2AccessTokenResponse();
|
OAuth2AccessTokenResponse accessTokenResponse = new OAuth2AccessTokenResponse();
|
||||||
accessTokenResponse.accessToken = new OAuth2AccessToken(
|
accessTokenResponse.accessToken = new OAuth2AccessToken(
|
||||||
this.tokenType, this.tokenValue, issuedAt, expiresAt, this.scopes);
|
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(
|
accessTokenResponse.additionalParameters = Collections.unmodifiableMap(
|
||||||
CollectionUtils.isEmpty(this.additionalParameters) ? Collections.emptyMap() : this.additionalParameters);
|
CollectionUtils.isEmpty(this.additionalParameters) ? Collections.emptyMap() : this.additionalParameters);
|
||||||
return accessTokenResponse;
|
return accessTokenResponse;
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -40,4 +40,9 @@ public class AuthorizationGrantTypeTests {
|
||||||
public void getValueWhenImplicitGrantTypeThenReturnImplicit() {
|
public void getValueWhenImplicitGrantTypeThenReturnImplicit() {
|
||||||
assertThat(AuthorizationGrantType.IMPLICIT.getValue()).isEqualTo("implicit");
|
assertThat(AuthorizationGrantType.IMPLICIT.getValue()).isEqualTo("implicit");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getValueWhenRefreshTokenGrantTypeThenReturnRefreshToken() {
|
||||||
|
assertThat(AuthorizationGrantType.REFRESH_TOKEN.getValue()).isEqualTo("refresh_token");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 {
|
public class OAuth2AccessTokenResponseTests {
|
||||||
private static final String TOKEN_VALUE = "access-token";
|
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();
|
private static final long EXPIRES_IN = Instant.now().plusSeconds(5).toEpochMilli();
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
@ -88,6 +89,7 @@ public class OAuth2AccessTokenResponseTests {
|
||||||
.tokenType(OAuth2AccessToken.TokenType.BEARER)
|
.tokenType(OAuth2AccessToken.TokenType.BEARER)
|
||||||
.expiresIn(expiresAt.toEpochMilli())
|
.expiresIn(expiresAt.toEpochMilli())
|
||||||
.scopes(scopes)
|
.scopes(scopes)
|
||||||
|
.refreshToken(REFRESH_TOKEN_VALUE)
|
||||||
.additionalParameters(additionalParameters)
|
.additionalParameters(additionalParameters)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -97,6 +99,7 @@ public class OAuth2AccessTokenResponseTests {
|
||||||
assertThat(tokenResponse.getAccessToken().getIssuedAt()).isNotNull();
|
assertThat(tokenResponse.getAccessToken().getIssuedAt()).isNotNull();
|
||||||
assertThat(tokenResponse.getAccessToken().getExpiresAt()).isAfterOrEqualTo(expiresAt);
|
assertThat(tokenResponse.getAccessToken().getExpiresAt()).isAfterOrEqualTo(expiresAt);
|
||||||
assertThat(tokenResponse.getAccessToken().getScopes()).isEqualTo(scopes);
|
assertThat(tokenResponse.getAccessToken().getScopes()).isEqualTo(scopes);
|
||||||
|
assertThat(tokenResponse.getRefreshToken().getTokenValue()).isEqualTo(REFRESH_TOKEN_VALUE);
|
||||||
assertThat(tokenResponse.getAdditionalParameters()).isEqualTo(additionalParameters);
|
assertThat(tokenResponse.getAdditionalParameters()).isEqualTo(additionalParameters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue