NAME

Concierge::Auth::Pwd - Password-file Concierge::Auth backend using Crypt::Passphrase

VERSION

v0.5.2

SYNOPSIS

use Concierge::Auth::Pwd;

# Initialize with a password file
my $auth = Concierge::Auth::Pwd->new( file => '/path/to/auth.pwd' );

# Or without a file (generators and utilities only)
my $auth = Concierge::Auth::Pwd->new( no_file => 1 );

# --- Concierge::Auth::Base contract methods ---

my $result = $auth->enroll('alice', 'secret123');
my $result = $auth->authenticate('alice', 'secret123');
my $result = $auth->is_id_known('alice');
my $result = $auth->change_credentials('alice', 'newsecret456');
my $result = $auth->revoke('alice');

# --- Backend-specific methods (password-file only) ---

my ($ok, $msg) = $auth->setFile('/path/to/other.pwd');
my $hash        = $auth->encryptPwd('secret123');

# Generate tokens and random values (inherited from Concierge::Auth::Base)
my ($uuid, $msg)   = $auth->gen_uuid();           # v4 UUID
my ($id, $msg)     = $auth->gen_random_id();       # 40-char hex ID
my ($token, $msg)  = $auth->gen_random_token(32);
my ($string, $msg) = $auth->gen_random_string(16);
my ($phrase, $msg) = $auth->gen_word_phrase(4, 4, 7, '-');

DESCRIPTION

Concierge::Auth::Pwd is the built-in password-file backend for Concierge::Auth. It implements the Concierge::Auth::Base contract (authenticate, is_id_known, enroll, change_credentials, revoke) on top of a password store backed by Crypt::Passphrase with Argon2 encoding and Bcrypt validation for legacy password migration. Passwords are stored in a tab-separated file with file-locking for concurrent access.

Token and random value generation (gen_uuid, gen_random_id, gen_random_token, gen_random_string, gen_word_phrase) is not implemented by this module -- it is inherited from Concierge::Auth::Base's default implementations, which delegate to Concierge::Auth::Generators (using Crypt::PRNG for cryptographically secure random output). See "The Generators Guarantee" in Concierge::Auth::Base.

Concierge::Auth::Pwd is the default fully functional backend class provided with Concierge::Auth.

Three Method Layers

This module itself defines three layers of methods:

  • Contract methods that provide the interface defined by Concierge::Auth::Base:

    • authenticate

    • is_id_known

    • enroll

    • change_credentials

    • revoke

    Each of these methods must return its results in the form of a hashref with { success = 1|0, message => '...' }>, allowing the calling application to keep control even if the method fails.

  • Methods specific to how this backend class manages its password file, independent of, but in service to, the contract methods above.

  • Generator methods for creating secure tokens and random values. Generator methods are automatically provided from Concierge::Auth::Generators, but may be overridden; Concierge::Auth::Pwd does not override any of them.

CONSTRUCTOR

new

my $auth = Concierge::Auth::Pwd->new(%args);

Creates a new backend object. The Crypt::Passphrase encoder (Argon2) is initialized immediately.

Arguments:

file -- path to the password file. Created if it does not exist. File permissions are set to 0600. Croaks if the file cannot be opened or created.
no_file -- if true, skip file setup. The object can still generate tokens and hash passwords, but cannot perform ID or password checks.

If neither file nor no_file is provided, the object is still created (with a warning), but file-dependent methods will fail.

CONTRACT METHODS

authenticate

my $result = $auth->authenticate($user_id, $password);

Verifies that $password is valid for $user_id. Pure check, no side effects. Malformed/empty IDs or passwords are rejected without a file scan; a wrong-length password otherwise simply fails to match the stored hash, so no separate format check is applied to it here.

Returns { success = 1 }> or { success = 0, message => '...' }>.

is_id_known

my $result = $auth->is_id_known($user_id);

Checks whether $user_id has a record in the password file. Empty, malformed, or missing IDs and missing files are all simply "not known" for this backend -- there is no failure branch short of a genuine I/O error on a file that does exist.

Returns { success = 1, known => 1|0 }>.

enroll

my $result = $auth->enroll($user_id, $password);

Creates a new password record for $user_id. $user_id must meet the length and character constraints (this is the only contract method that enforces ID format policy, since it's the only one establishing a new ID). Fails if the ID already exists (use change_credentials to change an existing password).

Returns { success = 1, user_id => $user_id, status => 'created' }> or { success = 0, message => '...' }>.

change_credentials

my $result = $auth->change_credentials($user_id, $new_password);

Replaces the stored password hash for an existing $user_id. Fails if the ID is not found.

Returns { success = 1, user_id => $user_id }> or { success = 0, message => '...' }>.

revoke

my $result = $auth->revoke($user_id);

Removes the password record for $user_id. Fails if the ID is not found. No ID format policy check is applied -- a malformed-but-nonempty ID simply fails to match any record on file.

Returns { success = 1, user_id => $user_id }> or { success = 0, message => '...' }>.

validatePwd

my $result = $auth->validatePwd($password);

Checks whether $password meets the length constraints. Shared by enroll and change_credentials, both of which establish a new credential value; not used by authenticate, since a wrong-length submitted password simply fails to match the stored hash.

Returns { success = 1 }> or { success = 0, message => '...' }>.

BACKEND-SPECIFIC METHODS

File Management

setFile

my ($ok, $msg) = $auth->setFile($path);

Sets (or changes) the password file path. Creates the file if it does not exist and sets permissions to 0600.

rmFile

my ($file, $msg) = $auth->rmFile();

Deletes the password file and clears the stored path. In list context, returns the deleted file path on success.

clearFile

my ($ok, $msg) = $auth->clearFile();

Removes and re-creates the password file, effectively deleting all records.

pfile

my ($file, $msg) = $auth->pfile();

Returns the path to the configured password file.

Utilities

encryptPwd

my $hash = $auth->encryptPwd($password);

Returns the Argon2 hash of $password. Validates password constraints first.

Token and Value Generation

gen_uuid, gen_random_id, gen_random_token, gen_random_string, and gen_word_phrase are available on every instance but are not implemented in this module -- they are inherited default implementations from Concierge::Auth::Base, which delegate to Concierge::Auth::Generators and use its dual-return convention: ($value, $message) in list context, $value in scalar context. See "GENERATOR METHODS" in Concierge::Auth::Base for the full list and "The Generators Guarantee" in Concierge::Auth::Base for why this backend does not need to (but could) override them.

SEE ALSO

Concierge::Auth::Base -- the backend contract this module implements

Concierge::Auth::Generators -- functional interface to the generators

Concierge::Sessions, Concierge::Users -- companion Concierge components

Crypt::Passphrase, Crypt::PRNG

AUTHOR

Bruce Van Allen <bva@cruzio.com>

LICENSE

This module is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0.