pwproj.cgi: instead of resetting the password send an auth code
authorKyle J. McKay <mackyle@gmail.com>
Wed, 16 Apr 2014 11:32:14 +0000 (16 04:32 -0700)
committerKyle J. McKay <mackyle@gmail.com>
Wed, 16 Apr 2014 12:55:15 +0000 (16 05:55 -0700)
Allowing the project password to be reset by anyone invites abuse.

Instead of actually resetting the password to a random value, send
an authorization code that allows the password to be changed.

Although it's still possible for random individuals to generate
these authorization code emails, now all the project admin has to
do is ignore them rather than dealing with a changed password.

cgi/pwproj.cgi

index f0a4f97..36fb6be 100755 (executable)
@@ -1,5 +1,6 @@
 #!/usr/bin/perl
 # (c) Petr Baudis <pasky@suse.cz>
+# Portions Copyright (c) Kyle J. McKay <mackyle@gmail.com>
 # GPLv2
 
 use strict;
@@ -11,16 +12,14 @@ use Girocco::Config;
 use Girocco::Project;
 use Girocco::Util;
 
-
-sub genpwd {
-       # FLUFFY!
-       substr(crypt(rand, rand), 2);
-}
-
-
 my $gcgi = Girocco::CGI->new('Forgotten Project Password');
 my $cgi = $gcgi->cgi;
 
+unless ($Girocco::Config::project_passwords) {
+       print "<p>I don't manage passwords.</p>";
+       exit;
+}
+
 my $name = $cgi->param('name');
 
 unless (defined $name) {
@@ -46,44 +45,119 @@ $escname =~ s/[+]/%2B/g;
 my $mail = $proj->{email};
 
 my $y0 = $cgi->param('y0') || '';
-if ($y0 eq 'Reset Password' && $cgi->request_method eq 'POST') {
+if ($y0 eq 'Send authorization code' && $cgi->request_method eq 'POST') {
        # submitted
 
-       my $newpwd = genpwd();
+       my $auth = $proj->gen_auth('PWD');
 
-       defined(my $MAIL = mailer_pipe '-s', "[$Girocco::Config::name] New password for project $name", $mail)
+       defined(my $MAIL = mailer_pipe '-s',
+               "[$Girocco::Config::name] Password change authorization for project $name", $mail)
                or die "Cannot spawn mailer: $!";
        print $MAIL <<EOT;
 Hello,
 
-Somebody asked for the password for project $name to be reset. Since you are
-the project admin, you get to know the new password:
+Somebody asked for a password change authorization code to be sent for
+project $name on $Girocco::Config::name.  Since you are the project admin,
+you receive the authorization code.  If you don't want to actually change
+the password for project $name, just ignore this e-mail.  Otherwise use
+this code within 24 hours:
 
-       $newpwd
+       $auth
 
-In case you did not request the password to be reset, we apologize. Nevertheless,
-you have to use the reset password now (possibly to change it back).
+In case you did not request a password change authorization code, we
+apologize.
 
-Quick-link to the edit project page:
-
-       $Girocco::Config::webadmurl/editproj.cgi?name=$escname
+Should you run into any problems, please let us know.
 
 Have fun!
 EOT
        close $MAIL or die "mail $mail for $name died? $!";
 
-       $proj->update_password($newpwd);
+       print <<EOT;
+<p>The project admin should shortly receive an e-mail containing a project
+password change authorization code.  Please enter this code below to change
+the password for project $name on $Girocco::Config::name.  The code will
+expire in 24 hours or after you have used it to successfully change the
+password.</p>
+<form method="post" action="@{[url_path($Girocco::Config::webadmurl)]}/pwproj.cgi">
+<input type="hidden" name="name" value="$name" />
+<p>Authorization code: <input name="auth" size="50" /></p>
+<p><input type="submit" name="y0" value="Validate code" /></p>
+</form>
+EOT
+       exit;
+}
+if (($y0 eq 'Validate code' || $y0 eq 'Change password') && $cgi->request_method eq 'POST') {
+       # validation & change
+
+       $proj->{auth} && $proj->{authtype} && $proj->{authtype} eq 'PWD' or do {
+               print <<EOT;
+<p>There currently isn't any project password change authorization code on file for
+project $name.  Please <a href="@{[url_path($Girocco::Config::webadmurl)]}/pwproj.cgi?name=$escname"
+>generate one</a>.</p>
+EOT
+               exit;
+       };
+       my $auth = $gcgi->wparam('auth');
+       if ($auth ne $proj->{auth}) {
+               print <<EOT;
+<p>Invalid authorization code, please re-enter or
+<a href="@{[url_path($Girocco::Config::webadmurl)]}/pwproj.cgi?name=$escname"
+>generate a new one</a>.</p>
+<form method="post" action="@{[url_path($Girocco::Config::webadmurl)]}/pwproj.cgi">
+<input type="hidden" name="name" value="$name" />
+<p>Authorization code: <input name="auth" size="50" /></p>
+<p><input type="submit" name="y0" value="Validate code" /></p>
+</form>
+EOT
+               exit;
+       }
+       if ($y0 eq 'Change password') {
+               # changing password
+               my ($pwd, $pwd2) = ($cgi->param('pwd'), $cgi->param('pwd2'));
+               $pwd ||= ''; $pwd2 ||= '';
+               if ($pwd ne $pwd2) {
+                       $gcgi->err("Our high-paid security consultants have determined that the admin passwords you have entered do not match each other.");
+               } elsif (!$pwd || !$pwd2) {
+                       $gcgi->err("Empty passwords are not permitted.");
+               } else {
+                       $proj->del_auth;
+                       $proj->update_password($pwd);
+                       print <<EOT;
+<p>The project password for project $name has been successfully changed.</p>
+<p>You may now use the new password to edit the project settings
+<a href="@{[url_path($Girocco::Config::webadmurl)]}/editproj.cgi?name=$escname"
+>here</a>.</p>
+<p>Have a nice day.</p>
+EOT
+                       exit;
+               }
+       }
+       print <<EOT;
+<form method="post" action="@{[url_path($Girocco::Config::webadmurl)]}/pwproj.cgi">
+<input type="hidden" name="name" value="$name" />
+<input type="hidden" name="auth" value="$auth" />
+<table class="form">
+<tr><td class="formlabel">Project name:</td><td class="formdata">$name.git</td></tr>
+<tr><td class="formlabel">New admin password (twice):</td><td><input type="password" name="pwd" /><br />
+<input type="password" name="pwd2" /></td></tr>
+<tr><td class="formlabel"></td><td><input type="submit" name="y0" value="Change password" /></td></tr>
+</table>
+</form>
+EOT
+       exit;
+}
 
-       print "<p>Project password has been reset. Have a nice day.</p>\n";
+if ($cgi->request_method eq 'POST') {
+       print "<p>Invalid data. Go away, sorcerer.</p>\n";
        exit;
 }
 
 print <<EOT;
-<p>You are trying to make me reset password for project $name. I will send the new
-password to the project admin &lt;$mail&gt;.</p>
+<p>You are trying to make me change the password for project $name.  I will send
+an authorization code to change the password to the project admin &lt;$mail&gt;.</p>
 <form method="post" action="@{[url_path($Girocco::Config::webadmurl)]}/pwproj.cgi">
 <input type="hidden" name="name" value="$name" />
-<p><input type="submit" name="y0" value="Reset Password" /></p>
+<p><input type="submit" name="y0" value="Send authorization code" /></p>
 </form>
 EOT
-