1
0
mirror of synced 2026-08-06 02:08:01 +00:00

Revert authorization_code grant support

This reverts commit eae7afd9aa.
This commit is contained in:
Joe Grandja
2018-03-06 16:15:49 -05:00
parent c922fe3be1
commit a5bd76b6ed
17 changed files with 139 additions and 1518 deletions
@@ -1,88 +0,0 @@
/*
* 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.client.authentication;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.util.Assert;
/**
* An implementation of an {@link AuthenticationProvider} for the OAuth 2.0 Authorization Code Grant.
*
* <p>
* 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.
*
* @author Joe Grandja
* @since 5.1
* @see OAuth2AuthorizationCodeAuthenticationToken
* @see OAuth2AccessTokenResponseClient
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1">Section 4.1 Authorization Code Grant Flow</a>
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.3">Section 4.1.3 Access Token Request</a>
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.4">Section 4.1.4 Access Token Response</a>
*/
public class OAuth2AuthorizationCodeAuthenticationProvider implements AuthenticationProvider {
private final OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient;
/**
* Constructs an {@code OAuth2AuthorizationCodeAuthenticationProvider} using the provided parameters.
*
* @param accessTokenResponseClient the client used for requesting the access token credential from the Token Endpoint
*/
public OAuth2AuthorizationCodeAuthenticationProvider(
OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient) {
Assert.notNull(accessTokenResponseClient, "accessTokenResponseClient cannot be null");
this.accessTokenResponseClient = accessTokenResponseClient;
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthentication =
(OAuth2AuthorizationCodeAuthenticationToken) authentication;
OAuth2AuthorizationExchangeValidator.validate(
authorizationCodeAuthentication.getAuthorizationExchange());
OAuth2AccessTokenResponse accessTokenResponse =
this.accessTokenResponseClient.getTokenResponse(
new OAuth2AuthorizationCodeGrantRequest(
authorizationCodeAuthentication.getClientRegistration(),
authorizationCodeAuthentication.getAuthorizationExchange()));
OAuth2AccessToken accessToken = accessTokenResponse.getAccessToken();
OAuth2AuthorizationCodeAuthenticationToken authenticationResult =
new OAuth2AuthorizationCodeAuthenticationToken(
authorizationCodeAuthentication.getClientRegistration(),
authorizationCodeAuthentication.getAuthorizationExchange(),
accessToken);
authenticationResult.setDetails(authorizationCodeAuthentication.getDetails());
return authenticationResult;
}
@Override
public boolean supports(Class<?> authentication) {
return OAuth2AuthorizationCodeAuthenticationToken.class.isAssignableFrom(authentication);
}
}
@@ -1,114 +0,0 @@
/*
* 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.client.authentication;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
import org.springframework.util.Assert;
import java.util.Collections;
/**
* An {@link AbstractAuthenticationToken} for the OAuth 2.0 Authorization Code Grant.
*
* @author Joe Grandja
* @since 5.1
* @see AbstractAuthenticationToken
* @see ClientRegistration
* @see OAuth2AuthorizationExchange
* @see OAuth2AccessToken
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1">Section 4.1 Authorization Code Grant Flow</a>
*/
public class OAuth2AuthorizationCodeAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
private ClientRegistration clientRegistration;
private OAuth2AuthorizationExchange authorizationExchange;
private OAuth2AccessToken accessToken;
/**
* This constructor should be used when the Authorization Request/Response is complete.
*
* @param clientRegistration the client registration
* @param authorizationExchange the authorization exchange
*/
public OAuth2AuthorizationCodeAuthenticationToken(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 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
*/
public OAuth2AuthorizationCodeAuthenticationToken(ClientRegistration clientRegistration,
OAuth2AuthorizationExchange authorizationExchange,
OAuth2AccessToken accessToken) {
this(clientRegistration, authorizationExchange);
Assert.notNull(accessToken, "accessToken cannot be null");
this.accessToken = accessToken;
this.setAuthenticated(true);
}
@Override
public Object getPrincipal() {
return this.clientRegistration.getClientId();
}
@Override
public Object getCredentials() {
return this.accessToken != null ?
this.accessToken.getTokenValue() :
this.authorizationExchange.getAuthorizationResponse().getCode();
}
/**
* Returns the {@link ClientRegistration client registration}.
*
* @return the {@link ClientRegistration}
*/
public ClientRegistration getClientRegistration() {
return this.clientRegistration;
}
/**
* Returns the {@link OAuth2AuthorizationExchange authorization exchange}.
*
* @return the {@link OAuth2AuthorizationExchange}
*/
public OAuth2AuthorizationExchange getAuthorizationExchange() {
return this.authorizationExchange;
}
/**
* Returns the {@link OAuth2AccessToken access token}.
*
* @return the {@link OAuth2AccessToken}
*/
public OAuth2AccessToken getAccessToken() {
return this.accessToken;
}
}
@@ -1,54 +0,0 @@
/*
* 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.client.authentication;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse;
/**
* A validator for an &quot;exchange&quot; of an OAuth 2.0 Authorization Request and Response.
*
* @author Joe Grandja
* @since 5.1
* @see OAuth2AuthorizationExchange
*/
final class OAuth2AuthorizationExchangeValidator {
private static final String INVALID_STATE_PARAMETER_ERROR_CODE = "invalid_state_parameter";
private static final String INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE = "invalid_redirect_uri_parameter";
static void validate(OAuth2AuthorizationExchange authorizationExchange) {
OAuth2AuthorizationRequest authorizationRequest = authorizationExchange.getAuthorizationRequest();
OAuth2AuthorizationResponse authorizationResponse = authorizationExchange.getAuthorizationResponse();
if (authorizationResponse.statusError()) {
throw new OAuth2AuthenticationException(
authorizationResponse.getError(), authorizationResponse.getError().toString());
}
if (!authorizationResponse.getState().equals(authorizationRequest.getState())) {
OAuth2Error oauth2Error = new OAuth2Error(INVALID_STATE_PARAMETER_ERROR_CODE);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}
if (!authorizationResponse.getRedirectUri().equals(authorizationRequest.getRedirectUri())) {
OAuth2Error oauth2Error = new OAuth2Error(INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}
}
}
@@ -25,7 +25,11 @@ import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCo
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.util.Assert;
@@ -56,6 +60,8 @@ import java.util.Collection;
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.4">Section 4.1.4 Access Token Response</a>
*/
public class OAuth2LoginAuthenticationProvider implements AuthenticationProvider {
private static final String INVALID_STATE_PARAMETER_ERROR_CODE = "invalid_state_parameter";
private static final String INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE = "invalid_redirect_uri_parameter";
private final OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient;
private final OAuth2UserService<OAuth2UserRequest, OAuth2User> userService;
private GrantedAuthoritiesMapper authoritiesMapper = (authorities -> authorities);
@@ -91,8 +97,25 @@ public class OAuth2LoginAuthenticationProvider implements AuthenticationProvider
return null;
}
OAuth2AuthorizationExchangeValidator.validate(
authorizationCodeAuthentication.getAuthorizationExchange());
OAuth2AuthorizationRequest authorizationRequest = authorizationCodeAuthentication
.getAuthorizationExchange().getAuthorizationRequest();
OAuth2AuthorizationResponse authorizationResponse = authorizationCodeAuthentication
.getAuthorizationExchange().getAuthorizationResponse();
if (authorizationResponse.statusError()) {
throw new OAuth2AuthenticationException(
authorizationResponse.getError(), authorizationResponse.getError().toString());
}
if (!authorizationResponse.getState().equals(authorizationRequest.getState())) {
OAuth2Error oauth2Error = new OAuth2Error(INVALID_STATE_PARAMETER_ERROR_CODE);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}
if (!authorizationResponse.getRedirectUri().equals(authorizationRequest.getRedirectUri())) {
OAuth2Error oauth2Error = new OAuth2Error(INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}
OAuth2AccessTokenResponse accessTokenResponse =
this.accessTokenResponseClient.getTokenResponse(
@@ -1,192 +0,0 @@
/*
* 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.client.web;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
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.OAuth2AuthorizationCodeAuthenticationProvider;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
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.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.UriComponentsBuilder;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* A {@code Filter} for the OAuth 2.0 Authorization Code Grant,
* which handles the processing of the OAuth 2.0 Authorization Response.
*
* <p>
* The OAuth 2.0 Authorization Response is processed as follows:
*
* <ul>
* <li>
* Assuming the End-User (Resource Owner) has granted access to the Client, the Authorization Server will append the
* {@link OAuth2ParameterNames#CODE code} and {@link OAuth2ParameterNames#STATE state} parameters
* to the {@link OAuth2ParameterNames#REDIRECT_URI redirect_uri} (provided in the Authorization Request)
* and redirect the End-User's user-agent back to this {@code Filter} (the Client).
* </li>
* <li>
* This {@code Filter} will then create an {@link OAuth2AuthorizationCodeAuthenticationToken} with
* the {@link OAuth2ParameterNames#CODE code} received and
* delegate it to the {@link AuthenticationManager} to authenticate.
* </li>
* <li>
* Upon a successful authentication, an {@link OAuth2AuthorizedClient Authorized Client} is created by associating the
* {@link OAuth2AuthorizationCodeAuthenticationToken#getClientRegistration() client} to the
* {@link OAuth2AuthorizationCodeAuthenticationToken#getAccessToken() access token} and current {@code Principal}
* and saving it via the {@link OAuth2AuthorizedClientService}.
* </li>
* </ul>
*
* @author Joe Grandja
* @since 5.1
* @see OAuth2AuthorizationCodeAuthenticationToken
* @see OAuth2AuthorizationCodeAuthenticationProvider
* @see OAuth2AuthorizationRequest
* @see OAuth2AuthorizationResponse
* @see AuthorizationRequestRepository
* @see OAuth2AuthorizationRequestRedirectFilter
* @see ClientRegistrationRepository
* @see OAuth2AuthorizedClient
* @see OAuth2AuthorizedClientService
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1">Section 4.1 Authorization Code Grant</a>
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.2">Section 4.1.2 Authorization Response</a>
*/
public class OAuth2AuthorizationCodeGrantFilter extends OncePerRequestFilter {
private final ClientRegistrationRepository clientRegistrationRepository;
private final OAuth2AuthorizedClientService authorizedClientService;
private final AuthenticationManager authenticationManager;
private AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository =
new HttpSessionOAuth2AuthorizationRequestRepository();
private final AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
/**
* Constructs an {@code OAuth2AuthorizationCodeGrantFilter} using the provided parameters.
*
* @param clientRegistrationRepository the repository of client registrations
* @param authorizedClientService the authorized client service
* @param authenticationManager the authentication manager
*/
public OAuth2AuthorizationCodeGrantFilter(ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientService authorizedClientService,
AuthenticationManager authenticationManager) {
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
Assert.notNull(authorizedClientService, "authorizedClientService cannot be null");
Assert.notNull(authenticationManager, "authenticationManager cannot be null");
this.clientRegistrationRepository = clientRegistrationRepository;
this.authorizedClientService = authorizedClientService;
this.authenticationManager = authenticationManager;
}
/**
* Sets the repository for stored {@link OAuth2AuthorizationRequest}'s.
*
* @param authorizationRequestRepository the repository for stored {@link OAuth2AuthorizationRequest}'s
*/
public final void setAuthorizationRequestRepository(AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository) {
Assert.notNull(authorizationRequestRepository, "authorizationRequestRepository cannot be null");
this.authorizationRequestRepository = authorizationRequestRepository;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (this.shouldProcessAuthorizationResponse(request, response)) {
this.processAuthorizationResponse(request, response);
return;
}
filterChain.doFilter(request, response);
}
private boolean shouldProcessAuthorizationResponse(HttpServletRequest request, HttpServletResponse response) {
if (OAuth2AuthorizationResponseUtils.authorizationResponse(request) &&
(this.authorizationRequestRepository.loadAuthorizationRequest(request) != null)) {
return true;
}
return false;
}
private void processAuthorizationResponse(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
OAuth2AuthorizationRequest authorizationRequest = this.authorizationRequestRepository.loadAuthorizationRequest(request);
this.authorizationRequestRepository.removeAuthorizationRequest(request);
String registrationId = (String) authorizationRequest.getAdditionalParameters().get(OAuth2ParameterNames.REGISTRATION_ID);
ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId);
OAuth2AuthorizationResponse authorizationResponse = OAuth2AuthorizationResponseUtils.convert(request);
OAuth2AuthorizationCodeAuthenticationToken authenticationRequest = new OAuth2AuthorizationCodeAuthenticationToken(
clientRegistration, new OAuth2AuthorizationExchange(authorizationRequest, authorizationResponse));
authenticationRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
OAuth2AuthorizationCodeAuthenticationToken authenticationResult;
try {
authenticationResult = (OAuth2AuthorizationCodeAuthenticationToken)
this.authenticationManager.authenticate(authenticationRequest);
} catch (OAuth2AuthenticationException ex) {
OAuth2Error error = ex.getError();
UriComponentsBuilder uriBuilder = UriComponentsBuilder
.fromUriString(authorizationResponse.getRedirectUri())
.queryParam(OAuth2ParameterNames.ERROR, error.getErrorCode());
if (!StringUtils.isEmpty(error.getDescription())) {
uriBuilder.queryParam(OAuth2ParameterNames.ERROR_DESCRIPTION, error.getDescription());
}
if (!StringUtils.isEmpty(error.getUri())) {
uriBuilder.queryParam(OAuth2ParameterNames.ERROR_URI, error.getUri());
}
this.redirectStrategy.sendRedirect(request, response, uriBuilder.build().encode().toString());
return;
}
Authentication currentAuthentication = SecurityContextHolder.getContext().getAuthentication();
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
authenticationResult.getClientRegistration(),
currentAuthentication.getName(),
authenticationResult.getAccessToken());
this.authorizedClientService.saveAuthorizedClient(authorizedClient, currentAuthentication);
this.redirectStrategy.sendRedirect(request, response, authorizationResponse.getRedirectUri());
}
}
@@ -1,72 +0,0 @@
/*
* 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.client.web;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
/**
* Utility methods for an OAuth 2.0 Authorization Response.
*
* @author Joe Grandja
* @since 5.1
* @see OAuth2AuthorizationResponse
*/
final class OAuth2AuthorizationResponseUtils {
private OAuth2AuthorizationResponseUtils() {
}
static boolean authorizationResponse(HttpServletRequest request) {
return authorizationResponseSuccess(request) || authorizationResponseError(request);
}
static boolean authorizationResponseSuccess(HttpServletRequest request) {
return StringUtils.hasText(request.getParameter(OAuth2ParameterNames.CODE)) &&
StringUtils.hasText(request.getParameter(OAuth2ParameterNames.STATE));
}
static boolean authorizationResponseError(HttpServletRequest request) {
return StringUtils.hasText(request.getParameter(OAuth2ParameterNames.ERROR)) &&
StringUtils.hasText(request.getParameter(OAuth2ParameterNames.STATE));
}
static OAuth2AuthorizationResponse convert(HttpServletRequest request) {
String code = request.getParameter(OAuth2ParameterNames.CODE);
String errorCode = request.getParameter(OAuth2ParameterNames.ERROR);
String state = request.getParameter(OAuth2ParameterNames.STATE);
String redirectUri = request.getRequestURL().toString();
if (StringUtils.hasText(code)) {
return OAuth2AuthorizationResponse.success(code)
.redirectUri(redirectUri)
.state(state)
.build();
} else {
String errorDescription = request.getParameter(OAuth2ParameterNames.ERROR_DESCRIPTION);
String errorUri = request.getParameter(OAuth2ParameterNames.ERROR_URI);
return OAuth2AuthorizationResponse.error(errorCode)
.redirectUri(redirectUri)
.errorDescription(errorDescription)
.errorUri(errorUri)
.state(state)
.build();
}
}
}
@@ -35,6 +35,7 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -133,7 +134,7 @@ public class OAuth2LoginAuthenticationFilter extends AbstractAuthenticationProce
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
if (!OAuth2AuthorizationResponseUtils.authorizationResponse(request)) {
if (!this.authorizationResponseSuccess(request) && !this.authorizationResponseError(request)) {
OAuth2Error oauth2Error = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}
@@ -148,7 +149,7 @@ public class OAuth2LoginAuthenticationFilter extends AbstractAuthenticationProce
String registrationId = (String) authorizationRequest.getAdditionalParameters().get(OAuth2ParameterNames.REGISTRATION_ID);
ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId);
OAuth2AuthorizationResponse authorizationResponse = OAuth2AuthorizationResponseUtils.convert(request);
OAuth2AuthorizationResponse authorizationResponse = this.convert(request);
OAuth2LoginAuthenticationToken authenticationRequest = new OAuth2LoginAuthenticationToken(
clientRegistration, new OAuth2AuthorizationExchange(authorizationRequest, authorizationResponse));
@@ -181,4 +182,37 @@ public class OAuth2LoginAuthenticationFilter extends AbstractAuthenticationProce
Assert.notNull(authorizationRequestRepository, "authorizationRequestRepository cannot be null");
this.authorizationRequestRepository = authorizationRequestRepository;
}
private OAuth2AuthorizationResponse convert(HttpServletRequest request) {
String code = request.getParameter(OAuth2ParameterNames.CODE);
String errorCode = request.getParameter(OAuth2ParameterNames.ERROR);
String state = request.getParameter(OAuth2ParameterNames.STATE);
String redirectUri = request.getRequestURL().toString();
if (StringUtils.hasText(code)) {
return OAuth2AuthorizationResponse.success(code)
.redirectUri(redirectUri)
.state(state)
.build();
} else {
String errorDescription = request.getParameter(OAuth2ParameterNames.ERROR_DESCRIPTION);
String errorUri = request.getParameter(OAuth2ParameterNames.ERROR_URI);
return OAuth2AuthorizationResponse.error(errorCode)
.redirectUri(redirectUri)
.errorDescription(errorDescription)
.errorUri(errorUri)
.state(state)
.build();
}
}
private boolean authorizationResponseSuccess(HttpServletRequest request) {
return StringUtils.hasText(request.getParameter(OAuth2ParameterNames.CODE)) &&
StringUtils.hasText(request.getParameter(OAuth2ParameterNames.STATE));
}
private boolean authorizationResponseError(HttpServletRequest request) {
return StringUtils.hasText(request.getParameter(OAuth2ParameterNames.ERROR)) &&
StringUtils.hasText(request.getParameter(OAuth2ParameterNames.STATE));
}
}
@@ -1,146 +0,0 @@
/*
* 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.client.authentication;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponse;
import java.util.Collections;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.containsString;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Tests for {@link OAuth2AuthorizationCodeAuthenticationProvider}.
*
* @author Joe Grandja
*/
@PrepareForTest({ClientRegistration.class, OAuth2AuthorizationRequest.class,
OAuth2AuthorizationResponse.class, OAuth2AccessTokenResponse.class})
@RunWith(PowerMockRunner.class)
public class OAuth2AuthorizationCodeAuthenticationProviderTests {
private ClientRegistration clientRegistration;
private OAuth2AuthorizationRequest authorizationRequest;
private OAuth2AuthorizationResponse authorizationResponse;
private OAuth2AuthorizationExchange authorizationExchange;
private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient;
private OAuth2AuthorizationCodeAuthenticationProvider authenticationProvider;
@Rule
public ExpectedException exception = ExpectedException.none();
@Before
@SuppressWarnings("unchecked")
public void setUp() throws Exception {
this.clientRegistration = mock(ClientRegistration.class);
this.authorizationRequest = mock(OAuth2AuthorizationRequest.class);
this.authorizationResponse = mock(OAuth2AuthorizationResponse.class);
this.authorizationExchange = new OAuth2AuthorizationExchange(this.authorizationRequest, this.authorizationResponse);
this.accessTokenResponseClient = mock(OAuth2AccessTokenResponseClient.class);
this.authenticationProvider = new OAuth2AuthorizationCodeAuthenticationProvider(this.accessTokenResponseClient);
when(this.authorizationRequest.getState()).thenReturn("12345");
when(this.authorizationResponse.getState()).thenReturn("12345");
when(this.authorizationRequest.getRedirectUri()).thenReturn("http://example.com");
when(this.authorizationResponse.getRedirectUri()).thenReturn("http://example.com");
}
@Test
public void constructorWhenAccessTokenResponseClientIsNullThenThrowIllegalArgumentException() {
this.exception.expect(IllegalArgumentException.class);
new OAuth2AuthorizationCodeAuthenticationProvider(null);
}
@Test
public void supportsWhenTypeOAuth2AuthorizationCodeAuthenticationTokenThenReturnTrue() {
assertThat(this.authenticationProvider.supports(OAuth2AuthorizationCodeAuthenticationToken.class)).isTrue();
}
@Test
public void authenticateWhenAuthorizationErrorResponseThenThrowOAuth2AuthenticationException() {
this.exception.expect(OAuth2AuthenticationException.class);
this.exception.expectMessage(containsString(OAuth2ErrorCodes.INVALID_REQUEST));
when(this.authorizationResponse.statusError()).thenReturn(true);
when(this.authorizationResponse.getError()).thenReturn(new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST));
this.authenticationProvider.authenticate(
new OAuth2AuthorizationCodeAuthenticationToken(this.clientRegistration, this.authorizationExchange));
}
@Test
public void authenticateWhenAuthorizationResponseStateNotEqualAuthorizationRequestStateThenThrowOAuth2AuthenticationException() {
this.exception.expect(OAuth2AuthenticationException.class);
this.exception.expectMessage(containsString("invalid_state_parameter"));
when(this.authorizationRequest.getState()).thenReturn("12345");
when(this.authorizationResponse.getState()).thenReturn("67890");
this.authenticationProvider.authenticate(
new OAuth2AuthorizationCodeAuthenticationToken(this.clientRegistration, this.authorizationExchange));
}
@Test
public void authenticateWhenAuthorizationResponseRedirectUriNotEqualAuthorizationRequestRedirectUriThenThrowOAuth2AuthenticationException() {
this.exception.expect(OAuth2AuthenticationException.class);
this.exception.expectMessage(containsString("invalid_redirect_uri_parameter"));
when(this.authorizationRequest.getRedirectUri()).thenReturn("http://example.com");
when(this.authorizationResponse.getRedirectUri()).thenReturn("http://example2.com");
this.authenticationProvider.authenticate(
new OAuth2AuthorizationCodeAuthenticationToken(this.clientRegistration, this.authorizationExchange));
}
@Test
public void authenticateWhenAuthorizationSuccessResponseThenExchangedForAccessToken() {
OAuth2AccessToken accessToken = mock(OAuth2AccessToken.class);
OAuth2AccessTokenResponse accessTokenResponse = mock(OAuth2AccessTokenResponse.class);
when(accessTokenResponse.getAccessToken()).thenReturn(accessToken);
when(this.accessTokenResponseClient.getTokenResponse(any())).thenReturn(accessTokenResponse);
OAuth2AuthorizationCodeAuthenticationToken authenticationResult =
(OAuth2AuthorizationCodeAuthenticationToken) this.authenticationProvider.authenticate(
new OAuth2AuthorizationCodeAuthenticationToken(this.clientRegistration, this.authorizationExchange));
assertThat(authenticationResult.isAuthenticated()).isTrue();
assertThat(authenticationResult.getPrincipal()).isEqualTo(this.clientRegistration.getClientId());
assertThat(authenticationResult.getCredentials()).isEqualTo(accessToken.getTokenValue());
assertThat(authenticationResult.getAuthorities()).isEqualTo(Collections.emptyList());
assertThat(authenticationResult.getClientRegistration()).isEqualTo(this.clientRegistration);
assertThat(authenticationResult.getAuthorizationExchange()).isEqualTo(this.authorizationExchange);
assertThat(authenticationResult.getAccessToken()).isEqualTo(accessToken);
}
}
@@ -1,109 +0,0 @@
/*
* 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.client.authentication;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
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.endpoint.OAuth2AuthorizationResponse;
import java.util.Collections;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Tests for {@link OAuth2AuthorizationCodeAuthenticationToken}.
*
* @author Joe Grandja
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ClientRegistration.class, OAuth2AuthorizationExchange.class, OAuth2AuthorizationResponse.class})
public class OAuth2AuthorizationCodeAuthenticationTokenTests {
private ClientRegistration clientRegistration;
private OAuth2AuthorizationExchange authorizationExchange;
private OAuth2AccessToken accessToken;
@Before
public void setUp() {
this.clientRegistration = mock(ClientRegistration.class);
this.authorizationExchange = mock(OAuth2AuthorizationExchange.class);
this.accessToken = mock(OAuth2AccessToken.class);
}
@Test(expected = IllegalArgumentException.class)
public void constructorAuthorizationRequestResponseWhenClientRegistrationIsNullThenThrowIllegalArgumentException() {
new OAuth2AuthorizationCodeAuthenticationToken(null, this.authorizationExchange);
}
@Test(expected = IllegalArgumentException.class)
public void constructorAuthorizationRequestResponseWhenAuthorizationExchangeIsNullThenThrowIllegalArgumentException() {
new OAuth2AuthorizationCodeAuthenticationToken(this.clientRegistration, null);
}
@Test
public void constructorAuthorizationRequestResponseWhenAllParametersProvidedAndValidThenCreated() {
OAuth2AuthorizationResponse authorizationResponse = mock(OAuth2AuthorizationResponse.class);
when(authorizationResponse.getCode()).thenReturn("code");
when(this.authorizationExchange.getAuthorizationResponse()).thenReturn(authorizationResponse);
OAuth2AuthorizationCodeAuthenticationToken authentication =
new OAuth2AuthorizationCodeAuthenticationToken(this.clientRegistration, this.authorizationExchange);
assertThat(authentication.getPrincipal()).isEqualTo(this.clientRegistration.getClientId());
assertThat(authentication.getCredentials()).isEqualTo(this.authorizationExchange.getAuthorizationResponse().getCode());
assertThat(authentication.getAuthorities()).isEqualTo(Collections.emptyList());
assertThat(authentication.getClientRegistration()).isEqualTo(this.clientRegistration);
assertThat(authentication.getAuthorizationExchange()).isEqualTo(this.authorizationExchange);
assertThat(authentication.getAccessToken()).isNull();
assertThat(authentication.isAuthenticated()).isEqualTo(false);
}
@Test(expected = IllegalArgumentException.class)
public void constructorTokenRequestResponseWhenClientRegistrationIsNullThenThrowIllegalArgumentException() {
new OAuth2AuthorizationCodeAuthenticationToken(null, this.authorizationExchange, this.accessToken);
}
@Test(expected = IllegalArgumentException.class)
public void constructorTokenRequestResponseWhenAuthorizationExchangeIsNullThenThrowIllegalArgumentException() {
new OAuth2AuthorizationCodeAuthenticationToken(this.clientRegistration, null, this.accessToken);
}
@Test(expected = IllegalArgumentException.class)
public void constructorTokenRequestResponseWhenAccessTokenIsNullThenThrowIllegalArgumentException() {
new OAuth2AuthorizationCodeAuthenticationToken(this.clientRegistration, this.authorizationExchange, null);
}
@Test
public void constructorTokenRequestResponseWhenAllParametersProvidedAndValidThenCreated() {
OAuth2AuthorizationCodeAuthenticationToken authentication = new OAuth2AuthorizationCodeAuthenticationToken(
this.clientRegistration, this.authorizationExchange, this.accessToken);
assertThat(authentication.getPrincipal()).isEqualTo(this.clientRegistration.getClientId());
assertThat(authentication.getCredentials()).isEqualTo(this.accessToken.getTokenValue());
assertThat(authentication.getAuthorities()).isEqualTo(Collections.emptyList());
assertThat(authentication.getClientRegistration()).isEqualTo(this.clientRegistration);
assertThat(authentication.getAuthorizationExchange()).isEqualTo(this.authorizationExchange);
assertThat(authentication.getAccessToken()).isEqualTo(this.accessToken);
assertThat(authentication.isAuthenticated()).isEqualTo(true);
}
}
@@ -1,252 +0,0 @@
/*
* 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.client.web;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
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.authentication.OAuth2AuthorizationCodeAuthenticationToken;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationExchange;
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;
/**
* Tests for {@link OAuth2AuthorizationCodeGrantFilter}.
*
* @author Joe Grandja
*/
@PowerMockIgnore("javax.security.*")
@PrepareForTest({OAuth2AuthorizationRequest.class, OAuth2AuthorizationExchange.class, OAuth2AuthorizationCodeGrantFilter.class})
@RunWith(PowerMockRunner.class)
public class OAuth2AuthorizationCodeGrantFilterTests {
private ClientRegistration registration1;
private String principalName1 = "principal-1";
private ClientRegistrationRepository clientRegistrationRepository;
private OAuth2AuthorizedClientService authorizedClientService;
private AuthenticationManager authenticationManager;
private AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository;
private OAuth2AuthorizationCodeGrantFilter filter;
@Before
public void setUp() {
this.registration1 = ClientRegistration.withRegistrationId("registration-1")
.clientId("client-1")
.clientSecret("secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUriTemplate("{baseUrl}/callback/client-1")
.scope("user")
.authorizationUri("https://provider.com/oauth2/authorize")
.tokenUri("https://provider.com/oauth2/token")
.userInfoUri("https://provider.com/oauth2/user")
.userNameAttributeName("id")
.clientName("client-1")
.build();
this.clientRegistrationRepository = new InMemoryClientRegistrationRepository(this.registration1);
this.authorizedClientService = new InMemoryOAuth2AuthorizedClientService(this.clientRegistrationRepository);
this.authorizationRequestRepository = new HttpSessionOAuth2AuthorizationRequestRepository();
this.authenticationManager = mock(AuthenticationManager.class);
this.filter = spy(new OAuth2AuthorizationCodeGrantFilter(
this.clientRegistrationRepository, this.authorizedClientService, this.authenticationManager));
this.filter.setAuthorizationRequestRepository(this.authorizationRequestRepository);
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
securityContext.setAuthentication(new TestingAuthenticationToken(this.principalName1, "password"));
SecurityContextHolder.setContext(securityContext);
}
@Test(expected = IllegalArgumentException.class)
public void constructorWhenClientRegistrationRepositoryIsNullThenThrowIllegalArgumentException() {
new OAuth2AuthorizationCodeGrantFilter(null, this.authorizedClientService, this.authenticationManager);
}
@Test(expected = IllegalArgumentException.class)
public void constructorWhenAuthorizedClientServiceIsNullThenThrowIllegalArgumentException() {
new OAuth2AuthorizationCodeGrantFilter(this.clientRegistrationRepository, null, this.authenticationManager);
}
@Test(expected = IllegalArgumentException.class)
public void constructorWhenAuthenticationManagerIsNullThenThrowIllegalArgumentException() {
new OAuth2AuthorizationCodeGrantFilter(this.clientRegistrationRepository, this.authorizedClientService, null);
}
@Test(expected = IllegalArgumentException.class)
public void setAuthorizationRequestRepositoryWhenAuthorizationRequestRepositoryIsNullThenThrowIllegalArgumentException() {
this.filter.setAuthorizationRequestRepository(null);
}
@Test
public void doFilterWhenNotAuthorizationResponseThenNotProcessed() throws Exception {
String requestUri = "/path";
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
request.setServletPath(requestUri);
// NOTE: A valid Authorization Response contains either a 'code' or 'error' parameter.
HttpServletResponse response = mock(HttpServletResponse.class);
FilterChain filterChain = mock(FilterChain.class);
this.filter.doFilter(request, response, filterChain);
verify(filterChain).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
}
@Test
public void doFilterWhenAuthorizationRequestNotFoundThenNotProcessed() throws Exception {
String requestUri = "/path";
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
request.setServletPath(requestUri);
request.addParameter(OAuth2ParameterNames.CODE, "code");
request.addParameter(OAuth2ParameterNames.STATE, "state");
HttpServletResponse response = mock(HttpServletResponse.class);
FilterChain filterChain = mock(FilterChain.class);
this.filter.doFilter(request, response, filterChain);
verify(filterChain).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
}
@Test
public void doFilterWhenAuthorizationResponseValidThenAuthorizationRequestRemoved() throws Exception {
String requestUri = "/callback/client-1";
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
request.setServletPath(requestUri);
request.addParameter(OAuth2ParameterNames.CODE, "code");
request.addParameter(OAuth2ParameterNames.STATE, "state");
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain filterChain = mock(FilterChain.class);
this.setUpAuthorizationRequest(request, response, this.registration1);
this.setUpAuthenticationResult(this.registration1);
this.filter.doFilter(request, response, filterChain);
assertThat(this.authorizationRequestRepository.loadAuthorizationRequest(request)).isNull();
}
@Test
public void doFilterWhenAuthenticationFailsThenHandleOAuth2AuthenticationException() throws Exception {
String requestUri = "/callback/client-1";
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
request.setServletPath(requestUri);
request.addParameter(OAuth2ParameterNames.CODE, "code");
request.addParameter(OAuth2ParameterNames.STATE, "state");
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain filterChain = mock(FilterChain.class);
this.setUpAuthorizationRequest(request, response, this.registration1);
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT);
when(this.authenticationManager.authenticate(any(Authentication.class)))
.thenThrow(new OAuth2AuthenticationException(error, error.toString()));
this.filter.doFilter(request, response, filterChain);
assertThat(response.getRedirectedUrl()).isEqualTo("http://localhost/callback/client-1?error=invalid_grant");
}
@Test
public void doFilterWhenAuthorizationResponseSuccessThenAuthorizedClientSaved() throws Exception {
String requestUri = "/callback/client-1";
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
request.setServletPath(requestUri);
request.addParameter(OAuth2ParameterNames.CODE, "code");
request.addParameter(OAuth2ParameterNames.STATE, "state");
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain filterChain = mock(FilterChain.class);
this.setUpAuthorizationRequest(request, response, this.registration1);
this.setUpAuthenticationResult(this.registration1);
this.filter.doFilter(request, response, filterChain);
OAuth2AuthorizedClient authorizedClient = this.authorizedClientService.loadAuthorizedClient(
this.registration1.getRegistrationId(), this.principalName1);
assertThat(authorizedClient).isNotNull();
assertThat(authorizedClient.getClientRegistration()).isEqualTo(this.registration1);
assertThat(authorizedClient.getPrincipalName()).isEqualTo(this.principalName1);
assertThat(authorizedClient.getAccessToken()).isNotNull();
}
@Test
public void doFilterWhenAuthorizationResponseSuccessThenRedirected() throws Exception {
String requestUri = "/callback/client-1";
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
request.setServletPath(requestUri);
request.addParameter(OAuth2ParameterNames.CODE, "code");
request.addParameter(OAuth2ParameterNames.STATE, "state");
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain filterChain = mock(FilterChain.class);
this.setUpAuthorizationRequest(request, response, this.registration1);
this.setUpAuthenticationResult(this.registration1);
this.filter.doFilter(request, response, filterChain);
assertThat(response.getRedirectedUrl()).isEqualTo("http://localhost/callback/client-1");
}
private void setUpAuthorizationRequest(HttpServletRequest request, HttpServletResponse response,
ClientRegistration registration) {
Map<String, Object> additionalParameters = new HashMap<>();
additionalParameters.put(OAuth2ParameterNames.REGISTRATION_ID, registration.getRegistrationId());
OAuth2AuthorizationRequest authorizationRequest = mock(OAuth2AuthorizationRequest.class);
when(authorizationRequest.getAdditionalParameters()).thenReturn(additionalParameters);
this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequest, request, response);
}
private void setUpAuthenticationResult(ClientRegistration registration) {
OAuth2AuthorizationCodeAuthenticationToken authentication = mock(OAuth2AuthorizationCodeAuthenticationToken.class);
when(authentication.getClientRegistration()).thenReturn(registration);
when(authentication.getAuthorizationExchange()).thenReturn(mock(OAuth2AuthorizationExchange.class));
when(authentication.getAccessToken()).thenReturn(mock(OAuth2AccessToken.class));
when(this.authenticationManager.authenticate(any(Authentication.class))).thenReturn(authentication);
}
}
@@ -19,6 +19,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@@ -53,7 +54,9 @@ import java.util.HashMap;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.*;
import static org.powermock.api.mockito.PowerMockito.verifyPrivate;
/**
* Tests for {@link OAuth2LoginAuthenticationFilter}.
@@ -262,6 +265,25 @@ public class OAuth2LoginAuthenticationFilterTests {
verify(this.filter).attemptAuthentication(any(HttpServletRequest.class), any(HttpServletResponse.class));
}
@Test
public void attemptAuthenticationWhenAuthorizationRequestIsNullThenAuthorizationResponseNotCreated() throws Exception {
OAuth2LoginAuthenticationFilter filter = PowerMockito.spy(new OAuth2LoginAuthenticationFilter(
this.clientRegistrationRepository, this.authorizedClientService));
MockHttpServletRequest request = new MockHttpServletRequest();
request.addParameter(OAuth2ParameterNames.CODE, "code");
request.addParameter(OAuth2ParameterNames.STATE, "state");
MockHttpServletResponse response = new MockHttpServletResponse();
try {
filter.attemptAuthentication(request, response);
fail();
} catch (OAuth2AuthenticationException ex) {
verifyPrivate(filter, never()).invoke("convert", any(HttpServletRequest.class));
}
}
private void setUpAuthorizationRequest(HttpServletRequest request, HttpServletResponse response,
ClientRegistration registration) {
OAuth2AuthorizationRequest authorizationRequest = mock(OAuth2AuthorizationRequest.class);