[Mageia-sysadm] [249] commit implement forgot_password patch from Maarten Vanraes

root at mageia.org root at mageia.org
Sat Jan 8 00:20:15 CET 2011


Revision: 249
Author:   rda
Date:     2011-01-08 00:20:14 +0100 (Sat, 08 Jan 2011)
Log Message:
-----------
commit implement forgot_password patch from Maarten Vanraes

Modified Paths:
--------------
    identity/CatDap/trunk/catdap.yml
    identity/CatDap/trunk/root/index.tt

Added Paths:
-----------
    identity/CatDap/trunk/lib/CatDap/Controller/forgot_password.pm
    identity/CatDap/trunk/root/email/forgot_password.tt
    identity/CatDap/trunk/root/forgot_password/
    identity/CatDap/trunk/root/forgot_password/check.tt
    identity/CatDap/trunk/root/forgot_password/complete.tt
    identity/CatDap/trunk/root/forgot_password/confirm.tt
    identity/CatDap/trunk/root/forgot_password/index.tt

Modified: identity/CatDap/trunk/catdap.yml
===================================================================
--- identity/CatDap/trunk/catdap.yml	2011-01-07 23:15:42 UTC (rev 248)
+++ identity/CatDap/trunk/catdap.yml	2011-01-07 23:20:14 UTC (rev 249)
@@ -35,6 +35,12 @@
         login_blacklist:
                 - apache
 
+forgot_password:
+        secret:
+                path:   '/tmp/'
+                prefix: 'catdap-forgot_password-'
+                timeout: 259200
+
 authentication:
         default_realm: ldap
         realms:
@@ -55,6 +61,7 @@
                                 user_filter:    '(&(objectClass=inetOrgPerson)(uid=%s))'
                                 user_scope:     'one'
                                 user_field:     'uid'
+                                email_filter:   '(&(objectClass=inetOrgPerson)(|(mail=%s)(mailAlternateAddress=%s)))'
                                 use_roles:      1
                                 role_basedn:    'dc=mageia,dc=org'
                                 role_scope:     'sub'

