]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 1401463 - In bugzilla "you must reset password" state, all bug pages are force...
authorDylan William Hardison <dylan@hardison.net>
Mon, 25 Sep 2017 18:14:31 +0000 (14:14 -0400)
committerGitHub <noreply@github.com>
Mon, 25 Sep 2017 18:14:31 +0000 (14:14 -0400)
Bugzilla.pm
Bugzilla/Token.pm
reset_password.cgi
t/hash-sig.t [new file with mode: 0644]
template/en/default/account/reset-password.html.tmpl
template/en/default/global/user-error.html.tmpl

index 1f01979ea2b741f0f75d03e42442cf4c4aaf4763..9bce7301025d9b34f9e5bdf6c453428f8ae05e24 100644 (file)
@@ -396,7 +396,12 @@ sub login {
         # (tokens handles the 'forgot password' process)
         # otherwise redirect user to the reset-password page.
         if ( $ENV{SCRIPT_NAME} !~ m#/(?:reset_password|token)\.cgi$# ) {
-            print $cgi->redirect('reset_password.cgi');
+            my $self_url     = trim($cgi->self_url);
+            my $sig_type     = 'prev_url:' . $authenticated_user->id;
+            my $self_url_sig = issue_hash_sig($sig_type, $self_url);
+            my $redir_url    = URI->new( correct_urlbase() . "reset_password.cgi" );
+            $redir_url->query_form(prev_url => $self_url, prev_url_sig => $self_url_sig);
+            print $cgi->redirect($redir_url);
             exit;
         }
     }
index c6288f491f98d1873bc2f0c14c42e714c03c559c..4b12f836b22beb7f786cd2d207eaad4bd82b5aa7 100644 (file)
@@ -32,6 +32,7 @@ use base qw(Exporter);
                               issue_auth_delegation_token check_auth_delegation_token
                               check_token_data delete_token
                               issue_hash_token check_hash_token
+                              issue_hash_sig   check_hash_sig
                               set_token_extra_data get_token_extra_data);
 
 # 128 bits password:
@@ -221,6 +222,27 @@ sub issue_short_lived_session_token {
     return _create_token($user->id ? $user->id : undef, 'session.short', $data);
 }
 
