From: Dylan William Hardison
Date: Thu, 18 Apr 2019 14:26:08 +0000 (-0400)
Subject: Bug 1541555 - Add facility for requiring an API Key to always come from the same...
X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1d7edc53aebdb84bace923f02f86a75bf43cb0fa;p=thirdparty%2Fbugzilla.git
Bug 1541555 - Add facility for requiring an API Key to always come from the same IP address
---
diff --git a/Bugzilla/Auth/Login/APIKey.pm b/Bugzilla/Auth/Login/APIKey.pm
index 43032c584..f6d2dea38 100644
--- a/Bugzilla/Auth/Login/APIKey.pm
+++ b/Bugzilla/Auth/Login/APIKey.pm
@@ -47,18 +47,25 @@ sub get_login_info {
return {failure => AUTH_NODATA};
}
- my $api_key = Bugzilla::User::APIKey->new({name => $api_key_text});
+ my $api_key = Bugzilla::User::APIKey->new({name => $api_key_text});
+ my $remote_ip = remote_ip();
if (!$api_key or $api_key->api_key ne $api_key_text) {
# The second part checks the correct capitalisation. Silly MySQL
ThrowUserError("api_key_not_valid");
}
+ elsif ( $api_key->sticky
+ && $api_key->last_used_ip
+ && $api_key->last_used_ip ne $remote_ip)
+ {
+ ThrowUserError("api_key_not_valid");
+ }
elsif ($api_key->revoked) {
ThrowUserError('api_key_revoked');
}
- $api_key->update_last_used();
+ $api_key->update_last_used($remote_ip);
$self->set_app_id($api_key->app_id);
return {user_id => $api_key->user_id};
diff --git a/Bugzilla/User/APIKey.pm b/Bugzilla/User/APIKey.pm
index a30c6718f..86f7ba2db 100644
--- a/Bugzilla/User/APIKey.pm
+++ b/Bugzilla/User/APIKey.pm
@@ -14,7 +14,7 @@ use warnings;
use base qw(Bugzilla::Object);
use Bugzilla::User;
-use Bugzilla::Util qw(generate_random_password trim remote_ip);
+use Bugzilla::Util qw(generate_random_password trim);
use Bugzilla::Error;
#####################################################################
@@ -31,14 +31,16 @@ use constant DB_COLUMNS => qw(
revoked
last_used
last_used_ip
+ sticky
);
-use constant UPDATE_COLUMNS => qw(description revoked last_used last_used_ip);
+use constant UPDATE_COLUMNS => qw(description revoked last_used last_used_ip sticky);
use constant VALIDATORS => {
api_key => \&_check_api_key,
app_id => \&_check_app_id,
description => \&_check_description,
revoked => \&Bugzilla::Object::check_boolean,
+ sticky => \&Bugzilla::Object::check_boolean,
};
use constant LIST_ORDER => 'id';
use constant NAME_FIELD => 'api_key';
@@ -60,6 +62,7 @@ sub description { return $_[0]->{description} }
sub revoked { return $_[0]->{revoked} }
sub last_used { return $_[0]->{last_used} }
sub last_used_ip { return $_[0]->{last_used_ip} }
+sub sticky { return $_[0]->{sticky} }
# Helpers
sub user {
@@ -69,17 +72,17 @@ sub user {
}
sub update_last_used {
- my $self = shift;
- my $timestamp
- = shift || Bugzilla->dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
+ my ($self, $remote_ip) = @_;
+ my $timestamp = Bugzilla->dbh->selectrow_array('SELECT LOCALTIMESTAMP(0)');
$self->set('last_used', $timestamp);
- $self->set('last_used_ip', remote_ip());
+ $self->set('last_used_ip', $remote_ip);
$self->update;
}
# Setters
sub set_description { $_[0]->set('description', $_[1]); }
sub set_revoked { $_[0]->set('revoked', $_[1]); }
+sub set_sticky { $_[0]->set('sticky', $_[1]); }
# Validators
sub _check_api_key { return generate_random_password(40); }
diff --git a/docs/en/rst/using/preferences.rst b/docs/en/rst/using/preferences.rst
index d61dc4f8a..cfce75d6d 100644
--- a/docs/en/rst/using/preferences.rst
+++ b/docs/en/rst/using/preferences.rst
@@ -132,10 +132,15 @@ change your password everywhere.
You can create more than one API key if required. Each API key has an optional
description which can help you record what it is used for.
-On this page, you can unrevoke, revoke and change the description of existing
+On this page, you can unrevoke, revoke, make sticky, and change the description of existing
API keys for your login. A revoked key means that it cannot be used. The
description is optional and purely for your information.
+Sticky API keys may only be used from one IP address, which reduces the risk
+of the key being leaked. The IP address is the one the key was last used
+from. The expected workflow is that the sticky bit will be set once your application
+(or script) is setup. The sticky attribute may only be set, it can't ever be unset.
+
You can also create a new API key by selecting the checkbox under the 'New
API key' section of the page.
diff --git a/template/en/default/account/prefs/apikey.html.tmpl b/template/en/default/account/prefs/apikey.html.tmpl
index 19cec468f..3a27b0a9c 100644
--- a/template/en/default/account/prefs/apikey.html.tmpl
+++ b/template/en/default/account/prefs/apikey.html.tmpl
@@ -14,8 +14,9 @@
API keys are used to authenticate WebService API calls. You can create more than
one API key if required. Each API key has an optional description which can help
- you record what each key is used for.
-
+ you record what each key is used for.
+
+
Documentation on how to log in is available
here.
@@ -24,13 +25,14 @@
Existing API keys
You can update the description, and revoke or unrevoke existing API keys
-here.
+here. Sticky keys may only be used from the last IP that used the API key, and cannot be unset.
API key
Description (optional)
Last used
+
Sticky
Revoked
@@ -51,6 +53,12 @@ here.
[% ELSE %]
never used
[% END %]
+
+
+
param('description_' . $api_key->id);
my $revoked = !!$cgi->param('revoked_' . $api_key->id);
+ my $sticky = !!$cgi->param('sticky_' . $api_key->id);
- if ($description ne $api_key->description || $revoked != $api_key->revoked) {
+ if ( $description ne $api_key->description
+ || $revoked != $api_key->revoked
+ || $sticky != $api_key->sticky)
+ {
if ($user->mfa && !$revoked && $api_key->revoked) {
push @mfa_events,
{
@@ -862,7 +866,9 @@ sub SaveApiKey {
};
}
else {
- $api_key->set_all({description => $description, revoked => $revoked,});
+ $sticky = 1 if $api_key->sticky;
+ $api_key->set_all(
+ {description => $description, revoked => $revoked, sticky => $sticky});
$api_key->update();
if ($revoked) {
Bugzilla->log_user_request(undef, undef, 'api-key-revoke');