From 421ff7f194875db9634ea783d9dd5b6111f19df3 Mon Sep 17 00:00:00 2001 From: Byron Jones Date: Tue, 1 Sep 2015 13:01:20 +0800 Subject: Bug 1197073 - add support for 2fa using totp (eg. google authenticator) --- Bugzilla/MFA/TOTP.pm | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 Bugzilla/MFA/TOTP.pm (limited to 'Bugzilla/MFA') diff --git a/Bugzilla/MFA/TOTP.pm b/Bugzilla/MFA/TOTP.pm new file mode 100644 index 000000000..95e3d89aa --- /dev/null +++ b/Bugzilla/MFA/TOTP.pm @@ -0,0 +1,79 @@ +# 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. + +package Bugzilla::MFA::TOTP; +use strict; +use parent 'Bugzilla::MFA'; + +use Auth::GoogleAuth; +use Bugzilla::Error; +use Bugzilla::Token qw( issue_session_token ); +use Bugzilla::Util qw( template_var generate_random_password ); +use GD::Barcode::QRcode; +use MIME::Base64 qw( encode_base64 ); + +sub _auth { + my ($self) = @_; + return Auth::GoogleAuth->new({ + secret => $self->property_get('secret') // $self->property_get('secret.temp'), + issuer => template_var('terms')->{BugzillaTitle}, + key_id => $self->{user}->login, + }); +} + +sub enroll { + my ($self) = @_; + + # create a new secret for the user + # store it in secret.temp to avoid overwriting a valid secret + $self->property_set('secret.temp', generate_random_password(16)); + + # build the qr code + my $auth = $self->_auth(); + my $otpauth = $auth->qr_code(undef, undef, undef, 1); + my $png = GD::Barcode::QRcode->new($otpauth, { Version => 10, ModuleSize => 3 })->plot()->png(); + return { png => encode_base64($png), secret32 => $auth->secret32 }; +} + +sub enrolled { + my ($self) = @_; + + # make the temporary secret permanent + $self->property_set('secret', $self->property_get('secret.temp')); + $self->property_delete('secret.temp'); +} + +sub prompt { + my ($self, $params) = @_; + my $template = Bugzilla->template; + + my $vars = { + user => $params->{user}, + token => scalar issue_session_token('mfa', $params->{user}), + type => $params->{type}, + }; + + print Bugzilla->cgi->header(); + $template->process('mfa/totp/verify.html.tmpl', $vars) + || ThrowTemplateError($template->error()); +} + +sub check { + my ($self, $code) = @_; + $self->_auth()->verify($code) + || ThrowUserError('mfa_totp_bad_code'); +} + +sub check_login { + my ($self, $user) = @_; + my $cgi = Bugzilla->cgi; + + $self->check($cgi->param('code') // ''); + $user->authorizer->mfa_verified($user, $cgi->param('type')); +} + +1; -- cgit v1.2.3-24-g4f1b