org.orcid.frontend.web.controllers.RegistrationController.java Source code

Java tutorial

Introduction

Here is the source code for org.orcid.frontend.web.controllers.RegistrationController.java

Source

/**
 * =============================================================================
 *
 * 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.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
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.validation.Valid;

import org.apache.commons.codec.binary.Base64;
import org.jasypt.exceptions.EncryptionOperationNotPossibleException;
import org.orcid.core.constants.DefaultPreferences;
import org.orcid.core.manager.EncryptionManager;
import org.orcid.core.manager.InternalSSOManager;
import org.orcid.core.manager.LoadOptions;
import org.orcid.core.manager.NotificationManager;
import org.orcid.core.manager.OrcidProfileManager;
import org.orcid.core.manager.OrcidSearchManager;
import org.orcid.core.manager.RegistrationManager;
import org.orcid.core.manager.RegistrationRoleManager;
import org.orcid.core.manager.SecurityQuestionManager;
import org.orcid.core.manager.impl.OrcidUrlManager;
import org.orcid.core.utils.PasswordResetToken;
import org.orcid.frontend.web.controllers.helper.SearchOrcidSolrCriteria;
import org.orcid.frontend.web.forms.ChangeSecurityQuestionForm;
import org.orcid.frontend.web.forms.EmailAddressForm;
import org.orcid.frontend.web.forms.OneTimeResetPasswordForm;
import org.orcid.frontend.web.forms.PasswordTypeAndConfirmForm;
import org.orcid.frontend.web.util.RecaptchaVerifier;
import org.orcid.jaxb.model.message.ActivitiesVisibilityDefault;
import org.orcid.jaxb.model.message.Claimed;
import org.orcid.jaxb.model.message.CompletionDate;
import org.orcid.jaxb.model.message.ContactDetails;
import org.orcid.jaxb.model.message.CreationMethod;
import org.orcid.jaxb.model.message.Email;
import org.orcid.jaxb.model.message.FamilyName;
import org.orcid.jaxb.model.message.GivenNames;
import org.orcid.jaxb.model.message.OrcidBio;
import org.orcid.jaxb.model.message.OrcidHistory;
import org.orcid.jaxb.model.message.OrcidIdentifier;
import org.orcid.jaxb.model.message.OrcidInternal;
import org.orcid.jaxb.model.message.OrcidMessage;
import org.orcid.jaxb.model.message.OrcidProfile;
import org.orcid.jaxb.model.message.OrcidSearchResult;
import org.orcid.jaxb.model.message.PersonalDetails;
import org.orcid.jaxb.model.message.Preferences;
import org.orcid.jaxb.model.message.ReferredBy;
import org.orcid.jaxb.model.message.SecurityQuestionId;
import org.orcid.jaxb.model.message.SendChangeNotifications;
import org.orcid.jaxb.model.message.SendEmailFrequency;
import org.orcid.jaxb.model.message.SendOrcidNews;
import org.orcid.jaxb.model.message.SubmissionDate;
import org.orcid.jaxb.model.message.Visibility;
import org.orcid.jaxb.model.notification.amended.AmendedSection;
import org.orcid.password.constants.OrcidPasswordConstants;
import org.orcid.persistence.dao.EmailDao;
import org.orcid.persistence.dao.ProfileDao;
import org.orcid.persistence.jpa.entities.EmailEntity;
import org.orcid.pojo.DupicateResearcher;
import org.orcid.pojo.Redirect;
import org.orcid.pojo.ajaxForm.Checkbox;
import org.orcid.pojo.ajaxForm.Claim;
import org.orcid.pojo.ajaxForm.PojoUtil;
import org.orcid.pojo.ajaxForm.Registration;
import org.orcid.pojo.ajaxForm.Text;
import org.orcid.utils.DateUtils;
import org.orcid.utils.OrcidRequestUtil;
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.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.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.MapBindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
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.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.support.RequestContextUtils;

/**
 * @author Will Simpson
 */
@Controller
public class RegistrationController extends BaseController {

    public static Pattern givenNamesPattern = Pattern.compile("given_names=([^&]*)");
    public static Pattern familyNamesPattern = Pattern.compile("family_names=([^&]*)");
    public static Pattern emailPattern = Pattern.compile("email=([^&]*)");

    private static final Logger LOGGER = LoggerFactory.getLogger(RegistrationController.class);

    final static Integer DUP_SEARCH_START = 0;

    final static Integer DUP_SEARCH_ROWS = 25;

    public final static String GRECAPTCHA_SESSION_ATTRIBUTE_NAME = "verified-recaptcha-hash";

    private static Random rand = new Random();

    @Resource
    private OrcidUrlManager orcidUrlManager;

    @Resource
    private RegistrationManager registrationManager;

    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private SecurityQuestionManager securityQuestionManager;

    @Resource
    private RegistrationRoleManager registrationRoleManager;

    @Resource
    private OrcidProfileManager orcidProfileManager;

    @Resource
    private OrcidSearchManager orcidSearchManager;

    @Resource
    private EncryptionManager encryptionManager;

    @Resource
    private NotificationManager notificationManager;

    @Resource
    private ProfileDao profileDao;

    @Resource
    private EmailDao emailDao;

    @Resource
    private RecaptchaVerifier recaptchaVerifier;

    @Resource
    private InternalSSOManager internalSSOManager;

    public void setEncryptionManager(EncryptionManager encryptionManager) {
        this.encryptionManager = encryptionManager;
    }

    public void setRegistrationManager(RegistrationManager registrationManager) {
        this.registrationManager = registrationManager;
    }

    public void setOrcidSearchManager(OrcidSearchManager orcidSearchManager) {
        this.orcidSearchManager = orcidSearchManager;
    }

    public OrcidSearchManager getOrcidSearchManager() {
        return orcidSearchManager;
    }

    public void setOrcidProfileManager(OrcidProfileManager orcidProfileManager) {
        this.orcidProfileManager = orcidProfileManager;
    }

    @ModelAttribute("securityQuestions")
    public Map<String, String> retrieveSecurityQuestionsAsMap() {
        Map<String, String> securityQuestions = securityQuestionManager
                .retrieveSecurityQuestionsAsInternationalizedMap();
        Map<String, String> securityQuestionsWithMessages = new LinkedHashMap<String, String>();

        for (String key : securityQuestions.keySet()) {
            securityQuestionsWithMessages.put(key, getMessage(securityQuestions.get(key)));
        }

        return securityQuestionsWithMessages;
    }

