summaryrefslogtreecommitdiffstats
path: root/auth.cgi
blob: f069e3aec29f435e74a28c5bd0de8ef62eb2753a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/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;
use Digest::SHA qw(sha256_hex);
use LWP::UserAgent ();
use JSON qw(decode_json encode_json);

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 $app_id = sha256_hex($callback_base, $description);
    my $keys = Bugzilla::User::APIKey->match({
        user_id => $user->id,
        app_id  => $app_id,
        revoked => 0,
    });

    my $api_key;
    if (@$keys) {
        $api_key = $keys->[0];
    }
    else {
        $api_key = Bugzilla::User::APIKey->create({
            user_id     => $user->id,
            description => $description,
            app_id      => $app_id,
        });
        my $template = Bugzilla->template_inner($user->setting('lang'));
        my $vars = { user => $user, new_key => $api_key };
        my $message;
        $template->process('email/new-api-key.txt.tmpl', $vars, \$message)
          or ThrowTemplateError($template->error());

        MessageToMTA($message);
    }

    my $ua = LWP::UserAgent->new();
    $ua->timeout(2);
    $ua->protocols_allowed(['http', 'https']);
    # If the URL of the proxy is given, use it, else get this information
    # from the environment variable.
    if (my $proxy_url = Bugzilla->params->{'proxy_url'}) {
        $ua->proxy(['http', 'https'], $proxy_url);
    }
    else {
        $ua->env_proxy;
    }
    my $content = encode_json({ client_api_key => $api_key->api_key,
                                client_api_login => $user->login });
    my $resp = $ua->post($callback_uri,
                         'Content-Type' => 'application/json',
                         Content => $content);
    if ($resp->code == 200) {
        $callback_uri->query_param(client_api_login => $user->login);
        eval {
            my $data = decode_json($resp->content);
            $callback_uri->query_param(callback_result => $data->{result});
        };
        ThrowUserError('auth_delegation_json_error', { json_text => $resp->content }) if $@;

        print $cgi->redirect($callback_uri);
    }
    else {
        ThrowUserError('auth_delegation_post_error', { code => $resp->code });
    }
}
else {
    $args{token} = issue_auth_delegation_token($callback);

    print $cgi->header();
    $template->process("account/auth/delegation.html.tmpl", \%args)
      or ThrowTemplateError($template->error());
}