/**
* =============================================================================
*
* ORCID (R) Open Source
* http://orcid.org
*
* Copyright (c) 2012-2014 ORCID, Inc.
* Licensed under an MIT-Style License (MIT)
* http://orcid.org/open-source-license
*
* This copyright and license information (including a link to the full license)
* shall be included in its entirety in all copies or substantial portion of
* the software.
*
* =============================================================================
*/
package org.orcid.frontend.web.controllers;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.orcid.core.constants.OrcidOauth2Constants;
import org.orcid.core.oauth.OrcidRandomValueTokenServices;
import org.orcid.core.security.aop.LockedException;
import org.orcid.persistence.jpa.entities.ClientDetailsEntity;
import org.orcid.pojo.ajaxForm.OauthAuthorizeForm;
import org.orcid.pojo.ajaxForm.RequestInfoForm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.exceptions.InvalidScopeException;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.support.SimpleSessionStatus;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;
@Controller("oauthAuthorizeController")
public class OauthAuthorizeController extends OauthControllerBase {
private static final Logger LOGGER = LoggerFactory.getLogger(OauthAuthorizeController.class);
@Resource
protected OrcidRandomValueTokenServices tokenServices;
@RequestMapping(value = "/oauth/confirm_access", method = RequestMethod.GET)
public ModelAndView loginGetHandler(HttpServletRequest request, HttpServletResponse response, ModelAndView mav) throws UnsupportedEncodingException {
//Get and save the request information form
RequestInfoForm requestInfoForm = generateRequestInfoForm(request);
request.getSession().setAttribute(REQUEST_INFO_FORM, requestInfoForm);
Boolean justRegistered = (Boolean) request.getSession().getAttribute(OrcidOauth2Constants.JUST_REGISTERED);
if (justRegistered != null) {
request.getSession().removeAttribute(OrcidOauth2Constants.JUST_REGISTERED);
mav.addObject(OrcidOauth2Constants.JUST_REGISTERED, justRegistered);
}
boolean usePersistentTokens = false;
ClientDetailsEntity clientDetails = clientDetailsEntityCacheManager.retrieve(requestInfoForm.getClientId());
// validate client scopes
try {
authorizationEndpoint.validateScope(requestInfoForm.getScopesAsString(), clientDetails);
orcidOAuth2RequestValidator.validateClientIsEnabled(clientDetails);
} catch (InvalidScopeException | LockedException e) {
String redirectUriWithParams = requestInfoForm.getRedirectUrl();
if(e instanceof InvalidScopeException) {
redirectUriWithParams += "?error=invalid_scope&error_description=" + e.getMessage();
} else {
redirectUriWithParams += "?error=client_locked&error_description=" + e.getMessage();
}
RedirectView rView = new RedirectView(redirectUriWithParams);
ModelAndView error = new ModelAndView();
error.setView(rView);
return error;
}
// Check if the client has persistent tokens enabled
if (clientDetails.isPersistentTokensEnabled()) {
usePersistentTokens = true;
}
if (usePersistentTokens) {
boolean tokenLongLifeAlreadyExists = tokenServices.longLifeTokenExist(requestInfoForm.getClientId(), getEffectiveUserOrcid(), OAuth2Utils.parseParameterList(requestInfoForm.getScopesAsString()));
if (tokenLongLifeAlreadyExists) {
AuthorizationRequest authorizationRequest = (AuthorizationRequest) request.getSession().getAttribute("authorizationRequest");
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Map<String, String> requestParams = new HashMap<String, String>();
copyRequestParameters(request, requestParams);
Map<String, String> approvalParams = new HashMap<String, String>();
requestParams.put(OAuth2Utils.USER_OAUTH_APPROVAL, "true");
approvalParams.put(OAuth2Utils.USER_OAUTH_APPROVAL, "true");
requestParams.put(OrcidOauth2Constants.TOKEN_VERSION, OrcidOauth2Constants.PERSISTENT_TOKEN);
// Check if the client have persistent tokens enabled
requestParams.put(OrcidOauth2Constants.GRANT_PERSISTENT_TOKEN, "false");
if (hasPersistenTokensEnabled(requestInfoForm.getClientId())) {
// Then check if the client granted the persistent token
requestParams.put(OrcidOauth2Constants.GRANT_PERSISTENT_TOKEN, "true");
}
// Session status
SimpleSessionStatus status = new SimpleSessionStatus();
authorizationRequest.setRequestParameters(requestParams);
// Authorization request model
Map<String, Object> model = new HashMap<String, Object>();
model.put("authorizationRequest", authorizationRequest);
// Approve
RedirectView view = (RedirectView) authorizationEndpoint.approveOrDeny(approvalParams, model, status, auth);
ModelAndView authCodeView = new ModelAndView();
authCodeView.setView(view);
return authCodeView;
}
}
mav.addObject("hideUserVoiceScript", true);
mav.setViewName("confirm-oauth-access");
return mav;
}
@RequestMapping(value = { "/oauth/custom/authorize.json" }, method = RequestMethod.POST)
public @ResponseBody RequestInfoForm authorize(HttpServletRequest request, HttpServletResponse response, @RequestBody OauthAuthorizeForm form) {
RequestInfoForm requestInfoForm = (RequestInfoForm) request.getSession().getAttribute(REQUEST_INFO_FORM);
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
AuthorizationRequest authorizationRequest = (AuthorizationRequest) request.getSession().getAttribute("authorizationRequest");
Map<String, String> requestParams = new HashMap<String, String>(authorizationRequest.getRequestParameters());
Map<String, String> approvalParams = new HashMap<String, String>();
// Add the persistent token information
if (form.getApproved()) {
requestParams.put(OAuth2Utils.USER_OAUTH_APPROVAL, "true");
approvalParams.put(OAuth2Utils.USER_OAUTH_APPROVAL, "true");
} else {
requestParams.put(OAuth2Utils.USER_OAUTH_APPROVAL, "false");
approvalParams.put(OAuth2Utils.USER_OAUTH_APPROVAL, "false");
}
requestParams.put(OrcidOauth2Constants.TOKEN_VERSION, OrcidOauth2Constants.PERSISTENT_TOKEN);
// Check if the client have persistent tokens enabled
requestParams.put(OrcidOauth2Constants.GRANT_PERSISTENT_TOKEN, "false");
if (hasPersistenTokensEnabled(requestInfoForm.getClientId()))
// Then check if the client granted the persistent token
if (form.getPersistentTokenEnabled())
requestParams.put(OrcidOauth2Constants.GRANT_PERSISTENT_TOKEN, "true");
// strip /email/read-private scope if user has not consented
if (requestInfoForm.containsEmailReadPrivateScope() && !form.isEmailAccessAllowed()) {
requestInfoForm.removeEmailReadPrivateScope();
requestParams.put(OrcidOauth2Constants.SCOPE_PARAM, requestInfoForm.getScopesAsString());
}
// Session status
SimpleSessionStatus status = new SimpleSessionStatus();
authorizationRequest.setRequestParameters(requestParams);
// Authorization request model
Map<String, Object> model = new HashMap<String, Object>();
model.put("authorizationRequest", authorizationRequest);
// Approve
RedirectView view = (RedirectView) authorizationEndpoint.approveOrDeny(approvalParams, model, status, auth);
requestInfoForm.setRedirectUrl(view.getUrl());
if(new HttpSessionRequestCache().getRequest(request, response) != null)
new HttpSessionRequestCache().removeRequest(request, response);
LOGGER.info("OauthConfirmAccessController form.getRedirectUri being sent to client browser: " + requestInfoForm.getRedirectUrl());
return requestInfoForm;
}
/**
* Copies all request parameters into the provided params map
*
* @param request
* The server request
* @param params
* The map to copy the params
* */
private void copyRequestParameters(HttpServletRequest request, Map<String, String> params) {
if (request != null && request.getParameterMap() != null) {
Map<String, String[]> savedParams = request.getParameterMap();
copy(savedParams, params);
}
}
}