From d37a38432820036dbad62f962c281b44ae76383a Mon Sep 17 00:00:00 2001 From: Xavier Guimard Date: Mon, 19 Feb 2018 22:34:23 +0100 Subject: [PATCH] Move TOTP verification in Common (#1359) This Common module will be used also in admin interface --- lemonldap-ng-common/MANIFEST | 1 + .../lib/Lemonldap/NG/Common/TOTP.pm | 40 +++++++++++++ .../lib/Lemonldap/NG/Portal/2F/TOTP.pm | 56 ++++++------------- 3 files changed, 58 insertions(+), 39 deletions(-) create mode 100644 lemonldap-ng-common/lib/Lemonldap/NG/Common/TOTP.pm diff --git a/lemonldap-ng-common/MANIFEST b/lemonldap-ng-common/MANIFEST index 75a93f052..6ef5c0ab1 100644 --- a/lemonldap-ng-common/MANIFEST +++ b/lemonldap-ng-common/MANIFEST @@ -57,6 +57,7 @@ lib/Lemonldap/NG/Common/Regexp.pm lib/Lemonldap/NG/Common/Safelib.pm lib/Lemonldap/NG/Common/Session.pm lib/Lemonldap/NG/Common/Session/REST.pm +lib/Lemonldap/NG/Common/TOTP.pm lib/Lemonldap/NG/Common/UserAgent.pm Makefile.PL MANIFEST This list of files diff --git a/lemonldap-ng-common/lib/Lemonldap/NG/Common/TOTP.pm b/lemonldap-ng-common/lib/Lemonldap/NG/Common/TOTP.pm new file mode 100644 index 000000000..219480326 --- /dev/null +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/TOTP.pm @@ -0,0 +1,40 @@ +package Lemonldap::NG::Common::TOTP; + +use strict; +use Mouse; + +our $VERSION = '2.0.0'; + +sub verifyCode { + my ( $self, $interval, $range, $secret, $code ) = @_; + my $s = eval { decode_base32($secret) }; + if ($@) { + $self->logger->error('Bad characters in TOTP secret'); + return -1; + } + for ( 0 .. $range ) { + if ( $code eq $self->_code( $s, $_, $interval ) ) { + return 1; + } + } + return 0; +} + +sub _code { + my ( $self, $secret, $r, $interval ) = @_; + my $hmac = hmac_sha1_hex( + pack( 'H*', + sprintf( '%016x', int( ( time + $r * $interval ) / $interval ) ) ), + $secret, + ); + + return sprintf( + '%06d', + ( + hex( substr( $hmac, hex( substr( $hmac, -1 ) ) * 2, 8 ) ) & + 0x7fffffff + ) % 1000000 + ); +} + +1; diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/TOTP.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/TOTP.pm index 915db4ebe..b46236cab 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/TOTP.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/TOTP.pm @@ -12,7 +12,8 @@ use Lemonldap::NG::Portal::Main::Constants qw( our $VERSION = '2.0.0'; -extends 'Lemonldap::NG::Portal::Main::SecondFactor'; +extends 'Lemonldap::NG::Portal::Main::SecondFactor', + 'Lemonldap::NG::Common::TOTP'; # INITIALIZATION @@ -56,45 +57,22 @@ sub verify { return PE_FORMEMPTY; } - my $s = eval { decode_base32( $session->{_totp2fSecret} ) }; - if ($@) { - $self->logger->error("Bad characters in secret, aborting"); - return PE_ERROR; - } - for ( 0 .. $self->conf->{totp2fRange} ) { - 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( - ( time + $r * $self->conf->{totp2fInterval} ) / - $self->conf->{totp2fInterval} - ) - ) - ), - _decode_base32($secret), - ); - - return sprintf( - '%06d', - ( - hex( substr( $hmac, hex( substr( $hmac, -1 ) ) * 2, 8 ) ) & - 0x7fffffff - ) % 1000000 + my $r = $self->verifyCode( + $self->conf->{totp2fInterval}, + $self->conf->{totp2fRange}, + $session->{_totp2fSecret}, $code ); + if ( $r == -1 ) { return PE_ERROR; } + elsif ($r) { + $self->userLogger->info('TOTP succeed'); + return PE_OK; + } + else { + $self->userLogger->notice( 'Invalid TOTP for ' + . $session->{ $self->conf->{whatToTrace} } + . ')' ); + return PE_BADCREDENTIALS; + } } 1;