NAME

Data::Passphrase - rule-based passphrase strength checker

VERSION

This documentation refers to Data::Passphrase version 0.0.7.

SYNOPSIS

Object-oriented interface:

use Data::Passphrase;

# build passphrase object
my $passphrase_object = Data::Passphrase->new({
    username => $ENV{LOGNAME},
});

# evaluate each rule in turn
for (;;) {
    print 'Passphrase (clear): ';
    chomp (my $passphrase = <STDIN>);

    $passphrase_object->set_passphrase($passphrase);
    $passphrase_object->validate();

    my $code    = $passphrase_object->get_code   ();
    my $message = $passphrase_object->get_message();
    my $score   = $passphrase_object->get_score  ();
    print "$code $message, score: $score\%\n";
}

Procedural interface:

use Data::Passphrase qw(validate_passphrase);

for (;;) {
    print 'Passphrase (clear): ';
    chomp (my $passphrase = <STDIN>);

    my $result = validate_passphrase {
        passphrase => $passphrase,
        username   => $ENV{LOGNAME},
    };

    print "$result->{code} $result->{message}, score: $result->{score}\%\n";
}

DESCRIPTION

This module provides object-oriented and procedural interfaces for checking passphrase strength against a set of customizable rules. An Apache handler that provides HTTP and SOAP services makes strength-checking possible by remote applications.

OBJECT-ORIENTED INTERFACE

This module provides an object class for each request, containing the username, the passphrase submitted, configuration data, and more. There is a constructor new, which takes a reference to a hash of initial attribute settings, and accessor methods of the form get_attribute() and set_attribute(). See "Attributes".

The object class overloads string and numeric conversion for convenience when writing rules. In string context, an object evaluates to the text of the passphrase itself. In numeric context, the object evaluates to the length of the passphrase.

Methods

In addition to the constructor and accessor methods, the following special methods are available.

get_data()

$value = $self->get_data($key)

Retrieve custom data $value associated with $key. Useful when a rule needs to cache data for retrieval by subsequent rules.

set_data()

$self->set_data($key, $value)

Associate custom data $value with $key for later retrieval. See also get_data().

validate()

$self->validate()

Evaluate each rule on the passphrase specified by the passphrase attribute. Rules are evaulated in the order specified, each one generating a separate score for the passphrase. The lowest score is returned as the overall passphrase score. After this method is called, the code, message, and score attributes will contain the results of the validation.

Attributes

The attributes below can be accessed via methods of the form get_attribute() and set_attribute().

code

HTTP-like status code to be returned at the end of the request.

debug

If TRUE, enable debugging to STDERR.

message

HTTP-like status message to be returned at the end of the request.

passphrase

The passphrase submitted by the user.

ruleset

The ruleset used to validate passphrases, either as a Data::Passphrase::Ruleset object or as a filename. Defaults to /etc/passphrase_rules.

score

The resultant score, usually between 0 and 100, for the passphrase.

username

The username, which may be useful to rules. Defaults to $r->user().

PROCEDURAL INTERFACE

validate_passphrase()

$results = validate_passphrase \%attributes

Validate a passphrase. Attributes passed in %attributes are the same as for the object-oriented interface. $results contains three entries -- code, message, and score -- whose values correspond to those returned by the object-oriented attributes of the same names.

RULES SPECIFICATION

Passphrase rules may be specified directly as Data::Passphrase::Rule objects or read from a script file (see "EXAMPLES"). This script should return a reference to a list of hash references, each of which is used to construct a Data::Passphrase::Rule object. Hence, the following attributes have meaning to the module and related programs:

code

status code returned if passphrase fails this rule

message

status message returned if passphrase fails this rule

test

passphrase(s) used to test this rule

validate

code to do the validation and return a score

When validating passphrases, each subroutine referenced by validate will be called in turn. If every rule's validate subroutine returns a value exceeding the passing score (which defaults to 0.6), a code of 200 and message of Passphrase accepted will be returned; otherwise, the code and message specified will be returned.

Validation

The validation subroutine is called with two arguments: an Data::Passphrase object, and a reference to a hash of user-defined data. The Data::Passphrase class makes use of operator overloading to allow some convenient syntax in the rules. In string context, the object evaluates to the text of the passphrase to avoid the need to call get_passphrase(). In numeric context, the object evaluates to the length of the passphrase.

Using the set_data() method, a rule can stow away data for use by a later rule. The data is stored as key/value pairs in a hash. A reference to this hash is passed as the second argument to the validate method; you can also use get_data() to get to it.

Return values from the validate subroutine are interpreted as follows:

-1

The candidate passphrase has passed this rule. Return 200 Passphrase accepted without processing any subsequent rules.

0 to < 0.6

The candidate passphrase has failed this rule. Continue with subsequent rules; the lowest score returned by all the rules will be multiplied by 100, have it's non-integer part removed, and returned.

>= 0.6

The candidate passphrase has passed this rule. Continue with subsequent rules and return 200 Passphrase accepted if the passphrase passes all of them. The lowest score returned by all the rules will be multiplied by 100, have it's non-integer part removed, and returned.

Status Codes

For the benefit of the HTTP services provided by Data::Passphrase::Apache, most rules should use codes in the 4xx range, which according to RFC 2616 denotes a client error. It's wise to avoid codes in the 40x or 41x range because they already have common meanings. Choosing a different code for each rule makes it easier for applications to understand why a passphrase was rejected, but it's not required.

Status Messages

The HTTP services provided by Data::Passphrase::Apache build status lines from the code and message attributes. The string "Passphrase " is prepended to the latter. The message should always be phrased as if the passphrase failed to pass the rule, for example, is too short.

Testing

The test attribute specifies one or more passphrases that should fail the rule and is meant to be used by an external program such as the included passphrase-test program. It may be represented in any way understandable by the test program, but passphrase-test expects a single passphrase in a scalar, a reference to an array of one or more passphrases, or a reference to a subroutine that returns zero or more passphrases. This attribute also serves as documentation for the rule in the form of example passphrases the rule is meant to disallow.

EXAMPLES

Here's an example with only one rule:

Readonly my $MINIMUM_TOTAL_CHARACTERS => 15;

return [
    {
        code     => 450,
        message  => 'is too short',
        test     => 'X' x ($MINIMUM_TOTAL_CHARACTERS - 1),
        validate => sub { $_[0] >= $MINIMUM_TOTAL_CHARACTERS },
    },
];
__EOF__

This rule causes 450 Passphrase is too short and a score of 0 to be returned for any passphrase shorter than 15 characters. The validate subroutine can use $_[0] as a comparator because in numeric context it evaluates to the length of the passphrase even though it's an Data::Passphrase object. The test data is just a string of 14 Xs -- the passphrase-test script will check to make sure this string results in a 450.

The validate routine can be written to provide a more informative score:

test     => { 'X' x ($MINIMUM_TOTAL_CHARACTERS - 1)
              => { score => 56 } },
validate => sub { $_[0] / ($MINIMUM_TOTAL_CHARACTERS / 0.6) },

By dividing by a "preferred" length, we get a score that varies based on the length of the candidate passphrase. In this case we divide by 25, which makes 15 a passing score. Specifying a hash for the test attribute lets us test the score of a passphrase that should fail.

For more examples, see the included passphrase_rules file.

FILES

/etc/passphrase_rules

AUTHOR

Andrew J. Korty <ajk@iu.edu>

SEE ALSO

Data::Passphrase::Apache(3), Data::Passphrase::Ruleset(3)