+sub issue_hash_sig {
+    my ($type, $data, $salt) = @_;
+    $data //= "";
+    $salt //= generate_random_password(16);
+
+    my $hmac = hmac_sha256_base64(
+        $salt,
+        $type,
+        $data,
+        Bugzilla->localconfig->{site_wide_secret}
+    );
+    return sprintf("%s|%s|%x", $salt, $hmac, length($data));
+}
+
+sub check_hash_sig {
+    my ($type, $sig, $data) = @_;
+    return 0 unless defined $sig && defined $data;
+    my ($salt, undef, $len) = split(/\|/, $sig, 3);
+    return length($data) == hex($len) && $sig eq issue_hash_sig($type, $data, $salt);
+}
+
 sub issue_hash_token {
     my ($data, $time) = @_;
     $data ||= [];
index 86ace9e12f03f29b55a6c4bd7edba0cf0fe6feae..a79fea063fd50aa08120bbba56b09317946bbafe 100755 (executable)
@@ -17,14 +17,34 @@ use Bugzilla;
 use Bugzilla::Constants;
 use Bugzilla::Error;
 use Bugzilla::Token;
-use Bugzilla::Util qw( bz_crypt );
+use Bugzilla::Util qw( bz_crypt trim );
+use Data::Dumper;
 
-my $cgi = Bugzilla->cgi;
-my $user = Bugzilla->login(LOGIN_REQUIRED);
-my $template = Bugzilla->template;
-my $dbh = Bugzilla->dbh;
+my $cgi          = Bugzilla->cgi;
+my $user         = Bugzilla->login(LOGIN_REQUIRED);
+my $template     = Bugzilla->template;
+my $dbh          = Bugzilla->dbh;
+my $prev_url     = $cgi->param('prev_url');
+my $prev_url_sig = $cgi->param('prev_url_sig');
+my $sig_type     = 'prev_url:' . $user->id;
+my $prev_url_ok  = check_hash_sig($sig_type, $prev_url_sig, $prev_url );
 
-ThrowUserError('reset_password_denied') unless $user->password_change_required;
+unless ($prev_url_ok) {
+    open my $fh, '>', '/tmp/dump.pl' or die $!;
+    print $fh Dumper([$prev_url, $prev_url_sig]);
+    close $fh or die $!;
+}
+
+unless ($user->password_change_required) {
+    ThrowUserError(
+        'reset_password_denied',
+        {
+            prev_url_ok => $prev_url_ok,
+            prev_url    => $prev_url,
+        }
+    );
+
+}
 
 if ($cgi->param('do_save')) {
     my $token = $cgi->param('token');
@@ -64,14 +84,32 @@ if ($cgi->param('do_save')) {
 
     # done
     print $cgi->header();
-    $template->process('index.html.tmpl', { message => 'password_changed' })
-        || ThrowTemplateError($template->error());
+    $template->process(
+        'account/reset-password.html.tmpl',
+        {
+            message          => 'password_changed',
+            prev_url         => $prev_url,
+            prev_url_ok      => $prev_url_ok,
+            password_changed => 1
+        }
+    ) || ThrowTemplateError( $template->error() );
+
 }
 
 else {
     my $token = issue_session_token('reset_password');
 
     print $cgi->header();
-    $template->process('account/reset-password.html.tmpl', { token => $token })
-        || ThrowTemplateError($template->error());
+    $template->process(
+        'account/reset-password.html.tmpl',
+        {
+            token        => $token,
+            prev_url     => $prev_url,
+            prev_url_ok  => $prev_url_ok,
+            prev_url_sig => $prev_url_sig,
+            sig_type => $sig_type,
+        }
+    ) || ThrowTemplateError( $template->error() );
+
+
 }
diff --git a/t/hash-sig.t b/t/hash-sig.t
new file mode 100644 (file)
index 0000000..30d3098
--- /dev/null
@@ -0,0 +1,24 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+use strict;
+use warnings;
+use 5.10.1;
+use lib qw( . lib local/lib/perl5 );
+use Bugzilla::Util qw(generate_random_password);
+use Bugzilla::Token qw(issue_hash_sig check_hash_sig);
+use Test::More;
+
+my $localconfig = { site_wide_secret => generate_random_password(256) };
+{
+    package Bugzilla;
+    sub localconfig { $localconfig }
+}
+
+my $sig = issue_hash_sig("hero", "batman");
+ok(check_hash_sig("hero", $sig, "batman"), "sig for batman checks out");
+
+done_testing();
\ No newline at end of file
index ca60c5772c25f7a3b85f487b01bd6e4e24851a55..a2bec34fd226b5653ed2175d250513fbd67c3dca 100644 (file)
@@ -71,6 +71,20 @@ $(function() {
 
 <h1>Password Reset</h1>
 
+[% BLOCK link %]
+  <a href="[% prev_url FILTER html %]">[% prev_url FILTER html %]</a>
+[% END %]
+
+[% IF password_changed && prev_url_ok %]
+  <p>Continue to [% PROCESS link %]</p>
+  [% RETURN %]
+[% ELSIF prev_url_ok %]
+  <p>
+    If you've already reset your password, you may continue to [% PROCESS link %]
+  </p>
+[% END %]
+
+
 <p>
   [% user.password_change_reason || "You are required to update your password." FILTER html %]
 </p>
@@ -82,6 +96,8 @@ $(function() {
 <form method="POST" action="reset_password.cgi">
 <input type="hidden" name="token" value="[% token FILTER html %]">
 <input type="hidden" name="do_save" value="1">
+<input type="hidden" name="prev_url" value="[% prev_url FILTER html %]">
+<input type="hidden" name="prev_url_sig" value="[% prev_url_sig FILTER html %]">
 
 <div class="flex">
   <div id="password-reset" class="flex-left">
index 3e4d7c4a0cb2795853ce9fff7f5f3bbb0af63264..9eefbcb73aa714c2ce0bd2eeedd3374d9de1f607 100644 (file)
   [% ELSIF error == "reset_password_denied" %]
     [% title = "Reset Password Denied" %]
     You cannot reset your password without administrative permission.
+    [% IF prev_url_ok %]
+      Continue to <a href="[% prev_url FILTER html %]">[% prev_url FILTER html %]</a>.
+    [% END %]
 
   [% ELSIF error == "no_axes_defined" %]
     [% title = "No Axes Defined" %]