org.georchestra.console.ws.passwordrecovery.PasswordRecoveryFormController.java Source code

Java tutorial

Introduction

Here is the source code for org.georchestra.console.ws.passwordrecovery.PasswordRecoveryFormController.java

Source

/*
 * Copyright (C) 2009-2018 by the geOrchestra PSC
 *
 * This file is part of geOrchestra.
 *
 * geOrchestra is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * geOrchestra is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * geOrchestra.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.georchestra.console.ws.passwordrecovery;

import java.io.IOException;
import java.util.List;
import java.util.UUID;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.georchestra.commons.configuration.GeorchestraConfiguration;
import org.georchestra.console.Configuration;
import org.georchestra.console.bs.ReCaptchaParameters;
import org.georchestra.console.ds.AccountDao;
import org.georchestra.console.ds.DataServiceException;
import org.georchestra.console.ds.RoleDao;
import org.georchestra.console.ds.UserTokenDao;
import org.georchestra.console.dto.Account;
import org.georchestra.console.dto.Role;
import org.georchestra.console.mailservice.MailService;
import org.georchestra.console.ws.utils.RecaptchaUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.NameNotFoundException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
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.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;

/**
 * Manage the user interactions required to implement the lost password workflow:
 * <p>
 * <ul>
 *
 * <li>Present a form in order to ask for the user's mail.</li>
 *
 * <li>If the given email matches one of the LDAP users, an email is sent to this user with a unique http URL to reset his password.</li>
 *
 * <li>As result of this interaction the view EmailSentForm.jsp is presented</li>
 * </ul>
 * </p>
 *
 * @author Mauricio Pazos
 */
@Controller
@SessionAttributes(types = PasswordRecoveryFormBean.class)
public class PasswordRecoveryFormController {

    protected static final Log LOG = LogFactory.getLog(PasswordRecoveryFormController.class.getName());

    // collaborations
    private AccountDao accountDao;
    private RoleDao roleDao;
    private MailService mailService;
    private UserTokenDao userTokenDao;
    private Configuration config;
    private ReCaptchaParameters reCaptchaParameters;

    @Autowired
    private GeorchestraConfiguration georConfig;

    @Autowired
    public PasswordRecoveryFormController(AccountDao dao, RoleDao gDao, MailService mailSrv,
            UserTokenDao userTokenDao, Configuration cfg, ReCaptchaParameters reCaptchaParameters) {
        this.accountDao = dao;
        this.roleDao = gDao;
        this.mailService = mailSrv;
        this.userTokenDao = userTokenDao;
        this.config = cfg;
        this.reCaptchaParameters = reCaptchaParameters;
    }

    @InitBinder
    public void initForm(WebDataBinder dataBinder) {

        dataBinder.setAllowedFields(new String[] { "email", "recaptcha_response_field" });
    }

    @RequestMapping(value = "/account/passwordRecovery", method = RequestMethod.GET)
    public String setupForm(HttpServletRequest request,
            @RequestParam(value = "email", required = false) String email, Model model) throws IOException {

        HttpSession session = request.getSession();
        PasswordRecoveryFormBean formBean = new PasswordRecoveryFormBean();
        formBean.setEmail(email);

        model.addAttribute(formBean);
        session.setAttribute("reCaptchaPublicKey", this.reCaptchaParameters.getPublicKey());

        return "passwordRecoveryForm";
    }

    /**
     * Generates a new unique http URL based on a token, then an e-mail is sent to the user with instruction to change his password.
     *
     *
     * @param formBean      Contains the user's email
     * @param resultErrors    will be updated with the list of found errors.
     * @param sessionStatus
     *
     * @return the next view
     *
     * @throws IOException
     */
    @RequestMapping(value = "/account/passwordRecovery", method = RequestMethod.POST)
    public String generateToken(HttpServletRequest request, @ModelAttribute PasswordRecoveryFormBean formBean,
            BindingResult resultErrors, SessionStatus sessionStatus) throws IOException {

        RecaptchaUtils.validate(reCaptchaParameters, formBean.getRecaptcha_response_field(), resultErrors);
        if (resultErrors.hasErrors()) {
            return "passwordRecoveryForm";
        }

        try {
            Account account = this.accountDao.findByEmail(formBean.getEmail());
            List<Role> role = this.roleDao.findAllForUser(account.getUid());
            // Finds the user using the email as key, if it exists a new token is generated to include in the unique http URL.

            for (Role g : role) {
                if (g.getName().equals(Role.PENDING)) {
                    throw new NameNotFoundException("User in PENDING role");
                }
            }

            String token = UUID.randomUUID().toString();

            // if there is a previous token it is removed
            if (this.userTokenDao.exist(account.getUid())) {
                this.userTokenDao.delete(account.getUid());
            }

            this.userTokenDao.insertToken(account.getUid(), token);

            String contextPath = this.config.getPublicContextPath();
            String url = makeChangePasswordURL(this.georConfig.getProperty("publicUrl"), contextPath, token);

            ServletContext servletContext = request.getSession().getServletContext();
            this.mailService.sendChangePasswordURL(servletContext, account.getUid(), account.getCommonName(), url,
                    account.getEmail());

            sessionStatus.setComplete();

            return "emailWasSent";

        } catch (DataServiceException e) {

            throw new IOException(e);

        } catch (NameNotFoundException e) {

            resultErrors.rejectValue("email", "email.error.notFound", "No user found for this email.");

            return "passwordRecoveryForm";

        }
    }

    /**
     * Create the URL to change the password based on the provided token
     *
     * @return a new URL to change password
     */
    private String makeChangePasswordURL(final String publicUrl, final String contextPath, final String token) {

        StringBuilder strBuilder = new StringBuilder(publicUrl);
        strBuilder.append(contextPath);
        strBuilder.append("/account/newPassword?token=").append(token);
        String url = strBuilder.toString();

        if (LOG.isDebugEnabled()) {
            LOG.debug("generated url:" + url);
        }

        return url;
    }

    @ModelAttribute("passwordRecoveryFormBean")
    public PasswordRecoveryFormBean getPasswordRecoveryFormBean() {
        return new PasswordRecoveryFormBean();
    }

    public void setGeorConfig(GeorchestraConfiguration georConfig) {
        this.georConfig = georConfig;
    }
}