lemonldap-ng/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/U2F.pm

138 lines
3.5 KiB
Perl
Raw Normal View History

2017-02-04 08:55:47 +01:00
# U2F second factor authentication
#
# This plugin handle authentications to ask U2F second factor for users that
# have registered their U2F key
2017-02-02 22:48:32 +01:00
package Lemonldap::NG::Portal::Plugins::U2F;
2017-03-06 13:18:04 +01:00
use 5.16.0;
2017-02-02 22:48:32 +01:00
use strict;
use Mouse;
2017-02-07 13:52:56 +01:00
use Lemonldap::NG::Portal::Main::Constants qw(
PE_ERROR
PE_OK
PE_SENDRESPONSE
PE_U2FFAILED
2017-02-07 13:52:56 +01:00
);
2017-02-02 22:48:32 +01:00
our $VERSION = '2.0.0';
2017-03-23 12:17:01 +01:00
extends 'Lemonldap::NG::Portal::Main::SecondFactor',
'Lemonldap::NG::Portal::Lib::U2F';
2017-02-04 08:55:47 +01:00
# INITIALIZATION
2017-03-23 07:20:06 +01:00
has rule => ( is => 'rw' );
2017-03-23 12:17:01 +01:00
has prefix => ( is => 'ro', default => 'u' );
2017-02-02 22:48:32 +01:00
sub init {
2017-02-04 08:55:47 +01:00
my ($self) = @_;
2017-03-23 12:17:01 +01:00
return 0
unless ( $self->Lemonldap::NG::Portal::Main::SecondFactor::init()
and $self->Lemonldap::NG::Portal::Lib::U2F::init() );
2017-02-02 22:48:32 +01:00
1;
}
2017-02-04 08:55:47 +01:00
# RUNNING METHODS
# Main method
sub run {
2017-03-23 12:17:01 +01:00
my ( $self, $req, $token ) = @_;
2017-03-23 07:20:06 +01:00
2017-02-07 13:52:56 +01:00
my ( $kh, $uk );
# Check if user is registered
2017-03-23 12:17:01 +01:00
if ( my $res = $self->loadUser( $req->sessionInfo ) ) {
2017-02-07 13:52:56 +01:00
return PE_ERROR if ( $res == -1 );
my $challenge = $self->crypter->authenticationChallenge;
my $tmp = $self->p->sendHtml(
$req,
'u2fcheck',
params => {
SKIN => $self->conf->{portalSkin},
CHALLENGE => $challenge,
TOKEN => $token
}
);
2017-03-23 12:17:01 +01:00
$self->logger->debug("Prepare U2F verification");
$req->response($tmp);
return PE_SENDRESPONSE;
2017-02-07 13:52:56 +01:00
}
return PE_OK;
}
sub verify {
2017-03-23 12:17:01 +01:00
my ( $self, $req, $session ) = @_;
2017-03-22 23:18:28 +01:00
# Check U2F signature
if ( my $resp = $req->param('signature') ) {
2017-03-23 12:17:01 +01:00
unless ( $self->loadUser($session) == 1 ) {
$req->error(PE_ERROR);
return $self->fail($req);
2017-02-07 13:52:56 +01:00
}
if ( $self->crypter->authenticationVerify($resp) ) {
2017-03-23 12:17:01 +01:00
$self->userLogger->info('U2F signature verified');
return PE_OK;
2017-02-07 13:52:56 +01:00
}
else {
$self->userLogger->notice( 'Invalid U2F signature for '
2017-03-23 12:17:01 +01:00
. $session->{ $self->conf->{whatToTrace} } . ' ('
. Crypt::U2F::Server::u2fclib_getError()
. ')' );
$req->error(PE_U2FFAILED);
2017-02-20 22:59:31 +01:00
$req->authResult(PE_U2FFAILED);
return $self->fail($req);
2017-02-07 13:52:56 +01:00
}
}
else {
$self->userLogger->notice( 'No U2F response for user'
2017-03-23 12:17:01 +01:00
. $session->{ $self->conf->{whatToTrace} } );
2017-02-20 22:59:31 +01:00
$req->authResult(PE_U2FFAILED);
return $self->fail($req);
2017-02-07 13:52:56 +01:00
}
}
sub fail {
my ( $self, $req ) = @_;
2017-03-23 12:17:01 +01:00
$req->response(
$self->p->sendHtml(
$req,
'u2fcheck',
params => {
AUTH_ERROR => $req->error,
AUTH_ERROR_TYPE => $req->error_type,
SKIN => $self->conf->{portalSkin},
FAILED => 1
}
)
);
2017-03-23 12:17:01 +01:00
return PE_SENDRESPONSE;
}
2017-02-07 13:52:56 +01:00
sub loadUser {
2017-03-23 12:17:01 +01:00
my ( $self, $session ) = @_;
2017-02-07 13:52:56 +01:00
my ( $kh, $uk );
2017-03-23 12:17:01 +01:00
if ( ( $kh = $session->{_u2fKeyHandle} )
and ( $uk = $session->{_u2fUserKey} ) )
2017-02-07 13:52:56 +01:00
{
2017-02-08 19:10:06 +01:00
$self->crypter->{keyHandle} = $self->decode_base64url($kh);
$self->crypter->{publicKey} = $self->decode_base64url($uk);
2017-03-06 13:18:04 +01:00
unless ($self->crypter->setKeyHandle
and $self->crypter->setPublicKey )
2017-02-07 13:52:56 +01:00
{
2017-02-15 07:41:50 +01:00
$self->logger->error(
'U2F error: ' . Crypt::U2F::Server::u2fclib_getError() );
2017-02-07 13:52:56 +01:00
return -1;
}
return 1;
}
else {
2017-03-23 12:17:01 +01:00
$self->userLogger->info("U2F: user not registered");
2017-02-07 13:52:56 +01:00
return 0;
}
2017-02-04 08:55:47 +01:00
}
2017-02-02 22:48:32 +01:00
1;