lemonldap-ng/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/TOTP.pm

101 lines
2.2 KiB
Perl
Raw Normal View History

2018-02-19 14:23:33 +01:00
package Lemonldap::NG::Portal::2F::TOTP;
use strict;
use Mouse;
use Lemonldap::NG::Portal::Main::Constants qw(
PE_BADCREDENTIALS
PE_ERROR
PE_FORMEMPTY
PE_OK
PE_SENDRESPONSE
);
our $VERSION = '2.0.0';
extends 'Lemonldap::NG::Portal::Main::SecondFactor';
# INITIALIZATION
2018-02-19 22:15:06 +01:00
has prefix => ( is => 'ro', default => 'totp' );
2018-02-19 14:23:33 +01:00
sub init {
my ($self) = @_;
2018-02-19 22:15:06 +01:00
if ( $self->conf->{totp2fActivation} eq '1' ) {
$self->conf->{totp2fActivation} = '$_totp2fSecret';
2018-02-19 14:23:33 +01:00
}
2018-02-19 22:15:06 +01:00
$self->conf->{totp2fInterval} ||= 30;
$self->conf->{totp2fRange} ||= 1;
2018-02-19 14:23:33 +01:00
return $self->SUPER::init();
}
# RUNNING METHODS
sub run {
my ( $self, $req, $token ) = @_;
# Prepare form
my $tmp = $self->p->sendHtml(
$req,
'ext2fcheck',
params => {
SKIN => $self->conf->{portalSkin},
TOKEN => $token
}
);
$self->logger->debug("Prepare TOTP 2F verification");
$req->response($tmp);
return PE_SENDRESPONSE;
}
sub verify {
my ( $self, $req, $session ) = @_;
my $code;
unless ( $code = $req->param('code') ) {
$self->userLogger->error('TOTP 2F: no code');
return PE_FORMEMPTY;
}
2018-02-19 22:15:06 +01:00
my $s = eval { decode_base32( $session->{_totp2fSecret} ) };
2018-02-19 14:23:33 +01:00
if ($@) {
$self->logger->error("Bad characters in secret, aborting");
return PE_ERROR;
}
2018-02-19 22:15:06 +01:00
for ( 0 .. $self->conf->{totp2fRange} ) {
2018-02-19 14:23:33 +01:00
if ( $code eq $self->code( $s, $_ ) ) {
$self->userLogger->info('TOTP verified');
return PE_OK;
}
}
$self->userLogger->notice(
'Invalid TOTP for ' . $session->{ $self->conf->{whatToTrace} } . ')' );
return PE_BADCREDENTIALS;
}
sub code {
my ( $self, $secret, $r ) = @_;
my $hmac = hmac_sha1_hex(
pack(
'H*',
sprintf(
'%016x',
int(
2018-02-19 22:15:06 +01:00
( time + $r * $self->conf->{totp2fInterval} ) /
$self->conf->{totp2fInterval}
2018-02-19 14:23:33 +01:00
)
)
),
_decode_base32($secret),
);
return sprintf(
'%06d',
(
hex( substr( $hmac, hex( substr( $hmac, -1 ) ) * 2, 8 ) ) &
0x7fffffff
) % 1000000
);
}
1;