Added: identity/CatDap/trunk/lib/CatDap/Controller/forgot_password.pm
===================================================================
--- identity/CatDap/trunk/lib/CatDap/Controller/forgot_password.pm	                        (rev 0)
+++ identity/CatDap/trunk/lib/CatDap/Controller/forgot_password.pm	2011-01-07 23:20:14 UTC (rev 249)
@@ -0,0 +1,270 @@
+package CatDap::Controller::forgot_password;
+use Moose;
+use namespace::autoclean;
+use Email::Valid;
+use Data::UUID;
+
+BEGIN {extends 'Catalyst::Controller'; }
+
+=head1 NAME
+
+CatDap::Controller::forgot_password - Catalyst Controller
+
+=head1 DESCRIPTION
+
+Catalyst Controller.
+
+=head1 METHODS
+
+=cut
+
+
+=head2 index
+
+=cut
+
+sub index :Path :Args(0) : Form {
+	my ( $self, $c ) = @_;
+
+	if (defined $c->user) {
+		# if we're logged in, we haven't forgotten the password
+		$c->log->debug('Redirecting to /user');
+		$c->res->redirect('/user');
+	}
+}
+
+sub check : Local {
+	my ( $self, $c ) = @_;
+
+	my %details = %{$c->request->params};
+	my $username = lc($c->request->params->{uid});
+	my @errors;
+	$c->stash(errors => []);
+	my $email = $c->request->params->{mail};
+	if (! Email::Valid->address($email)) {
+		push @errors, $c->loc('Invalid email address');
+	}
+
+	if (@errors) {
+		$c->stash(errors => \@errors);
+		$c->stash(template => 'forgot_password/index.tt');
+		return;
+	}
+
+	# check in LDAP now that we have validated username and email
+	my $emailfilter = $c->config->{'authentication'}{'realms'}{'ldap'}{'store'}{'email_filter'};
+	$emailfilter =~ s/\%s/$email/g,
+	$c->log->debug("Searching for email $email with filter $emailfilter");
+	my $mesg = $c->model('Proxy')->search($emailfilter);
+	if (!$mesg->entries()) {
+		push @errors,$c->loc(
+			'This email address is not bound to an account'
+		);
+	}
+
+	if (@errors) {
+		$c->stash(errors => \@errors);
+		$c->stash(template => 'forgot_password/index.tt');
+		return;
+	}
+
+	if ($mesg->code) {
+		push @errors,$mesg->error;
+		$c->log->info( sprintf("finding email $email failed: %s", $mesg->error) );
+		$c->stash(errors => \@errors);
+		$c->stash(template => 'register/index.tt');
+		return;
+	}
+
+	my $secret = gen_secret($c, $email);
+
+	$c->stash(
+		email => {
+			'to'		=> $email,
+			'from'		=> ${$c->config}{'emailfrom'},
+			'subject'	=> ${$c->config}{'apptitle'} . " - " . $c->loc('Forgot password'),
+			'template'	=> 'forgot_password.tt',
+		},
+		url => $c->uri_for('/forgot_password/confirm') . "?secret=$secret",
+	);
+
+	$c->log->info("Sending forgot password mail to email address $email");
+	$c->forward( $c->view('Email::Template') );
+	if ( @{ $c->error } ) {
+		my $errors = join "\n",@{ $c->error };
+		$c->log->info("Sending activation mail to $email failed: $errors");
+		$c->response->body($c->loc('An error occured sending the email, please try again later. Errors [_1]', $errors));
+		$c->error(0); # Reset the error condition if you need to
+	}
+	$c->stash(template => 'forgot_password/complete.tt');
+}
+
+sub confirm : Local {
+	my ($self, $c) = @_;
+	my $secret = $c->req->param('secret');
+	my @errors;
+
+	# show confirm page which can enter new password
+	if (defined $c->user) {
+		# if we're logged in, we haven't forgotten the password
+		$c->log->debug('Redirecting to /user');
+		$c->res->redirect('/user');
+	}
+
+	# find secret
+	my $email = find_secret($c, $secret);
+	if (!$email) {
+		push @errors, "Secret has expired, please try again.";
+		$c->stash(errors => \@errors);
+		$c->stash(template => 'forgot_password/index.tt');
+		return;
+	}
+	my $mesg = find_user_email($c, $email);
+	if ($mesg->code) {
+		push @errors, "Secret has expired, please try again.";
+		$c->stash(errors => \@errors);
+		$c->stash(template => 'forgot_password/index.tt');
+		return;
+	}
+
+	# show template to enter a new password
+	$c->stash(secret => $secret, template => 'forgot_password/confirm.tt');
+}
+
+sub change_password : Local {
+	my ($self, $c) = @_;
+	my @errors = ();
+	my $secret = $c->req->param('secret');
+	my $newpass;
+
+	# find secret
+	my $email = find_secret($c, $secret);
+	if (!$email) {
+		push @errors, "Secret has expired, please try again.";
+		$c->stash(errors => \@errors);
+		$c->stash(template => 'forgot_password/index.tt');
+		return;
+	}
+	my $mesg = find_user_email($c, $email);
+	if ( $mesg->code) {
+		push @errors, "Secret has expired, please try again.";
+		$c->stash(errors => \@errors);
+		$c->stash(template => 'forgot_password/index.tt');
+		return;
+	}
+	my $entry = $mesg->entry;
+
+	# check if both passwords are equal and are confirm the validation norms
+	if ($c->req->param('newpassword1') eq $c->req->param('newpassword2')) {
+		$newpass = $c->req->param('newpassword1');
+	} else {
+		push @errors, "New passwords dont match";
+	}
+	# if error show confirm page again to retry
+	if (@errors) {
+		$c->stash(errors => \@errors);
+		$c->stash(template => 'forgot_password/confirm.tt');
+		return;
+	}
+
+	# change password
+	my $pp = Net::LDAP::Control::PasswordPolicy->new;
+	$mesg = $c->model('Proxy')->set_password(
+		user => $entry->dn,
+		newpasswd => $newpass,
+		control => [ $pp ],
+	);
+	if ($mesg->code) {
+		my $perror = $mesg->error;
+		push @errors, "Password change failed: $perror";
+		$c->detach;
+	}
+
+	# if error show confirm page again to retry
+	if (@errors) {
+		$c->stash(errors => \@errors);
+		$c->stash(template => 'forgot_password/confirm.tt');
+		return;
+	}
+
+	# TODO: log in by setting the $c->user
+
+	# remove the stored secret
+	remove_secret($c, $secret);
+
+	# redirect to /
+	$c->log->debug('Redirecting to /');
+	$c->res->redirect('/');
+}
+
+sub gen_secret {
+	my ($c, $email) = @_;
+	my $ug = new Data::UUID;
+	# generate a unique secret
+	my $secret = $ug->create_str();
+	my $filename = $c->config->{'forgot_password'}{'secret'}{'path'} .'/'. $c->config->{'forgot_password'}{'secret'}{'prefix'} . $secret;
+	# store secret with email
+	open FILE, ">$filename";
+	print FILE $email;
+	close FILE;
+	return $secret;
+}
+
+sub find_secret {
+	my ($c, $secret) = @_;
+	my $email;
+	my $filename = $c->config->{'forgot_password'}{'secret'}{'path'} .'/'. $c->config->{'forgot_password'}{'secret'}{'prefix'} . $secret;
+	my $timeout = 259200; # 3days in seconds
+	if ($c->config->{'forgot_password'}{'secret'}{'timeout'}) {
+		$timeout = $c->config->{'forgot_password'}{'secret'}{'timeout'};
+	}
+
+	# find secret
+	if (!$secret || !open(FILE, "<$filename")) {
+		# if secret is wrong, timeout expired?
+		return '';
+	}
+	read(FILE, $email, 255);
+	close FILE;
+
+	# check the time, and see if it's longer than timeout
+	my @s = stat($filename);
+	if (time() > $s[9] + $timeout) {
+		# expired
+		return '';
+	}
+
+	return $email;
+}
+
+sub remove_secret {
+	my ($c, $secret) = @_;
+	my $filename = $c->config->{'forgot_password'}{'secret'}{'path'} .'/'. $c->config->{'forgot_password'}{'secret'}{'prefix'} . $secret;
+	unlink $filename;
+}
+
+sub find_user_email {
+	my ($c, $email) = @_;
+
+	# find user by email;
+	my $emailfilter = $c->config->{'authentication'}{'realms'}{'ldap'}{'store'}{'email_filter'};
+	$emailfilter =~ s/\%s/$email/g,
+	$c->log->debug("Searching for email $email with filter $emailfilter");
+	return $c->model('Proxy')->search($emailfilter);
+}
+
+
+=head1 AUTHOR
+
+Buchan Milne
+
+=head1 LICENSE
+
+This library is free software. You can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
+
+__PACKAGE__->meta->make_immutable;
+
+1;

