All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.kryshchuk.imcollector.auth.provider.SimpleAuthProvider Maven / Gradle / Ivy

The newest version!
/*
 * imcollector Authentication
 * Copyright (C) 2013  Yuriy Kryshchuk
 * 
 * This program 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.
 * 
 * This program 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 this program.  If not, see .
 */
package com.kryshchuk.imcollector.auth.provider;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import play.Application;
import play.data.Form;
import play.i18n.Lang;
import play.i18n.Messages;
import play.mvc.Call;
import play.mvc.Http.Context;

import com.feth.play.module.mail.Mailer.Mail.Body;
import com.feth.play.module.pa.PlayAuthenticate;
import com.feth.play.module.pa.providers.password.UsernamePasswordAuthProvider;
import com.kryshchuk.imcollector.auth.LinkedAccount;
import com.kryshchuk.imcollector.auth.TokenType;
import com.kryshchuk.imcollector.auth.User;
import com.kryshchuk.imcollector.auth.UserNotFoundException;
import com.kryshchuk.imcollector.auth.dao.AuthFactoryBuilder;
import com.kryshchuk.imcollector.auth.dao.UserDAO;
import com.kryshchuk.imcollector.auth.form.SimpleLogin;
import com.kryshchuk.imcollector.auth.form.SimpleSignup;

/**
 * @author yura
 * @since 1.0
 */
