[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