// This may look like C code, but it's really -*- C++ -*-
/*
 * Copyright (C) 2011 Emweb bvba, Kessel-Lo, Belgium.
 *
 * See the LICENSE file for terms of use.
 */
#ifndef WT_AUTH_ABSTRACT_PASSWORD_AUTH_H_
#define WT_AUTH_ABSTRACT_PASSWORD_AUTH_H_

#include <Wt/WValidator>
#include <Wt/WString>

#include <Wt/Auth/User>

namespace Wt {
  namespace Auth {

class AuthService;
class User;

/*! \brief Enumeration for a password verification result
 *
 * \sa AbstractPasswordService::verifyPassword()
 *
 * \ingroup auth
 */
enum PasswordResult {
  PasswordInvalid, //!< The password is invalid
  LoginThrottling, //!< The attempt was not processed because of throttling
  PasswordValid    //!< The password is valid
};

/*! \class AbstractPasswordService Wt/Auth/AbstractPasswordService
 *  \brief Abstract password authentication service
 *
 * This abstract class defines the interface for password authentication.
 *
 * It provides methods to verify a password, to update a password, and to
 * throttle password verification attempts.
 *
 * \sa PasswordService a default implementation
 *
 * \ingroup auth
 */
class WT_API AbstractPasswordService
{
public:
  /*! \class AbstractStrengthValidator
   *  \brief Validator for password strength.
   *
   * This class defines a specialized validator interface for evaluating
   * password strength. The implementation allows to evaluate strength on
   * a numeric scale (from 0 to 5) in addition to the normal validator
   * functionality of validating a password.
   *
   * The actual computation is done by validateStrength(), which returns
   * an opaque number that is interpreted with isValid(), message() and
   * strength() methods.
   *
   * \sa strengthValidator()
   */
  class WT_API AbstractStrengthValidator : public Wt::WValidator
  {
  public:
    /*! \brief Evaluates the strength of a password.
     *
     * The result is an opaque number which is interpreted by
     * isValid(), message() and strength().
     *
     * The validator may take into account the user's login name and
     * email address, to exclude passwords that are too similar to
     * these.
     */
    virtual int evaluateStrength(const WT_USTRING& password,
				 const WT_USTRING& loginName,
				 const std::string& email) const = 0;

    /*! \brief Returns whether the password is considered strong enough.
     *
     * This is used by validate() to return the validation state.
     */
    virtual bool isValid(int result) const = 0;

    /*! \brief Returns a message describing a password strength.
     *
     * When the password is not strong enough, this should return a message
     * which helps the user pick a stronger password.
     */
    virtual WString message(int result) const = 0;

    /*! \brief Returns the password strength in a scale of 0 to 5.
     *
     * The default implementation simply returns 5 for a valid, and 0
     * for an invalid password.
     *
     * \note This is currently not used.
     */
    virtual int strength(int result) const;

    /*! \brief Validates a password.
     *
     * This uses evaluateStrength(), isValid() and message() to return the
     * result of password validation.
     */
    virtual Result validate(const WT_USTRING& password,
			    const WT_USTRING& loginName,
			    const std::string& email) const;

    /*! \brief Validates a password.
     *
     * Calls validate(password, WString::Empty, "");
     */
    virtual Result validate(const WT_USTRING& password) const;
  };

  /*! \brief Destructor.
   */
  virtual ~AbstractPasswordService();

  /*! \brief Returns the basic authentication service.
   */
  virtual const AuthService& baseAuth() const = 0;

  /*! \brief Returns whether password attempt throttling is enabled.
   */
  virtual bool attemptThrottlingEnabled() const = 0;

  /*! \brief Returns a validator which checks that a password is strong enough.
   */
  virtual AbstractStrengthValidator *strengthValidator() const = 0;

  /*! \brief Returns the delay for this user for a next authentication
   *         attempt.
   *
   * If password attempt throttling is enabled, then this returns the
   * number of seconds this user must wait for a new authentication
   * attempt, presumably because of a number of failed attempts.
   *
   * \sa attemptThrottlingEnabled()
   */
  virtual int delayForNextAttempt(const User& user) const = 0;

  /*! \brief Verifies a password for a given user.
   *
   * The supplied password is verified against the user's credentials
   * stored in the database. If password account throttling is
   * enabled, it may also refuse an authentication attempt.
   *
   * \sa setVerifier(), setAttemptThrottlingEnabled()
   */
  virtual PasswordResult verifyPassword(const User& user,
					const WT_USTRING& password) const = 0;

  /*! \brief Sets a new password for the given user.
   *
   * This stores a new password for the user in the database. 
   */
  virtual void updatePassword(const User& user, const WT_USTRING& password)
    const = 0;
};

  }
}

#endif // WT_AUTH_ABSTRACT_PASSWORD_AUTH