public abstract class SimpleAuthProvider extends
    UsernamePasswordAuthProvider {

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

  private static final String SETTING_KEY_VERIFICATION_LINK_SECURE = SETTING_KEY_MAIL + "." + "verificationLink.secure";

  private static final String SETTING_KEY_PASSWORD_RESET_LINK_SECURE = SETTING_KEY_MAIL + "."
      + "passwordResetLink.secure";

  private static final String SETTING_KEY_LINK_LOGIN_AFTER_PASSWORD_RESET = "loginAfterPasswordReset";

  private static final String EMAIL_TEMPLATE_FALLBACK_LANGUAGE = "en";

  public SimpleAuthProvider(final Application app) {
    super(app);
    LOGGER.trace("Instantiated");
  }

  public static SimpleAuthProvider getProvider() {
    return (SimpleAuthProvider) PlayAuthenticate.getProvider(UsernamePasswordAuthProvider.PROVIDER_KEY);
  }

  @Override
  protected List neededSettingKeys() {
    final List needed = new ArrayList<>(super.neededSettingKeys());
    needed.add(SETTING_KEY_VERIFICATION_LINK_SECURE);
    needed.add(SETTING_KEY_PASSWORD_RESET_LINK_SECURE);
    needed.add(SETTING_KEY_LINK_LOGIN_AFTER_PASSWORD_RESET);
    return needed;
  }

  public boolean isLoginAfterPasswordReset() {
    return getConfiguration().getBoolean(SETTING_KEY_LINK_LOGIN_AFTER_PASSWORD_RESET);
  }

  @Override
  protected SimpleLoginAuthUser buildLoginAuthUser(final SimpleLogin login, final Context ctx) {
    return new SimpleLoginAuthUser(login);
  }

  @Override
  protected SimpleSignupAuthUser buildSignupAuthUser(final SimpleSignup signup, final Context ctx) {
    return new SimpleSignupAuthUser(signup);
  }

  @Override
  protected String generateVerificationRecord(final SimpleSignupAuthUser user) {
    try {
      final UserDAO dao = AuthFactoryBuilder.getFactory().getUserDAO();
      return generateVerificationRecord(dao.find(user));
    } catch (final UserNotFoundException e) {
      LOGGER.error("Could not generate verification record for {}", user, e);
      return generateToken();
    }
  }

  protected String generateVerificationRecord(final User user) {
    final String token = generateToken();
    // Do database actions, etc.
    AuthFactoryBuilder.getFactory().getTokenActionDAO().create(TokenType.EMAIL_VERIFICATION, token, user);
    return token;
  }

  @Override
  protected Form getLoginForm() {
    return SimpleLogin.LOGIN_FORM;
  }

  @Override
  protected Form getSignupForm() {
    return SimpleSignup.FORM;
  }

  @Override
  protected Body getVerifyEmailMailingBody(final String token, final SimpleSignupAuthUser user, final Context ctx) {

    final boolean isSecure = getConfiguration().getBoolean(SETTING_KEY_VERIFICATION_LINK_SECURE);
    final String url = getAccountVerifyCall(token).absoluteURL(ctx.request(), isSecure);

    final Lang lang = Lang.preferred(ctx.request().acceptLanguages());
    final String langCode = lang.code();

    final String html = getEmailTemplate("views.html.account.email.verify_email", langCode, url, token, user.getName(),
        user.getEmail());
    final String text = getEmailTemplate("views.txt.account.email.verify_email", langCode, url, token, user.getName(),
        user.getEmail());

    return new Body(text, html);
  }

  @Override
  protected String getVerifyEmailMailingSubject(final SimpleSignupAuthUser user, final Context ctx) {
    return Messages.get("imcollector.auth.email.subject.verify_email");
  }

  protected abstract Call getAccountVerifyCall(String token);

  @Override
  protected UsernamePasswordAuthProvider.LoginResult loginUser(final SimpleLoginAuthUser authUser) {
    try {
      final UserDAO dao = AuthFactoryBuilder.getFactory().getUserDAO();
      final User u = dao.find(authUser);
      if (!u.isEmailValidated()) {
        return LoginResult.USER_UNVERIFIED;
      } else {
        for (final LinkedAccount acc : u.getLinkedAccounts()) {
          if (getKey().equals(acc.getProvider())) {
            if (authUser.checkPassword(acc.getUserId(), authUser.getPassword())) {
              // Password was correct
              return LoginResult.USER_LOGGED_IN;
            } else {
              // if you don't return here,
              // you would allow the user to have
              // multiple passwords defined
              // usually we don't want this
              return LoginResult.WRONG_PASSWORD;
            }
          }
        }
        return LoginResult.WRONG_PASSWORD;
      }
    } catch (final UserNotFoundException e) {
      return LoginResult.NOT_FOUND;
    }
  }

  @Override
  protected UsernamePasswordAuthProvider.SignupResult signupUser(final SimpleSignupAuthUser user) {
    final UserDAO dao = AuthFactoryBuilder.getFactory().getUserDAO();
    try {
      final User u = dao.find(user);
      if (u.isEmailValidated()) {
        // This user exists, has its email validated and is active
        return SignupResult.USER_EXISTS;
      } else {
        // this user exists, is active but has not yet validated its
        // email
        return SignupResult.USER_EXISTS_UNVERIFIED;
      }
    } catch (final UserNotFoundException e) {
      // The user either does not exist or is inactive - create a new one
      final User newUser = dao.create(user);
      LOGGER.debug("New user created {}", newUser);
      // Usually the email should be verified before allowing login, however
      // if you return
      // return SignupResult.USER_CREATED;
      // then the user gets logged in directly
      return SignupResult.USER_CREATED_UNVERIFIED;
    }
  }

  @Override
  protected SimpleLoginAuthUser transformAuthUser(final SimpleSignupAuthUser authUser, final Context context) {
    return new SimpleLoginAuthUser(authUser.getEmail());
  }

  private Class loadTemplateClass(final String templateClassName) throws ClassNotFoundException {
    return Thread.currentThread().getContextClassLoader().loadClass(templateClassName);
  }

  private Class findTemplateClass(final String template, final String lang) {
    try {
      return loadTemplateClass(template + "_" + lang);
    } catch (final ClassNotFoundException e) {
      LOGGER.warn("Template {} could not be found in requested language {}", template, lang);
      try {
        return loadTemplateClass(template + "_" + EMAIL_TEMPLATE_FALLBACK_LANGUAGE);
      } catch (final ClassNotFoundException ee) {
        LOGGER.error("Template {} could not be found in fallback language {}", template,
            EMAIL_TEMPLATE_FALLBACK_LANGUAGE);
        return null;
      }
    }
  }

  private String getEmailTemplate(final String template, final String langCode, final String url, final String token,
      final String name, final String email) {
    final Class cls = findTemplateClass(template, langCode);
    if (cls == null) {
      throw new IllegalArgumentException("No email template available for " + template);
    } else {
      try {
        final Method htmlRender = cls.getMethod("render", String.class, String.class, String.class, String.class);
        return htmlRender.invoke(null, url, token, name, email).toString();
      } catch (final Exception e) {
        LOGGER.error("Cannot invoke render for emailTemplate {}", template, e);
        throw new IllegalStateException("Failed to render email template", e);
      }
    }
  }

  public void sendPasswordResetMailing(final User user, final Context ctx) {
    final String token = generatePasswordResetRecord(user);
    final String subject = getPasswordResetMailingSubject(user, ctx);
    final Body body = getPasswordResetMailingBody(token, user, ctx);
    sendMail(subject, body, getEmailName(user));
  }

  public void sendVerifyEmailMailingAfterSignup(final User user, final Context ctx) {

    final String subject = getVerifyEmailMailingSubjectAfterSignup(user, ctx);
    final String token = generateVerificationRecord(user);
    final Body body = getVerifyEmailMailingBodyAfterSignup(token, user, ctx);
    sendMail(subject, body, getEmailName(user));
  }

  private Body getVerifyEmailMailingBodyAfterSignup(final String token, final User user, final Context ctx) {

    final boolean isSecure = getConfiguration().getBoolean(SETTING_KEY_VERIFICATION_LINK_SECURE);
    final String url = getAccountVerifyCall(token).absoluteURL(ctx.request(), isSecure);

    final Lang lang = Lang.preferred(ctx.request().acceptLanguages());
    final String langCode = lang.code();

    final String html = getEmailTemplate("views.html.account.email.verify_email", langCode, url, token, user.getName(),
        user.getEmail());
    final String text = getEmailTemplate("views.txt.account.email.verify_email", langCode, url, token, user.getName(),
        user.getEmail());

    return new Body(text, html);
  }

  private String getVerifyEmailMailingSubjectAfterSignup(final User user, final Context ctx) {
    return Messages.get("imcollector.auth.email.subject.verify_signup");
  }

  private Body getPasswordResetMailingBody(final String token, final User user, final Context ctx) {

    final boolean isSecure = getConfiguration().getBoolean(SETTING_KEY_PASSWORD_RESET_LINK_SECURE);
    final String url = getAccountResetPasswordCall(token).absoluteURL(ctx.request(), isSecure);

    final Lang lang = Lang.preferred(ctx.request().acceptLanguages());
    final String langCode = lang.code();

    final String html = getEmailTemplate("views.html.account.email.password_reset", langCode, url, token,
        user.getName(), user.getEmail());
    final String text = getEmailTemplate("views.txt.account.email.password_reset", langCode, url, token,
        user.getName(), user.getEmail());

    return new Body(text, html);
  }

  protected abstract Call getAccountResetPasswordCall(String token);

  private String getPasswordResetMailingSubject(final User user, final Context ctx) {
    return Messages.get("imcollector.auth.email.subject.password_reset");
  }

  private String getEmailName(final User user) {
    return getEmailName(user.getEmail(), user.getName());
  }

  private String generatePasswordResetRecord(final User user) {
    final String token = generateToken();
    AuthFactoryBuilder.getFactory().getTokenActionDAO().create(TokenType.PASSWORD_RESET, token, user);
    return token;
  }

  private static String generateToken() {
    return UUID.randomUUID().toString();
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy