3 package Catalyst::Plugin::Authentication::Credential::Password;
9 use Catalyst::Exception ();
13 my ( $c, $user, $password, @rest ) = @_;
19 $user = $_->param("login")
21 || $_->param("username")
24 "Can't login a user without a user object or user ID param")
32 $password = $_->param("password")
33 || $_->param("passwd")
36 $c->log->debug("Can't login a user without a password")
42 unless ( Scalar::Util::blessed($user)
43 and $user->isa("Catalyst::Plugin::Authentication::User") )
45 if ( my $user_obj = $c->get_user( $user, $password, @rest ) ) {
49 $c->log->debug("User '$user' doesn't exist in the default store")
55 if ( $c->_check_password( $user, $password ) ) {
56 $c->set_authenticated($user);
57 $c->log->debug("Successfully authenticated user '$user'.")
63 "Failed to authenticate user '$user'. Reason: 'Incorrect password'")
70 my ( $c, $user, $password ) = @_;
72 if ( $user->supports(qw/password clear/) ) {
73 return $user->password eq $password;
75 elsif ( $user->supports(qw/password crypted/) ) {
76 my $crypted = $user->crypted_password;
77 return $crypted eq crypt( $password, $crypted );
79 elsif ( $user->supports(qw/password hashed/) ) {
81 my $d = Digest->new( $user->hash_algorithm );
82 $d->add( $user->password_pre_salt || '' );
84 $d->add( $user->password_post_salt || '' );
86 my $stored = $user->hashed_password;
87 my $computed = $d->clone()->digest;
88 my $b64computed = $d->clone()->b64digest;
90 return ( ( $computed eq $stored )
91 || ( unpack( "H*", $computed ) eq $stored )
92 || ( $b64computed eq $stored)
93 || ( $b64computed.'=' eq $stored) );
95 elsif ( $user->supports(qw/password salted_hash/) ) {
96 require Crypt::SaltedHash;
99 $user->can("password_salt_len") ? $user->password_salt_len : 0;
101 return Crypt::SaltedHash->validate( $user->hashed_password, $password,
104 elsif ( $user->supports(qw/password self_check/) ) {
106 # while somewhat silly, this is to prevent code duplication
107 return $user->check_password($password);
111 Catalyst::Exception->throw(
112 "The user object $user does not support any "
113 . "known password authentication mechanism." );
125 Catalyst::Plugin::Authentication::Credential::Password - Authenticate a user
132 Authentication::Store::Foo
133 Authentication::Credential::Password
136 package MyApp::Controller::Auth;
139 # if you place an action named 'login' in your application's root (as
140 # opposed to inside a controller) the following snippet will recurse,
141 # giving you lots of grief.
142 # never name actions in the root controller after plugin methods - use
143 # controllers and : Global instead.
146 my ( $self, $c ) = @_;
148 $c->login( $c->req->param('username'), $c->req->param('password') );
153 This authentication credential checker takes a username (or userid) and a
154 password, and tries various methods of comparing a password based on what
155 the chosen store's user objects support:
159 =item clear text password
161 If the user has clear a clear text password it will be compared directly.
163 =item crypted password
165 If UNIX crypt hashed passwords are supported, they will be compared using
166 perl's builtin C<crypt> function.
168 =item hashed password
170 If the user object supports hashed passwords, they will be used in conjunction
179 =item login $username, $password
181 Try to log a user in.
183 C<$username> can be a string (e.g. retrieved from a form) or an object.
184 If the object is a L<Catalyst::Plugin::Authentication::User> it will be used
185 as is. Otherwise C<< $c->get_user >> is used to retrieve it.
187 C<$password> is a string.
189 If C<$username> or C<$password> are not provided, the query parameters
190 C<login>, C<user>, C<username> and C<password>, C<passwd>, C<pass> will
197 After the user is logged in, the user object for the current logged in user
198 can be retrieved from the context using the C<< $c->user >> method.
200 The current user can be logged out again by calling the C<< $c->logout >>
203 =head1 SUPPORTING THIS PLUGIN
205 For a User class to support credential verification using this plugin, it
206 needs to indicate what sort of password a given user supports
207 by implementing the C<supported_features> method in one or many of the
210 =head2 Clear Text Passwords
214 $user->supported_features(qw/password clear/);
222 Returns the user's clear text password as a string to be compared with C<eq>.
226 =head2 Crypted Passwords
230 $user->supported_features(qw/password crypted/);
236 =item crypted_password
238 Return's the user's crypted password as a string, with the salt as the first two chars.
242 =head2 Hashed Passwords
246 $user->supported_features(qw/password hashed/);
252 =item hashed_password
254 Return's the hash of the user's password as B<binary>.
258 Returns a string suitable for feeding into L<Digest/new>.
260 =item password_pre_salt
262 =item password_post_salt
264 Returns a string to be hashed before/after the user's password. Typically only
269 =head2 Crypt::SaltedHash Passwords
273 $user->supported_features(qw/password salted_hash/);
279 =item hashed_password
281 Returns the hash of the user's password as returned from L<Crypt-SaltedHash>->generate.
289 =item password_salt_len
291 Returns the length of salt used to generate the salted hash.