summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Bugzilla/Config/Auth.pm5
-rw-r--r--Bugzilla/Token.pm50
-rwxr-xr-xauth.cgi88
-rw-r--r--template/en/default/account/auth/delegation.html.tmpl37
-rw-r--r--template/en/default/admin/params/auth.html.tmpl4
-rw-r--r--template/en/default/global/user-error.html.tmpl23
6 files changed, 207 insertions, 0 deletions
diff --git a/Bugzilla/Config/Auth.pm b/Bugzilla/Config/Auth.pm
index f87126713..217805bea 100644
--- a/Bugzilla/Config/Auth.pm
+++ b/Bugzilla/Config/Auth.pm
@@ -143,6 +143,11 @@ sub get_param_list {
type => 'b',
default => '1'
},
+ {
+ name => 'auth_delegation',
+ type => 'b',
+ default => 0,
+ },
);
return @param_list;
}
diff --git a/Bugzilla/Token.pm b/Bugzilla/Token.pm
index 750c36435..7edcd4226 100644
--- a/Bugzilla/Token.pm
+++ b/Bugzilla/Token.pm
@@ -40,10 +40,12 @@ use Date::Format;
use Date::Parse;
use File::Basename;
use Digest::MD5 qw(md5_hex);
+use Digest::SHA qw(hmac_sha256_base64);
use base qw(Exporter);
@Bugzilla::Token::EXPORT = qw(issue_api_token issue_session_token
+ issue_auth_delegation_token check_auth_delegation_token
check_token_data delete_token
issue_hash_token check_hash_token);
@@ -65,6 +67,37 @@ sub issue_api_token {
return $token // _create_token($user->id, 'api_token', '');
}
+sub issue_auth_delegation_token {
+ my ($uri) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $user = Bugzilla->user;
+ my $checksum = hmac_sha256_base64($user->id, $uri, Bugzilla->localconfig->{'site_wide_secret'});
+
+ return _create_token($user->id, 'auth_delegation', $checksum);
+}
+
+sub check_auth_delegation_token {
+ my ($token, $uri) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $user = Bugzilla->user;
+
+ my ($eventdata) = $dbh->selectrow_array("
+ SELECT eventdata FROM tokens
+ WHERE token = ? AND tokentype = 'auth_delegation'
+ AND (" . $dbh->sql_date_math('issuedate', '+', (MAX_TOKEN_AGE * 24 - 12), 'HOUR') . ") > NOW()",
+ undef, $token);
+
+ if ($eventdata) {
+ my $checksum = hmac_sha256_base64($user->id, $uri, Bugzilla->localconfig->{'site_wide_secret'});
+ if ($eventdata eq $checksum) {
+ delete_token($token);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
# Creates and sends a token to create a new user account.
# It assumes that the login has the correct format and is not already in use.
sub issue_new_user_account_token {
@@ -628,6 +661,23 @@ although they can be used separately.
Returns: A unique token.
+=item C<issue_auth_delegation_token($uri)>
+
+ Description: Creates and returns a token used to validate auth delegation confirmations.
+
+ Params: $uri - The uri that auth will be delegated to.
+
+ Returns: A unique token.
+
+=item C<check_auth_delegation_token($token, $uri)>
+
+ Description: Checks if a token $token is a confirmation token for $uri.
+
+ Params: $token - The token returned by issue_auth_delegation_token()
+ $uri - The uri that auth will be delegated to.
+
+ Returns: a boolean value
+
=item C<check_token_data($token, $event)>
Description: Makes sure the $token has been created by the currently logged in
diff --git a/auth.cgi b/auth.cgi
new file mode 100755
index 000000000..ad9017048
--- /dev/null
+++ b/auth.cgi
@@ -0,0 +1,88 @@
+#!/usr/bin/perl -wT
+# 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 5.10.1;
+use strict;
+use warnings;
+
+use lib qw(. lib);
+
+use Bugzilla;
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Hook;
+use Bugzilla::Util qw(trick_taint);
+use Bugzilla::Token qw(issue_auth_delegation_token check_auth_delegation_token);
+use Bugzilla::Mailer qw(MessageToMTA);
+
+use URI;
+use URI::QueryParam;
+
+Bugzilla->login(LOGIN_REQUIRED);
+
+ThrowUserError('auth_delegation_disabled') unless Bugzilla->params->{auth_delegation};
+
+my $cgi = Bugzilla->cgi;
+my $template = Bugzilla->template;
+my $user = Bugzilla->user;
+my $callback = $cgi->param('callback') or ThrowUserError("auth_delegation_missing_callback");
+my $description = $cgi->param('description') or ThrowUserError("auth_delegation_missing_description");
+
+trick_taint($callback);
+trick_taint($description);
+
+my $callback_uri = URI->new($callback);
+my $callback_base = $callback_uri->clone;
+$callback_base->query(undef);
+
+my $skip_confirmation = 0;
+my %args = ( skip_confirmation => \$skip_confirmation,
+ callback => $callback_uri,
+ description => $description,
+ callback_base => $callback_base );
+
+Bugzilla::Hook::process('auth_delegation_confirm', \%args);
+
+my $confirmed = lc($cgi->request_method) eq 'post' && $cgi->param('confirm');
+
+if ($confirmed || $skip_confirmation) {
+ my $token = $cgi->param('token');
+ unless ($skip_confirmation) {
+ ThrowUserError("auth_delegation_missing_token") unless $token;
+ trick_taint($token);
+
+ unless (check_auth_delegation_token($token, $callback)) {
+ ThrowUserError('auth_delegation_invalid_token',
+ { token => $token, callback => $callback });
+ }
+ }
+
+ my $new_key = Bugzilla::User::APIKey->create({
+ user_id => $user->id,
+ description => $description,
+ });
+ my $template = Bugzilla->template_inner($user->setting('lang'));
+ my $vars = { user => $user, new_key => $new_key };
+ my $message;
+ $template->process('email/new-api-key.txt.tmpl', $vars, \$message)
+ or ThrowTemplateError($template->error());
+
+ MessageToMTA($message);
+
+ $callback_uri->query_param(client_api_key => $new_key->api_key);
+ $callback_uri->query_param(client_api_login => $user->login);
+
+ print $cgi->redirect($callback_uri);
+}
+else {
+ $args{token} = issue_auth_delegation_token($callback);
+
+ print $cgi->header();
+ $template->process("account/auth/delegation.html.tmpl", \%args)
+ or ThrowTemplateError($template->error());
+}
diff --git a/template/en/default/account/auth/delegation.html.tmpl b/template/en/default/account/auth/delegation.html.tmpl
new file mode 100644
index 000000000..2afdf1dc7
--- /dev/null
+++ b/template/en/default/account/auth/delegation.html.tmpl
@@ -0,0 +1,37 @@
+[%# 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.
+ #%]
+
+[% PROCESS global/header.html.tmpl
+ title = "Auth Delegation Request" %]
+
+<h1>[% title FILTER html %] </h1>
+<p>
+ A third-party website (<a href="[% callback_base FILTER html %]">[% callback_base FILTER html %]</a>)
+ would like to have <strong>complete</strong> access to your [% terms.Bugzilla %] account.
+</p>
+
+<p>The description of the site reads:
+ <blockquote>
+ [% description FILTER html %]
+ </blockquote>
+</p>
+
+<p>Do you want this website to have <strong>complete</strong> access to your [% terms.Bugzilla %]
+ account?</p>
+
+<div>
+ <form action="auth.cgi" method="post">
+ <input type="hidden" name="confirm" value="1">
+ <input type="hidden" name="callback" value="[% callback FILTER html %]">
+ <input type="hidden" name="description" value="[% description FILTER html %]">
+ <input type="hidden" name="token" value="[% token FILTER html %]">
+ <input type="submit" name="submit" value="Accept">
+ </form>
+</div>
+
+[% PROCESS global/footer.html.tmpl %]
diff --git a/template/en/default/admin/params/auth.html.tmpl b/template/en/default/admin/params/auth.html.tmpl
index 85d707706..fea4239b3 100644
--- a/template/en/default/admin/params/auth.html.tmpl
+++ b/template/en/default/admin/params/auth.html.tmpl
@@ -150,4 +150,8 @@
"complexity rules and minimum length requirements when the user logs " _
"into the $terms.Bugzilla web interface. If it doesn't, the user would " _
"not be able to log in, and recieve a message to reset their password."
+
+ auth_delegation =>
+ "If set, $terms.Bugzilla will allow third party applications " _
+ "to request API keys for users."
%]
diff --git a/template/en/default/global/user-error.html.tmpl b/template/en/default/global/user-error.html.tmpl
index 5b2f50116..8c7958649 100644
--- a/template/en/default/global/user-error.html.tmpl
+++ b/template/en/default/global/user-error.html.tmpl
@@ -129,6 +129,29 @@
account creation. Please contact an administrator to get a new account
created.
+ [% ELSIF error == "auth_delegation_disabled" %]
+ [% title = "Can't use auth delegation" %]
+ This site does not have auth delegation enabled.
+ Please contact an administrator if you require this functionality.
+
+ [% ELSIF error == "auth_delegation_missing_callback" %]
+ [% title = "Auth delegation impossible without callback URI" %]
+ It looks like auth delegation was attempted, but no callback URI was passed.
+ You were sent here by some other site; please contact them for support.
+
+ [% ELSIF error == "auth_delegation_missing_description" %]
+ [% title = "Auth delegation impossible without description" %]
+ It looks like auth delegation was attempted, but no description was passed.
+ You were sent here by some other site; please contact them for support.
+
+ [% ELSIF error == "auth_delegation_missing_token" %]
+ [% title = "Auth delegation can't be confirmed" %]
+ Auth delegation cannot be confirmed due to missing or invalid token.
+
+ [% ELSIF error == "auth_delegation_invalid_token" %]
+ [% title = "Auth delegation can't be confirmed" %]
+ Auth delegation cannot be confirmed due to missing or invalid token.
+
[% ELSIF error == "auth_failure" %]
[% title = "Authorization Required" %]
[% admindocslinks = {'groups.html' => 'Group Security'} %]