Yubikey 2nd factor (closes: #1399)
parent
396fc2362b
commit
c6908b87a2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,53 @@ |
|||||||
|
package Lemonldap::NG::Portal::2F::Register::Yubikey; |
||||||
|
|
||||||
|
use strict; |
||||||
|
use Mouse; |
||||||
|
use Lemonldap::NG::Portal::Main::Constants qw( |
||||||
|
PE_FORMEMPTY |
||||||
|
PE_ERROR |
||||||
|
PE_OK |
||||||
|
); |
||||||
|
|
||||||
|
our $VERSION = '2.0.0'; |
||||||
|
|
||||||
|
extends 'Lemonldap::NG::Portal::Main::Plugin'; |
||||||
|
|
||||||
|
# INITIALIZATION |
||||||
|
|
||||||
|
has prefix => ( is => 'rw', default => 'yubikey' ); |
||||||
|
|
||||||
|
has template => ( is => 'ro', default => 'yubikey2fregister' ); |
||||||
|
|
||||||
|
has logo => ( is => 'rw', default => 'u2f.png' ); |
||||||
|
|
||||||
|
sub init { |
||||||
|
my ($self) = @_; |
||||||
|
$self->conf->{yubikey2fPublicIDSize} ||= 12; |
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
# RUNNING METHODS |
||||||
|
|
||||||
|
# Main method |
||||||
|
sub run { |
||||||
|
my ( $self, $req, $action ) = @_; |
||||||
|
if ( $action eq 'register' ) { |
||||||
|
my $otp = $req->param('otp'); |
||||||
|
if ( $otp and length($otp) > 12 ) { |
||||||
|
my $keys = $req->userData->{_yubikeys} || ''; |
||||||
|
$keys .= ( $keys ? ', ' : '' ) |
||||||
|
. substr( $otp, 0, $self->conf->{yubikeyPublicIDSize} ); |
||||||
|
$self->p->updatePersistentSession( $req, { _yubikeys => $keys } ); |
||||||
|
} |
||||||
|
else { |
||||||
|
$self->userLogger->error('Yubikey 2F: no code'); |
||||||
|
return PE_FORMEMPTY; |
||||||
|
} |
||||||
|
} |
||||||
|
else { |
||||||
|
$self->userLogger->error("Unknown Yubikey action $action"); |
||||||
|
return PE_ERROR; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
1; |
@ -0,0 +1,109 @@ |
|||||||
|
package Lemonldap::NG::Portal::2F::Yubikey; |
||||||
|
|
||||||
|
use strict; |
||||||
|
use Mouse; |
||||||
|
use Lemonldap::NG::Portal::Main::Constants qw( |
||||||
|
PE_BADCREDENTIALS |
||||||
|
PE_FORMEMPTY |
||||||
|
PE_OK |
||||||
|
PE_SENDRESPONSE |
||||||
|
); |
||||||
|
|
||||||
|
our $VERSION = '2.0.0'; |
||||||
|
|
||||||
|
extends 'Lemonldap::NG::Portal::Main::SecondFactor'; |
||||||
|
|
||||||
|
# INITIALIZATION |
||||||
|
|
||||||
|
has prefix => ( is => 'ro', default => 'yubikey' ); |
||||||
|
|
||||||
|
has logo => ( is => 'rw', default => 'u2f.png' ); |
||||||
|
|
||||||
|
has yubi => ( is => 'rw' ); |
||||||
|
|
||||||
|
sub init { |
||||||
|
my ($self) = @_; |
||||||
|
eval { require Auth::Yubikey_WebClient }; |
||||||
|
if ($@) { |
||||||
|
$self->logger->error($@); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
if ( $self->conf->{yubikey2fSelfRegistration} |
||||||
|
and $self->conf->{yubikey2fActivation} eq '1' ) |
||||||
|
{ |
||||||
|
$self->conf->{yubikey2fActivation} = '$_yubikeys'; |
||||||
|
} |
||||||
|
unless ($self->conf->{yubikey2fClientID} |
||||||
|
and $self->conf->{yubikey2fSecretKey} ) |
||||||
|
{ |
||||||
|
$self->logger->error( |
||||||
|
"Missing mandatory parameters (Client ID and secret key)"); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
$self->conf->{yubikey2fPublicIDSize} ||= 12; |
||||||
|
$self->yubi( |
||||||
|
Auth::Yubikey_WebClient->new( |
||||||
|
{ |
||||||
|
id => $self->conf->{yubikey2fClientID}, |
||||||
|
api => $self->conf->{yubikey2fSecretKey}, |
||||||
|
nonce => $self->conf->{yubikey2fNonce}, |
||||||
|
url => $self->conf->{yubikey2fUrl} |
||||||
|
} |
||||||
|
) |
||||||
|
); |
||||||
|
return $self->SUPER::init(); |
||||||
|
} |
||||||
|
|
||||||
|
sub run { |
||||||
|
my ( $self, $req, $token ) = @_; |
||||||
|
|
||||||
|
unless ( $req->{sessionInfo}->{_yubikeys} ) { |
||||||
|
$self->userLogger->warn( 'User ' |
||||||
|
. $req->{sessionInfo}->{ $self->conf->{whatToTrace} } |
||||||
|
. ' has no Yubikey registered' ); |
||||||
|
return PE_BADCREDENTIALS; |
||||||
|
} |
||||||
|
|
||||||
|
# Prepare form |
||||||
|
my $tmp = $self->p->sendHtml( |
||||||
|
$req, |
||||||
|
'ext2fcheck', |
||||||
|
params => { |
||||||
|
SKIN => $self->conf->{portalSkin}, |
||||||
|
TOKEN => $token, |
||||||
|
TARGET => '/yubikey2fcheck', |
||||||
|
INPUTLOGO => 'yubikey.png', |
||||||
|
LEGEND => 'clickOnYubikey', |
||||||
|
} |
||||||
|
); |
||||||
|
$self->logger->debug("Display Yubikey form"); |
||||||
|
|
||||||
|
$req->response($tmp); |
||||||
|
return PE_SENDRESPONSE; |
||||||
|
} |
||||||
|
|
||||||
|
sub verify { |
||||||
|
my ( $self, $req, $session ) = @_; |
||||||
|
my $code; |
||||||
|
unless ( $code = $req->param('code') ) { |
||||||
|
$self->userLogger->error('Yubikey 2F: no code'); |
||||||
|
return PE_FORMEMPTY; |
||||||
|
} |
||||||
|
|
||||||
|
# Verify OTP |
||||||
|
if ( |
||||||
|
index( substr( $code, 0, $self->conf->{yubikey2fPublicIDSize} ), |
||||||
|
$session->{_yubikeys} ) == -1 |
||||||
|
) |
||||||
|
{ |
||||||
|
$self->userLogger->warn('Yubikey not registered'); |
||||||
|
return PE_BADCREDENTIALS; |
||||||
|
} |
||||||
|
if ( $self->yubi->otp($code) ne 'OK' ) { |
||||||
|
$self->userLogger->warn('Yubikey verification failed'); |
||||||
|
return PE_BADCREDENTIALS; |
||||||
|
} |
||||||
|
PE_OK; |
||||||
|
} |
||||||
|
|
||||||
|
1 |
@ -0,0 +1,25 @@ |
|||||||
|
<TMPL_INCLUDE NAME="header.tpl"> |
||||||
|
|
||||||
|
<div class="container"> |
||||||
|
<div id="color" class="message message-positive alert"><span id="msg" trspan="clickOnYubikey"></span></div> |
||||||
|
</div> |
||||||
|
<main id="menucontent" class="container"> |
||||||
|
<div class="panel panel-info"> |
||||||
|
<div class="panel-body"> |
||||||
|
<form action="/2fregisters/yubikey/register" method="post"> |
||||||
|
<div class="form-group"> |
||||||
|
<input id="otp" name="otp" /> |
||||||
|
</div> |
||||||
|
</form> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</main> |
||||||
|
|
||||||
|
<div class="buttons"> |
||||||
|
<a id="goback" href="<TMPL_VAR NAME="PORTAL_URL"><TMPL_IF NAME="AUTH_URL">/?url=<TMPL_VAR NAME="AUTH_URL"></TMPL_IF>" class="btn btn-primary" role="button"> |
||||||
|
<span class="glyphicon glyphicon-home"></span> |
||||||
|
<span trspan="goToPortal">Go to portal</span> |
||||||
|
</a> |
||||||
|
</div> |
||||||
|
|
||||||
|
<TMPL_INCLUDE NAME="footer.tpl"> |
Loading…
Reference in new issue