[Jifty-commit] r2863 - in jifty/branches/template-declare: .
lib/Jifty/Plugin/Authentication/Password/Model
jifty-commit at lists.jifty.org
jifty-commit at lists.jifty.org
Tue Feb 27 23:11:27 EST 2007
Author: jesse
Date: Tue Feb 27 23:11:26 2007
New Revision: 2863
Added:
jifty/branches/template-declare/lib/Jifty/Plugin/Authentication/Password/Action/
jifty/branches/template-declare/lib/Jifty/Plugin/Authentication/Password/Action/GeneratePasswordToken.pm (contents, props changed)
jifty/branches/template-declare/lib/Jifty/Plugin/Authentication/Password/Action/Login.pm (contents, props changed)
Modified:
jifty/branches/template-declare/ (props changed)
jifty/branches/template-declare/lib/Jifty/Plugin/Authentication/Password/Model/User.pm
Log:
r48594 at pinglin: jesse | 2007-02-27 23:09:39 -0500
* Extracting code from hiveminder to do login and password checks.
Added: jifty/branches/template-declare/lib/Jifty/Plugin/Authentication/Password/Action/GeneratePasswordToken.pm
==============================================================================
--- (empty file)
+++ jifty/branches/template-declare/lib/Jifty/Plugin/Authentication/Password/Action/GeneratePasswordToken.pm Tue Feb 27 23:11:26 2007
@@ -0,0 +1,53 @@
+use warnings;
+use strict;
+
+=head1 NAME
+
+Jifty::Plugin::Authentication::PasswordAction::GeneratePasswordToken
+
+=cut
+
+package Jifty::Plugin::Authentication::PasswordAction::GeneratePasswordToken;
+use base qw/Jifty::Action/;
+
+=head2 arguments
+
+We need the username of the user we're fetching a token for, so we can
+return the salt.
+
+=cut
+
+sub arguments {
+ return( { username => { mandatory => 1 } });
+
+}
+
+
+=head2 take_action
+
+Generate a token and throw it back to the browser. Also, return the
+user's password salt in $self->result->content.
+
+
+=cut
+
+sub take_action {
+ my $self = shift;
+
+ my $username = $self->argument_value('username');
+ my $class = Jifty->app_class('Model','User');
+ my $user = $class->new(current_user => Jifty::CurrentUser->superuser);
+ $user->load_by_cols(username => $username);
+ unless($user->id) {
+ $self->result->error('No such user');
+ }
+
+ my $password = $user->_value('password');
+
+ my $token = time();
+ $self->result->content(token => $token);
+ $self->result->content(salt => ($password ? $password->[1] : ""));
+ Jifty->web->session->set(login_token => $token);
+}
+
+1;
Added: jifty/branches/template-declare/lib/Jifty/Plugin/Authentication/Password/Action/Login.pm
==============================================================================
--- (empty file)
+++ jifty/branches/template-declare/lib/Jifty/Plugin/Authentication/Password/Action/Login.pm Tue Feb 27 23:11:26 2007
@@ -0,0 +1,166 @@
+use warnings;
+use strict;
+
+=head1 NAME
+
+Jifty::Plugin::Authentication::Password::Action::Login
+
+=cut
+
+package Jifty::Plugin::Authentication::Password::Action::Login;
+use base qw/Jifty::Action/;
+use Digest::MD5 qw(md5_hex);
+
+use constant TOKEN_EXPIRE_TIME => 30;
+
+=head2 arguments
+
+Return the username and password form fields
+
+=cut
+
+sub arguments {
+ return( { username => { label => 'Email username',
+ mandatory => 1,
+ ajax_validates => 1,
+ } ,
+
+ password => { type => 'password',
+ label => 'Password',
+ # mandatory in some cases; see validate_password
+ mandatory => 0,
+ },
+ hashed_password => { type => 'hidden',
+ label => 'Hashed Password',
+ },
+ remember => { type => 'checkbox',
+ label => 'Remember me?',
+ hints => 'Your browser can remember your login for you',
+ default => 0,
+ },
+ token => { type => 'hidden',
+ label => 'token',
+ mandatory => 0 },
+
+ });
+
+}
+
+=head2 validate_username ADDRESS
+
+Makes sure that the username submitted is a legal username and that there's a user in the database with it.
+
+Overridden from Jifty::Action::Record.
+
+=cut
+
+sub validate_username {
+ my $self = shift;
+ my $username = shift;
+
+ my $u = Jifty::Plugin::Authentication::Password::Model::User->new(current_user => Jifty::Plugin::Authentication::Password::CurrentUser->superuser);
+ $u->load_by_cols( username => $username );
+ return $self->validation_error(username => 'We do not have an account that matches that username.') unless ($u->id);
+
+ return $self->validation_ok('username');
+}
+
+
+=head2 validate_password PASSWORD
+
+Makes sure that the password submitted actually exists, unless there's a token and a hashed
+password.
+
+Overridden from Jifty::Action::Record.
+
+=cut
+
+sub validate_password {
+ my $self = shift;
+ my $pw = shift;
+ my $token = $self->argument_value('token') ||'';
+ my $hashedpw = $self->argument_value('hashed_password') ;
+
+
+ if ($token eq '') { # we have no token, validate in a standard way
+ if ($pw eq '') {
+ return $self->validation_error(password => "Please fill in this field." );
+ }
+ } else { # we have a token, so we should have a hashed pw
+ my $emptypw = '';
+ my $blankhash = md5_hex("$token $emptypw");
+ if ($hashedpw eq $blankhash) {
+ return $self->validation_error(password => "Please fill in this field." );
+ }
+
+ }
+
+
+ return $self->validation_ok('password');
+}
+
+=head2 validate_token TOKEN
+
+Make sure we issued the token within the last 30 seconds, otherwise
+time out the request.
+
+=cut
+
+sub validate_token {
+ my $self = shift;
+ my $value = shift;
+ if ($value) {
+ if(int $value < (time - TOKEN_EXPIRE_TIME)) {
+ return $self->validation_error(token => "Your login attempt has timed out. Please try again.");
+ }
+ if ($value ne Jifty->web->session->get('login_token')) {
+ return $self->validation_error(token => "That didn't work. Please try again.");
+ }
+ Jifty->web->session->set(login_token => '');
+ }
+ return $self->validation_ok("token");
+}
+
+=head2 take_action
+
+Actually check the user's password. If it's right, log them in.
+Otherwise, throw an error.
+
+
+=cut
+
+sub take_action {
+ my $self = shift;
+ my $user = Jifty->app_class('CurrentUser')->new( username => $self->argument_value('username'));
+
+ my $password = $self->argument_value('password');
+ my $token = $self->argument_value('token') || '';
+ my $hashedpw = $self->argument_value('hashed_password');
+
+ if ($token ne '') { # browser supports javascript, do password hashing
+ unless ( $user->id && $user->hashed_password_is($hashedpw, $token)){
+ $self->result->error( 'You may have mistyped your username or password. Give it another shot.' );
+ return;
+ }
+ Jifty->web->session->set(login_token => '');
+ }
+ else { # no password hashing over the wire
+ unless ( $user->id && $user->password_is($password)){
+ $self->result->error( 'You may have mistyped your username or password. Give it another shot.' );
+ return;
+ }
+ }
+
+
+ # Set up our login message
+ $self->result->message("Welcome back, " . $user->user_object->name . "." );
+
+ # Actually do the signin thing.
+ Jifty->web->current_user($user);
+ Jifty->web->session->expires($self->argument_value('remember') ? '+1y' : undef);
+ Jifty->web->session->set_cookie;
+
+ return 1;
+}
+
+1;
Modified: jifty/branches/template-declare/lib/Jifty/Plugin/Authentication/Password/Model/User.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Plugin/Authentication/Password/Model/User.pm (original)
+++ jifty/branches/template-declare/lib/Jifty/Plugin/Authentication/Password/Model/User.pm Tue Feb 27 23:11:26 2007
@@ -5,11 +5,119 @@
use Jifty::DBI::Schema;
use base 'Jifty::DBI::Record::Plugin';
use Jifty::Plugin::Authentication::Password::Record schema {
- column password => type is 'text', render as 'Password', is unreadable;
+
+
+column auth_token =>
+ render_as 'unrendered',
+ type is 'varchar',
+ default is '',
+ label is 'Athentication token',
+ since '0.2.34';
+
+
+
+column password =>
+ is mandatory,
+ is unreadable,
+ label is 'Password',
+ type is 'varchar',
+ hints is 'Your password should be at least six characters',
+ render_as 'password',
+ filters are 'Jifty::DBI::Filter::SaltHash';
+
+
};
-# Your model-specific methods go here.
+
+=head2 password_is PASSWORD
+
+Checks if the user's password matches the provided I<PASSWORD>.
+
+=cut
+
+sub password_is {
+ my $self = shift;
+ my $pass = shift;
+
+ return undef unless $self->_value('password');
+
+ my ($hash, $salt) = @{$self->_value('password')};
+
+ return 1 if ( $hash eq Digest::MD5::md5_hex($pass . $salt) );
+ return undef;
+
+}
+
+=head2 hashed_password_is HASH TOKEN
+
+Check if the given I<HASH> is the result of hashing our (already
+salted and hashed) password with I<TOKEN>
+
+=cut
+
+sub hashed_password_is {
+ my $self = shift;
+ my $hash = shift;
+ my $token = shift;
+
+ my $password = $self->_value('password');
+ return $password && Digest::MD5::md5_hex("$token " . $password->[0]) eq $hash;
+}
+
+
+=head2 validate_password
+
+Makes sure that the password is six characters long or longer.
+
+=cut
+
+sub validate_password {
+ my $self = shift;
+ my $new_value = shift;
+
+ return ( 0, q{Passwords need to be at least six characters long} )
+ if length($new_value) < 6;
+
+ return 1;
+}
+
+
+sub after_create {
+ my $self = shift;
+ $self->regenerate_auth_token;
+
+
+}
+
+=head2 after_set_password
+
+Regenerate auth tokens on password change
+
+=cut
+
+sub after_set_password {
+ my $self = shift;
+ $self->regenerate_auth_token;
+}
+
+=head2 regenerate_auth_token
+
+Generate a new auth_token for this user. This will invalidate any
+existing feed URLs.
+
+=cut
+
+sub regenerate_auth_token {
+ my $self = shift;
+ my $auth_token = '';
+
+ $auth_token .= unpack('H2', chr(int rand(255))) for (1..16);
+
+ $self->set_auth_token($auth_token);
+}
+
+
1;
More information about the Jifty-commit
mailing list