/*
* ****************************************************************************
* Cloud Foundry
* Copyright (c) [2009-2016] Pivotal Software, Inc. All Rights Reserved.
*
* This product is licensed to you under the Apache License, Version 2.0 (the "License").
* You may not use this product except in compliance with the License.
*
* This product includes a number of subcomponents with
* separate copyright notices and license terms. Your use of these
* subcomponents is subject to the terms and conditions of the
* subcomponent's license, as noted in the LICENSE file.
* ****************************************************************************
*/
package org.cloudfoundry.identity.uaa.oauth;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.exceptions.RedirectMismatchException;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.endpoint.RedirectResolver;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Set;
import static java.util.Arrays.stream;
import static java.util.Collections.EMPTY_SET;
import static java.util.Optional.ofNullable;
import static org.cloudfoundry.identity.uaa.util.UaaUrlUtils.addFragmentComponent;
import static org.cloudfoundry.identity.uaa.util.UaaUrlUtils.addQueryParameter;
import static org.springframework.util.StringUtils.hasText;
public class AuthorizePromptNoneEntryPoint implements AuthenticationEntryPoint {
private static Log logger = LogFactory.getLog(AuthorizePromptNoneEntryPoint.class);
private final AuthenticationFailureHandler failureHandler;
private final ClientDetailsService clientDetailsService;
private final RedirectResolver redirectResolver;
public AuthorizePromptNoneEntryPoint(AuthenticationFailureHandler failureHandler,
ClientDetailsService clientDetailsService,
RedirectResolver redirectResolver) {
this.failureHandler = failureHandler;
this.clientDetailsService = clientDetailsService;
this.redirectResolver = redirectResolver;
}
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
String clientId = request.getParameter(OAuth2Utils.CLIENT_ID);
String redirectUri = request.getParameter(OAuth2Utils.REDIRECT_URI);
String[] responseTypes = ofNullable(request.getParameter(OAuth2Utils.RESPONSE_TYPE)).map(rt -> rt.split(" ")).orElse(new String[0]);
//client_id is a required parameter
if (!hasText(clientId)) {
logger.debug("[prompt=none] Missing client_id parameter");
response.setStatus(HttpStatus.BAD_REQUEST.value());
return;
}
ClientDetails client;
try {
client = clientDetailsService.loadClientByClientId(clientId);
} catch (ClientRegistrationException e) {
logger.debug("[prompt=none] Unable to look up client for client_id="+clientId, e);
response.setStatus(HttpStatus.BAD_REQUEST.value());
return;
}
Set<String> redirectUris = ofNullable(client.getRegisteredRedirectUri()).orElse(EMPTY_SET);
//if the client doesn't have a redirect uri set, the parameter is required.
if (redirectUris.size()==0 && !hasText(redirectUri)) {
logger.debug("[prompt=none] Missing redirect_uri");
response.setStatus(HttpStatus.BAD_REQUEST.value());
return;
}
String resolvedRedirect;
try {
resolvedRedirect = redirectResolver.resolveRedirect(redirectUri, client);
} catch (RedirectMismatchException rme) {
logger.debug("[prompt=none] Invalid redirect " + redirectUri + " did not match one of the registered values");
response.setStatus(HttpStatus.BAD_REQUEST.value());
return;
}
failureHandler.onAuthenticationFailure(request, response, authException);
boolean implicit = stream(responseTypes).noneMatch("code"::equalsIgnoreCase);
String redirectLocation = implicit ? addFragmentComponent(resolvedRedirect, "error=login_required") : addQueryParameter(resolvedRedirect, "error", "login_required");
response.sendRedirect(redirectLocation);
}
}