diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java
index 2f33a462e5..1a4117baa7 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java
@@ -1014,7 +1014,7 @@ public final class HttpSecurity extends
* }
*
* @Bean
- * public AuthorizationGrantTokenExchanger<OAuth2AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger() {
+ * public AuthorizationGrantTokenExchanger<OAuth2LoginAuthenticationToken> authorizationCodeTokenExchanger() {
* // Custom implementation that exchanges an "Authorization Code Grant" for an "Access Token"
* return new AuthorizationCodeTokenExchangerImpl();
* }
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AbstractOAuth2AuthorizationGrantAuthenticationToken.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AbstractOAuth2AuthorizationGrantAuthenticationToken.java
deleted file mode 100644
index 4638f70787..0000000000
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/AbstractOAuth2AuthorizationGrantAuthenticationToken.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2002-2017 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.client.authentication;
-
-import org.springframework.security.authentication.AbstractAuthenticationToken;
-import org.springframework.security.core.SpringSecurityCoreVersion;
-import org.springframework.security.oauth2.core.AuthorizationGrantType;
-import org.springframework.util.Assert;
-
-import java.util.Collections;
-
-/**
- * Base implementation of an {@link AbstractAuthenticationToken} that holds
- * an authorization grant credential for a specific {@link AuthorizationGrantType}.
- *
- * @author Joe Grandja
- * @since 5.0
- * @see AuthorizationGrantType
- * @see Section 1.3 Authorization Grant
- */
-public abstract class AbstractOAuth2AuthorizationGrantAuthenticationToken extends AbstractAuthenticationToken {
- private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
- private final AuthorizationGrantType authorizationGrantType;
-
- protected AbstractOAuth2AuthorizationGrantAuthenticationToken(AuthorizationGrantType authorizationGrantType) {
- super(Collections.emptyList());
- Assert.notNull(authorizationGrantType, "authorizationGrantType cannot be null");
- this.authorizationGrantType = authorizationGrantType;
- }
-
- public AuthorizationGrantType getGrantType() {
- return this.authorizationGrantType;
- }
-}
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthenticationToken.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthenticationToken.java
index f73354df5d..3885e19c65 100644
--- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthenticationToken.java
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2AuthenticationToken.java
@@ -19,7 +19,6 @@ import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
-import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.util.Assert;
@@ -30,34 +29,33 @@ import java.util.Collection;
* that represents an OAuth 2.0 {@link Authentication}.
*
* This {@link Authentication} associates an {@link OAuth2User} Principal
- * to an {@link OAuth2AuthorizedClient}, which the End-User (Principal) granted authorization to
+ * to the identifier of the {@link #getAuthorizedClientRegistrationId() Authorized Client},
+ * which the End-User (Principal) granted authorization to
* so that it can access its protected resource(s) at the UserInfo Endpoint.
*
* @author Joe Grandja
* @since 5.0
* @see AbstractAuthenticationToken
- * @see OAuth2AuthorizedClient
* @see OAuth2User
- *
- * @param The type of OAuth 2.0 User
- * @param The type of Authorized Client
*/
-public class OAuth2AuthenticationToken extends AbstractAuthenticationToken {
+public class OAuth2AuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
- private final U principal;
- private final C authorizedClient;
+ private final OAuth2User principal;
+ private final String authorizedClientRegistrationId;
- public OAuth2AuthenticationToken(U principal, Collection extends GrantedAuthority> authorities, C authorizedClient) {
+ public OAuth2AuthenticationToken(OAuth2User principal,
+ Collection extends GrantedAuthority> authorities,
+ String authorizedClientRegistrationId) {
super(authorities);
Assert.notNull(principal, "principal cannot be null");
- Assert.notNull(authorizedClient, "authorizedClient cannot be null");
+ Assert.hasText(authorizedClientRegistrationId, "authorizedClientRegistrationId cannot be empty");
this.principal = principal;
- this.authorizedClient = authorizedClient;
+ this.authorizedClientRegistrationId = authorizedClientRegistrationId;
this.setAuthenticated(true);
}
@Override
- public U getPrincipal() {
+ public OAuth2User getPrincipal() {
return this.principal;
}
@@ -67,7 +65,7 @@ public class OAuth2AuthenticationTokenauthorization code grant credential for a specific client identified in {@link #getClientRegistration()}.
- *
- * @author Joe Grandja
- * @since 5.0
- * @see AbstractOAuth2AuthorizationGrantAuthenticationToken
- * @see ClientRegistration
- * @see OAuth2AuthorizationRequest
- * @see OAuth2AuthorizationResponse
- * @see Section 1.3.1 Authorization Code Grant
- */
-public class OAuth2AuthorizationCodeAuthenticationToken extends AbstractOAuth2AuthorizationGrantAuthenticationToken {
- private final ClientRegistration clientRegistration;
- private final OAuth2AuthorizationExchange authorizationExchange;
-
- public OAuth2AuthorizationCodeAuthenticationToken(ClientRegistration clientRegistration,
- OAuth2AuthorizationExchange authorizationExchange) {
-
- super(AuthorizationGrantType.AUTHORIZATION_CODE);
- Assert.notNull(clientRegistration, "clientRegistration cannot be null");
- Assert.notNull(authorizationExchange, "authorizationExchange cannot be null");
- this.clientRegistration = clientRegistration;
- this.authorizationExchange = authorizationExchange;
- this.setAuthenticated(false);
- }
-
- @Override
- public Object getPrincipal() {
- return "";
- }
-
- @Override
- public Object getCredentials() {
- return "";
- }
-
- public ClientRegistration getClientRegistration() {
- return this.clientRegistration;
- }
-
- public OAuth2AuthorizationExchange getAuthorizationExchange() {
- return this.authorizationExchange;
- }
-}
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 65c20fd023..b285bfdb68 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
@@ -20,7 +20,6 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
-import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.endpoint.AuthorizationGrantTokenExchanger;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
@@ -37,12 +36,12 @@ import org.springframework.util.Assert;
import java.util.Collection;
/**
- * An implementation of an {@link AuthenticationProvider}
- * for the OAuth 2.0 Authorization Code Grant Flow.
+ * An implementation of an {@link AuthenticationProvider} for OAuth 2.0 Login,
+ * which leverages the OAuth 2.0 Authorization Code Grant Flow.
*
* This {@link AuthenticationProvider} is responsible for authenticating
- * an authorization code credential with the authorization server's Token Endpoint
- * and if valid, exchanging it for an access token credential.
+ * an Authorization Code credential with the Authorization Server's Token Endpoint
+ * and if valid, exchanging it for an Access Token credential.
*
* It will also obtain the user attributes of the End-User (Resource Owner)
* from the UserInfo Endpoint using an {@link OAuth2UserService}
@@ -50,10 +49,9 @@ import java.util.Collection;
*
* @author Joe Grandja
* @since 5.0
- * @see OAuth2AuthorizationCodeAuthenticationToken
- * @see OAuth2AuthenticationToken
+ * @see OAuth2LoginAuthenticationToken
+ * @see AuthorizationGrantTokenExchanger
* @see OAuth2UserService
- * @see OAuth2AuthorizedClient
* @see OAuth2User
* @see Section 4.1 Authorization Code Grant Flow
* @see Section 4.1.3 Access Token Request
@@ -78,8 +76,8 @@ public class OAuth2LoginAuthenticationProvider implements AuthenticationProvider
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
- OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthentication =
- (OAuth2AuthorizationCodeAuthenticationToken) authentication;
+ OAuth2LoginAuthenticationToken authorizationCodeAuthentication =
+ (OAuth2LoginAuthenticationToken) authentication;
// Section 3.1.2.1 Authentication Request - http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
// scope
@@ -124,14 +122,15 @@ public class OAuth2LoginAuthenticationProvider implements AuthenticationProvider
OAuth2User oauth2User = this.userService.loadUser(
new OAuth2UserRequest(authorizationCodeAuthentication.getClientRegistration(), accessToken));
- OAuth2AuthorizedClient oauth2AuthorizedClient = new OAuth2AuthorizedClient(
- authorizationCodeAuthentication.getClientRegistration(), oauth2User.getName(), accessToken);
-
Collection extends GrantedAuthority> mappedAuthorities =
this.authoritiesMapper.mapAuthorities(oauth2User.getAuthorities());
- OAuth2AuthenticationToken authenticationResult =
- new OAuth2AuthenticationToken<>(oauth2User, mappedAuthorities, oauth2AuthorizedClient);
+ OAuth2LoginAuthenticationToken authenticationResult = new OAuth2LoginAuthenticationToken(
+ oauth2User,
+ mappedAuthorities,
+ authorizationCodeAuthentication.getClientRegistration(),
+ authorizationCodeAuthentication.getAuthorizationExchange(),
+ accessToken);
authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
return authenticationResult;
@@ -144,6 +143,6 @@ public class OAuth2LoginAuthenticationProvider implements AuthenticationProvider
@Override
public boolean supports(Class> authentication) {
- return OAuth2AuthorizationCodeAuthenticationToken.class.isAssignableFrom(authentication);
+ return OAuth2LoginAuthenticationToken.class.isAssignableFrom(authentication);
}
}
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
new file mode 100644
index 0000000000..bdfcf43d57
--- /dev/null
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/authentication/OAuth2LoginAuthenticationToken.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2012-2017 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.client.authentication;
+
+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.endpoint.OAuth2AuthorizationExchange;
+import org.springframework.security.oauth2.core.user.OAuth2User;
+import org.springframework.util.Assert;
+
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * An {@link AbstractAuthenticationToken} for OAuth 2.0 Login,
+ * which leverages the OAuth 2.0 Authorization Code Grant Flow.
+ *
+ * @author Joe Grandja
+ * @since 5.0
+ * @see AbstractAuthenticationToken
+ * @see OAuth2User
+ * @see ClientRegistration
+ * @see OAuth2AuthorizationExchange
+ * @see OAuth2AccessToken
+ * @see Section 4.1 Authorization Code Grant Flow
+ */
+public class OAuth2LoginAuthenticationToken extends AbstractAuthenticationToken {
+ private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
+ private OAuth2User principal;
+ private ClientRegistration clientRegistration;
+ private OAuth2AuthorizationExchange authorizationExchange;
+ private OAuth2AccessToken accessToken;
+
+ /**
+ * This constructor should be used when the Authorization Request/Response is complete.
+ *
+ * @param clientRegistration
+ * @param authorizationExchange
+ */
+ public OAuth2LoginAuthenticationToken(ClientRegistration clientRegistration,
+ OAuth2AuthorizationExchange authorizationExchange) {
+
+ super(Collections.emptyList());
+ Assert.notNull(clientRegistration, "clientRegistration cannot be null");
+ Assert.notNull(authorizationExchange, "authorizationExchange cannot be null");
+ this.clientRegistration = clientRegistration;
+ this.authorizationExchange = authorizationExchange;
+ this.setAuthenticated(false);
+ }
+
+ /**
+ * 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 principal
+ * @param authorities
+ * @param clientRegistration
+ * @param authorizationExchange
+ * @param accessToken
+ */
+ public OAuth2LoginAuthenticationToken(OAuth2User principal,
+ Collection extends GrantedAuthority> authorities,
+ ClientRegistration clientRegistration,
+ OAuth2AuthorizationExchange authorizationExchange,
+ OAuth2AccessToken accessToken) {
+ super(authorities);
+ Assert.notNull(principal, "principal cannot be null");
+ Assert.notNull(clientRegistration, "clientRegistration cannot be null");
+ Assert.notNull(authorizationExchange, "authorizationExchange cannot be null");
+ Assert.notNull(accessToken, "accessToken cannot be null");
+ this.principal = principal;
+ this.clientRegistration = clientRegistration;
+ this.authorizationExchange = authorizationExchange;
+ this.accessToken = accessToken;
+ this.setAuthenticated(true);
+ }
+
+ @Override
+ public OAuth2User getPrincipal() {
+ return this.principal;
+ }
+
+ @Override
+ public Object getCredentials() {
+ return "";
+ }
+
+ public ClientRegistration getClientRegistration() {
+ return this.clientRegistration;
+ }
+
+ public OAuth2AuthorizationExchange getAuthorizationExchange() {
+ return this.authorizationExchange;
+ }
+
+ public OAuth2AccessToken getAccessToken() {
+ return this.accessToken;
+ }
+}
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 b5b57cffb4..c78286dac4 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
@@ -20,12 +20,10 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
+import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken;
import org.springframework.security.oauth2.client.endpoint.AuthorizationGrantTokenExchanger;
-import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
-import org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
import org.springframework.security.oauth2.client.jwt.JwtDecoderRegistry;
-import org.springframework.security.oauth2.client.oidc.OidcAuthorizedClient;
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;
@@ -55,19 +53,18 @@ import java.util.List;
* for the OpenID Connect Core 1.0 Authorization Code Grant Flow.
*
* This {@link AuthenticationProvider} is responsible for authenticating
- * an authorization code credential with the authorization server's Token Endpoint
- * and if valid, exchanging it for an access token credential.
+ * an Authorization Code credential with the Authorization Server's Token Endpoint
+ * and if valid, exchanging it for an Access Token credential.
*
- * It will also obtain the user attributes of the End-User (resource owner)
+ * It will also obtain the user attributes of the End-User (Resource Owner)
* from the UserInfo Endpoint using an {@link OAuth2UserService}
* which will create a Principal in the form of an {@link OidcUser}.
*
* @author Joe Grandja
* @since 5.0
- * @see OAuth2AuthorizationCodeAuthenticationToken
- * @see OAuth2AuthenticationToken
+ * @see OidcAuthorizationCodeAuthenticationToken
+ * @see AuthorizationGrantTokenExchanger
* @see OidcUserService
- * @see OidcAuthorizedClient
* @see OidcUser
* @see Section 3.1 Authorization Code Grant Flow
* @see Section 3.1.3.1 Token Request
@@ -97,8 +94,8 @@ public class OidcAuthorizationCodeAuthenticationProvider implements Authenticati
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
- OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthentication =
- (OAuth2AuthorizationCodeAuthenticationToken) authentication;
+ OAuth2LoginAuthenticationToken authorizationCodeAuthentication =
+ (OAuth2LoginAuthenticationToken) authentication;
// Section 3.1.2.1 Authentication Request - http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
// scope
@@ -160,14 +157,16 @@ public class OidcAuthorizationCodeAuthenticationProvider implements Authenticati
OidcUser oidcUser = this.userService.loadUser(
new OidcUserRequest(clientRegistration, accessToken, idToken));
- OidcAuthorizedClient oidcAuthorizedClient = new OidcAuthorizedClient(
- clientRegistration, oidcUser.getName(), accessToken, idToken);
-
Collection extends GrantedAuthority> mappedAuthorities =
this.authoritiesMapper.mapAuthorities(oidcUser.getAuthorities());
- OAuth2AuthenticationToken authenticationResult =
- new OAuth2AuthenticationToken<>(oidcUser, mappedAuthorities, oidcAuthorizedClient);
+ OidcAuthorizationCodeAuthenticationToken authenticationResult = new OidcAuthorizationCodeAuthenticationToken(
+ oidcUser,
+ mappedAuthorities,
+ authorizationCodeAuthentication.getClientRegistration(),
+ authorizationCodeAuthentication.getAuthorizationExchange(),
+ accessToken,
+ idToken);
authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
return authenticationResult;
@@ -180,7 +179,7 @@ public class OidcAuthorizationCodeAuthenticationProvider implements Authenticati
@Override
public boolean supports(Class> authentication) {
- return OAuth2AuthorizationCodeAuthenticationToken.class.isAssignableFrom(authentication);
+ return OAuth2LoginAuthenticationToken.class.isAssignableFrom(authentication);
}
private void validateIdToken(OidcIdToken idToken, ClientRegistration clientRegistration) {
diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationToken.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationToken.java
new file mode 100644
index 0000000000..b61563b09e
--- /dev/null
+++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/authentication/OidcAuthorizationCodeAuthenticationToken.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2012-2017 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.client.oidc.authentication;
+
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken;
+import org.springframework.security.oauth2.client.registration.ClientRegistration;
+import org.springframework.security.oauth2.core.OAuth2AccessToken;
+import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
+import org.springframework.security.oauth2.core.oidc.OidcIdToken;
+import org.springframework.security.oauth2.core.oidc.user.OidcUser;
+import org.springframework.util.Assert;
+
+import java.util.Collection;
+
+/**
+ * An {@link OAuth2LoginAuthenticationToken} for OpenID Connect 1.0 Authentication,
+ * which leverages the Authorization Code Flow.
+ *
+ * @author Joe Grandja
+ * @since 5.0
+ * @see OAuth2LoginAuthenticationToken
+ * @see OidcIdToken
+ * @see 3.1 Authorization Code Flow
+ */
+public class OidcAuthorizationCodeAuthenticationToken extends OAuth2LoginAuthenticationToken {
+ private OidcIdToken idToken;
+
+ /**
+ * This constructor should be used when the Authentication Request/Response is complete.
+ *
+ * @param clientRegistration
+ * @param authorizationExchange
+ */
+ public OidcAuthorizationCodeAuthenticationToken(ClientRegistration clientRegistration,
+ OAuth2AuthorizationExchange authorizationExchange) {
+
+ super(clientRegistration, authorizationExchange);
+ }
+
+ /**
+ * This constructor should be used when the Token Request/Response is complete,
+ * which indicates that the Authorization Code Flow has fully completed
+ * and OpenID Connect 1.0 Authentication has been achieved.
+ *
+ * @param principal
+ * @param authorities
+ * @param clientRegistration
+ * @param authorizationExchange
+ * @param accessToken
+ * @param idToken
+ */
+ public OidcAuthorizationCodeAuthenticationToken(OidcUser principal,
+ Collection extends GrantedAuthority> authorities,
+ ClientRegistration clientRegistration,
+ OAuth2AuthorizationExchange authorizationExchange,
+ OAuth2AccessToken accessToken,
+ OidcIdToken idToken) {
+
+ super(principal, authorities, clientRegistration, authorizationExchange, accessToken);
+ Assert.notNull(idToken, "idToken cannot be null");
+ this.idToken = idToken;
+ }
+
+ public OidcIdToken getIdToken() {
+ return this.idToken;
+ }
+}
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 af05907d49..7dac454c63 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
@@ -21,8 +21,8 @@ import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
-import org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken;
import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationProvider;
+import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.token.InMemoryAccessTokenRepository;
@@ -35,7 +35,6 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExch
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
-import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -60,7 +59,7 @@ import java.io.IOException;
* and redirect the end-user's user-agent back to this Filter (the client).
*
*
- * This Filter will then create an {@link OAuth2AuthorizationCodeAuthenticationToken} with
+ * This Filter will then create an {@link OAuth2LoginAuthenticationToken} with
* the {@link OAuth2ParameterNames#CODE} received in the previous step and delegate it to
* {@link OAuth2LoginAuthenticationProvider#authenticate(Authentication)} (indirectly via {@link AuthenticationManager}).
*
@@ -69,7 +68,7 @@ import java.io.IOException;
* @author Joe Grandja
* @since 5.0
* @see AbstractAuthenticationProcessingFilter
- * @see OAuth2AuthorizationCodeAuthenticationToken
+ * @see OAuth2LoginAuthenticationToken
* @see OAuth2AuthenticationToken
* @see OAuth2LoginAuthenticationProvider
* @see OAuth2AuthorizationRequest
@@ -136,19 +135,29 @@ public class OAuth2LoginAuthenticationFilter extends AbstractAuthenticationProce
.redirectUri(authorizationRequest.getRedirectUri())
.build();
- OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthentication = new OAuth2AuthorizationCodeAuthenticationToken(
+ OAuth2LoginAuthenticationToken authenticationRequest = new OAuth2LoginAuthenticationToken(
clientRegistration, new OAuth2AuthorizationExchange(authorizationRequest, authorizationResponse));
- authorizationCodeAuthentication.setDetails(this.authenticationDetailsSource.buildDetails(request));
+ authenticationRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
- OAuth2AuthenticationToken oauth2Authentication =
- (OAuth2AuthenticationToken) this.getAuthenticationManager().authenticate(authorizationCodeAuthentication);
+ OAuth2LoginAuthenticationToken authenticationResult =
+ (OAuth2LoginAuthenticationToken)this.getAuthenticationManager().authenticate(authenticationRequest);
+
+ OAuth2AuthenticationToken oauth2Authentication = new OAuth2AuthenticationToken(
+ authenticationResult.getPrincipal(),
+ authenticationResult.getAuthorities(),
+ authenticationResult.getClientRegistration().getRegistrationId());
+
+ OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
+ authenticationResult.getClientRegistration(),
+ oauth2Authentication.getName(),
+ authenticationResult.getAccessToken());
this.authorizedClientService.saveAuthorizedClient(
- oauth2Authentication.getAuthorizedClient(), oauth2Authentication);
+ authorizedClient, oauth2Authentication);
this.accessTokenRepository.saveToken(
- oauth2Authentication.getAuthorizedClient().getAccessToken(),
- oauth2Authentication.getAuthorizedClient().getClientRegistration(),
+ authorizedClient.getAccessToken(),
+ authorizedClient.getClientRegistration(),
oauth2Authentication);
return oauth2Authentication;
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 ba638ccf4d..b6ca644d6c 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
@@ -27,9 +27,9 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
+import org.springframework.security.oauth2.client.authentication.OAuth2LoginAuthenticationToken;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
@@ -48,6 +48,7 @@ import java.util.HashMap;
import java.util.Map;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
/**
* Tests {@link OAuth2LoginAuthenticationFilter}.
@@ -99,13 +100,18 @@ public class OAuth2LoginAuthenticationFilterTests {
@Test
public void doFilterWhenAuthorizationCodeSuccessResponseThenAuthenticationSuccessHandlerIsCalled() throws Exception {
ClientRegistration clientRegistration = TestUtil.githubClientRegistration();
- OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
- clientRegistration, "principal", mock(OAuth2AccessToken.class));
+ OAuth2User oauth2User = mock(OAuth2User.class);
+ when(oauth2User.getName()).thenReturn("principal name");
+ OAuth2LoginAuthenticationToken loginAuthentication = mock(OAuth2LoginAuthenticationToken.class);
+ when(loginAuthentication.getPrincipal()).thenReturn(oauth2User);
+ when(loginAuthentication.getClientRegistration()).thenReturn(clientRegistration);
+ when(loginAuthentication.getAccessToken()).thenReturn(mock(OAuth2AccessToken.class));
+
OAuth2AuthenticationToken userAuthentication = new OAuth2AuthenticationToken(
- mock(OAuth2User.class), AuthorityUtils.createAuthorityList("ROLE_USER"), authorizedClient);
+ oauth2User, AuthorityUtils.NO_AUTHORITIES, clientRegistration.getRegistrationId());
SecurityContextHolder.getContext().setAuthentication(userAuthentication);
AuthenticationManager authenticationManager = mock(AuthenticationManager.class);
- Mockito.when(authenticationManager.authenticate(Matchers.any(Authentication.class))).thenReturn(userAuthentication);
+ when(authenticationManager.authenticate(Matchers.any(Authentication.class))).thenReturn(loginAuthentication);
OAuth2LoginAuthenticationFilter filter = Mockito.spy(setupFilter(authenticationManager, clientRegistration));
AuthenticationSuccessHandler successHandler = mock(AuthenticationSuccessHandler.class);
diff --git a/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java b/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java
index e87c1a5a97..c45f6c62ea 100644
--- a/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java
+++ b/samples/boot/oauth2login/src/integration-test/java/org/springframework/security/samples/OAuth2LoginApplicationTests.java
@@ -30,12 +30,16 @@ import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService;
+import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
+import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.endpoint.AuthorizationGrantTokenExchanger;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
@@ -388,5 +392,13 @@ public class OAuth2LoginApplicationTests {
@EnableAutoConfiguration
@ComponentScan(basePackages = "sample.web")
public static class SpringBootApplicationTestConfig {
+
+ @Autowired
+ private ClientRegistrationRepository clientRegistrationRepository;
+
+ @Bean
+ public OAuth2AuthorizedClientService authorizedClientService() {
+ return new InMemoryOAuth2AuthorizedClientService<>(this.clientRegistrationRepository);
+ }
}
}
diff --git a/samples/boot/oauth2login/src/main/java/sample/config/OAuth2LoginConfig.java b/samples/boot/oauth2login/src/main/java/sample/config/OAuth2LoginConfig.java
new file mode 100644
index 0000000000..fa9ab9f264
--- /dev/null
+++ b/samples/boot/oauth2login/src/main/java/sample/config/OAuth2LoginConfig.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2002-2017 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 sample.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.oauth2.client.InMemoryOAuth2AuthorizedClientService;
+import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
+import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
+import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
+
+/**
+ * @author Joe Grandja
+ */
+@Configuration
+public class OAuth2LoginConfig {
+
+ @Autowired
+ private ClientRegistrationRepository clientRegistrationRepository;
+
+ @Bean
+ public OAuth2AuthorizedClientService authorizedClientService() {
+ return new InMemoryOAuth2AuthorizedClientService<>(this.clientRegistrationRepository);
+ }
+}
diff --git a/samples/boot/oauth2login/src/main/java/sample/web/MainController.java b/samples/boot/oauth2login/src/main/java/sample/web/MainController.java
index 1b5a42585e..d9364274fe 100644
--- a/samples/boot/oauth2login/src/main/java/sample/web/MainController.java
+++ b/samples/boot/oauth2login/src/main/java/sample/web/MainController.java
@@ -15,10 +15,11 @@
*/
package sample.web;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
-import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
+import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
-import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
@@ -37,21 +38,26 @@ import java.util.Map;
@Controller
public class MainController {
+ @Autowired
+ private OAuth2AuthorizedClientService authorizedClientService;
+
@RequestMapping("/")
- public String index(Model model, @AuthenticationPrincipal OAuth2User user, OAuth2AuthenticationToken authentication) {
- model.addAttribute("userName", user.getName());
- model.addAttribute("clientName", authentication.getAuthorizedClient().getClientRegistration().getClientName());
+ public String index(Model model, OAuth2AuthenticationToken authentication) {
+ OAuth2AuthorizedClient authorizedClient = this.getAuthorizedClient(authentication);
+ model.addAttribute("userName", authentication.getName());
+ model.addAttribute("clientName", authorizedClient.getClientRegistration().getClientName());
return "index";
}
@RequestMapping("/userinfo")
public String userinfo(Model model, OAuth2AuthenticationToken authentication) {
+ OAuth2AuthorizedClient authorizedClient = this.getAuthorizedClient(authentication);
Map userAttributes = Collections.emptyMap();
- String userInfoEndpointUri = authentication.getAuthorizedClient().getClientRegistration()
+ String userInfoEndpointUri = authorizedClient.getClientRegistration()
.getProviderDetails().getUserInfoEndpoint().getUri();
if (!StringUtils.isEmpty(userInfoEndpointUri)) { // userInfoEndpointUri is optional for OIDC Clients
userAttributes = WebClient.builder()
- .filter(oauth2Credentials(authentication))
+ .filter(oauth2Credentials(authorizedClient))
.build()
.get()
.uri(userInfoEndpointUri)
@@ -63,11 +69,16 @@ public class MainController {
return "userinfo";
}
- private ExchangeFilterFunction oauth2Credentials(OAuth2AuthenticationToken authentication) {
+ private OAuth2AuthorizedClient getAuthorizedClient(OAuth2AuthenticationToken authentication) {
+ return this.authorizedClientService.loadAuthorizedClient(
+ authentication.getAuthorizedClientRegistrationId(), authentication);
+ }
+
+ private ExchangeFilterFunction oauth2Credentials(OAuth2AuthorizedClient authorizedClient) {
return ExchangeFilterFunction.ofRequestProcessor(
clientRequest -> {
ClientRequest authorizedRequest = ClientRequest.from(clientRequest)
- .header(HttpHeaders.AUTHORIZATION, "Bearer " + authentication.getAuthorizedClient().getAccessToken().getTokenValue())
+ .header(HttpHeaders.AUTHORIZATION, "Bearer " + authorizedClient.getAccessToken().getTokenValue())
.build();
return Mono.just(authorizedRequest);
});