summaryrefslogtreecommitdiffstats
path: root/extensions/GitHubAuth/lib
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/GitHubAuth/lib')
-rw-r--r--extensions/GitHubAuth/lib/Client.pm134
-rw-r--r--extensions/GitHubAuth/lib/Client/Error.pm42
-rw-r--r--extensions/GitHubAuth/lib/Config.pm24
-rw-r--r--extensions/GitHubAuth/lib/Login.pm329
-rw-r--r--extensions/GitHubAuth/lib/Verify.pm6
5 files changed, 275 insertions, 260 deletions
diff --git a/extensions/GitHubAuth/lib/Client.pm b/extensions/GitHubAuth/lib/Client.pm
index 291501961..328bab48f 100644
--- a/extensions/GitHubAuth/lib/Client.pm
+++ b/extensions/GitHubAuth/lib/Client.pm
@@ -16,7 +16,8 @@ use URI;
use URI::QueryParam;
use Digest;
-use Bugzilla::Extension::GitHubAuth::Client::Error qw(ThrowUserError ThrowCodeError);
+use Bugzilla::Extension::GitHubAuth::Client::Error
+ qw(ThrowUserError ThrowCodeError);
use Bugzilla::Util qw(remote_ip);
use constant DIGEST_HASH => 'SHA1';
@@ -24,107 +25,108 @@ use constant DIGEST_HASH => 'SHA1';
use fields qw(user_agent);
use constant {
- GH_ACCESS_TOKEN_URI => 'https://github.com/login/oauth/access_token',
- GH_AUTHORIZE_URI => 'https://github.com/login/oauth/authorize',
- GH_USER_EMAILS_URI => 'https://api.github.com/user/emails',
+ GH_ACCESS_TOKEN_URI => 'https://github.com/login/oauth/access_token',
+ GH_AUTHORIZE_URI => 'https://github.com/login/oauth/authorize',
+ GH_USER_EMAILS_URI => 'https://api.github.com/user/emails',
};
sub new {
- my ($class, %init) = @_;
- my $self = $class->fields::new();
+ my ($class, %init) = @_;
+ my $self = $class->fields::new();
- return $self;
+ return $self;
}
sub login_uri {
- my ($class, $target_uri) = @_;
+ my ($class, $target_uri) = @_;
- my $uri = URI->new(Bugzilla->localconfig->{urlbase} . "github.cgi");
- $uri->query_form(target_uri => $target_uri);
- return $uri;
+ my $uri = URI->new(Bugzilla->localconfig->{urlbase} . "github.cgi");
+ $uri->query_form(target_uri => $target_uri);
+ return $uri;
}
sub authorize_uri {
- my ($class, $state) = @_;
+ my ($class, $state) = @_;
- my $uri = URI->new(GH_AUTHORIZE_URI);
- $uri->query_form(
- client_id => Bugzilla->params->{github_client_id},
- scope => 'user:email',
- state => $state,
- redirect_uri => Bugzilla->localconfig->{urlbase} . "github.cgi",
- );
+ my $uri = URI->new(GH_AUTHORIZE_URI);
+ $uri->query_form(
+ client_id => Bugzilla->params->{github_client_id},
+ scope => 'user:email',
+ state => $state,
+ redirect_uri => Bugzilla->localconfig->{urlbase} . "github.cgi",
+ );
- return $uri;
+ return $uri;
}
sub get_email_key {
- my ($class, $email) = @_;
-
- my $cgi = Bugzilla->cgi;
- my $digest = Digest->new(DIGEST_HASH);
- $digest->add($email);
- $digest->add(remote_ip());
- $digest->add($cgi->cookie('Bugzilla_github_token') // Bugzilla->request_cache->{github_token} // '');
- $digest->add(Bugzilla->localconfig->{site_wide_secret});
- return $digest->hexdigest;
+ my ($class, $email) = @_;
+
+ my $cgi = Bugzilla->cgi;
+ my $digest = Digest->new(DIGEST_HASH);
+ $digest->add($email);
+ $digest->add(remote_ip());
+ $digest->add($cgi->cookie('Bugzilla_github_token')
+ // Bugzilla->request_cache->{github_token} // '');
+ $digest->add(Bugzilla->localconfig->{site_wide_secret});
+ return $digest->hexdigest;
}
sub _handle_response {
- my ($self, $response) = @_;
- my $data = eval {
- decode_json($response->content);
- };
- if ($@) {
- ThrowCodeError("github_bad_response", { message => "Unable to parse json response" });
- }
-
- unless ($response->is_success) {
- ThrowCodeError("github_error", { response => $response });
- }
- return $data;
+ my ($self, $response) = @_;
+ my $data = eval { decode_json($response->content); };
+ if ($@) {
+ ThrowCodeError("github_bad_response",
+ {message => "Unable to parse json response"});
+ }
+
+ unless ($response->is_success) {
+ ThrowCodeError("github_error", {response => $response});
+ }
+ return $data;
}
sub get_access_token {
- my ($self, $code) = @_;
-
- my $response = $self->user_agent->post(
- GH_ACCESS_TOKEN_URI,
- { client_id => Bugzilla->params->{github_client_id},
- client_secret => Bugzilla->params->{github_client_secret},
- code => $code },
- Accept => 'application/json',
- );
- my $data = $self->_handle_response($response);
- return $data->{access_token} if exists $data->{access_token};
+ my ($self, $code) = @_;
+
+ my $response = $self->user_agent->post(GH_ACCESS_TOKEN_URI,
+ {
+ client_id => Bugzilla->params->{github_client_id},
+ client_secret => Bugzilla->params->{github_client_secret},
+ code => $code
+ },
+ Accept => 'application/json',
+ );
+ my $data = $self->_handle_response($response);
+ return $data->{access_token} if exists $data->{access_token};
}
sub get_user_emails {
- my ($self, $access_token) = @_;
- my $uri = URI->new(GH_USER_EMAILS_URI);
- $uri->query_form(access_token => $access_token);
+ my ($self, $access_token) = @_;
+ my $uri = URI->new(GH_USER_EMAILS_URI);
+ $uri->query_form(access_token => $access_token);
- my $response = $self->user_agent->get($uri, Accept => 'application/json');
+ my $response = $self->user_agent->get($uri, Accept => 'application/json');
- return $self->_handle_response($response);
+ return $self->_handle_response($response);
}
sub user_agent {
- my ($self) = @_;
- $self->{user_agent} //= $self->_build_user_agent;
+ my ($self) = @_;
+ $self->{user_agent} //= $self->_build_user_agent;
- return $self->{user_agent};
+ return $self->{user_agent};
}
sub _build_user_agent {
- my ($self) = @_;
- my $ua = LWP::UserAgent->new( timeout => 10 );
+ my ($self) = @_;
+ my $ua = LWP::UserAgent->new(timeout => 10);
- if (Bugzilla->params->{proxy_url}) {
- $ua->proxy('https', Bugzilla->params->{proxy_url});
- }
+ if (Bugzilla->params->{proxy_url}) {
+ $ua->proxy('https', Bugzilla->params->{proxy_url});
+ }
- return $ua;
+ return $ua;
}
1;
diff --git a/extensions/GitHubAuth/lib/Client/Error.pm b/extensions/GitHubAuth/lib/Client/Error.pm
index adb6ec07b..00e8415d1 100644
--- a/extensions/GitHubAuth/lib/Client/Error.pm
+++ b/extensions/GitHubAuth/lib/Client/Error.pm
@@ -16,39 +16,39 @@ use Bugzilla::Error ();
use base qw(Exporter);
use fields qw(type error vars);
-our @EXPORT = qw(ThrowUserError ThrowCodeError);
+our @EXPORT = qw(ThrowUserError ThrowCodeError);
our $USE_EXCEPTION_OBJECTS = 0;
sub _new {
- my ($class, $type, $error, $vars) = @_;
- my $self = $class->fields::new();
- $self->{type} = $type;
- $self->{error} = $error;
- $self->{vars} = $vars // {};
+ my ($class, $type, $error, $vars) = @_;
+ my $self = $class->fields::new();
+ $self->{type} = $type;
+ $self->{error} = $error;
+ $self->{vars} = $vars // {};
- return $self;
+ return $self;
}
-sub type { $_[0]->{type} }
+sub type { $_[0]->{type} }
sub error { $_[0]->{error} }
-sub vars { $_[0]->{vars} }
+sub vars { $_[0]->{vars} }
sub ThrowUserError {
- if ($USE_EXCEPTION_OBJECTS) {
- die __PACKAGE__->_new('user', @_);
- }
- else {
- Bugzilla::Error::ThrowUserError(@_);
- }
+ if ($USE_EXCEPTION_OBJECTS) {
+ die __PACKAGE__->_new('user', @_);
+ }
+ else {
+ Bugzilla::Error::ThrowUserError(@_);
+ }
}
sub ThrowCodeError {
- if ($USE_EXCEPTION_OBJECTS) {
- die __PACKAGE__->_new('code', @_);
- }
- else {
- Bugzilla::Error::ThrowCodeError(@_);
- }
+ if ($USE_EXCEPTION_OBJECTS) {
+ die __PACKAGE__->_new('code', @_);
+ }
+ else {
+ Bugzilla::Error::ThrowCodeError(@_);
+ }
}
1;
diff --git a/extensions/GitHubAuth/lib/Config.pm b/extensions/GitHubAuth/lib/Config.pm
index 0c8874129..b718b4be5 100644
--- a/extensions/GitHubAuth/lib/Config.pm
+++ b/extensions/GitHubAuth/lib/Config.pm
@@ -16,22 +16,14 @@ use Bugzilla::Config::Common;
our $sortkey = 1350;
sub get_param_list {
- my ($class) = @_;
-
- my @params = (
- {
- name => 'github_client_id',
- type => 't',
- default => '',
- },
- {
- name => 'github_client_secret',
- type => 't',
- default => '',
- },
- );
-
- return @params;
+ my ($class) = @_;
+
+ my @params = (
+ {name => 'github_client_id', type => 't', default => '',},
+ {name => 'github_client_secret', type => 't', default => '',},
+ );
+
+ return @params;
}
1;
diff --git a/extensions/GitHubAuth/lib/Login.pm b/extensions/GitHubAuth/lib/Login.pm
index 073fbfeea..df3195bc7 100644
--- a/extensions/GitHubAuth/lib/Login.pm
+++ b/extensions/GitHubAuth/lib/Login.pm
@@ -24,187 +24,208 @@ use Bugzilla::Extension::GitHubAuth::Client;
use Bugzilla::Extension::GitHubAuth::Client::Error ();
use Bugzilla::Error;
-use constant { requires_verification => 1,
- is_automatic => 1,
- user_can_create_account => 1 };
+use constant {requires_verification => 1, is_automatic => 1,
+ user_can_create_account => 1};
sub get_login_info {
- my ($self) = @_;
- my $cgi = Bugzilla->cgi;
- my $github_action = Bugzilla->request_cache->{github_action};
-
- return { failure => AUTH_NODATA } unless $github_action;
-
- my $response;
- if ($github_action eq 'login') {
- $response = $self->_get_login_info_from_github();
- }
- elsif ($github_action eq 'email') {
- $response = $self->_get_login_info_from_email();
- }
-
- if (!exists $response->{failure}) {
- if (exists $response->{user}) {
- # existing account
- my $user = $response->{user};
- return { failure => AUTH_ERROR,
- user_error => 'github_auth_account_too_powerful' } if $user->in_group('no-github-auth');
- return { failure => AUTH_ERROR,
- user_error => 'mfa_prevents_login',
- details => { provider => 'GitHub' } } if $user->mfa;
- $response = {
- username => $user->login,
- user_id => $user->id,
- github_auth => 1,
- };
+ my ($self) = @_;
+ my $cgi = Bugzilla->cgi;
+ my $github_action = Bugzilla->request_cache->{github_action};
+
+ return {failure => AUTH_NODATA} unless $github_action;
+
+ my $response;
+ if ($github_action eq 'login') {
+ $response = $self->_get_login_info_from_github();
+ }
+ elsif ($github_action eq 'email') {
+ $response = $self->_get_login_info_from_email();
+ }
+
+ if (!exists $response->{failure}) {
+ if (exists $response->{user}) {
+
+ # existing account
+ my $user = $response->{user};
+ return {
+ failure => AUTH_ERROR,
+ user_error => 'github_auth_account_too_powerful'
}
- else {
- # new account
- my $email = $response->{email};
- $response = {
- username => $email,
- github_auth => 1,
- };
+ if $user->in_group('no-github-auth');
+ return {
+ failure => AUTH_ERROR,
+ user_error => 'mfa_prevents_login',
+ details => {provider => 'GitHub'}
}
+ if $user->mfa;
+ $response = {username => $user->login, user_id => $user->id, github_auth => 1,};
}
- return $response;
+ else {
+ # new account
+ my $email = $response->{email};
+ $response = {username => $email, github_auth => 1,};
+ }
+ }
+ return $response;
}
sub _get_login_info_from_github {
- my ($self) = @_;
- my $cgi = Bugzilla->cgi;
- my $template = Bugzilla->template;
- my $code = $cgi->param('code');
-
- return { failure => AUTH_ERROR, error => 'github_missing_code' } unless $code;
-
- trick_taint($code);
-
- my $client = Bugzilla::Extension::GitHubAuth::Client->new;
-
- my ($access_token, $emails);
- eval {
- # The following variable lets us catch and return (rather than throw) errors
- # from our github client code, as required by the Auth API.
- local $Bugzilla::Extension::GitHubAuth::Client::Error::USE_EXCEPTION_OBJECTS = 1;
- $access_token = $client->get_access_token($code);
- $emails = $client->get_user_emails($access_token);
- };
- my $e = $@;
- if (blessed $e && $e->isa('Bugzilla::Extension::GitHubAuth::Client::Error')) {
- my $key = $e->type eq 'user' ? 'user_error' : 'error';
- return { failure => AUTH_ERROR, $key => $e->error, details => $e->vars };
- }
- elsif ($e) {
- die $e;
- }
-
- my @emails = map { $_->{email} }
- grep { $_->{verified} && $_->{email} !~ /\@users\.noreply\.github\.com$/ } @$emails;
-
- my @bugzilla_users;
- my @github_emails;
- foreach my $email (@emails) {
- my $user = Bugzilla::User->new({name => $email, cache => 1});
- if ($user) {
- push @bugzilla_users, $user;
- }
- else {
- push @github_emails, $email;
- }
- }
- my @allowed_bugzilla_users = grep { not $_->in_group('no-github-auth') } @bugzilla_users;
-
- if (@allowed_bugzilla_users == 1) {
- my ($user) = @allowed_bugzilla_users;
- return { user => $user };
- }
- elsif (@allowed_bugzilla_users > 1) {
- $self->{github_failure} = {
- template => 'account/auth/github-verify-account.html.tmpl',
- vars => {
- bugzilla_users => \@allowed_bugzilla_users,
- choose_email => _mk_choose_email(\@emails),
- },
- };
- return { failure => AUTH_NODATA };
- }
- elsif (@allowed_bugzilla_users == 0 && @bugzilla_users > 0 && @github_emails == 0) {
- return { failure => AUTH_ERROR,
- user_error => 'github_auth_account_too_powerful' };
- }
- elsif (@github_emails) {
- $self->{github_failure} = {
- template => 'account/auth/github-verify-account.html.tmpl',
- vars => {
- github_emails => \@github_emails,
- choose_email => _mk_choose_email(\@emails),
- },
- };
- return { failure => AUTH_NODATA };
+ my ($self) = @_;
+ my $cgi = Bugzilla->cgi;
+ my $template = Bugzilla->template;
+ my $code = $cgi->param('code');
+
+ return {failure => AUTH_ERROR, error => 'github_missing_code'} unless $code;
+
+ trick_taint($code);
+
+ my $client = Bugzilla::Extension::GitHubAuth::Client->new;
+
+ my ($access_token, $emails);
+ eval {
+ # The following variable lets us catch and return (rather than throw) errors
+ # from our github client code, as required by the Auth API.
+ local $Bugzilla::Extension::GitHubAuth::Client::Error::USE_EXCEPTION_OBJECTS
+ = 1;
+ $access_token = $client->get_access_token($code);
+ $emails = $client->get_user_emails($access_token);
+ };
+ my $e = $@;
+ if (blessed $e && $e->isa('Bugzilla::Extension::GitHubAuth::Client::Error')) {
+ my $key = $e->type eq 'user' ? 'user_error' : 'error';
+ return {failure => AUTH_ERROR, $key => $e->error, details => $e->vars};
+ }
+ elsif ($e) {
+ die $e;
+ }
+
+ my @emails
+ = map { $_->{email} }
+ grep { $_->{verified} && $_->{email} !~ /\@users\.noreply\.github\.com$/ }
+ @$emails;
+
+ my @bugzilla_users;
+ my @github_emails;
+ foreach my $email (@emails) {
+ my $user = Bugzilla::User->new({name => $email, cache => 1});
+ if ($user) {
+ push @bugzilla_users, $user;
}
else {
- return { failure => AUTH_ERROR, user_error => 'github_no_emails' };
+ push @github_emails, $email;
}
+ }
+ my @allowed_bugzilla_users
+ = grep { not $_->in_group('no-github-auth') } @bugzilla_users;
+
+ if (@allowed_bugzilla_users == 1) {
+ my ($user) = @allowed_bugzilla_users;
+ return {user => $user};
+ }
+ elsif (@allowed_bugzilla_users > 1) {
+ $self->{github_failure} = {
+ template => 'account/auth/github-verify-account.html.tmpl',
+ vars => {
+ bugzilla_users => \@allowed_bugzilla_users,
+ choose_email => _mk_choose_email(\@emails),
+ },
+ };
+ return {failure => AUTH_NODATA};
+ }
+ elsif (@allowed_bugzilla_users == 0
+ && @bugzilla_users > 0
+ && @github_emails == 0)
+ {
+ return {
+ failure => AUTH_ERROR,
+ user_error => 'github_auth_account_too_powerful'
+ };
+ }
+ elsif (@github_emails) {
+ $self->{github_failure} = {
+ template => 'account/auth/github-verify-account.html.tmpl',
+ vars => {
+ github_emails => \@github_emails,
+ choose_email => _mk_choose_email(\@emails),
+ },
+ };
+ return {failure => AUTH_NODATA};
+ }
+ else {
+ return {failure => AUTH_ERROR, user_error => 'github_no_emails'};
+ }
}
sub _get_login_info_from_email {
- my ($self) = @_;
- my $cgi = Bugzilla->cgi;
- my $email = $cgi->param('email') or return { failure => AUTH_ERROR,
- user_error => 'github_invalid_email',
- details => { email => '' } };
- trick_taint($email);
-
- unless (any { $_ eq $email } @{ Bugzilla->request_cache->{github_emails} }) {
- return { failure => AUTH_ERROR,
- user_error => 'github_invalid_email',
- details => { email => $email }};
- }
+ my ($self) = @_;
+ my $cgi = Bugzilla->cgi;
+ my $email = $cgi->param('email')
+ or return {
+ failure => AUTH_ERROR,
+ user_error => 'github_invalid_email',
+ details => {email => ''}
+ };
+ trick_taint($email);
- my $user = Bugzilla::User->new({name => $email, cache => 1});
- $cgi->remove_cookie('Bugzilla_github_token');
- return $user ? { user => $user } : { email => $email };
+ unless (any { $_ eq $email } @{Bugzilla->request_cache->{github_emails}}) {
+ return {
+ failure => AUTH_ERROR,
+ user_error => 'github_invalid_email',
+ details => {email => $email}
+ };
+ }
+
+ my $user = Bugzilla::User->new({name => $email, cache => 1});
+ $cgi->remove_cookie('Bugzilla_github_token');
+ return $user ? {user => $user} : {email => $email};
}
sub fail_nodata {
- my ($self) = @_;
- my $cgi = Bugzilla->cgi;
- my $template = Bugzilla->template;
+ my ($self) = @_;
+ my $cgi = Bugzilla->cgi;
+ my $template = Bugzilla->template;
- ThrowUserError('login_required') if Bugzilla->usage_mode != USAGE_MODE_BROWSER;
+ ThrowUserError('login_required') if Bugzilla->usage_mode != USAGE_MODE_BROWSER;
- my $file = $self->{github_failure}{template} // "account/auth/login.html.tmpl";
- my $vars = $self->{github_failure}{vars} // { target => $cgi->url(-relative=>1) };
+ my $file = $self->{github_failure}{template} // "account/auth/login.html.tmpl";
+ my $vars = $self->{github_failure}{vars}
+ // {target => $cgi->url(-relative => 1)};
- print $cgi->header();
- $template->process($file, $vars) or ThrowTemplateError($template->error());
- exit;
+ print $cgi->header();
+ $template->process($file, $vars) or ThrowTemplateError($template->error());
+ exit;
}
sub _store_emails {
- my ($emails) = @_;
- my $state = issue_short_lived_session_token("github_email");
- set_token_extra_data($state, { type => 'github_email',
- emails => $emails,
- target_uri => Bugzilla->request_cache->{github_target_uri} });
-
- Bugzilla->cgi->send_cookie(-name => 'github_state',
- -value => $state,
- -httponly => 1);
- return $state;
+ my ($emails) = @_;
+ my $state = issue_short_lived_session_token("github_email");
+ set_token_extra_data(
+ $state,
+ {
+ type => 'github_email',
+ emails => $emails,
+ target_uri => Bugzilla->request_cache->{github_target_uri}
+ }
+ );
+
+ Bugzilla->cgi->send_cookie(
+ -name => 'github_state',
+ -value => $state,
+ -httponly => 1
+ );
+ return $state;
}
sub _mk_choose_email {
- my ($emails) = @_;
- my $state = _store_emails($emails);
-
- return sub {
- my $email = shift;
- my $uri = URI->new(Bugzilla->localconfig->{urlbase} . "github.cgi");
- $uri->query_form( state => $state, email => $email );
- return $uri;
- };
+ my ($emails) = @_;
+ my $state = _store_emails($emails);
+
+ return sub {
+ my $email = shift;
+ my $uri = URI->new(Bugzilla->localconfig->{urlbase} . "github.cgi");
+ $uri->query_form(state => $state, email => $email);
+ return $uri;
+ };
}
1;
diff --git a/extensions/GitHubAuth/lib/Verify.pm b/extensions/GitHubAuth/lib/Verify.pm
index f399af02e..078353c80 100644
--- a/extensions/GitHubAuth/lib/Verify.pm
+++ b/extensions/GitHubAuth/lib/Verify.pm
@@ -16,11 +16,11 @@ use base qw(Bugzilla::Auth::Verify);
use Bugzilla::Constants qw( AUTH_NO_SUCH_USER );
sub check_credentials {
- my ($self, $login_data) = @_;
+ my ($self, $login_data) = @_;
- return { failure => AUTH_NO_SUCH_USER } unless $login_data->{github_auth};
+ return {failure => AUTH_NO_SUCH_USER} unless $login_data->{github_auth};
- return $login_data;
+ return $login_data;
}
1;