Skip to content

Commit 3cf3faf

Browse files
Dylan William Hardisondylanwh
authored andcommitted
Bug 1163760: Backport upstream bug 1144468 to bmo to add authentication delegation
1 parent f2c52df commit 3cf3faf

File tree

6 files changed

+207
-0
lines changed

6 files changed

+207
-0
lines changed

Bugzilla/Config/Auth.pm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ sub get_param_list {
143143
type => 'b',
144144
default => '1'
145145
},
146+
{
147+
name => 'auth_delegation',
148+
type => 'b',
149+
default => 0,
150+
},
146151
);
147152
return @param_list;
148153
}

Bugzilla/Token.pm

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,12 @@ use Date::Format;
4040
use Date::Parse;
4141
use File::Basename;
4242
use Digest::MD5 qw(md5_hex);
43+
use Digest::SHA qw(hmac_sha256_base64);
4344

4445
use base qw(Exporter);
4546

4647
@Bugzilla::Token::EXPORT = qw(issue_api_token issue_session_token
48+
issue_auth_delegation_token check_auth_delegation_token
4749
check_token_data delete_token
4850
issue_hash_token check_hash_token);
4951

@@ -65,6 +67,37 @@ sub issue_api_token {
6567
return $token // _create_token($user->id, 'api_token', '');
6668
}
6769

