|
@@ -15,29 +15,21 @@
|
|
|
*/
|
|
|
package org.springframework.security.oauth2.server.authorization.web;
|
|
|
|
|
|
-import java.io.IOException;
|
|
|
-import java.util.stream.Stream;
|
|
|
-
|
|
|
-import javax.servlet.FilterChain;
|
|
|
-import javax.servlet.ServletException;
|
|
|
-import javax.servlet.http.HttpServletRequest;
|
|
|
-import javax.servlet.http.HttpServletResponse;
|
|
|
-
|
|
|
-import org.springframework.core.convert.converter.Converter;
|
|
|
+import org.springframework.http.HttpMethod;
|
|
|
import org.springframework.http.HttpStatus;
|
|
|
+import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
|
|
import org.springframework.security.core.Authentication;
|
|
|
import org.springframework.security.core.context.SecurityContextHolder;
|
|
|
import org.springframework.security.crypto.keygen.Base64StringKeyGenerator;
|
|
|
import org.springframework.security.crypto.keygen.StringKeyGenerator;
|
|
|
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
|
|
-import org.springframework.security.oauth2.core.OAuth2AuthorizationException;
|
|
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
|
|
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
|
|
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
|
|
+import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType;
|
|
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
|
|
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
|
|
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
|
|
-import org.springframework.security.oauth2.server.authorization.TokenType;
|
|
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
|
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
|
|
|
import org.springframework.security.web.DefaultRedirectStrategy;
|
|
@@ -45,201 +37,257 @@ import org.springframework.security.web.RedirectStrategy;
|
|
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
|
|
import org.springframework.security.web.util.matcher.RequestMatcher;
|
|
|
import org.springframework.util.Assert;
|
|
|
+import org.springframework.util.LinkedMultiValueMap;
|
|
|
+import org.springframework.util.MultiValueMap;
|
|
|
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;
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.Base64;
|
|
|
+import java.util.Collections;
|
|
|
+import java.util.HashSet;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
+
|
|
|
/**
|
|
|
+ * A {@code Filter} for the OAuth 2.0 Authorization Code Grant,
|
|
|
+ * which handles the processing of the OAuth 2.0 Authorization Request.
|
|
|
+ *
|
|
|
* @author Joe Grandja
|
|
|
* @author Paurav Munshi
|
|
|
* @since 0.0.1
|
|
|
+ * @see RegisteredClientRepository
|
|
|
+ * @see OAuth2AuthorizationService
|
|
|
+ * @see OAuth2Authorization
|
|
|
+ * @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.1">Section 4.1.1 Authorization Request</a>
|
|
|
*/
|
|
|
public class OAuth2AuthorizationEndpointFilter extends OncePerRequestFilter {
|
|
|
-
|
|
|
- private static final String DEFAULT_ENDPOINT = "/oauth2/authorize";
|
|
|
-
|
|
|
- private Converter<HttpServletRequest, OAuth2AuthorizationRequest> authorizationRequestConverter = new OAuth2AuthorizationRequestConverter();
|
|
|
- private RegisteredClientRepository registeredClientRepository;
|
|
|
- private OAuth2AuthorizationService authorizationService;
|
|
|
- private StringKeyGenerator codeGenerator = new Base64StringKeyGenerator();
|
|
|
- private RedirectStrategy authorizationRedirectStrategy = new DefaultRedirectStrategy();
|
|
|
- private RequestMatcher authorizationEndpointMatcher = new AntPathRequestMatcher(DEFAULT_ENDPOINT);
|
|
|
-
|
|
|
+ /**
|
|
|
+ * The default endpoint {@code URI} for authorization requests.
|
|
|
+ */
|
|
|
+ public static final String DEFAULT_AUTHORIZATION_ENDPOINT_URI = "/oauth2/authorize";
|
|
|
+
|
|
|
+ private final RegisteredClientRepository registeredClientRepository;
|
|
|
+ private final OAuth2AuthorizationService authorizationService;
|
|
|
+ private final RequestMatcher authorizationEndpointMatcher;
|
|
|
+ private final StringKeyGenerator codeGenerator = new Base64StringKeyGenerator(Base64.getUrlEncoder());
|
|
|
+ private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Constructs an {@code OAuth2AuthorizationEndpointFilter} using the provided parameters.
|
|
|
+ *
|
|
|
+ * @param registeredClientRepository the repository of registered clients
|
|
|
+ * @param authorizationService the authorization service
|
|
|
+ */
|
|
|
public OAuth2AuthorizationEndpointFilter(RegisteredClientRepository registeredClientRepository,
|
|
|
OAuth2AuthorizationService authorizationService) {
|
|
|
- Assert.notNull(registeredClientRepository, "registeredClientRepository cannot be null.");
|
|
|
- Assert.notNull(authorizationService, "authorizationService cannot be null.");
|
|
|
- this.registeredClientRepository = registeredClientRepository;
|
|
|
- this.authorizationService = authorizationService;
|
|
|
- }
|
|
|
-
|
|
|
- public final void setAuthorizationRequestConverter(
|
|
|
- Converter<HttpServletRequest, OAuth2AuthorizationRequest> authorizationRequestConverter) {
|
|
|
- Assert.notNull(authorizationRequestConverter, "authorizationRequestConverter cannot be set to null");
|
|
|
- this.authorizationRequestConverter = authorizationRequestConverter;
|
|
|
- }
|
|
|
-
|
|
|
- public final void setCodeGenerator(StringKeyGenerator codeGenerator) {
|
|
|
- Assert.notNull(codeGenerator, "codeGenerator cannot be set to null");
|
|
|
- this.codeGenerator = codeGenerator;
|
|
|
- }
|
|
|
-
|
|
|
- public final void setAuthorizationRedirectStrategy(RedirectStrategy authorizationRedirectStrategy) {
|
|
|
- Assert.notNull(authorizationRedirectStrategy, "authorizationRedirectStrategy cannot be set to null");
|
|
|
- this.authorizationRedirectStrategy = authorizationRedirectStrategy;
|
|
|
+ this(registeredClientRepository, authorizationService, DEFAULT_AUTHORIZATION_ENDPOINT_URI);
|
|
|
}
|
|
|
|
|
|
- public final void setAuthorizationEndpointMatcher(RequestMatcher authorizationEndpointMatcher) {
|
|
|
- Assert.notNull(authorizationEndpointMatcher, "authorizationEndpointMatcher cannot be set to null");
|
|
|
- this.authorizationEndpointMatcher = authorizationEndpointMatcher;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
|
|
|
- boolean pathMatch = this.authorizationEndpointMatcher.matches(request);
|
|
|
- String responseType = request.getParameter(OAuth2ParameterNames.RESPONSE_TYPE);
|
|
|
- boolean responseTypeMatch = OAuth2ParameterNames.CODE.equals(responseType);
|
|
|
- if (pathMatch && responseTypeMatch) {
|
|
|
- return false;
|
|
|
- }else {
|
|
|
- return true;
|
|
|
- }
|
|
|
+ /**
|
|
|
+ * Constructs an {@code OAuth2AuthorizationEndpointFilter} using the provided parameters.
|
|
|
+ *
|
|
|
+ * @param registeredClientRepository the repository of registered clients
|
|
|
+ * @param authorizationService the authorization service
|
|
|
+ * @param authorizationEndpointUri the endpoint {@code URI} for authorization requests
|
|
|
+ */
|
|
|
+ public OAuth2AuthorizationEndpointFilter(RegisteredClientRepository registeredClientRepository,
|
|
|
+ OAuth2AuthorizationService authorizationService, String authorizationEndpointUri) {
|
|
|
+ Assert.notNull(registeredClientRepository, "registeredClientRepository cannot be null");
|
|
|
+ Assert.notNull(authorizationService, "authorizationService cannot be null");
|
|
|
+ Assert.hasText(authorizationEndpointUri, "authorizationEndpointUri cannot be empty");
|
|
|
+ this.registeredClientRepository = registeredClientRepository;
|
|
|
+ this.authorizationService = authorizationService;
|
|
|
+ this.authorizationEndpointMatcher = new AntPathRequestMatcher(
|
|
|
+ authorizationEndpointUri, HttpMethod.GET.name());
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- protected void doFilterInternal(HttpServletRequest request,
|
|
|
- HttpServletResponse response, FilterChain filterChain)
|
|
|
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
|
|
throws ServletException, IOException {
|
|
|
|
|
|
- RegisteredClient client = null;
|
|
|
- OAuth2AuthorizationRequest authorizationRequest = null;
|
|
|
- OAuth2Authorization authorization = null;
|
|
|
-
|
|
|
- try {
|
|
|
- checkUserAuthenticated();
|
|
|
- Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
|
|
- client = fetchRegisteredClient(request);
|
|
|
-
|
|
|
- authorizationRequest = this.authorizationRequestConverter.convert(request);
|
|
|
- validateAuthorizationRequest(authorizationRequest, client);
|
|
|
-
|
|
|
- String code = this.codeGenerator.generateKey();
|
|
|
- authorization = buildOAuth2Authorization(auth, client, authorizationRequest, code);
|
|
|
- this.authorizationService.save(authorization);
|
|
|
+ if (!this.authorizationEndpointMatcher.matches(request) || !isPrincipalAuthenticated()) {
|
|
|
+ filterChain.doFilter(request, response);
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- String redirectUri = getRedirectUri(authorizationRequest, client);
|
|
|
- sendCodeOnSuccess(request, response, authorizationRequest, redirectUri, code);
|
|
|
+// TODO
|
|
|
+// The authorization server validates the request to ensure that all
|
|
|
+// required parameters are present and valid. If the request is valid,
|
|
|
+// the authorization server authenticates the resource owner and obtains
|
|
|
+// an authorization decision (by asking the resource owner or by
|
|
|
+// establishing approval via other means).
|
|
|
+
|
|
|
+ MultiValueMap<String, String> parameters = getParameters(request);
|
|
|
+ String stateParameter = parameters.getFirst(OAuth2ParameterNames.STATE);
|
|
|
+
|
|
|
+ // client_id (REQUIRED)
|
|
|
+ String clientId = parameters.getFirst(OAuth2ParameterNames.CLIENT_ID);
|
|
|
+ if (!StringUtils.hasText(clientId) ||
|
|
|
+ parameters.get(OAuth2ParameterNames.CLIENT_ID).size() != 1) {
|
|
|
+ OAuth2Error error = createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.CLIENT_ID);
|
|
|
+ sendErrorResponse(request, response, error, stateParameter, null); // when redirectUri is null then don't redirect
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ RegisteredClient registeredClient = this.registeredClientRepository.findByClientId(clientId);
|
|
|
+ if (registeredClient == null) {
|
|
|
+ OAuth2Error error = createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.CLIENT_ID);
|
|
|
+ sendErrorResponse(request, response, error, stateParameter, null); // when redirectUri is null then don't redirect
|
|
|
+ return;
|
|
|
+ } else if (!registeredClient.getAuthorizationGrantTypes().contains(AuthorizationGrantType.AUTHORIZATION_CODE)) {
|
|
|
+ OAuth2Error error = createError(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT, OAuth2ParameterNames.CLIENT_ID);
|
|
|
+ sendErrorResponse(request, response, error, stateParameter, null); // when redirectUri is null then don't redirect
|
|
|
+ return;
|
|
|
}
|
|
|
- catch(OAuth2AuthorizationException authorizationException) {
|
|
|
- OAuth2Error authorizationError = authorizationException.getError();
|
|
|
|
|
|
- if (authorizationError.getErrorCode().equals(OAuth2ErrorCodes.INVALID_REQUEST)
|
|
|
- || authorizationError.getErrorCode().equals(OAuth2ErrorCodes.ACCESS_DENIED)) {
|
|
|
- sendErrorInResponse(response, authorizationError);
|
|
|
- }
|
|
|
- else if (authorizationError.getErrorCode().equals(OAuth2ErrorCodes.UNSUPPORTED_RESPONSE_TYPE)
|
|
|
- || authorizationError.getErrorCode().equals(OAuth2ErrorCodes.UNAUTHORIZED_CLIENT)) {
|
|
|
- String redirectUri = getRedirectUri(authorizationRequest, client);
|
|
|
- sendErrorInRedirect(request, response, authorizationRequest, authorizationError, redirectUri);
|
|
|
- }
|
|
|
- else {
|
|
|
- throw new ServletException(authorizationException);
|
|
|
+ // redirect_uri (OPTIONAL)
|
|
|
+ String redirectUriParameter = parameters.getFirst(OAuth2ParameterNames.REDIRECT_URI);
|
|
|
+ if (StringUtils.hasText(redirectUriParameter)) {
|
|
|
+ if (!registeredClient.getRedirectUris().contains(redirectUriParameter) ||
|
|
|
+ parameters.get(OAuth2ParameterNames.REDIRECT_URI).size() != 1) {
|
|
|
+ OAuth2Error error = createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.REDIRECT_URI);
|
|
|
+ sendErrorResponse(request, response, error, stateParameter, null); // when redirectUri is null then don't redirect
|
|
|
+ return;
|
|
|
}
|
|
|
+ } else if (registeredClient.getRedirectUris().size() != 1) {
|
|
|
+ OAuth2Error error = createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.REDIRECT_URI);
|
|
|
+ sendErrorResponse(request, response, error, stateParameter, null); // when redirectUri is null then don't redirect
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
- }
|
|
|
-
|
|
|
- private void checkUserAuthenticated() {
|
|
|
- Authentication currentAuth = SecurityContextHolder.getContext().getAuthentication();
|
|
|
- if (currentAuth==null || !currentAuth.isAuthenticated()) {
|
|
|
- throw new OAuth2AuthorizationException(new OAuth2Error(OAuth2ErrorCodes.ACCESS_DENIED));
|
|
|
+ String redirectUri = StringUtils.hasText(redirectUriParameter) ?
|
|
|
+ redirectUriParameter : registeredClient.getRedirectUris().iterator().next();
|
|
|
+
|
|
|
+ // response_type (REQUIRED)
|
|
|
+ String responseType = parameters.getFirst(OAuth2ParameterNames.RESPONSE_TYPE);
|
|
|
+ if (!StringUtils.hasText(responseType) ||
|
|
|
+ parameters.get(OAuth2ParameterNames.RESPONSE_TYPE).size() != 1) {
|
|
|
+ OAuth2Error error = createError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.RESPONSE_TYPE);
|
|
|
+ sendErrorResponse(request, response, error, stateParameter, redirectUri);
|
|
|
+ return;
|
|
|
+ } else if (!responseType.equals(OAuth2AuthorizationResponseType.CODE.getValue())) {
|
|
|
+ OAuth2Error error = createError(OAuth2ErrorCodes.UNSUPPORTED_RESPONSE_TYPE, OAuth2ParameterNames.RESPONSE_TYPE);
|
|
|
+ sendErrorResponse(request, response, error, stateParameter, redirectUri);
|
|
|
+ return;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- private RegisteredClient fetchRegisteredClient(HttpServletRequest request) throws OAuth2AuthorizationException {
|
|
|
- String clientId = request.getParameter(OAuth2ParameterNames.CLIENT_ID);
|
|
|
- if (StringUtils.isEmpty(clientId)) {
|
|
|
- throw new OAuth2AuthorizationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST));
|
|
|
- }
|
|
|
+ Authentication principal = SecurityContextHolder.getContext().getAuthentication();
|
|
|
+ String code = this.codeGenerator.generateKey();
|
|
|
+ OAuth2AuthorizationRequest authorizationRequest = convertAuthorizationRequest(request);
|
|
|
|
|
|
- RegisteredClient client = this.registeredClientRepository.findByClientId(clientId);
|
|
|
- if (client==null) {
|
|
|
- throw new OAuth2AuthorizationException(new OAuth2Error(OAuth2ErrorCodes.ACCESS_DENIED));
|
|
|
- }
|
|
|
+ OAuth2Authorization authorization = OAuth2Authorization.withRegisteredClient(registeredClient)
|
|
|
+ .principalName(principal.getName())
|
|
|
+ .attribute(OAuth2ParameterNames.class.getName().concat(".CODE"), code)
|
|
|
+ .attribute(OAuth2AuthorizationRequest.class.getName(), authorizationRequest)
|
|
|
+ .build();
|
|
|
|
|
|
- boolean isAuthorizationGrantAllowed = Stream.of(client.getAuthorizationGrantTypes())
|
|
|
- .anyMatch(grantType -> grantType.contains(AuthorizationGrantType.AUTHORIZATION_CODE));
|
|
|
- if (!isAuthorizationGrantAllowed) {
|
|
|
- throw new OAuth2AuthorizationException(new OAuth2Error(OAuth2ErrorCodes.ACCESS_DENIED));
|
|
|
- }
|
|
|
+ this.authorizationService.save(authorization);
|
|
|
|
|
|
- return client;
|
|
|
+// TODO security checks for code parameter
|
|
|
+// The authorization code MUST expire shortly after it is issued to mitigate the risk of leaks.
|
|
|
+// A maximum authorization code lifetime of 10 minutes is RECOMMENDED.
|
|
|
+// The client MUST NOT use the authorization code more than once.
|
|
|
+// If an authorization code is used more than once, the authorization server MUST deny the request
|
|
|
+// and SHOULD revoke (when possible) all tokens previously issued based on that authorization code.
|
|
|
+// The authorization code is bound to the client identifier and redirection URI.
|
|
|
|
|
|
+ sendAuthorizationResponse(request, response, authorizationRequest, code, redirectUri);
|
|
|
}
|
|
|
|
|
|
- private OAuth2Authorization buildOAuth2Authorization(Authentication auth, RegisteredClient client,
|
|
|
- OAuth2AuthorizationRequest authorizationRequest, String code) {
|
|
|
- OAuth2Authorization authorization = OAuth2Authorization.withRegisteredClient(client)
|
|
|
- .principalName(auth.getPrincipal().toString())
|
|
|
- .attribute(TokenType.AUTHORIZATION_CODE.getValue(), code)
|
|
|
- .attributes(attirbutesMap -> attirbutesMap.putAll(authorizationRequest.getAttributes()))
|
|
|
- .build();
|
|
|
+ private void sendAuthorizationResponse(HttpServletRequest request, HttpServletResponse response,
|
|
|
+ OAuth2AuthorizationRequest authorizationRequest, String code, String redirectUri) throws IOException {
|
|
|
|
|
|
- return authorization;
|
|
|
+ UriComponentsBuilder uriBuilder = UriComponentsBuilder
|
|
|
+ .fromUriString(redirectUri)
|
|
|
+ .queryParam(OAuth2ParameterNames.CODE, code);
|
|
|
+ if (StringUtils.hasText(authorizationRequest.getState())) {
|
|
|
+ uriBuilder.queryParam(OAuth2ParameterNames.STATE, authorizationRequest.getState());
|
|
|
+ }
|
|
|
+ this.redirectStrategy.sendRedirect(request, response, uriBuilder.toUriString());
|
|
|
}
|
|
|
|
|
|
+ private void sendErrorResponse(HttpServletRequest request, HttpServletResponse response,
|
|
|
+ OAuth2Error error, String state, String redirectUri) throws IOException {
|
|
|
|
|
|
- private void validateAuthorizationRequest(OAuth2AuthorizationRequest authorizationRequest, RegisteredClient client) {
|
|
|
- String redirectUri = authorizationRequest.getRedirectUri();
|
|
|
- if (StringUtils.isEmpty(redirectUri) && client.getRedirectUris().size() > 1) {
|
|
|
- throw new OAuth2AuthorizationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST));
|
|
|
+ if (redirectUri == null) {
|
|
|
+ // TODO Send default html error response
|
|
|
+ response.sendError(HttpStatus.BAD_REQUEST.value(), error.toString());
|
|
|
+ return;
|
|
|
}
|
|
|
- if (!StringUtils.isEmpty(redirectUri) && !client.getRedirectUris().contains(redirectUri)) {
|
|
|
- throw new OAuth2AuthorizationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST));
|
|
|
+
|
|
|
+ UriComponentsBuilder uriBuilder = UriComponentsBuilder
|
|
|
+ .fromUriString(redirectUri)
|
|
|
+ .queryParam(OAuth2ParameterNames.ERROR, error.getErrorCode());
|
|
|
+ if (StringUtils.hasText(error.getDescription())) {
|
|
|
+ uriBuilder.queryParam(OAuth2ParameterNames.ERROR_DESCRIPTION, error.getDescription());
|
|
|
}
|
|
|
+ if (StringUtils.hasText(error.getUri())) {
|
|
|
+ uriBuilder.queryParam(OAuth2ParameterNames.ERROR_URI, error.getUri());
|
|
|
+ }
|
|
|
+ if (StringUtils.hasText(state)) {
|
|
|
+ uriBuilder.queryParam(OAuth2ParameterNames.STATE, state);
|
|
|
+ }
|
|
|
+ this.redirectStrategy.sendRedirect(request, response, uriBuilder.toUriString());
|
|
|
}
|
|
|
|
|
|
- private String getRedirectUri(OAuth2AuthorizationRequest authorizationRequest, RegisteredClient client) {
|
|
|
- return !StringUtils.isEmpty(authorizationRequest.getRedirectUri())
|
|
|
- ? authorizationRequest.getRedirectUri()
|
|
|
- : client.getRedirectUris().stream().findFirst().get();
|
|
|
+ private static boolean isPrincipalAuthenticated() {
|
|
|
+ return isPrincipalAuthenticated(SecurityContextHolder.getContext().getAuthentication());
|
|
|
}
|
|
|
|
|
|
- private void sendCodeOnSuccess(HttpServletRequest request, HttpServletResponse response,
|
|
|
- OAuth2AuthorizationRequest authorizationRequest, String redirectUri, String code) throws IOException {
|
|
|
- UriComponentsBuilder redirectUriBuilder = UriComponentsBuilder.fromUriString(redirectUri)
|
|
|
- .queryParam(OAuth2ParameterNames.CODE, code);
|
|
|
- if (!StringUtils.isEmpty(authorizationRequest.getState())) {
|
|
|
- redirectUriBuilder.queryParam(OAuth2ParameterNames.STATE, authorizationRequest.getState());
|
|
|
- }
|
|
|
-
|
|
|
- String finalRedirectUri = redirectUriBuilder.toUriString();
|
|
|
- this.authorizationRedirectStrategy.sendRedirect(request, response, finalRedirectUri);
|
|
|
+ private static boolean isPrincipalAuthenticated(Authentication principal) {
|
|
|
+ return principal != null &&
|
|
|
+ !AnonymousAuthenticationToken.class.isAssignableFrom(principal.getClass()) &&
|
|
|
+ principal.isAuthenticated();
|
|
|
}
|
|
|
|
|
|
- private void sendErrorInResponse(HttpServletResponse response, OAuth2Error authorizationError) throws IOException {
|
|
|
- int errorStatus = -1;
|
|
|
- String errorCode = authorizationError.getErrorCode();
|
|
|
- if (errorCode.equals(OAuth2ErrorCodes.ACCESS_DENIED)) {
|
|
|
- errorStatus=HttpStatus.FORBIDDEN.value();
|
|
|
- }
|
|
|
- else {
|
|
|
- errorStatus=HttpStatus.INTERNAL_SERVER_ERROR.value();
|
|
|
- }
|
|
|
- response.sendError(errorStatus, authorizationError.getErrorCode());
|
|
|
+ private static OAuth2Error createError(String errorCode, String parameterName) {
|
|
|
+ return new OAuth2Error(errorCode, "OAuth 2.0 Parameter: " + parameterName,
|
|
|
+ "https://tools.ietf.org/html/rfc6749#section-4.1.2.1");
|
|
|
}
|
|
|
|
|
|
- private void sendErrorInRedirect(HttpServletRequest request, HttpServletResponse response,
|
|
|
- OAuth2AuthorizationRequest authorizationRequest, OAuth2Error authorizationError,
|
|
|
- String redirectUri) throws IOException {
|
|
|
- UriComponentsBuilder redirectUriBuilder = UriComponentsBuilder.fromUriString(redirectUri)
|
|
|
- .queryParam(OAuth2ParameterNames.ERROR, authorizationError.getErrorCode());
|
|
|
+ private static OAuth2AuthorizationRequest convertAuthorizationRequest(HttpServletRequest request) {
|
|
|
+ MultiValueMap<String, String> parameters = getParameters(request);
|
|
|
|
|
|
- if (!StringUtils.isEmpty(authorizationRequest.getState())) {
|
|
|
- redirectUriBuilder.queryParam(OAuth2ParameterNames.STATE, authorizationRequest.getState());
|
|
|
+ Set<String> scopes = Collections.emptySet();
|
|
|
+ if (parameters.containsKey(OAuth2ParameterNames.SCOPE)) {
|
|
|
+ String scope = parameters.getFirst(OAuth2ParameterNames.SCOPE);
|
|
|
+ scopes = new HashSet<>(Arrays.asList(StringUtils.delimitedListToStringArray(scope, " ")));
|
|
|
}
|
|
|
|
|
|
- String finalRedirectURI = redirectUriBuilder.toUriString();
|
|
|
- this.authorizationRedirectStrategy.sendRedirect(request, response, finalRedirectURI);
|
|
|
+ return OAuth2AuthorizationRequest.authorizationCode()
|
|
|
+ .authorizationUri(request.getRequestURL().toString())
|
|
|
+ .clientId(parameters.getFirst(OAuth2ParameterNames.CLIENT_ID))
|
|
|
+ .redirectUri(parameters.getFirst(OAuth2ParameterNames.REDIRECT_URI))
|
|
|
+ .scopes(scopes)
|
|
|
+ .state(parameters.getFirst(OAuth2ParameterNames.STATE))
|
|
|
+ .additionalParameters(additionalParameters ->
|
|
|
+ parameters.entrySet().stream()
|
|
|
+ .filter(e -> !e.getKey().equals(OAuth2ParameterNames.RESPONSE_TYPE) &&
|
|
|
+ !e.getKey().equals(OAuth2ParameterNames.CLIENT_ID) &&
|
|
|
+ !e.getKey().equals(OAuth2ParameterNames.REDIRECT_URI) &&
|
|
|
+ !e.getKey().equals(OAuth2ParameterNames.SCOPE) &&
|
|
|
+ !e.getKey().equals(OAuth2ParameterNames.STATE))
|
|
|
+ .forEach(e -> additionalParameters.put(e.getKey(), e.getValue().get(0))))
|
|
|
+ .build();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static MultiValueMap<String, String> getParameters(HttpServletRequest request) {
|
|
|
+ Map<String, String[]> parameterMap = request.getParameterMap();
|
|
|
+ MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>(parameterMap.size());
|
|
|
+ parameterMap.forEach((key, values) -> {
|
|
|
+ if (values.length > 0) {
|
|
|
+ for (String value : values) {
|
|
|
+ parameters.add(key, value);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return parameters;
|
|
|
}
|
|
|
}
|