NAME

Plack::Middleware::Auth::Complex - Feature-rich authentication system

SYNOPSIS

use Plack::Builder;

builder {
  enable 'Auth::Complex', dbi_connect => ['dbi:Pg:dbname=mydb', '', ''], mail_from => 'nobody@example.org';
  sub {
    my ($env) = @_;
    [200, [], ['Hello ' . ($env->{REMOTE_USER} // 'unregistered user')]]
  }
}

DESCRIPTION

AuthComplex is an authentication system for Plack applications that allows user registration, password changing and password reset.

AuthComplex sets REMOTE_USER if the request includes correct basic authentication and intercepts POST requests to some configurable URLs. It also sets $env->{authcomplex} to itself before passing the request.

Some options can be controlled by passing a hashref to the constructor. More customization can be achieved by subclassing this module.

Intercepted URLs

Only POST requests are intercepted. Parameters can be either query parameters or body parameters. Using query parameters is not recommended. These endpoints return 200 for success, 400 for client error and 500 for server errors. All parameters are mandatory.

POST /action/register?username=user&password=pw&confirm_password=pw&email=user@example.org

This URL creates a new user with the given username, password and email. The two passwords must match, the user must match username_regex and the user must not already exist.

POST /action/passwd?password=oldpw&new_password=newpw&confirm_new_password=newpw

This URL changes the password of a user. The user must be authenticated (otherwise the endpoint will return 401).

POST /action/request-reset?username=user

This URL requests a password reset token for the given user. The token will be sent to the user's email address.

A reset token in the default implementation is base64(HMAC-SHA1("$username $passphrase $expiration_unix_time")) . ":$expiration_user_time".

POST /action/reset?username=user&new_password=pw&confirm_new_password=pw&token=token

This URL performs a password reset.

Constructor arguments

dbi_connect

Arrayref of arguments to pass to DBI->connect. Defaults to ['dbi:Pg', '', ''].

entropy_source

Data::Entropy::Source object to get random numbers from. By default uses /dev/urandom via Data::Entropy::RawSource::Local if possible, or the default entropy source otherwise. A warning is printed if the default entropy source is used, to supress it set this argument to the default entropy source.

use_scrypt

Boolean determining whether to use the scrypt algorithm via the Authen::Passphrase::Scrypt module.

If true, the default implementation of hash_passphrase uses scrypt and check_passphrase accepts scrypt passphrases (in addition to passphrases supported by Authen::Passphrase).

If false, the default implementation of hash_passphrase uses bcrypt and check_passphrase only accepts passphrases supported by Authen::Passphrase.

The default value is true if Authen::Passphrase::Scrypt is installed, false otherwise.

post_connect_cb

Callback (coderef) that is called just after connecting to the database. Used by the testsuite to create the users table.

select_user

SQL statement that selects a user by username. Defaults to 'SELECT id, passphrase, email FROM users WHERE id = ?'.

update_pass

SQL statement that updates a user's password. Defaults to 'UPDATE users SET passphrase = ? WHERE id = ?'.

insert_user

SQL statement that inserts a user. Defaults to 'INSERT INTO users (id, passphrase, email) VALUES (?,?,?)'.

hmackey

HMAC key used for password reset tokens. If not provided it is generated randomly, in which case reset tokens do not persist across application restarts.

mail_from

From: header of password reset emails. If not provided, password reset is disabled.

mail_subject

The subject of password reset emails. Defaults to 'Password reset token'.

realm

Authentication realm. Defaults to 'restricted area'.

cache_fail

If true, all authentication results are cached. If false, only successful logins are cached. Defaults to false.

cache_max_age

Authentication cache timeout, in seconds. Authentication results are cached for this number of seconds to avoid expensive hashing. Defaults to 5 minutes.

token_max_age

Password reset token validity, in seconds. Defaults to 1 hour.

username_regex

Regular expression that matches valid usernames. Defaults to qr/^\w{2,20}$/as.

invalid_username

Error message returned when the username does not match username_regex. Defaults to 'Invalid username'

register_url

URL for registering. Defaults to '/action/register'.

passwd_url

URL for changing your password. Defaults to '/action/passwd'.

request_reset_url

URL for requesting a password reset token by email. Defaults to '/action/request-reset'.

reset_url

URL for resetting your password with a reset token. Defaults to '/action/reset'.

Methods

default_opts

Returns a list of default options for the constructor.

new(\%opts)

Creates a new AuthComplex object.

init

Called when the first request is received. The default implementation connects to the database, calls post_connect_cb and prepares the SQL statements.

create_user($parms)

Inserts a new user into the database. $parms is a Hash::MultiValue object containing the request parameters.

get_user($username)

Returns a hashref with (at least) the following keys: passphrase (the RFC2307-formatted passphrase of the user), email (the user's email address).

check_passphrase($username, $passphrase)

Returns true if the given plaintext passphrase matches the one obtained from database. Default implementation uses Authen::Passphrase (and Authen::Passphrase::Scrypt if use_scrypt is true).

hash_passphrase($passphrase)

Returns a RFC2307-formatted hash of the passphrase.

If use_scrypt is true, default implementation uses Authen::Passphrase::Scrypt with default parameters.

If use_scrypt is false, default implementation uses Authen::Passphrase::BlowfishCrypt with a cost of 10 and a random salt.

set_passphrase($username, $passphrase)

Changes a user's passphrase to the given value.

make_reset_hmac($username, [@data])

Returns the HMAC part of the reset token.

mail_body($username, $token)

Returns the body of the password reset email for the given username and password reset token.

send_reset_email($username)

Generates a new reset token and sends it to the user via email.

response($code, $body)

Helper method. Returns a PSGI response with the given response code and string body.

reply($message)

Shorthand for response(200, $message).

bad_request($message)

Shorthand for response(400, $message).

internal_server_error($message)

Shorthand for response(500, $message).

unauthorized

Returns a 401 Authorization required response.

call_register($req)

Handles the /action/register endpoint. $req is a Plack::Request object.

call_passwd($req)

Handles the /action/passwd endpoint. $req is a Plack::Request object.

call_request_reset($req)

Handles the /action/request-reset endpoint. $req is a Plack::Request object.

call_reset($req)

Handles the /action/reset endpoint. $req is a Plack::Request object.

AUTHOR

Marius Gavrilescu, <marius@ieval.ro>

COPYRIGHT AND LICENSE

Copyright (C) 2015-2017 by Marius Gavrilescu

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.20.1 or, at your option, any later version of Perl 5 you may have available.