70+
sub issue_auth_delegation_token {
71+
my ($uri) = @_;
72+
my $dbh = Bugzilla->dbh;
73+
my $user = Bugzilla->user;
74+
my $checksum = hmac_sha256_base64($user->id, $uri, Bugzilla->localconfig->{'site_wide_secret'});
75+
76+
return _create_token($user->id, 'auth_delegation', $checksum);
77+
}
78+
79+
sub check_auth_delegation_token {
80+
my ($token, $uri) = @_;
81+
my $dbh = Bugzilla->dbh;
82+
my $user = Bugzilla->user;
83+
84+
my ($eventdata) = $dbh->selectrow_array("
85+
SELECT eventdata FROM tokens
86+
WHERE token = ? AND tokentype = 'auth_delegation'
87+
AND (" . $dbh->sql_date_math('issuedate', '+', (MAX_TOKEN_AGE * 24 - 12), 'HOUR') . ") > NOW()",
88+
undef, $token);
89+
90+
if ($eventdata) {
91+
my $checksum = hmac_sha256_base64($user->id, $uri, Bugzilla->localconfig->{'site_wide_secret'});
92+
if ($eventdata eq $checksum) {
93+
delete_token($token);
94+
return 1;
95+
}
96+
}
97+
98+
return 0;
99+
}
100+
68101
# Creates and sends a token to create a new user account.
69102
# It assumes that the login has the correct format and is not already in use.
70103
sub issue_new_user_account_token {
@@ -628,6 +661,23 @@ although they can be used separately.
628661
629662
Returns: A unique token.
630663
664+
=item C<issue_auth_delegation_token($uri)>
665+
666+
Description: Creates and returns a token used to validate auth delegation confirmations.
667+
668+
Params: $uri - The uri that auth will be delegated to.
669+
670+
Returns: A unique token.
671+
672+
=item C<check_auth_delegation_token($token, $uri)>
673+
674+
Description: Checks if a token $token is a confirmation token for $uri.
675+
676+
Params: $token - The token returned by issue_auth_delegation_token()
677+
$uri - The uri that auth will be delegated to.
678+
679+
Returns: a boolean value
680+
631681
=item C<check_token_data($token, $event)>
632682
633683
Description: Makes sure the $token has been created by the currently logged in

auth.cgi

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#!/usr/bin/perl -wT
2+
# This Source Code Form is subject to the terms of the Mozilla Public
3+
# License, v. 2.0. If a copy of the MPL was not distributed with this
4+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
5+
#
6+
# This Source Code Form is "Incompatible With Secondary Licenses", as
7+
# defined by the Mozilla Public License, v. 2.0.
8+
9+
use 5.10.1;
10+
use strict;
11+
use warnings;
12+
13+
use lib qw(. lib);
14+
15+
use Bugzilla;
16+
use Bugzilla::Constants;
17+
use Bugzilla::Error;
18+
use Bugzilla::Hook;
19+
use Bugzilla::Util qw(trick_taint);
20+
use Bugzilla::Token qw(issue_auth_delegation_token check_auth_delegation_token);
21+
use Bugzilla::Mailer qw(MessageToMTA);
22+
23+
use URI;
24+
use URI::QueryParam;
25+
26+
Bugzilla->login(LOGIN_REQUIRED);
27+
28+
ThrowUserError('auth_delegation_disabled') unless Bugzilla->params->{auth_delegation};
29+
30+
my $cgi = Bugzilla->cgi;
31+
my $template = Bugzilla->template;
32+
my $user = Bugzilla->user;
33+
my $callback = $cgi->param('callback') or ThrowUserError("auth_delegation_missing_callback");
34+
my $description = $cgi->param('description') or ThrowUserError("auth_delegation_missing_description");
35+
36+
trick_taint($callback);
37+
trick_taint($description);
38+
39+
my $callback_uri = URI->new($callback);
40+
my $callback_base = $callback_uri->clone;
41+
$callback_base->query(undef);
42+
43+
my $skip_confirmation = 0;
44+
my %args = ( skip_confirmation => \$skip_confirmation,
45+
callback => $callback_uri,
46+
description => $description,
47+
callback_base => $callback_base );
48+
49+
Bugzilla::Hook::process('auth_delegation_confirm', \%args);
50+
51+
my $confirmed = lc($cgi->request_method) eq 'post' && $cgi->param('confirm');
52+
53+
if ($confirmed || $skip_confirmation) {
54+
my $token = $cgi->param('token');
55+
unless ($skip_confirmation) {
56+
ThrowUserError("auth_delegation_missing_token") unless $token;
57+
trick_taint($token);
58+
59+
unless (check_auth_delegation_token($token, $callback)) {
60+
ThrowUserError('auth_delegation_invalid_token',
61+
{ token => $token, callback => $callback });
62+
}
63+
}
64+
65+
my $new_key = Bugzilla::User::APIKey->create({
66+
user_id => $user->id,
67+
description => $description,
68+
});
69+
my $template = Bugzilla->template_inner($user->setting('lang'));
70+
my $vars = { user => $user, new_key => $new_key };
71+
my $message;
72+
$template->process('email/new-api-key.txt.tmpl', $vars, \$message)
73+
or ThrowTemplateError($template->error());
74+
75+
MessageToMTA($message);
76+
77+
$callback_uri->query_param(client_api_key => $new_key->api_key);
78+
$callback_uri->query_param(client_api_login => $user->login);
79+
80+
print $cgi->redirect($callback_uri);
81+
}
82+
else {
83+
$args{token} = issue_auth_delegation_token($callback);
84+
85+
print $cgi->header();
86+
$template->process("account/auth/delegation.html.tmpl", \%args)
87+
or ThrowTemplateError($template->error());
88+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[%# This Source Code Form is subject to the terms of the Mozilla Public
2+
# License, v. 2.0. If a copy of the MPL was not distributed with this
3+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4+
#
5+
# This Source Code Form is "Incompatible With Secondary Licenses", as
6+
# defined by the Mozilla Public License, v. 2.0.
7+
#%]
8+
9+
[% PROCESS global/header.html.tmpl
10+
title = "Auth Delegation Request" %]
11+
12+
<h1>[% title FILTER html %] </h1>
13+
<p>
14+
A third-party website (<a href="[% callback_base FILTER html %]">[% callback_base FILTER html %]</a>)
15+
would like to have <strong>complete</strong> access to your [% terms.Bugzilla %] account.
16+
</p>
17+
18+
<p>The description of the site reads:
19+
<blockquote>
20+
[% description FILTER html %]
21+
</blockquote>
22+
</p>
23+
24+
<p>Do you want this website to have <strong>complete</strong> access to your [% terms.Bugzilla %]
25+
account?</p>
26+
27+
<div>
28+
<form action="auth.cgi" method="post">
29+
<input type="hidden" name="confirm" value="1">
30+
<input type="hidden" name="callback" value="[% callback FILTER html %]">
31+
<input type="hidden" name="description" value="[% description FILTER html %]">
32+
<input type="hidden" name="token" value="[% token FILTER html %]">
33+
<input type="submit" name="submit" value="Accept">
34+
</form>
35+
</div>
36+
37+
[% PROCESS global/footer.html.tmpl %]

template/en/default/admin/params/auth.html.tmpl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,4 +150,8 @@
150150
"complexity rules and minimum length requirements when the user logs " _
151151
"into the $terms.Bugzilla web interface. If it doesn't, the user would " _
152152
"not be able to log in, and recieve a message to reset their password."
153+
154+
auth_delegation =>
155+
"If set, $terms.Bugzilla will allow third party applications " _
156+
"to request API keys for users."
153157
%]

template/en/default/global/user-error.html.tmpl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,29 @@
129129
account creation. Please contact an administrator to get a new account
130130
created.
131131

132+
[% ELSIF error == "auth_delegation_disabled" %]
133+
[% title = "Can't use auth delegation" %]
134+
This site does not have auth delegation enabled.
135+
Please contact an administrator if you require this functionality.
136+
137+
[% ELSIF error == "auth_delegation_missing_callback" %]
138+
[% title = "Auth delegation impossible without callback URI" %]
139+
It looks like auth delegation was attempted, but no callback URI was passed.
140+
You were sent here by some other site; please contact them for support.
141+
142+
[% ELSIF error == "auth_delegation_missing_description" %]
143+
[% title = "Auth delegation impossible without description" %]
144+
It looks like auth delegation was attempted, but no description was passed.
145+
You were sent here by some other site; please contact them for support.
146+
147+
[% ELSIF error == "auth_delegation_missing_token" %]
148+
[% title = "Auth delegation can't be confirmed" %]
149+
Auth delegation cannot be confirmed due to missing or invalid token.
150+
151+
[% ELSIF error == "auth_delegation_invalid_token" %]
152+
[% title = "Auth delegation can't be confirmed" %]
153+
Auth delegation cannot be confirmed due to missing or invalid token.
154+
132155
[% ELSIF error == "auth_failure" %]
133156
[% title = "Authorization Required" %]
134157
[% admindocslinks = {'groups.html' => 'Group Security'} %]

0 commit comments

Comments
 (0)