    @RequestMapping(value = "/register.json", method = RequestMethod.GET)
    public @ResponseBody Registration getRegister(HttpServletRequest request, HttpServletResponse response) {
        // Remove the session hash if needed
        if (request.getSession().getAttribute(GRECAPTCHA_SESSION_ATTRIBUTE_NAME) != null) {
            request.getSession().removeAttribute(GRECAPTCHA_SESSION_ATTRIBUTE_NAME);
        }
        Registration reg = new Registration();

        reg.getEmail().setRequired(true);

        reg.getEmailConfirm().setRequired(true);

        reg.getPassword();
        reg.getPasswordConfirm();
        reg.getEmail();

        reg.getFamilyNames().setRequired(false);

        reg.getGivenNames().setRequired(true);

        reg.getSendChangeNotifications().setValue(true);
        reg.getSendOrcidNews().setValue(true);
        reg.getSendMemberUpdateRequests().setValue(true);
        reg.getSendEmailFrequencyDays().setValue(SendEmailFrequency.WEEKLY.value());
        reg.getTermsOfUse().setValue(false);
        setError(reg.getTermsOfUse(), "AssertTrue.registrationForm.acceptTermsAndConditions");

        SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response);
        if (savedRequest != null) {
            String url = savedRequest.getRedirectUrl();

            Matcher emailMatcher = emailPattern.matcher(url);
            if (emailMatcher.find()) {
                String tempEmail = emailMatcher.group(1);
                try {
                    tempEmail = URLDecoder.decode(tempEmail, "UTF-8");
                } catch (UnsupportedEncodingException e) {
                }
                if (!orcidProfileManager.emailExists(tempEmail)) {
                    reg.getEmail().setValue(tempEmail);
                }
            }

            Matcher givenNamesMatcher = givenNamesPattern.matcher(url);
            if (givenNamesMatcher.find())
                try {
                    reg.getGivenNames().setValue(URLDecoder.decode(givenNamesMatcher.group(1), "UTF-8"));
                } catch (UnsupportedEncodingException e) {
                    LOGGER.info("error parsing users family name from oauth url", e);
                }

            Matcher familyNamesMatcher = familyNamesPattern.matcher(url);
            if (familyNamesMatcher.find())
                try {
                    reg.getFamilyNames().setValue(URLDecoder.decode(familyNamesMatcher.group(1), "UTF-8"));
                } catch (UnsupportedEncodingException e) {
                    LOGGER.info("error parsing users family name from oauth url", e);
                }
        }
        long numVal = generateRandomNumForValidation();
        reg.setValNumServer(numVal);
        reg.setValNumClient(0);
        return reg;
    }

    public long generateRandomNumForValidation() {
        int numCheck = rand.nextInt(1000000);
        if (numCheck % 2 != 0)
            numCheck += 1;
        return numCheck;
    }

    public static OrcidProfile toProfile(Registration reg, HttpServletRequest request) {
        OrcidProfile profile = new OrcidProfile();
        OrcidBio bio = new OrcidBio();

        ContactDetails contactDetails = new ContactDetails();
        contactDetails.addOrReplacePrimaryEmail(new org.orcid.jaxb.model.message.Email(reg.getEmail().getValue()));
        Preferences preferences = new Preferences();
        preferences.setSendChangeNotifications(
                new SendChangeNotifications(reg.getSendChangeNotifications().getValue()));
        preferences.setSendOrcidNews(new SendOrcidNews(reg.getSendOrcidNews().getValue()));
        preferences.setActivitiesVisibilityDefault(new ActivitiesVisibilityDefault(
                Visibility.fromValue(reg.getActivitiesVisibilityDefault().getVisibility().value())));
        preferences.setNotificationsEnabled(DefaultPreferences.NOTIFICATIONS_ENABLED);
        if (PojoUtil.isEmpty(reg.getSendEmailFrequencyDays())) {
            preferences.setSendEmailFrequencyDays(DefaultPreferences.SEND_EMAIL_FREQUENCY_DAYS);
        } else {
            preferences.setSendEmailFrequencyDays(reg.getSendEmailFrequencyDays().getValue());
        }

        if (reg.getSendMemberUpdateRequests() == null) {
            preferences.setSendMemberUpdateRequests(DefaultPreferences.SEND_MEMBER_UPDATE_REQUESTS);
        } else {
            preferences.setSendMemberUpdateRequests(reg.getSendMemberUpdateRequests().getValue());
        }

        PersonalDetails personalDetails = new PersonalDetails();
        personalDetails.setFamilyName(new FamilyName(reg.getFamilyNames().getValue()));
        personalDetails.setGivenNames(new GivenNames(reg.getGivenNames().getValue()));

        bio.setContactDetails(contactDetails);
        bio.setPersonalDetails(personalDetails);
        OrcidInternal internal = new OrcidInternal();
        internal.setPreferences(preferences);
        profile.setOrcidBio(bio);
        if (!PojoUtil.isEmpty(reg.getReferredBy()))
            internal.setReferredBy(new ReferredBy(reg.getReferredBy().getValue()));

        profile.setOrcidInternal(internal);

        OrcidHistory orcidHistory = new OrcidHistory();
        orcidHistory.setClaimed(new Claimed(true));
        orcidHistory.setCreationMethod(CreationMethod.fromValue(reg.getCreationType().getValue()));

        profile.setOrcidHistory(orcidHistory);
        orcidHistory.setSubmissionDate(new SubmissionDate(DateUtils.convertToXMLGregorianCalendar(new Date())));

        profile.setPassword(reg.getPassword().getValue());

        profile.setUserLastIp(OrcidRequestUtil.getIpAddress(request));
        return profile;
    }

    @RequestMapping(value = "/register.json", method = RequestMethod.POST)
    public @ResponseBody Registration setRegister(HttpServletRequest request, @RequestBody Registration reg) {
        validateRegistrationFields(request, reg);
        validateGrcaptcha(request, reg);
        return reg;
    }

    public void validateGrcaptcha(HttpServletRequest request, @RequestBody Registration reg) {
        // If recatcha wasn't loaded do nothing. This is for countries that
        // block google.
        if (reg.getGrecaptchaWidgetId().getValue() != null) {
            if (reg.getGrecaptcha() == null) {
                reg.setGrecaptcha(new Text());
                reg.getGrecaptcha().setErrors(new ArrayList<String>());
                setError(reg.getGrecaptcha(), "registrationForm.recaptcha.error");
                setError(reg, "registrationForm.recaptcha.error");
            } else {
                reg.getGrecaptcha().setErrors(new ArrayList<String>());
            }

            if (request.getSession().getAttribute(GRECAPTCHA_SESSION_ATTRIBUTE_NAME) != null) {
                if (!encryptionManager.encryptForExternalUse(reg.getGrecaptcha().getValue())
                        .equals(request.getSession().getAttribute(GRECAPTCHA_SESSION_ATTRIBUTE_NAME))) {
                    setError(reg.getGrecaptcha(), "registrationForm.recaptcha.error");
                    setError(reg, "registrationForm.recaptcha.error");
                }
            } else if (!recaptchaVerifier.verify(reg.getGrecaptcha().getValue())) {
                reg.getGrecaptcha().setErrors(new ArrayList<String>());
                setError(reg.getGrecaptcha(), "registrationForm.recaptcha.error");
                setError(reg, "registrationForm.recaptcha.error");
            } else {
                request.getSession().setAttribute(GRECAPTCHA_SESSION_ATTRIBUTE_NAME,
                        encryptionManager.encryptForExternalUse(reg.getGrecaptcha().getValue()));
            }
        }
    }

    @RequestMapping(value = "/registerConfirm.json", method = RequestMethod.POST)
    public @ResponseBody Redirect setRegisterConfirm(HttpServletRequest request, HttpServletResponse response,
            @RequestBody Registration reg) {
        Redirect r = new Redirect();

        boolean usedCaptcha = false;

        // If recatcha wasn't loaded do nothing. This is for countries that
        // block google.
        if (reg.getGrecaptchaWidgetId().getValue() != null) {
            // If the captcha verified key is not in the session, redirect to
            // the login page
            if (request.getSession().getAttribute(GRECAPTCHA_SESSION_ATTRIBUTE_NAME) == null
                    || PojoUtil.isEmpty(reg.getGrecaptcha())
                    || !encryptionManager.encryptForExternalUse(reg.getGrecaptcha().getValue())
                            .equals(request.getSession().getAttribute(GRECAPTCHA_SESSION_ATTRIBUTE_NAME))) {
                r.setUrl(getBaseUri() + "/register");
                return r;
            }

            usedCaptcha = true;
        }

        // Remove the session hash if needed
        if (request.getSession().getAttribute(GRECAPTCHA_SESSION_ATTRIBUTE_NAME) != null) {
            request.getSession().removeAttribute(GRECAPTCHA_SESSION_ATTRIBUTE_NAME);
        }

        // make sure validation still passes
        validateRegistrationFields(request, reg);
        if (reg.getErrors() != null && reg.getErrors().size() > 0) {
            r.getErrors().add("Please revalidate at /register.json");
            return r;
        }

        if (reg.getValNumServer() == 0 || reg.getValNumClient() != reg.getValNumServer() / 2) {
            r.setUrl(getBaseUri() + "/register");
            return r;
        }

        createMinimalRegistrationAndLogUserIn(request, response, toProfile(reg, request), usedCaptcha);
        String redirectUrl = calculateRedirectUrl(request, response);
        r.setUrl(redirectUrl);
        return r;
    }

    public void validateRegistrationFields(HttpServletRequest request, Registration reg) {
        reg.setErrors(new ArrayList<String>());

        registerGivenNameValidate(reg);
        registerPasswordValidate(reg);
        registerPasswordConfirmValidate(reg);
        regEmailValidate(request, reg, false, false);
        registerTermsOfUseValidate(reg);

        copyErrors(reg.getEmailConfirm(), reg);
        copyErrors(reg.getEmail(), reg);
        copyErrors(reg.getGivenNames(), reg);
        copyErrors(reg.getPassword(), reg);
        copyErrors(reg.getPasswordConfirm(), reg);
        copyErrors(reg.getTermsOfUse(), reg);
    }

    private String calculateRedirectUrl(HttpServletRequest request, HttpServletResponse response) {
        SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response);
        if (savedRequest != null) {
            String savedUrl = savedRequest.getRedirectUrl();
            if (savedUrl != null) {
                try {
                    String path = new URL(savedUrl).getPath();
                    if (path != null && path.contains("/oauth/")) {
                        // This redirect url is OK
                        return savedUrl;
                    }
                } catch (MalformedURLException e) {
                    LOGGER.debug("Malformed saved redirect url: {}", savedUrl);
                }
            }
        }
        return getBaseUri() + "/my-orcid";
    }

    @RequestMapping(value = "/registerPasswordConfirmValidate.json", method = RequestMethod.POST)
    public @ResponseBody Registration registerPasswordConfirmValidate(@RequestBody Registration reg) {
        passwordConfirmValidate(reg.getPasswordConfirm(), reg.getPassword());
        return reg;
    }

    @RequestMapping(value = "/registerPasswordValidate.json", method = RequestMethod.POST)
    public @ResponseBody Registration registerPasswordValidate(@RequestBody Registration reg) {
        passwordValidate(reg.getPasswordConfirm(), reg.getPassword());
        return reg;
    }

    @RequestMapping(value = "/claimPasswordConfirmValidate.json", method = RequestMethod.POST)
    public @ResponseBody Claim claimPasswordConfirmValidate(@RequestBody Claim claim) {
        passwordConfirmValidate(claim.getPasswordConfirm(), claim.getPassword());
        return claim;
    }

    @RequestMapping(value = "/claimPasswordValidate.json", method = RequestMethod.POST)
    public @ResponseBody Claim claimPasswordValidate(@RequestBody Claim claim) {
        passwordValidate(claim.getPasswordConfirm(), claim.getPassword());
        return claim;
    }

    private void passwordConfirmValidate(Text passwordConfirm, Text password) {
        passwordConfirm.setErrors(new ArrayList<String>());
        // validate passwords match
        if (passwordConfirm.getValue() == null || !passwordConfirm.getValue().equals(password.getValue())) {
            setError(passwordConfirm, "FieldMatch.registrationForm");
        }
    }

    private void passwordValidate(Text passwordConfirm, Text password) {
        password.setErrors(new ArrayList<String>());
        // validate password regex
        if (password.getValue() == null
                || !password.getValue().matches(OrcidPasswordConstants.ORCID_PASSWORD_REGEX)) {
            setError(password, "Pattern.registrationForm.password");
        }

        if (passwordConfirm.getValue() != null) {
            passwordConfirmValidate(passwordConfirm, password);
        }
    }

    @RequestMapping(value = "/registerTermsOfUseValidate.json", method = RequestMethod.POST)
    public @ResponseBody Registration registerTermsOfUseValidate(@RequestBody Registration reg) {
        termsOfUserValidate(reg.getTermsOfUse());
        return reg;
    }

    @RequestMapping(value = "/claimTermsOfUseValidate.json", method = RequestMethod.POST)
    public @ResponseBody Claim claimTermsOfUseValidate(@RequestBody Claim claim) {
        termsOfUserValidate(claim.getTermsOfUse());
        return claim;
    }

    private void termsOfUserValidate(Checkbox termsOfUser) {
        termsOfUser.setErrors(new ArrayList<String>());
        if (termsOfUser.getValue() != true) {
            setError(termsOfUser, "AssertTrue.registrationForm.acceptTermsAndConditions");
        }
    }

    @RequestMapping(value = "/registerGivenNamesValidate.json", method = RequestMethod.POST)
    public @ResponseBody Registration registerGivenNameValidate(@RequestBody Registration reg) {
        super.givenNameValidate(reg.getGivenNames());
        return reg;
    }

    @RequestMapping(value = "/registerEmailValidate.json", method = RequestMethod.POST)
    public @ResponseBody Registration regEmailValidate(HttpServletRequest request, @RequestBody Registration reg) {
        return regEmailValidate(request, reg, false, true);
    }

    public Registration regEmailValidate(HttpServletRequest request, Registration reg, boolean isOauthRequest,
            boolean isKeyup) {
        reg.getEmail().setErrors(new ArrayList<String>());
        if (!isKeyup && (reg.getEmail().getValue() == null || reg.getEmail().getValue().trim().isEmpty())) {
            setError(reg.getEmail(), "Email.registrationForm.email");
        }
        // validate email
        MapBindingResult mbr = new MapBindingResult(new HashMap<String, String>(), "Email");
        // make sure there are no dups
        validateEmailAddress(reg.getEmail().getValue(), false, true, request, mbr);

        for (ObjectError oe : mbr.getAllErrors()) {
            if (isOauthRequest && oe.getCode().equals("orcid.frontend.verify.duplicate_email")) {
                // XXX
                reg.getEmail().getErrors().add(getMessage("oauth.registration.duplicate_email", oe.getArguments()));
            } else {
                reg.getEmail().getErrors().add(getMessage(oe.getCode(), oe.getArguments()));
            }
        }

        // validate confirm if already field out
        if (reg.getEmailConfirm().getValue() != null) {
            regEmailConfirmValidate(reg);
        }

        return reg;
    }

    @RequestMapping(value = "/registerEmailConfirmValidate.json", method = RequestMethod.POST)
    public @ResponseBody Registration regEmailConfirmValidate(@RequestBody Registration reg) {
        reg.getEmailConfirm().setErrors(new ArrayList<String>());
        // normalize to "" sometimes angular sends null
        if (reg.getEmail().getValue() == null)
            reg.getEmail().setValue("");
        if (reg.getEmailConfirm().getValue() == null)
            reg.getEmailConfirm().setValue("");
        if (!reg.getEmailConfirm().getValue().equalsIgnoreCase(reg.getEmail().getValue())) {
            setError(reg.getEmailConfirm(), "StringMatchIgnoreCase.registrationForm");
        }

        return reg;
    }

    @RequestMapping(value = "/register", method = RequestMethod.GET)
    public ModelAndView register(HttpServletRequest request, HttpServletResponse response) {
        ModelAndView mav = new ModelAndView("register");
        SavedRequest savedRequest = new HttpSessionRequestCache().getRequest(request, response);
        LOGGER.debug("Saved url before registration is: "
                + (savedRequest != null ? savedRequest.getRedirectUrl() : " no saved request"));
        return mav;
    }

    @RequestMapping(value = "/dupicateResearcher.json", method = RequestMethod.GET)
    public @ResponseBody List<DupicateResearcher> getDupicateResearcher(
            @RequestParam("givenNames") String givenNames, @RequestParam("familyNames") String familyNames) {
        List<DupicateResearcher> drList = new ArrayList<DupicateResearcher>();

        List<OrcidProfile> potentialDuplicates = findPotentialDuplicatesByFirstNameLastName(givenNames,
                familyNames);
        for (OrcidProfile op : potentialDuplicates) {
            DupicateResearcher dr = new DupicateResearcher();
            if (op.getOrcidBio() != null) {
                if (op.getOrcidBio().getContactDetails() != null) {
                    if (op.getOrcidBio().getContactDetails().retrievePrimaryEmail() != null) {
                        dr.setEmail(op.getOrcidBio().getContactDetails().retrievePrimaryEmail().getValue());
                    }
                }
                FamilyName familyName = op.getOrcidBio().getPersonalDetails().getFamilyName();
                if (familyName != null) {
                    dr.setFamilyNames(familyName.getContent());
                }
                dr.setGivenNames(op.getOrcidBio().getPersonalDetails().getGivenNames().getContent());
                dr.setInstitution(null);
            }
            OrcidIdentifier orcidIdentifier = op.getOrcidIdentifier();
            // Everything should be reindexed with orcid-identifier by now, but
            // check for null just in case.
            if (orcidIdentifier != null) {
                dr.setOrcid(orcidIdentifier.getPath());
            }
            drList.add(dr);
        }

        return drList;
    }

    @RequestMapping(value = "/reset-password", method = RequestMethod.GET)
    public ModelAndView resetPassword() {
        ModelAndView mav = new ModelAndView("reset_password");
        EmailAddressForm resetPasswordForm = new EmailAddressForm();
        mav.addObject(resetPasswordForm);
        return mav;
    }

    @RequestMapping(value = "/reset-password", method = RequestMethod.POST)
    public ModelAndView issuePasswordResetRequest(HttpServletRequest request,
            @ModelAttribute @Valid EmailAddressForm resetPasswordForm, BindingResult bindingResult) {

        String submittedEmail = resetPasswordForm.getUserEmailAddress();

        ModelAndView mav = new ModelAndView("reset_password");

        // if the email doesn't exist, or any other form errors.. don't bother
        // hitting db
        if (bindingResult.hasErrors()) {
            mav.addAllObjects(bindingResult.getModel());
            return mav;
        }

        OrcidProfile profile = orcidProfileManager.retrieveOrcidProfileByEmail(submittedEmail,
                LoadOptions.BIO_ONLY);
        // if the email can't be found on the system, then add to errors
        if (profile == null) {

            String[] codes = { "orcid.frontend.reset.password.email_not_found" };
            String[] args = { submittedEmail };
            bindingResult.addError(new FieldError("userEmailAddress", "userEmailAddress", submittedEmail, false,
                    codes, args, "Email not found"));
            mav.addAllObjects(bindingResult.getModel());
            return mav;
        }

        else {
            if (profile.isDeactivated()) {
                mav.addObject("disabledAccount", true);
                return mav;
            } else {
                registrationManager.resetUserPassword(submittedEmail, profile);
                mav.addObject("passwordResetSuccessful", true);
                return mav;
            }
        }
    }

    @RequestMapping(value = "/resend-claim", method = RequestMethod.GET)
    public ModelAndView viewResendClaimEmail(@RequestParam(value = "email", required = false) String email) {
        ModelAndView mav = new ModelAndView("resend_claim");
        EmailAddressForm emailAddressForm = new EmailAddressForm();
        emailAddressForm.setUserEmailAddress(email);
        mav.addObject(emailAddressForm);
        return mav;
    }

    @RequestMapping(value = "/resend-claim", method = RequestMethod.POST)
    public ModelAndView resendClaimEmail(HttpServletRequest request,
            @ModelAttribute @Valid EmailAddressForm emailAddressForm, BindingResult bindingResult) {
        String userEmailAddress = emailAddressForm.getUserEmailAddress();
        ModelAndView mav = new ModelAndView("resend_claim");
        // if the email doesn't exist, or any other form errors.. don't bother
        // hitting db
        if (bindingResult.hasErrors()) {
            mav.addAllObjects(bindingResult.getModel());
            return mav;
        }
        OrcidProfile profile = orcidProfileManager.retrieveOrcidProfileByEmail(userEmailAddress);
        // if the email can't be found on the system, then add to errors
        if (profile == null) {

            String[] codes = { "orcid.frontend.reset.password.email_not_found" };
            String[] args = { userEmailAddress };
            bindingResult.addError(new FieldError("userEmailAddress", "userEmailAddress", userEmailAddress, false,
                    codes, args, "Email not found"));
            mav.addAllObjects(bindingResult.getModel());
            return mav;
        } else {
            if (profile.getOrcidHistory() != null && profile.getOrcidHistory().isClaimed()) {
                mav.addObject("alreadyClaimed", true);
                return mav;
            } else {
                notificationManager.sendApiRecordCreationEmail(userEmailAddress, profile);
                mav.addObject("claimResendSuccessful", true);
                return mav;
            }
        }
    }

    private void automaticallyLogin(HttpServletRequest request, String password, OrcidProfile orcidProfile) {
        UsernamePasswordAuthenticationToken token = null;
        try {
            String orcid = orcidProfile.getOrcidIdentifier().getPath();
            // Force refresh of profile entity to ensure new password value is
            // picked up from DB.
            profileDao.refresh(profileDao.find(orcid));
            token = new UsernamePasswordAuthenticationToken(orcid, password);
            token.setDetails(new WebAuthenticationDetails(request));
            Authentication authentication = authenticationManager.authenticate(token);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        } catch (AuthenticationException e) {
            // this should never happen
            SecurityContextHolder.getContext().setAuthentication(null);
            LOGGER.warn("User {0} should have been logged-in, but we unable to due to a problem", e,
                    (token != null ? token.getPrincipal() : "empty principle"));
        }
    }

    @RequestMapping(value = "/verify-email/{encryptedEmail}", method = RequestMethod.GET)
    public ModelAndView verifyEmail(HttpServletRequest request,
            @PathVariable("encryptedEmail") String encryptedEmail, RedirectAttributes redirectAttributes)
            throws NoSuchRequestHandlingMethodException, UnsupportedEncodingException {
        return buildVerificationView(request, encryptedEmail, redirectAttributes);
    }

    @RequestMapping(value = "/reset-password-email/{encryptedEmail}", method = RequestMethod.GET)
    public ModelAndView resetPasswordEmail(HttpServletRequest request,
            @PathVariable("encryptedEmail") String encryptedEmail, RedirectAttributes redirectAttributes) {

        PasswordResetToken passwordResetToken = buildResetTokenFromEncryptedLink(encryptedEmail);
        if (isTokenExpired(passwordResetToken)) {
            redirectAttributes.addFlashAttribute("passwordResetLinkExpired", true);
            return new ModelAndView("redirect:/reset-password");
        }

        OneTimeResetPasswordForm form = new OneTimeResetPasswordForm();
        form.setSecurityQuestionId(0);
        // otherwise, straight to the screen with the option to set a security
        // question
        return buildPasswordScreenWithOptionalSecurityQuestion(form);
    }

    @RequestMapping(value = "/reset-password-form-validate.json", method = RequestMethod.POST)
    public @ResponseBody PasswordTypeAndConfirmForm resetPasswordConfirmValidate(
            @RequestBody PasswordTypeAndConfirmForm resetPasswordForm) {
        resetPasswordValidateFields(resetPasswordForm.getPassword(), resetPasswordForm.getRetypedPassword());
        return resetPasswordForm;
    }

    private void resetPasswordValidateFields(Text password, Text retypedPassword) {
        if (password == null) {
            password = new Text();
        }

        if (retypedPassword == null) {
            retypedPassword = new Text();
        }
        password.setErrors(new ArrayList<String>());
        retypedPassword.setErrors(new ArrayList<String>());

        // validate password regex
        if (password.getValue() == null
                || !password.getValue().matches(OrcidPasswordConstants.ORCID_PASSWORD_REGEX)) {
            setError(password, "Pattern.registrationForm.password");
        }

        // validate passwords match
        if (retypedPassword.getValue() != null && !retypedPassword.getValue().equals(password.getValue())) {
            setError(retypedPassword, "FieldMatch.registrationForm");
        }
    }

    @RequestMapping(value = "/password-reset.json", method = RequestMethod.GET)
    public @ResponseBody PasswordTypeAndConfirmForm getResetPassword(HttpServletRequest request) {
        PasswordTypeAndConfirmForm form = new PasswordTypeAndConfirmForm();
        form.setPassword(new Text());
        form.setRetypedPassword(new Text());
        return form;
    }

    private ModelAndView buildPasswordScreenWithOptionalSecurityQuestion(
            OneTimeResetPasswordForm oneTimeResetPasswordForm) {
        ModelAndView combinedView = new ModelAndView("password_one_time_reset_optional_security_questions");
        combinedView.addObject(oneTimeResetPasswordForm);
        return combinedView;
    }

    @RequestMapping(value = "/answer-security-question/{encryptedEmail}", method = RequestMethod.GET)
    public ModelAndView buildAnswerSecurityQuestionView(@PathVariable("encryptedEmail") String encryptedEmail,
            RedirectAttributes redirectAttributes) {

        PasswordResetToken passwordResetToken = buildResetTokenFromEncryptedLink(encryptedEmail);
        if (isTokenExpired(passwordResetToken)) {
            redirectAttributes.addFlashAttribute("passwordResetLinkExpired", true);
            return new ModelAndView("redirect:/reset-password");
        }

        int securityQuestionId = deriveSecurityIdByEmailForUser(passwordResetToken.getEmail());
        ModelAndView answerSecurityQuestionView = new ModelAndView("answer_security_question");
        ChangeSecurityQuestionForm changeSecurityQuestionForm = new ChangeSecurityQuestionForm();
        changeSecurityQuestionForm.setSecurityQuestionId(securityQuestionId);
        String securityQuestion = retrieveSecurityQuestionsAsMap().get(String.valueOf(securityQuestionId));
        answerSecurityQuestionView.addObject("securityQuestionText", securityQuestion);
        answerSecurityQuestionView.addObject(changeSecurityQuestionForm);
        return answerSecurityQuestionView;
    }

    @RequestMapping(value = "/answer-security-question/{encryptedEmail}", method = RequestMethod.POST)
    public ModelAndView submitSecurityAnswer(@PathVariable("encryptedEmail") String encryptedEmail,
            @Valid ChangeSecurityQuestionForm changeSecurityQuestionForm, BindingResult bindingResult,
            RedirectAttributes redirectAttributes) {

        PasswordResetToken passwordResetToken = buildResetTokenFromEncryptedLink(encryptedEmail);
        OrcidProfile retrievedProfile = orcidProfileManager
                .retrieveOrcidProfileByEmail(passwordResetToken.getEmail(), LoadOptions.INTERNAL_ONLY);

        if (bindingResult.hasErrors()) {
            ModelAndView errorView = buildAnswerSecurityQuestionView(encryptedEmail, redirectAttributes);
            errorView.addAllObjects(bindingResult.getModel());
            return errorView;
        }

        String securityAnswer = retrievedProfile.getSecurityQuestionAnswer();
        if (!changeSecurityQuestionForm.getSecurityQuestionAnswer().trim()
                .equalsIgnoreCase(securityAnswer.trim())) {
            ModelAndView errorView = buildAnswerSecurityQuestionView(encryptedEmail, redirectAttributes);
            errorView.addObject("securityQuestionIncorrect", true);
            return errorView;
        }
        // build password standalone view
        return new ModelAndView("redirect:/one-time-password/" + encryptedEmail);
    }

    @RequestMapping(value = "/one-time-password/{encryptedEmail}", method = RequestMethod.GET)
    public ModelAndView buildPasswordOneTimeResetView(@PathVariable("encryptedEmail") String encryptedEmail) {
        ModelAndView mav = new ModelAndView("password_one_time_reset");
        PasswordTypeAndConfirmForm passwordTypeAndConfirmForm = new PasswordTypeAndConfirmForm();
        mav.addObject("passwordTypeAndConfirmForm", passwordTypeAndConfirmForm);
        return mav;
    }

    @RequestMapping(value = "/one-time-password/{encryptedEmail}", method = RequestMethod.POST)
    public ModelAndView confirmPasswordOneTimeResetView(HttpServletRequest request, HttpServletResponse response,
            @PathVariable("encryptedEmail") String encryptedEmail,
            @Valid PasswordTypeAndConfirmForm passwordTypeAndConfirmForm, BindingResult bindingResult,
            RedirectAttributes redirectAttributes) {

        PasswordResetToken passwordResetToken = buildResetTokenFromEncryptedLink(encryptedEmail);
        if (isTokenExpired(passwordResetToken)) {
            redirectAttributes.addFlashAttribute("passwordResetLinkExpired", true);
            return new ModelAndView("redirect:/reset-password");
        }

        if (bindingResult.hasErrors()) {
            ModelAndView errorView = buildPasswordOneTimeResetView(encryptedEmail);
            errorView.addAllObjects(bindingResult.getModel());
            return errorView;
        }

        OrcidProfile passwordOnlyProfileUpdate = orcidProfileManager
                .retrieveOrcidProfileByEmail(passwordResetToken.getEmail(), LoadOptions.INTERNAL_ONLY);
        passwordOnlyProfileUpdate.setPassword(passwordTypeAndConfirmForm.getPassword() == null ? null
                : passwordTypeAndConfirmForm.getPassword().getValue());
        return updatePasswordAndGoToAccountsPage(request, response, passwordOnlyProfileUpdate);
    }

    @RequestMapping(value = "/reset-password-email/{encryptedEmail}", method = RequestMethod.POST)
    public ModelAndView submitPasswordReset(HttpServletRequest request, HttpServletResponse response,
            @PathVariable("encryptedEmail") String encryptedEmail,
            @Valid OneTimeResetPasswordForm oneTimeResetPasswordForm, BindingResult bindingResult,
            RedirectAttributes redirectAttributes) {

        PasswordResetToken passwordResetToken = buildResetTokenFromEncryptedLink(encryptedEmail);
        // double check link not expired - someone could send a curl request..
        if (isTokenExpired(passwordResetToken)) {
            redirectAttributes.addFlashAttribute("passwordResetLinkExpired", true);
            return new ModelAndView("redirect:/reset-password");
        }

        // validate the form and redirect back to the reset view
        if (bindingResult.hasErrors()) {
            ModelAndView errorView = buildPasswordScreenWithOptionalSecurityQuestion(oneTimeResetPasswordForm);
            errorView.addAllObjects(bindingResult.getModel());
            return errorView;

        }
        // update password, and optionally question and answer
        OrcidProfile profileToUpdate = orcidProfileManager
                .retrieveOrcidProfileByEmail(passwordResetToken.getEmail(), LoadOptions.INTERNAL_ONLY);
        profileToUpdate.setPassword(oneTimeResetPasswordForm.getPassword().getValue());
        if (oneTimeResetPasswordForm.isSecurityDetailsPopulated()) {
            profileToUpdate.getOrcidInternal().getSecurityDetails().setSecurityQuestionId(
                    new SecurityQuestionId(oneTimeResetPasswordForm.getSecurityQuestionId()));
            profileToUpdate.setSecurityQuestionAnswer(oneTimeResetPasswordForm.getSecurityQuestionAnswer());
        }

        return updatePasswordAndGoToAccountsPage(request, response, profileToUpdate);

    }

    private ModelAndView updatePasswordAndGoToAccountsPage(HttpServletRequest request, HttpServletResponse response,
            OrcidProfile updatedProfile) {
        orcidProfileManager.updatePasswordInformation(updatedProfile);
        String redirectUrl = calculateRedirectUrl(request, response);
        return new ModelAndView("redirect:" + redirectUrl);
    }

    private Integer deriveSecurityIdByEmailForUser(String email) {
        Integer securityQuestionVal = null;
        OrcidProfile retrievedProfile = orcidProfileManager.retrieveOrcidProfileByEmail(email,
                LoadOptions.INTERNAL_ONLY);
        if (retrievedProfile != null) {
            SecurityQuestionId securityQuestion = retrievedProfile.getOrcidInternal().getSecurityDetails()
                    .getSecurityQuestionId();
            securityQuestionVal = securityQuestion != null
                    ? (int) retrievedProfile.getOrcidInternal().getSecurityDetails().getSecurityQuestionId()
                            .getValue()
                    : null;

        }
        return securityQuestionVal;
    }

    private PasswordResetToken buildResetTokenFromEncryptedLink(String encryptedLink) {

        try {
            String paramsString = encryptionManager
                    .decryptForExternalUse(new String(Base64.decodeBase64(encryptedLink), "UTF-8"));
            return new PasswordResetToken(paramsString);
        } catch (UnsupportedEncodingException e) {
            LOGGER.error("Could not decrypt " + encryptedLink);
            throw new RuntimeException(getMessage("web.orcid.decrypt_passwordreset.exception"));
        }

    }

    private boolean isTokenExpired(PasswordResetToken passwordResetToken) {

        Date expiryDateOfOneHourFromIssueDate = org.apache.commons.lang.time.DateUtils
                .addHours(passwordResetToken.getIssueDate(), 1);
        Date now = new Date();
        return (expiryDateOfOneHourFromIssueDate.getTime() < now.getTime());
    }

    @RequestMapping(value = "/claim/{encryptedEmail}", method = RequestMethod.GET)
    public ModelAndView verifyClaim(HttpServletRequest request,
            @PathVariable("encryptedEmail") String encryptedEmail, RedirectAttributes redirectAttributes)
            throws NoSuchRequestHandlingMethodException, UnsupportedEncodingException {
        try {
            String decryptedEmail = encryptionManager
                    .decryptForExternalUse(new String(Base64.decodeBase64(encryptedEmail), "UTF-8"));
            if (!isEmailOkForCurrentUser(decryptedEmail)) {
                return new ModelAndView("wrong_user");
            }
            OrcidProfile profileToClaim = orcidProfileManager.retrieveOrcidProfileByEmail(decryptedEmail);
            if (profileToClaim.getOrcidHistory().isClaimed()) {
                return new ModelAndView("redirect:/signin?alreadyClaimed");
            }
            ModelAndView mav = new ModelAndView("claim");
            return mav;
        } catch (EncryptionOperationNotPossibleException e) {
            LOGGER.warn("Error decypting claim email from the claim profile link");
            return new ModelAndView("redirect:/signin?invalidClaimUrl");
        }
    }

    @RequestMapping(value = "/claim/{encryptedEmail}.json", method = RequestMethod.GET)
    public @ResponseBody Claim verifyClaimJson(HttpServletRequest request,
            @PathVariable("encryptedEmail") String encryptedEmail, RedirectAttributes redirectAttributes)
            throws NoSuchRequestHandlingMethodException, UnsupportedEncodingException {
        Claim c = new Claim();
        c.getSendChangeNotifications().setValue(true);
        c.getSendOrcidNews().setValue(true);
        c.getTermsOfUse().setValue(false);
        claimTermsOfUseValidate(c);
        return c;
    }

    @RequestMapping(value = "/claim/{encryptedEmail}.json", method = RequestMethod.POST)
    public @ResponseBody Claim submitClaimJson(HttpServletRequest request,
            @PathVariable("encryptedEmail") String encryptedEmail, @RequestBody Claim claim)
            throws NoSuchRequestHandlingMethodException, UnsupportedEncodingException {
        claim.setErrors(new ArrayList<String>());
        String decryptedEmail = encryptionManager
                .decryptForExternalUse(new String(Base64.decodeBase64(encryptedEmail), "UTF-8")).trim();
        if (!isEmailOkForCurrentUser(decryptedEmail)) {
            claim.setUrl(getBaseUri() + "/claim/wrong_user");
            return claim;
        }
        OrcidProfile profileToClaim = orcidProfileManager.retrieveOrcidProfileByEmail(decryptedEmail);
        if (profileToClaim.getOrcidHistory().isClaimed()) {
            // Already claimed so send to sign in page
            claim.setUrl(getBaseUri() + "/signin?alreadyClaimed");
            return claim;
        }

        claimPasswordValidate(claim);
        claimPasswordConfirmValidate(claim);
        claimTermsOfUseValidate(claim);

        copyErrors(claim.getPassword(), claim);
        copyErrors(claim.getPasswordConfirm(), claim);
        copyErrors(claim.getTermsOfUse(), claim);

        if (claim.getErrors().size() > 0) {
            return claim;
        }
        OrcidProfile orcidProfile = confirmEmailAndClaim(decryptedEmail, profileToClaim, claim, request);
        orcidProfile.setPassword(claim.getPassword().getValue());
        orcidProfileManager.updatePasswordInformation(orcidProfile);
        automaticallyLogin(request, claim.getPassword().getValue(), orcidProfile);
        claim.setUrl(getBaseUri() + "/my-orcid?recordClaimed");
        return claim;
    }

    @RequestMapping(value = "/claim/wrong_user", method = RequestMethod.GET)
    public ModelAndView claimWrongUser(HttpServletRequest request) {
        return new ModelAndView("wrong_user");
    }

    private ModelAndView buildVerificationView(HttpServletRequest request, String encryptedEmail,
            RedirectAttributes redirectAttributes)
            throws UnsupportedEncodingException, NoSuchRequestHandlingMethodException {
        try {
            String decryptedEmail = encryptionManager
                    .decryptForExternalUse(new String(Base64.decodeBase64(encryptedEmail), "UTF-8"));
            EmailEntity emailEntity = emailDao.find(decryptedEmail);
            String emailOrcid = emailEntity.getProfile().getId();
            if (!getCurrentUserOrcid().equals(emailOrcid)) {
                return new ModelAndView("wrong_user");
            }
            emailEntity.setVerified(true);
            emailEntity.setCurrent(true);
            emailDao.merge(emailEntity);
            profileDao.updateLocale(emailOrcid, org.orcid.jaxb.model.message.Locale
                    .fromValue(RequestContextUtils.getLocale(request).toString()));
            redirectAttributes.addFlashAttribute("emailVerified", true);
        } catch (EncryptionOperationNotPossibleException eonpe) {
            LOGGER.warn("Error decypting verify email from the verify email link");
            redirectAttributes.addFlashAttribute("invalidVerifyUrl", true);
        }
        return new ModelAndView("redirect:/my-orcid");
    }

    private OrcidProfile confirmEmailAndClaim(String decryptedEmail, OrcidProfile orcidProfile, Claim claim,
            HttpServletRequest request) throws NoSuchRequestHandlingMethodException {
        if (orcidProfile == null) {
            throw new NoSuchRequestHandlingMethodException(request);
        }
        orcidProfileManager.addLocale(orcidProfile, RequestContextUtils.getLocale(request));
        Email email = orcidProfile.getOrcidBio().getContactDetails().getEmailByString(decryptedEmail);
        email.setVerified(true);
        email.setCurrent(true);
        OrcidHistory orcidHistory = orcidProfile.getOrcidHistory();
        orcidHistory.setClaimed(new Claimed(true));
        CompletionDate completionDate = orcidHistory.getCompletionDate();
        if (completionDate == null) {
            orcidHistory.setCompletionDate(new CompletionDate(DateUtils.convertToXMLGregorianCalendar(new Date())));
        }
        if (claim != null) {
            Preferences preferences = orcidProfile.getOrcidInternal().getPreferences();
            if (preferences == null) {
                preferences = new Preferences();
            }
            preferences.setSendChangeNotifications(
                    new SendChangeNotifications(claim.getSendChangeNotifications().getValue()));
            preferences.setSendOrcidNews(new SendOrcidNews(claim.getSendOrcidNews().getValue()));
            preferences.setActivitiesVisibilityDefault(
                    new ActivitiesVisibilityDefault(claim.getActivitiesVisibilityDefault().getVisibility()));
        }
        OrcidProfile profileToReturn = orcidProfileManager.updateOrcidProfile(orcidProfile);
        notificationManager.sendAmendEmail(profileToReturn, AmendedSection.UNKNOWN);
        return profileToReturn;
    }

    private List<OrcidProfile> findPotentialDuplicatesByFirstNameLastName(String firstName, String lastName) {
        LOGGER.info("About to search for potential duplicates during registration for first name={}, last name={}",
                firstName, lastName);
        List<OrcidProfile> orcidProfiles = new ArrayList<OrcidProfile>();
        SearchOrcidSolrCriteria queryForm = new SearchOrcidSolrCriteria();

        queryForm.setGivenName(firstName);
        queryForm.setFamilyName(lastName);

        String query = queryForm.deriveQueryString();
        OrcidMessage visibleProfiles = orcidSearchManager.findOrcidsByQuery(query, DUP_SEARCH_START,
                DUP_SEARCH_ROWS);
        if (visibleProfiles.getOrcidSearchResults() != null) {
            for (OrcidSearchResult searchResult : visibleProfiles.getOrcidSearchResults().getOrcidSearchResult()) {
                orcidProfiles.add(searchResult.getOrcidProfile());
            }
        }
        LOGGER.info("Found {} potential duplicates during registration for first name={}, last name={}",
                new Object[] { orcidProfiles.size(), firstName, lastName });
        return orcidProfiles;

    }

    public void createMinimalRegistrationAndLogUserIn(HttpServletRequest request, HttpServletResponse response,
            OrcidProfile profileToSave, boolean usedCaptchaVerification) {
        String password = profileToSave.getPassword();
        UsernamePasswordAuthenticationToken token = null;
        try {
            profileToSave = createMinimalRegistration(request, profileToSave, usedCaptchaVerification);
            String orcidId = profileToSave.getOrcidIdentifier().getPath();
            token = new UsernamePasswordAuthenticationToken(profileToSave.getOrcidIdentifier().getPath(), password);
            token.setDetails(new WebAuthenticationDetails(request));
            Authentication authentication = authenticationManager.authenticate(token);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            if (internalSSOManager.enableCookie()) {
                //Set user cookie
                internalSSOManager.writeCookie(orcidId, request, response);
            }
        } catch (AuthenticationException e) {
            // this should never happen
            SecurityContextHolder.getContext().setAuthentication(null);
            LOGGER.warn("User {0} should have been logged-in, but we unable to due to a problem", e,
                    (token != null ? token.getPrincipal() : "empty principle"));
        }

    }

    public OrcidProfile createMinimalRegistration(HttpServletRequest request, OrcidProfile profileToSave,
            boolean usedCaptchaVerification) {
        orcidProfileManager.addLocale(profileToSave, RequestContextUtils.getLocale(request));
        String sessionId = request.getSession() == null ? null : request.getSession().getId();
        String email = profileToSave.getOrcidBio().getContactDetails().retrievePrimaryEmail().getValue();

        LOGGER.info("About to create profile from registration email={}, sessionid={}", email, sessionId);
        profileToSave = registrationManager.createMinimalRegistration(profileToSave, usedCaptchaVerification);
        notificationManager.sendWelcomeEmail(profileToSave,
                profileToSave.getOrcidBio().getContactDetails().retrievePrimaryEmail().getValue());
        request.getSession().setAttribute(ManageProfileController.CHECK_EMAIL_VALIDATED, false);
        LOGGER.info("Created profile from registration orcid={}, email={}, sessionid={}",
                new Object[] { profileToSave.getOrcidIdentifier().getPath(), email, sessionId });
        return profileToSave;
    }

}