From c24af5b15eeedec8fa84456458d1a6537e1b9887 Mon Sep 17 00:00:00 2001 From: Buchan Milne Date: Wed, 3 Nov 2010 16:14:41 +0000 Subject: Fixed registration sequence for password encryption with cookie instead of session id Initial work on admin password resets of users, email notification to user still not working --- lib/CatDap/Controller/admin.pm | 52 ++++++++++++++++++++++++++++++-- lib/CatDap/Controller/register.pm | 4 +-- lib/CatDap/Controller/user.pm | 62 ++++++++++++++++++++++++++++----------- 3 files changed, 97 insertions(+), 21 deletions(-) (limited to 'lib') diff --git a/lib/CatDap/Controller/admin.pm b/lib/CatDap/Controller/admin.pm index 99e011a..19fa15f 100644 --- a/lib/CatDap/Controller/admin.pm +++ b/lib/CatDap/Controller/admin.pm @@ -3,6 +3,7 @@ use Moose; use namespace::autoclean; use Data::UUID; use Data::Dumper; +use Net::LDAP::Extension::SetPassword; BEGIN { extends 'Catalyst::Controller'; } @@ -168,7 +169,7 @@ sub account_promote : Local { } my $idpool = $mesg->entry; my $uidnum = $idpool->uidNumber; - my $newuidnum = $uidnum++; + my $newuidnum = $uidnum+1; $entry->add( objectclass => [ 'posixAccount', 'ldapPublicKey' ], loginShell => '/bin/bash', @@ -370,7 +371,7 @@ sub account_group : Local { $c->detach('/user/login') if not $c->user; $c->assert_user_roles('Account Admins'); $c->stash( subpages => gensubpages('account') ); - $c->res-redirect($c->uri_for('/admin/account')) if $uid eq ''; + $c->res->redirect($c->uri_for('/admin/account')) if $uid eq ''; my (@errors,@newgroups,@groups); my ($mesg,$entry,$dn); @@ -463,6 +464,53 @@ sub account_addoc : Local { ); } +sub password : Local { + my ($self,$c,$uid) = @_; + $c->detach('/user/login') if not $c->user; + $c->assert_user_roles('Account Admins'); + $c->stash( subpages => gensubpages('account') ); + my (@errors,@mail); + my ($mesg,$entry,$newpass); + $c->res->redirect($c->uri_for('/admin/account')) if $uid eq ''; + + # Find the user so we have their email now for confirmation, or can easily + # set password if reset has been confirmed + $mesg = $c->model('user')->search("uid=$uid"); + push @errors,$mesg->error if $mesg->code; + if ($mesg->entries gt 1) { + push @errors,'More than one entry matched'; + $c->detach; + } + $entry = $mesg->entry; + @mail = $entry->mail; + + if (!$c->req->param('txnid')) { + my $txnid = Data::UUID->new->create_str(); + $c->session(txnid => $txnid); + $c->stash( uid => $uid, txnid => $txnid, mails => @mail); + return 1; + } + if ($c->req->param('txnid') != $c->session->{txnid}) { + push @errors,'Transaction ID mismatch'; + $c->detach; + } + $newpass = Data::UUID->new->create_str(); + my $pp = Net::LDAP::Control::PasswordPolicy->new; + $mesg = $entry->replace( userPassword => $newpass,pwdReset => 'TRUE' )->update; + if ($mesg->code) { + push @errors,"Password reset failed: " . $mesg->error; + $c->detach; + } + $c->stash->{email} = { + to => join ',',@mail, + subject => $c->config->{apptitle} . " - " . $c->loc('password reset'), + from => $c->config->{emailfrom}, + template => 'admin/password.tt', + }; + $c->forward( $c->view('Email::Template') ); +} + + sub group : Local { my ( $self, $c ) = @_; $c->detach('/user/login') if not $c->user; diff --git a/lib/CatDap/Controller/register.pm b/lib/CatDap/Controller/register.pm index a321bdd..3838f26 100644 --- a/lib/CatDap/Controller/register.pm +++ b/lib/CatDap/Controller/register.pm @@ -126,8 +126,8 @@ EOF ); $c->stash->{email} = { to => $email, - from => 'no-reply@mageia.org', - subject => $c->loc('Mageia Identity Activation'), + from => ${$c->config}{emailfrom}, + subject => ${$c->config}{apptitle} . " - " . $c->loc('Activation'), body => $body, }; diff --git a/lib/CatDap/Controller/user.pm b/lib/CatDap/Controller/user.pm index c221eff..e2ce800 100644 --- a/lib/CatDap/Controller/user.pm +++ b/lib/CatDap/Controller/user.pm @@ -47,6 +47,11 @@ it (we need to handle failure to decrypt it better) sub auto : Private { my ( $self, $c ) = @_; + $c->log->info("Request path is currently: " . $c->req->path); + $c->log->info(Dumper($c->req->path)); + if ($c->req->path eq 'user/firstlogin') { + return 1; + } my $cipher; my $password; my $mesg; @@ -91,8 +96,8 @@ sub auto : Private { -cipher => 'Blowfish' ) or die $!; $password = $cipher->decrypt($c->session->{enc_password}); - $c->log->info("Re-authenticating user " . $c->session->{user}); - $c->authenticate({username => $c->session->{user},password => $password}); + $c->log->info("Re-authenticating user " . $c->user->username); + $c->authenticate({username => $c->user->username,password => $password}); $c->res->cookies->{'key'} = {value => $key, expires => '+10m'}; $c->stash(pages => roles2pages($c->user->roles)); @@ -267,7 +272,8 @@ sub password : Local { # re-encrypt the new password and forward to user view my $keyprefix = sprintf("%02x%02x%02x",split /\./,$c->req->address); - $cipher = Crypt::CBC->new( -key => $keyprefix . $c->sessionid, + my $key = $c->req->cookie('key')->value; + $cipher = Crypt::CBC->new( -key => $keyprefix . $key, -cipher => 'Blowfish' ) or die $!; $c->session->{enc_password} = $cipher->encrypt($newpass); @@ -281,21 +287,44 @@ sub firstlogin : Local { my ( $self, $c ) = @_; my ($mesg,$newpass,$cipher); - if (! $c->authenticate({ - username => $c->req->param('username'), - password => $c->req->param('key')}) ) { - $c->stash(errors => ['An error occurred']); - $c->res->redirect('/user'); - } + # we want to do our own authentication and caching here, as we + # dont want what auto does, and auto returns early for this path if ( not defined $c->req->param('newpassword1') or not defined $c->req->param('newpassword2')) { + if (! $c->authenticate({ + username => $c->req->param('username'), + password => $c->req->param('key')}) ) { + $c->stash(errors => ['An error occurred']); + $c->log->info("Failed to authenticate user in first login: " . $c->req->param('key')); + $c->res->redirect('/user'); + } + # cache password for next request with form data + my $keyprefix = sprintf("%02x%02x%02x",split /\./,$c->req->address); + my $key = Data::UUID->new->create_str(); + $cipher = Crypt::CBC->new( -key => $keyprefix . $key, + -cipher => 'Blowfish' + ) or die $!; + $c->session->{enc_password} = $cipher->encrypt($c->req->param('key')); + $c->response->cookies->{'key'} = { value => $key, expires => '+10m' }; $c->detach; } + if ($c->req->param('newpassword1') eq $c->req->param('newpassword2')) { $newpass = $c->req->param('newpassword1'); } else { push @{${$c->stash}{'errors'}},"New passwords dont match"; } + + #Re-authenticate user + my $keyprefix = sprintf("%02x%02x%02x",split /\./,$c->req->address); + my $key = $c->req->cookie('key')->value; + $cipher = Crypt::CBC->new( -key => $keyprefix . $key, + -cipher => 'Blowfish' + ) or die $!; + my $password = $cipher->decrypt($c->session->{enc_password}); + $c->authenticate({username => $c->req->param('username'),password => $password}) + or $c->log->info("Authenticating user for first password change failed"); + my $pp = Net::LDAP::Control::PasswordPolicy->new; $mesg = $c->model('User')->set_password( @@ -307,17 +336,16 @@ sub firstlogin : Local { my $perror = $mesg->error; push @{${$c->stash}{'errors'}},"Password change failed: $perror"; $c->detach; - } else { + } - # re-encrypt the new password and forward to user view - my $keyprefix = sprintf("%02x%02x%02x",split /\./,$c->req->address); - $cipher = Crypt::CBC->new( -key => $keyprefix . $c->sessionid, + # re-encrypt the new password and redirect to user view + $cipher = Crypt::CBC->new( -key => $keyprefix . $key, -cipher => 'Blowfish' ) or die $!; - $c->session->{enc_password} = $cipher->encrypt($newpass); - push @{${$c->stash}{'errors'}},"Password change succeeded"; - $c->res->redirect('/user'); - } + $c->session->{enc_password} = $cipher->encrypt($newpass); + $c->authenticate({username => $c->req->param('username'),password => $newpass}); + push @{${$c->stash}{'errors'}},"Password change succeeded"; + $c->res->redirect('/user'); } -- cgit v1.2.1