org.biokoframework.system.services.passwordreset.impl.EmailPasswordResetService.java Source code

Java tutorial

Introduction

Here is the source code for org.biokoframework.system.services.passwordreset.impl.EmailPasswordResetService.java

Source

/*
 * Copyright (c) 2014.
 *    Mikol Faro      <mikol.faro@gmail.com>
 *    Simone Mangano       <simone.mangano@ieee.org>
 *    Mattia Tortorelli   <mattia.tortorelli@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package org.biokoframework.system.services.passwordreset.impl;

import org.apache.log4j.Logger;
import org.biokoframework.system.entity.authentication.PasswordReset;
import org.biokoframework.system.entity.login.Login;
import org.biokoframework.system.entity.template.Template;
import org.biokoframework.system.repository.service.IRepositoryService;
import org.biokoframework.system.services.currenttime.ICurrentTimeService;
import org.biokoframework.system.services.email.EmailException;
import org.biokoframework.system.services.email.IEmailService;
import org.biokoframework.system.services.entity.IEntityBuilderService;
import org.biokoframework.system.services.passwordreset.IPasswordResetService;
import org.biokoframework.system.services.random.IRandomService;
import org.biokoframework.system.services.templates.ITemplatingService;
import org.biokoframework.system.services.templates.TemplatingException;
import org.biokoframework.utils.domain.ErrorEntity;
import org.biokoframework.utils.exception.ValidationException;
import org.biokoframework.utils.fields.FieldNames;
import org.biokoframework.utils.fields.Fields;
import org.biokoframework.utils.repository.Repository;
import org.biokoframework.utils.repository.RepositoryException;
import org.joda.time.DateTime;

import javax.inject.Inject;
import javax.inject.Named;
import java.util.Map;

import static org.joda.time.format.ISODateTimeFormat.dateTimeNoMillis;

/**
 * @author Mikol Faro <mikol.faro@gmail.com>
 * @date 2014 Apr 03
 */
public class EmailPasswordResetService implements IPasswordResetService {

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

    private static final String PASSWORD_RESET_TOKEN = "passwordResetToken";

    private final Repository<Login> fLoginRepo;
    private final Repository<PasswordReset> fPasswordResetRepo;

    private final IEntityBuilderService fEntityBuilder;
    private final ICurrentTimeService fCurrentTime;
    private final IRandomService fRandomToken;
    private final ITemplatingService fTemplatingService;
    private final IEmailService fEmailService;

    private final String fNoReplyAddress;

    @Inject
    public EmailPasswordResetService(IRepositoryService repos, IEntityBuilderService entityBuilderService,
            ICurrentTimeService currentTimeService, IRandomService randomTokenService, IEmailService emailService,
            ITemplatingService templatingService, @Named("noReplyEmailAddress") String noReplyAddress) {

        fEmailService = emailService;
        fTemplatingService = templatingService;
        fLoginRepo = repos.getRepository(Login.class);
        fPasswordResetRepo = repos.getRepository(PasswordReset.class);

        fEntityBuilder = entityBuilderService;
        fCurrentTime = currentTimeService;
        fRandomToken = randomTokenService;

        fNoReplyAddress = noReplyAddress;
    }

    @Override
    public void requestPasswordReset(String userEmail, Template template, Map<String, Object> templateContent) {

        Login login = fLoginRepo.retrieveByForeignKey(Login.USER_EMAIL, userEmail);
        if (login == null) {
            //            throw CommandExceptionsFactory.createEntityNotFound(Login.class.getSimpleName(), Login.USER_EMAIL, userEmail);
        } else {
            try {
                PasswordReset reset = createReset(login.getId());

                templateContent.put("token", reset.get(PasswordReset.TOKEN));

                template = fTemplatingService.compileTemplate(template, templateContent);

                String content = template.get(Template.BODY);
                String subject = template.get(Template.TITLE);

                fEmailService.sendASAP(userEmail, fNoReplyAddress, content, subject);

            } catch (ValidationException | RepositoryException exception) {
                LOGGER.error("Cannot save password reset entity", exception);
            } catch (TemplatingException exception) {
                LOGGER.error("Cannot compile template for password reset mail", exception);
            } catch (EmailException exception) {
                LOGGER.error("Cannot sand password reset mail", exception);
            }
        }

    }

    private PasswordReset createReset(String loginId) throws ValidationException, RepositoryException {
        DateTime tomorrow = fCurrentTime.getCurrentTimeAsDateTime().plusDays(1);
        String randomToken = fRandomToken.generateUUID().toString();

        PasswordReset passwordReset = fEntityBuilder.getInstance(PasswordReset.class,
                new Fields(PasswordReset.LOGIN_ID, loginId, PasswordReset.TOKEN_EXPIRATION,
                        tomorrow.toString(dateTimeNoMillis()), PasswordReset.TOKEN, randomToken));
        fPasswordResetRepo.save(passwordReset);
        return passwordReset;
    }

    @Override
    public void performPasswordReset(String token, String newPassword)
            throws ValidationException, RepositoryException {
        PasswordReset reset = fPasswordResetRepo.retrieveByForeignKey(PasswordReset.TOKEN, token);
        if (reset != null) {
            if (!isPast((String) reset.get(PasswordReset.TOKEN_EXPIRATION))) {
                String loginId = reset.get(PasswordReset.LOGIN_ID);
                Login login = fLoginRepo.retrieve(loginId);
                login.set(Login.PASSWORD, newPassword);
                fLoginRepo.save(login);
            } else {
                fPasswordResetRepo.delete(reset.getId());

                ErrorEntity error = new ErrorEntity();
                error.setAll(
                        new Fields(ErrorEntity.ERROR_CODE, FieldNames.TOKEN_EXPIRED_CODE, ErrorEntity.ERROR_MESSAGE,
                                "The token is expired", ErrorEntity.ERROR_FIELD, PasswordReset.TOKEN_EXPIRATION));

                throw new ValidationException(error);
            }
        }
    }

    private boolean isPast(String timeStamp) {
        DateTime expiration = DateTime.parse(timeStamp, dateTimeNoMillis());
        return fCurrentTime.getCurrentTimeAsDateTime().isAfter(expiration);
    }
}