Added: identity/CatDap/trunk/root/email/forgot_password.tt
===================================================================
--- identity/CatDap/trunk/root/email/forgot_password.tt	                        (rev 0)
+++ identity/CatDap/trunk/root/email/forgot_password.tt	2011-01-07 23:20:14 UTC (rev 249)
@@ -0,0 +1,7 @@
+[% l('Dear [_1],',cn) %]
+[% l('Your [_1] account has been requested to change the password. If you did not do this, or you do not want to change your password; you can just do nothing.',c.config.organisation) %]
+[% l('To reset your password, please follow the link below.') %]
+[% url %]
+
+--
+http://mageia.org/

Added: identity/CatDap/trunk/root/forgot_password/check.tt
===================================================================
--- identity/CatDap/trunk/root/forgot_password/check.tt	                        (rev 0)
+++ identity/CatDap/trunk/root/forgot_password/check.tt	2011-01-07 23:20:14 UTC (rev 249)
@@ -0,0 +1,4 @@
+<h2>Success</h2>
+<p>
+[% message %]
+</p>
\ No newline at end of file

Added: identity/CatDap/trunk/root/forgot_password/complete.tt
===================================================================
--- identity/CatDap/trunk/root/forgot_password/complete.tt	                        (rev 0)
+++ identity/CatDap/trunk/root/forgot_password/complete.tt	2011-01-07 23:20:14 UTC (rev 249)
@@ -0,0 +1,6 @@
+<h2>[% l('Email sent.') %]</h2>
+
+<p>
+    [% l('Operation was successful.') %]
+    [% l('Check your mail for password reset instructions.') %]
+</p>

