Java tutorial
/** * ============================================================================= * * 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.net.URLDecoder; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.ws.rs.core.Response; import org.apache.commons.lang.StringUtils; import org.orcid.core.constants.OrcidOauth2Constants; import org.orcid.core.manager.ClientDetailsEntityCacheManager; import org.orcid.core.manager.EncryptionManager; import org.orcid.core.manager.LoadOptions; import org.orcid.core.manager.OrcidProfileManager; import org.orcid.core.manager.ProfileEntityCacheManager; import org.orcid.core.oauth.OrcidRandomValueTokenServices; import org.orcid.core.oauth.service.OrcidAuthorizationEndpoint; import org.orcid.core.oauth.service.OrcidOAuth2RequestValidator; import org.orcid.core.security.aop.LockedException; import org.orcid.core.utils.JsonUtils; import org.orcid.jaxb.model.clientgroup.ClientType; import org.orcid.jaxb.model.message.CreationMethod; import org.orcid.jaxb.model.message.ErrorDesc; import org.orcid.jaxb.model.message.OrcidMessage; import org.orcid.jaxb.model.message.OrcidProfile; import org.orcid.jaxb.model.message.ScopePathType; import org.orcid.persistence.jpa.entities.ClientDetailsEntity; import org.orcid.persistence.jpa.entities.ProfileEntity; import org.orcid.pojo.ajaxForm.OauthAuthorizeForm; import org.orcid.pojo.ajaxForm.OauthForm; import org.orcid.pojo.ajaxForm.OauthRegistrationForm; import org.orcid.pojo.ajaxForm.PojoUtil; import org.orcid.pojo.ajaxForm.Text; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.oauth2.common.exceptions.InvalidRequestException; import org.springframework.security.oauth2.common.exceptions.InvalidScopeException; import org.springframework.security.oauth2.common.exceptions.RedirectMismatchException; import org.springframework.security.oauth2.common.util.OAuth2Utils; import org.springframework.security.oauth2.provider.AuthorizationRequest; import org.springframework.security.web.authentication.WebAuthenticationDetails; import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.SavedRequest; 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.RequestParam; 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; import com.orcid.api.common.server.delegator.OrcidClientCredentialEndPointDelegator; @Controller("oauthConfirmAccessController") @RequestMapping(value = "/oauth", method = RequestMethod.GET) public class OauthConfirmAccessController extends BaseController { private static final Logger LOGGER = LoggerFactory.getLogger(OauthConfirmAccessController.class); private static String PUBLIC_MEMBER_NAME = "PubApp"; private Pattern clientIdPattern = Pattern.compile("client_id=([^&]*)"); private Pattern orcidPattern = Pattern.compile("(&|\\?)orcid=([^&]*)"); private Pattern scopesPattern = Pattern.compile("scope=([^&]*)"); private Pattern redirectUriPattern = Pattern.compile("redirect_uri=([^&]*)"); private Pattern responseTypePattern = Pattern.compile("response_type=([^&]*)"); @Resource private OrcidProfileManager orcidProfileManager; @Resource private AuthenticationManager authenticationManager; @Resource private OrcidAuthorizationEndpoint authorizationEndpoint; @Resource private RegistrationController registrationController; @Resource private OrcidRandomValueTokenServices tokenServices; @Resource private OrcidClientCredentialEndPointDelegator orcidClientCredentialEndPointDelegator; @Resource(name = "profileEntityCacheManager") ProfileEntityCacheManager profileEntityCacheManager; @Resource private ClientDetailsEntityCacheManager clientDetailsEntityCacheManager; @Resource private EncryptionManager encryptionManager; @Resource private OrcidOAuth2RequestValidator orcidOAuth2RequestValidator; private static String REDIRECT_URI_ERROR = "/oauth/error/redirect-uri-mismatch?client_id={0}"; @RequestMapping(value = "/token", method = RequestMethod.POST) public @ResponseBody Object obtainOauth2TokenPost(HttpServletRequest request) { String clientId = request.getParameter("client_id"); String clientSecret = request.getParameter("client_secret"); String code = request.getParameter("code"); String state = request.getParameter("state"); String redirectUri = request.getParameter("redirect_uri"); String resourceId = request.getParameter("resource_id"); String refreshToken = request.getParameter("refresh_token"); String scopeList = request.getParameter("scope"); String grantType = request.getParameter("grant_type"); Set<String> scopes = new HashSet<String>(); if (StringUtils.isNotEmpty(scopeList)) { scopes = OAuth2Utils.parseParameterList(scopeList); } Response res = null; try { res = orcidClientCredentialEndPointDelegator.obtainOauth2Token(clientId, clientSecret, refreshToken, grantType, code, scopes, state, redirectUri, resourceId); } catch (Exception e) { return getLegacyOrcidEntity("OAuth2 problem", e); } String result = JsonUtils.convertToJsonString(res.getEntity()); return result; } private OrcidMessage getLegacyOrcidEntity(String prefix, Throwable e) { OrcidMessage entity = new OrcidMessage(); entity.setMessageVersion(OrcidMessage.DEFAULT_VERSION); entity.setErrorDesc(new ErrorDesc(prefix + " : " + e.getMessage())); return entity; } @RequestMapping(value = { "/signin", "/login" }, method = RequestMethod.GET) public ModelAndView loginGetHandler2(HttpServletRequest request, HttpServletResponse response, ModelAndView mav) { // find client name if available SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response); String clientName = ""; String clientId = ""; String clientGroupName = ""; String email = ""; String clientDescription = ""; String scope = ""; String redirectUri = ""; String responseType = ""; String orcid = null; boolean showLogin = false; // default to Reg boolean usePersistentTokens = false; if (savedRequest != null) { String url = savedRequest.getRedirectUrl(); if (url.toLowerCase().contains("show_login=true")) showLogin = true; //TODO: We should not load any info in the freemarker ModelAndViewObject, we should move all info we need to the forms Matcher matcher = clientIdPattern.matcher(url); if (matcher.find()) { clientId = matcher.group(1); if (clientId != null) { try { clientId = URLDecoder.decode(clientId, "UTF-8").trim(); } catch (UnsupportedEncodingException e) { } Matcher emailMatcher = RegistrationController.emailPattern.matcher(url); if (emailMatcher.find()) { String tempEmail = emailMatcher.group(1); try { tempEmail = URLDecoder.decode(tempEmail, "UTF-8").trim(); } catch (UnsupportedEncodingException e) { } if (orcidProfileManager.emailExists(tempEmail)) email = tempEmail; } Matcher orcidMatcher = orcidPattern.matcher(url); if (orcidMatcher.find()) { String tempOrcid = orcidMatcher.group(2); try { tempOrcid = URLDecoder.decode(tempOrcid, "UTF-8").trim(); } catch (UnsupportedEncodingException e) { } if (orcidProfileManager.exists(tempOrcid)) orcid = tempOrcid; } Matcher scopeMatcher = scopesPattern.matcher(url); if (scopeMatcher.find()) { scope = scopeMatcher.group(1); try { scope = URLDecoder.decode(scope, "UTF-8").trim(); scope = scope.replaceAll(" +", " "); } catch (UnsupportedEncodingException e) { } } Matcher redirectUriMatcher = redirectUriPattern.matcher(url); if (redirectUriMatcher.find()) { try { redirectUri = URLDecoder.decode(redirectUriMatcher.group(1), "UTF-8").trim(); } catch (UnsupportedEncodingException e) { } } Matcher responseTypeMatcher = responseTypePattern.matcher(url); if (responseTypeMatcher.find()) { responseType = responseTypeMatcher.group(1); try { responseType = URLDecoder.decode(responseType, "UTF-8").trim(); } catch (UnsupportedEncodingException e) { } } // Get client name ClientDetailsEntity clientDetails = clientDetailsEntityCacheManager.retrieve(clientId); // Check if the client has persistent tokens enabled if (clientDetails.isPersistentTokensEnabled()) usePersistentTokens = true; // validate client scopes try { authorizationEndpoint.validateScope(scope, clientDetails); orcidOAuth2RequestValidator.validateClientIsEnabled(clientDetails); } catch (InvalidScopeException ise) { String redirectUriWithParams = redirectUri; redirectUriWithParams += "?error=invalid_scope&error_description=" + ise.getMessage(); RedirectView rView = new RedirectView(redirectUriWithParams); ModelAndView error = new ModelAndView(); error.setView(rView); return error; } catch (LockedException le) { String redirectUriWithParams = redirectUri; redirectUriWithParams += "?error=client_locked&error_description=" + le.getMessage(); RedirectView rView = new RedirectView(redirectUriWithParams); ModelAndView error = new ModelAndView(); error.setView(rView); return error; } // If client details is ok, continue clientName = clientDetails.getClientName() == null ? "" : clientDetails.getClientName(); clientDescription = clientDetails.getClientDescription() == null ? "" : clientDetails.getClientDescription(); // If client type is null it means it is a public client if (clientDetails.getClientType() == null) { clientGroupName = PUBLIC_MEMBER_NAME; } else if (!PojoUtil.isEmpty(clientDetails.getGroupProfileId())) { ProfileEntity groupProfile = profileEntityCacheManager .retrieve(clientDetails.getGroupProfileId()); clientGroupName = groupProfile.getCreditName(); } // If the group name is empty, use the same as the client // name, since it should be a SSO user if (StringUtils.isBlank(clientGroupName)) { clientGroupName = clientName; } } } } mav.addObject("scopes", ScopePathType.getScopesFromSpaceSeparatedString(scope)); mav.addObject("scopesString", scope); mav.addObject("redirect_uri", redirectUri); mav.addObject("response_type", responseType); mav.addObject("client_name", clientName); mav.addObject("client_id", clientId); mav.addObject("client_group_name", clientGroupName); mav.addObject("client_description", clientDescription); mav.addObject("userId", orcid != null ? orcid : email); mav.addObject("hideUserVoiceScript", true); mav.addObject("usePersistentTokens", usePersistentTokens); mav.addObject("showLogin", String.valueOf(showLogin)); mav.setViewName("oauth_login"); return mav; } @RequestMapping(value = "/confirm_access", method = RequestMethod.GET) public ModelAndView loginGetHandler(HttpServletRequest request, HttpServletResponse response, ModelAndView mav, @RequestParam("client_id") String clientId, @RequestParam("scope") String scope, @RequestParam("redirect_uri") String redirectUri) { OrcidProfile profile = orcidProfileManager.retrieveOrcidProfile(getCurrentUserOrcid(), LoadOptions.BIO_ONLY); clientId = (clientId != null) ? clientId.trim() : clientId; scope = (scope != null) ? scope.trim().replaceAll(" +", " ") : scope; redirectUri = (redirectUri != null) ? redirectUri.trim() : redirectUri; Boolean justRegistered = (Boolean) request.getSession().getAttribute(OrcidOauth2Constants.JUST_REGISTERED); if (justRegistered != null) { request.getSession().removeAttribute(OrcidOauth2Constants.JUST_REGISTERED); mav.addObject(OrcidOauth2Constants.JUST_REGISTERED, justRegistered); } String clientName = ""; String clientDescription = ""; String clientGroupName = ""; String clientWebsite = ""; boolean usePersistentTokens = false; ClientDetailsEntity clientDetails = clientDetailsEntityCacheManager.retrieve(clientId); clientName = clientDetails.getClientName() == null ? "" : clientDetails.getClientName(); clientDescription = clientDetails.getClientDescription() == null ? "" : clientDetails.getClientDescription(); clientWebsite = clientDetails.getClientWebsite() == null ? "" : clientDetails.getClientWebsite(); // validate client scopes try { authorizationEndpoint.validateScope(scope, clientDetails); orcidOAuth2RequestValidator.validateClientIsEnabled(clientDetails); } catch (InvalidScopeException ise) { String redirectUriWithParams = redirectUri; redirectUriWithParams += "?error=invalid_scope&error_description=" + ise.getMessage(); RedirectView rView = new RedirectView(redirectUriWithParams); ModelAndView error = new ModelAndView(); error.setView(rView); return error; } catch (LockedException le) { String redirectUriWithParams = redirectUri; redirectUriWithParams += "?error=client_locked&error_description=" + le.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 tokenAlreadyExists = tokenServices.tokenAlreadyExists(clientId, getEffectiveUserOrcid(), OAuth2Utils.parseParameterList(scope)); if (tokenAlreadyExists) { 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(clientId)) { // 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; } } if (clientDetails.getClientType() == null) { clientGroupName = PUBLIC_MEMBER_NAME; } else if (!PojoUtil.isEmpty(clientDetails.getGroupProfileId())) { ProfileEntity groupProfile = profileEntityCacheManager.retrieve(clientDetails.getGroupProfileId()); clientGroupName = groupProfile.getCreditName(); } // If the group name is empty, use the same as the client name, since it // should be a SSO user if (StringUtils.isBlank(clientGroupName)) { clientGroupName = clientName; } mav.addObject("profile", profile); mav.addObject("client_name", clientName); mav.addObject("client_description", clientDescription); mav.addObject("client_group_name", clientGroupName); mav.addObject("client_website", clientWebsite); mav.addObject("scopes", ScopePathType.getScopesFromSpaceSeparatedString(scope)); mav.addObject("scopesString", scope); mav.addObject("hideUserVoiceScript", true); mav.addObject("usePersistentTokens", usePersistentTokens); mav.setViewName("confirm-oauth-access"); return mav; } //XXX @RequestMapping(value = "/custom/authorize/empty.json", method = RequestMethod.GET) public @ResponseBody OauthAuthorizeForm getEmptyAuthorizeForm(HttpServletRequest request, HttpServletResponse response) { OauthAuthorizeForm empty = new OauthAuthorizeForm(); Text emptyText = Text.valueOf(StringUtils.EMPTY); empty.setPassword(emptyText); empty.setRedirectUri(emptyText); empty.setResponseType(emptyText); empty.setScope(emptyText); empty.setUserName(emptyText); //Set required params empty empty.setStateParam(emptyText); empty.setClientId(emptyText); empty.setClientName(emptyText); empty.setMemberName(emptyText); //Set the state param and the client and member names fillOauthFormWithRequestInformation(empty, request, response); return empty; } @RequestMapping(value = { "/custom/signin.json", "/custom/login.json" }, method = RequestMethod.POST) public @ResponseBody OauthAuthorizeForm authenticateAndAuthorize(HttpServletRequest request, HttpServletResponse response, @RequestBody OauthAuthorizeForm form) { // Clean form errors form.setErrors(new ArrayList<String>()); boolean willBeRedirected = false; if (form.getApproved()) { // Validate name and password validateUserNameAndPassword(form); if (form.getErrors().isEmpty()) { try { // Authenticate user Authentication auth = authenticateUser(request, form); // Create authorization params SimpleSessionStatus status = new SimpleSessionStatus(); Map<String, Object> model = new HashMap<String, Object>(); Map<String, String> params = new HashMap<String, String>(); Map<String, String> approvalParams = new HashMap<String, String>(); // Set params setOauthParams(form, params, approvalParams, false); // Authorize try { authorizationEndpoint.authorize(model, params, status, auth); } catch (RedirectMismatchException rUriError) { String redirectUri = this.getBaseUri() + REDIRECT_URI_ERROR; // Set the client id redirectUri = redirectUri.replace("{0}", form.getClientId().getValue()); // Set the response type if needed if (!PojoUtil.isEmpty(form.getResponseType())) redirectUri += "&response_type=" + form.getResponseType().getValue(); // Set the redirect uri if (!PojoUtil.isEmpty(form.getRedirectUri())) redirectUri += "&redirect_uri=" + form.getRedirectUri().getValue(); // Set the scope param if (!PojoUtil.isEmpty(form.getScope())) redirectUri += "&scope=" + form.getScope().getValue(); // Copy the state param if present if (params != null && params.containsKey("state")) redirectUri += "&state=" + params.get("state"); form.setRedirectUri(Text.valueOf(redirectUri)); LOGGER.info( "OauthConfirmAccessController form.getRedirectUri being sent to client browser: " + form.getRedirectUri()); return form; } // Approve RedirectView view = (RedirectView) authorizationEndpoint.approveOrDeny(approvalParams, model, status, auth); form.setRedirectUri(Text.valueOf(view.getUrl())); willBeRedirected = true; } catch (AuthenticationException ae) { form.getErrors().add(getMessage("orcid.frontend.security.bad_credentials")); } } } else { String stateParam = null; if (!PojoUtil.isEmpty(form.getStateParam())) { stateParam = form.getStateParam().getValue(); } form.setRedirectUri(Text.valueOf(buildDenyRedirectUri(form.getRedirectUri().getValue(), stateParam))); willBeRedirected = true; } // If there was an authentication error, dont log since the user will // not be redirected yet if (willBeRedirected) { SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response); if (savedRequest != null) LOGGER.info("OauthConfirmAccessController original request: " + savedRequest.getRedirectUrl()); LOGGER.info("OauthConfirmAccessController form.getRedirectUri being sent to client browser: " + form.getRedirectUri()); } return form; } @RequestMapping(value = "/custom/register/empty.json", method = RequestMethod.GET) public @ResponseBody OauthRegistrationForm getRegister(HttpServletRequest request, HttpServletResponse response) { // Remove the session hash if needed if (request.getSession().getAttribute(RegistrationController.GRECAPTCHA_SESSION_ATTRIBUTE_NAME) != null) { request.getSession().removeAttribute(RegistrationController.GRECAPTCHA_SESSION_ATTRIBUTE_NAME); } OauthRegistrationForm empty = new OauthRegistrationForm( registrationController.getRegister(request, response)); // Creation type in oauth will always be member referred empty.setCreationType(Text.valueOf(CreationMethod.MEMBER_REFERRED.value())); Text emptyText = Text.valueOf(StringUtils.EMPTY); empty.setClientId(emptyText); empty.setPassword(emptyText); empty.setRedirectUri(emptyText); empty.setResponseType(emptyText); empty.setScope(emptyText); //Set the state param and the client and member names fillOauthFormWithRequestInformation(empty, request, response); return empty; } /** * Fill the for with the state param and the client and member names. * * @param form * @param request * @param response * */ private void fillOauthFormWithRequestInformation(OauthForm form, HttpServletRequest request, HttpServletResponse response) { Map<String, String[]> requestParams = new HashMap<String, String[]>(); SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response); //Get the params from the saved request if (savedRequest != null) { requestParams = savedRequest.getParameterMap(); } else { //If there are no saved request, get them from the session AuthorizationRequest authorizationRequest = (AuthorizationRequest) request.getSession() .getAttribute("authorizationRequest"); Map<String, String> authRequestParams = new HashMap<String, String>( authorizationRequest.getRequestParameters()); for (String param : authRequestParams.keySet()) { requestParams.put(param, new String[] { authRequestParams.get(param) }); } } if (requestParams == null || requestParams.isEmpty()) { throw new InvalidRequestException("Unable to find parameters"); } //Save state param if (requestParams.containsKey(OrcidOauth2Constants.STATE_PARAM)) { if (requestParams.get(OrcidOauth2Constants.STATE_PARAM).length > 0) form.setStateParam(Text.valueOf(requestParams.get(OrcidOauth2Constants.STATE_PARAM)[0])); } //Get and set client info if (!requestParams.containsKey(OrcidOauth2Constants.CLIENT_ID_PARAM)) { throw new InvalidRequestException("Empty client id"); } String clientId = requestParams.get(OrcidOauth2Constants.CLIENT_ID_PARAM)[0]; try { clientId = URLDecoder.decode(clientId, "UTF-8").trim(); } catch (UnsupportedEncodingException e) { throw new InvalidRequestException("Unable to parse client id: " + e); } ClientDetailsEntity clientDetails = clientDetailsEntityCacheManager.retrieve(clientId); try { orcidOAuth2RequestValidator.validateClientIsEnabled(clientDetails); } catch (LockedException le) { throw new InvalidRequestException("Client " + clientId + " is locked"); } String clientName = clientDetails.getClientName() == null ? "" : clientDetails.getClientName(); String memberName = null; // If it is the if (ClientType.PUBLIC_CLIENT.equals(clientDetails.getClientType())) { memberName = PUBLIC_MEMBER_NAME; } else { ProfileEntity groupProfile = profileEntityCacheManager.retrieve(clientDetails.getGroupProfileId()); memberName = groupProfile.getCreditName(); } form.setClientName(Text.valueOf(clientName)); form.setMemberName(Text.valueOf(memberName)); form.setClientId(Text.valueOf(clientId)); //If it is a new registration, set the referred by flag if (form instanceof OauthRegistrationForm) { ((OauthRegistrationForm) form).setReferredBy(Text.valueOf(clientId)); } } @RequestMapping(value = "/custom/register.json", method = RequestMethod.POST) public @ResponseBody OauthRegistrationForm checkRegisterForm(HttpServletRequest request, HttpServletResponse response, @RequestBody OauthRegistrationForm form) { form.setErrors(new ArrayList<String>()); if (form.getApproved()) { registrationController.validateRegistrationFields(request, form); registrationController.validateGrcaptcha(request, form); } else { SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response); String stateParam = null; if (savedRequest != null && savedRequest.getParameterMap() != null && savedRequest.getParameterValues("state") != null) { if (savedRequest.getParameterValues("state").length > 0) stateParam = savedRequest.getParameterValues("state")[0]; } form.setRedirectUri(Text.valueOf(buildDenyRedirectUri(form.getRedirectUri().getValue(), stateParam))); } return form; } @RequestMapping(value = "/custom/registerConfirm.json", method = RequestMethod.POST) public @ResponseBody OauthRegistrationForm registerAndAuthorize(HttpServletRequest request, HttpServletResponse response, @RequestBody OauthRegistrationForm form) { if (form.getApproved()) { boolean usedCaptcha = false; // If recatcha wasn't loaded do nothing. This is for countries that // block google. if (form.getGrecaptchaWidgetId().getValue() != null) { // If the captcha verified key is not in the session, redirect // to // the login page if (request.getSession() .getAttribute(RegistrationController.GRECAPTCHA_SESSION_ATTRIBUTE_NAME) == null || PojoUtil.isEmpty(form.getGrecaptcha()) || !encryptionManager.encryptForExternalUse(form.getGrecaptcha().getValue()) .equals(request.getSession() .getAttribute(RegistrationController.GRECAPTCHA_SESSION_ATTRIBUTE_NAME))) { String redirectUri = this.getBaseUri() + REDIRECT_URI_ERROR; // Set the client id redirectUri = redirectUri.replace("{0}", form.getClientId().getValue()); // Set the response type if needed if (!PojoUtil.isEmpty(form.getResponseType())) redirectUri += "&response_type=" + form.getResponseType().getValue(); // Set the redirect uri if (!PojoUtil.isEmpty(form.getRedirectUri())) redirectUri += "&redirect_uri=" + form.getRedirectUri().getValue(); // Set the scope param if (!PojoUtil.isEmpty(form.getScope())) redirectUri += "&scope=" + form.getScope().getValue(); // Copy the state param if present if (!PojoUtil.isEmpty(request.getParameter("state"))) redirectUri += "&state=" + request.getParameter("state"); form.setRedirectUri(Text.valueOf(redirectUri)); SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response); if (savedRequest != null) LOGGER.info( "OauthConfirmAccessController original request: " + savedRequest.getRedirectUrl()); LOGGER.info("OauthConfirmAccessController form.getRedirectUri being sent to client browser: " + form.getRedirectUri()); return form; } usedCaptcha = true; } // Remove the session hash if needed if (request.getSession() .getAttribute(RegistrationController.GRECAPTCHA_SESSION_ATTRIBUTE_NAME) != null) { request.getSession().removeAttribute(RegistrationController.GRECAPTCHA_SESSION_ATTRIBUTE_NAME); } // Check there are no errors registrationController.validateRegistrationFields(request, form); if (form.getErrors().isEmpty()) { // Register user registrationController.createMinimalRegistration(request, RegistrationController.toProfile(form, request), usedCaptcha); // Authenticate user String email = form.getEmail().getValue(); String password = form.getPassword().getValue(); Authentication auth = authenticateUser(request, email, password); // Create authorization params SimpleSessionStatus status = new SimpleSessionStatus(); Map<String, Object> model = new HashMap<String, Object>(); Map<String, String> params = new HashMap<String, String>(); Map<String, String> approvalParams = new HashMap<String, String>(); // Set params setOauthParams(form, params, approvalParams, true); // Authorize try { authorizationEndpoint.authorize(model, params, status, auth); } catch (RedirectMismatchException rUriError) { String redirectUri = this.getBaseUri() + REDIRECT_URI_ERROR; // Set the client id redirectUri = redirectUri.replace("{0}", form.getClientId().getValue()); // Set the response type if needed if (!PojoUtil.isEmpty(form.getResponseType())) redirectUri += "&response_type=" + form.getResponseType().getValue(); // Set the redirect uri if (!PojoUtil.isEmpty(form.getRedirectUri())) redirectUri += "&redirect_uri=" + form.getRedirectUri().getValue(); // Set the scope param if (!PojoUtil.isEmpty(form.getScope())) redirectUri += "&scope=" + form.getScope().getValue(); // Copy the state param if present if (params != null && params.containsKey("state")) redirectUri += "&state=" + params.get("state"); form.setRedirectUri(Text.valueOf(redirectUri)); LOGGER.info("OauthConfirmAccessController form.getRedirectUri being sent to client browser: " + form.getRedirectUri()); return form; } // Approve RedirectView view = (RedirectView) authorizationEndpoint.approveOrDeny(approvalParams, model, status, auth); form.setRedirectUri(Text.valueOf(view.getUrl())); } } else { form.setRedirectUri(Text.valueOf( buildDenyRedirectUri(form.getRedirectUri().getValue(), request.getParameter("state")))); } SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response); if (savedRequest != null) { if (savedRequest != null) LOGGER.info("OauthConfirmAccessController original request: " + savedRequest.getRedirectUrl()); LOGGER.info("OauthConfirmAccessController original request: " + savedRequest.getRedirectUrl()); } LOGGER.info("OauthConfirmAccessController form.getRedirectUri being sent to client browser: " + form.getRedirectUri()); return form; } /** * Set the needed params for the Oauth request * * @param savedRequest * @param form * @param params * @param approvalParams * @param justRegistred * */ private void setOauthParams(OauthForm form, Map<String, String> params, Map<String, String> approvalParams, boolean justRegistred) { // Then, put the custom authorization params // Token version params.put(OrcidOauth2Constants.TOKEN_VERSION, OrcidOauth2Constants.PERSISTENT_TOKEN); // Client ID params.put(OrcidOauth2Constants.CLIENT_ID_PARAM, form.getClientId().getValue()); // Redirect URI if (!PojoUtil.isEmpty(form.getRedirectUri())) { params.put(OrcidOauth2Constants.REDIRECT_URI_PARAM, form.getRedirectUri().getValue()); } else { params.put(OrcidOauth2Constants.REDIRECT_URI_PARAM, new String()); } // Scope if (!PojoUtil.isEmpty(form.getScope())) { params.put(OrcidOauth2Constants.SCOPE_PARAM, form.getScope().getValue()); } // Response type if (!PojoUtil.isEmpty(form.getResponseType())) { params.put(OrcidOauth2Constants.RESPONSE_TYPE_PARAM, form.getResponseType().getValue()); } // State param if (!PojoUtil.isEmpty(form.getStateParam())) { params.put(OrcidOauth2Constants.STATE_PARAM, form.getStateParam().getValue()); } // Approved if (justRegistred) { if (form.getApproved()) { params.put(OAuth2Utils.USER_OAUTH_APPROVAL, "true"); approvalParams.put(OAuth2Utils.USER_OAUTH_APPROVAL, "true"); } else { params.put(OAuth2Utils.USER_OAUTH_APPROVAL, "false"); approvalParams.put(OAuth2Utils.USER_OAUTH_APPROVAL, "false"); } } else { params.put(OAuth2Utils.USER_OAUTH_APPROVAL, "true"); approvalParams.put(OAuth2Utils.USER_OAUTH_APPROVAL, "true"); } // Set persistent tokens flag params.put(OrcidOauth2Constants.GRANT_PERSISTENT_TOKEN, "false"); if (hasPersistenTokensEnabled(form.getClientId().getValue())) { // Then check if the client granted the persistent token if (form.getPersistentTokenEnabled()) { params.put(OrcidOauth2Constants.GRANT_PERSISTENT_TOKEN, "true"); } } } @RequestMapping(value = { "/custom/authorize.json" }, method = RequestMethod.POST) public @ResponseBody OauthAuthorizeForm authorize(HttpServletRequest request, HttpServletResponse response, @RequestBody OauthAuthorizeForm 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(form.getClientId().getValue())) // Then check if the client granted the persistent token if (form.getPersistentTokenEnabled()) 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); form.setRedirectUri(Text.valueOf(view.getUrl())); SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response); if (savedRequest != null) LOGGER.info("OauthConfirmAccessController original request: " + savedRequest.getRedirectUrl()); LOGGER.info("OauthConfirmAccessController form.getRedirectUri being sent to client browser: " + form.getRedirectUri()); return form; } /** * Builds the redirect uri string to use when the user deny the request * * @param redirectUri * Redirect uri * @return the redirect uri string with the deny params * */ private String buildDenyRedirectUri(String redirectUri, String stateParam) { if (!PojoUtil.isEmpty(redirectUri)) { if (redirectUri.contains("?")) { redirectUri = redirectUri.concat("&error=access_denied&error_description=User denied access"); } else { redirectUri = redirectUri.concat("?error=access_denied&error_description=User denied access"); } } if (!PojoUtil.isEmpty(stateParam)) redirectUri += "&state=" + stateParam; return redirectUri; } /** * 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); } } private void copy(Map<String, String[]> savedParams, Map<String, String> params) { if (savedParams != null && !savedParams.isEmpty()) { for (String key : savedParams.keySet()) { String[] values = savedParams.get(key); if (values != null && values.length > 0) params.put(key, values[0]); } } } /***************************** * Authenticate user methods ****************************/ private Authentication authenticateUser(HttpServletRequest request, OauthAuthorizeForm form) throws AuthenticationException { UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken( form.getUserName().getValue(), form.getPassword().getValue()); token.setDetails(new WebAuthenticationDetails(request)); return authenticateUser(token); } private Authentication authenticateUser(HttpServletRequest request, String email, String password) { UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(email, password); token.setDetails(new WebAuthenticationDetails(request)); return authenticateUser(token); } private Authentication authenticateUser(UsernamePasswordAuthenticationToken token) { Authentication authentication = authenticationManager.authenticate(token); SecurityContextHolder.getContext().setAuthentication(authentication); return authentication; } /***************************** * Validators ****************************/ private void validateUserNameAndPassword(OauthAuthorizeForm form) { if (PojoUtil.isEmpty(form.getUserName()) || PojoUtil.isEmpty(form.getPassword())) { form.getErrors().add(getMessage("orcid.frontend.security.bad_credentials")); } } @RequestMapping(value = "/custom/register/validatePasswordConfirm.json", method = RequestMethod.POST) public @ResponseBody OauthRegistrationForm validatePasswordConfirm(@RequestBody OauthRegistrationForm reg) { registrationController.registerPasswordConfirmValidate(reg); return reg; } @RequestMapping(value = "/custom/register/validatePassword.json", method = RequestMethod.POST) public @ResponseBody OauthRegistrationForm validatePassword(@RequestBody OauthRegistrationForm reg) { registrationController.registerPasswordValidate(reg); return reg; } @RequestMapping(value = "/custom/register/validateTermsOfUse.json", method = RequestMethod.POST) public @ResponseBody OauthRegistrationForm validateTermsOfUse(@RequestBody OauthRegistrationForm reg) { registrationController.registerTermsOfUseValidate(reg); return reg; } @RequestMapping(value = "/custom/register/validateGivenNames.json", method = RequestMethod.POST) public @ResponseBody OauthRegistrationForm validateGivenName(@RequestBody OauthRegistrationForm reg) { registrationController.registerGivenNameValidate(reg); return reg; } @RequestMapping(value = "/custom/register/validateEmail.json", method = RequestMethod.POST) public @ResponseBody OauthRegistrationForm validateEmail(HttpServletRequest request, @RequestBody OauthRegistrationForm reg) { registrationController.regEmailValidate(request, reg, true, false); return reg; } @RequestMapping(value = "/custom/register/validateEmailConfirm.json", method = RequestMethod.POST) public @ResponseBody OauthRegistrationForm validateEmailConfirm(@RequestBody OauthRegistrationForm reg) { registrationController.regEmailConfirmValidate(reg); return reg; } /** * Checks if the client has the persistent tokens enabled * * @return true if the persistent tokens are enabled for that client * @throws IllegalArgumentException * */ private boolean hasPersistenTokensEnabled(String clientId) throws IllegalArgumentException { ClientDetailsEntity clientDetails = clientDetailsEntityCacheManager.retrieve(clientId); if (clientDetails == null) throw new IllegalArgumentException(getMessage("web.orcid.oauth_invalid_client.exception")); return clientDetails.isPersistentTokensEnabled(); } }