summaryrefslogtreecommitdiffstats
path: root/extensions/GitHubAuth/lib/Login.pm
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/GitHubAuth/lib/Login.pm')
-rw-r--r--extensions/GitHubAuth/lib/Login.pm329
1 files changed, 175 insertions, 154 deletions
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;