Added: identity/CatDap/trunk/root/forgot_password/confirm.tt
===================================================================
--- identity/CatDap/trunk/root/forgot_password/confirm.tt	                        (rev 0)
+++ identity/CatDap/trunk/root/forgot_password/confirm.tt	2011-01-07 23:20:14 UTC (rev 249)
@@ -0,0 +1,21 @@
+
+<h1>[% l('Enter new password.') %]</h1>
+
+<div id="input_form">
+<form method="post" action="/forgot_password/change_password">
+	<table>
+		<tr>
+			<td><label for="newpassword1_">[% l('New Password') %]</label></td>
+			<td><input id="newpassword1_" name="newpassword1" type="password" value="" /></td>
+		</tr><tr>
+			<td><label for="newpassword2_">[% l('Repeat New Password') %]</label></td>
+			<td><input id="newpassword2_" name="newpassword2" type="password" value="" /></td>
+		</tr><tr>
+			<td colspan="2" style="text-align:center;">
+				<input type="hidden" name="secret" value="[% secret %]" />
+				<button type="submit" value="[% l('Set new password') %]">[% l('Set new password') %]</button>
+			</td>
+		</tr>
+	</table>
+</form>
+</div>

Added: identity/CatDap/trunk/root/forgot_password/index.tt
===================================================================
--- identity/CatDap/trunk/root/forgot_password/index.tt	                        (rev 0)
+++ identity/CatDap/trunk/root/forgot_password/index.tt	2011-01-07 23:20:14 UTC (rev 249)
@@ -0,0 +1,17 @@
+
+<h1>[% l('Forgot your password?') %]</h1>
+
+<div id="input_form">
+<form method="post" action="/forgot_password/check">
+	<table>
+		<tr>
+			<td><label for="mail_">[% l('Email address') %]</label></td>
+			<td><input id="mail_" type="text" name="mail" value="[% c.request.params.mail %]" /></td>
+		</tr><tr>
+			<td colspan="2" style="text-align:center;">
+				<button type="submit" value="[% l('Reset password') %]">[% l('Reset password') %]</button>
+			</td>
+		</tr>
+	</table>
+</form>
+</div>

Modified: identity/CatDap/trunk/root/index.tt
===================================================================
--- identity/CatDap/trunk/root/index.tt	2011-01-07 23:15:42 UTC (rev 248)
+++ identity/CatDap/trunk/root/index.tt	2011-01-07 23:20:14 UTC (rev 249)
@@ -14,8 +14,7 @@
             </div>
             <div id="login_form_line">
                         <span><a href="/register">[% l('Register') %]</a> |
-                        @todo [% l('Forgotten password?') %]
-                        <!--<a href="/forgot_password">[% l('Forgotten password?') %]</a> -->
+                        <a href="/forgot_password">[% l('Forgotten password?') %]</a>
             </span>
             </div>
 </form>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: </pipermail/mageia-sysadm/attachments/20110108/f0712891/attachment-0001.html>


More information about the Mageia-sysadm mailing list