This commit is contained in:
Christophe Maudoux 2018-04-10 16:15:14 +02:00
parent 051acdd51e
commit 87a583dd51
8 changed files with 142 additions and 223 deletions

View File

@ -27,7 +27,7 @@ sub types {
BEGIN {
${^WARNING_BITS} =
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x05";
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x01";
}
eval "$s $val";
my $err = join(
@ -662,7 +662,7 @@ sub attributes {
BEGIN {
${^WARNING_BITS} =
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x05";
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x01";
}
eval "$s $val";
my $err = join(
@ -1026,7 +1026,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
BEGIN {
${^WARNING_BITS} =
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x05";
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x01";
}
eval $s;
my $err = join(
@ -1111,7 +1111,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
BEGIN {
${^WARNING_BITS} =
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x05";
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x01";
}
eval "$s $val";
my $err = join(
@ -1134,7 +1134,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
BEGIN {
${^WARNING_BITS} =
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x05";
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x01";
}
eval "$s $val";
my $err = join(
@ -1489,7 +1489,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
BEGIN {
${^WARNING_BITS} =
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x05";
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x01";
}
eval $s;
my $err = join(
@ -1526,7 +1526,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
BEGIN {
${^WARNING_BITS} =
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x05";
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x01";
}
eval "$s $val";
my $err = join(
@ -1885,7 +1885,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
BEGIN {
${^WARNING_BITS} =
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x05";
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x01";
}
eval "$s $val";
my $err = join(
@ -2222,7 +2222,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
BEGIN {
${^WARNING_BITS} =
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x05";
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x01";
}
eval "$s $val";
my $err = join(
@ -2925,7 +2925,7 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
BEGIN {
${^WARNING_BITS} =
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x05";
"\x54\x55\x55\x55\x15\x55\x55\x55\x55\x55\x51\x55\x55\x55\x55\x55\x55\x01";
}
eval "$s $val";
my $err = join(
@ -3004,19 +3004,19 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
'default' => 0,
'select' => [
{
'k' => 0,
'k' => '0',
'v' => 'unsecuredCookie'
},
{
'k' => 1,
'k' => '1',
'v' => 'securedCookie'
},
{
'k' => 2,
'k' => '2',
'v' => 'doubleCookie'
},
{
'k' => 3,
'k' => '3',
'v' => 'doubleCookieForSingleSession'
}
],

View File

@ -98,63 +98,48 @@ sub run {
$self->logger->debug('TOTP code verified');
# Now code is verified, let's store the master key in persistent data
my $secret = '';
my $secret = '';
my $_2fDevices = eval {
$self->logger->debug("Looking for 2F Devices ...");
# Read existing 2FDevices
# Reading existing 2FDevices
from_json( $req->userData->{_2fDevices}, { allow_nonref => 1 } );
};
unless ($_2fDevices) {
$self->logger->debug("No 2F Device found");
$_2fDevices = [];
};
#my $_2fDevices = eval {
#$self->logger->debug("Loading 2F Devices ...");
}
## Read existing 2FDevices
#from_json( $req->userData->{_2fDevices}, { allow_nonref => 1 } );
#};
# Reading existing TOTP
my @totp2f = grep { $_->{type} eq "TOTP" } @$_2fDevices;
unless ( @totp2f ) {
unless (@totp2f) {
$self->logger->debug("No TOTP Device found");
# Set default value
push @totp2f, { _secret => '' } ;
push @totp2f, { _secret => '' };
}
# Loading TOTP secret
foreach ( @totp2f ) {
$self->logger->debug("Reading TOTP secret if exists ...");
$secret = $_->{_secret};
}
if ( $token->{_totp2fSecret} eq $secret ) {
return $self->p->sendError( $req, 'totpExistingKey', 200 );
}
### USER CAN ONLY REGISTER ONE TOTP ###
# Delete TOTP 2F devices registered
my @keep = ();
# Loading TOTP secret
foreach (@totp2f) {
$self->logger->debug("Reading TOTP secret if exists ...");
$secret = $_->{_secret};
}
if ( $token->{_totp2fSecret} eq $secret ) {
return $self->p->sendError( $req, 'totpExistingKey', 200 );
}
### USER CAN ONLY REGISTER ONE TOTP ###
# Delete TOTP 2F devices previously registered
my @keep = ();
while (@$_2fDevices) {
my $element = shift @$_2fDevices;
$self->logger->debug("Looking for TOTP to delete ...");
push @keep, $element unless ( $element->{type} eq "TOTP" );
}
#$self->logger->debug("Delete previously registered TOTP");
#$self->p->updatePersistentSession( $req,
#{ _2fDevices => to_json( \@keep ) } );
# Check if user can register one more device
#my $size = @$_2fDevices;
my $size = @keep;
my $maxSize = $self->conf->{max2FDevices};
$self->logger->debug("Nbr 2FDevices = $size / $maxSize");
@ -164,8 +149,7 @@ sub run {
400 );
}
# Store TOTP secret
#push @{$_2fDevices},
# Store TOTP secret
push @keep,
{
type => 'TOTP',
@ -177,9 +161,7 @@ sub run {
$self->logger->debug(
"Append 2F Device : { type => 'TOTP', name => $TOTPName }");
$self->p->updatePersistentSession( $req,
#{ _2fDevices => to_json($_2fDevices) } );
{ _2fDevices => to_json( \@keep ) } );
$self->userLogger->notice('TOTP registration succeed');
return [ 200, [ 'Content-Type' => 'application/json' ],
['{"result":1}'] ];
@ -187,50 +169,50 @@ sub run {
# Get or generate master key
elsif ( $action eq 'getkey' ) {
my $nk = 0;
my $nk = 0;
my $secret = '';
my $_2fDevices = eval {
$self->logger->debug("Loading 2F Devices ...");
# Read existing 2FDevices
from_json( $req->userData->{_2fDevices}, { allow_nonref => 1 } );
};
# Loading TOTP secret
my @totp2f = grep { $_->{type} eq "TOTP" } @$_2fDevices;
unless ( @totp2f ) {
unless (@totp2f) {
$self->logger->debug("No TOTP found");
# Set default value
push @totp2f, { _secret => '' } ;
};
# Loading TOTP secret
foreach ( @totp2f ) {
$self->logger->debug("Reading TOTP secret if exists ...");
$secret = $_->{_secret};
};
push @totp2f, { _secret => '' };
}
# Loading TOTP secret
foreach (@totp2f) {
$self->logger->debug("Reading TOTP secret if exists ...");
$secret = $_->{_secret};
}
if ( ( $req->param('newkey') and $self->conf->{totp2fUserCanChangeKey} )
or not $secret )
{
$secret = $self->newSecret;
$self->logger->debug("Generating new secret = $secret");
$nk = 1;
$nk = 1;
}
elsif ( $req->param('newkey') ) {
return $self->p->sendError( $req, 'notAuthorized', 200 );
}
elsif ( $self->conf->{totp2fDisplayExistingSecret} ) {
$self->logger->debug("User secret = $secret");
}
else {
return $self->p->sendError( $req, 'totpExistingKey', 200 );
};
}
# Secret is stored in a token: we choose to not accept secret returned
# by Ajax request to avoid some attacks
@ -259,7 +241,7 @@ sub run {
interval => $self->conf->{totp2fInterval}
}
);
};
}
# Check if unregistration is allowed
unless ( $self->conf->{totp2fUserCanChangeKey} ) {
@ -267,7 +249,7 @@ sub run {
}
# Delete TOTP
if ( $action eq 'delete' ) {
if ( $action eq 'delete' ) {
my $epoch = $req->param('epoch');
my $_2fDevices = eval {
$self->logger->debug("Loading 2F Devices ...");
@ -276,6 +258,7 @@ sub run {
from_json( $req->userData->{_2fDevices}, { allow_nonref => 1 } );
};
# Delete TOTP 2F device
my @keep = ();
while (@$_2fDevices) {
my $element = shift @$_2fDevices;
@ -292,7 +275,6 @@ sub run {
['{"result":1}'] ];
}
}
1;

View File

@ -45,6 +45,7 @@ sub run {
$_2fDevices = [];
}
# Check if user can register one more 2F device
my $size = @$_2fDevices;
my $maxSize = $self->conf->{max2FDevices};
$self->logger->debug("Registered 2F Device(s) : $size / $maxSize");
@ -123,14 +124,6 @@ sub run {
$self->p->updatePersistentSession( $req,
{ _2fDevices => to_json($_2fDevices) } );
#$self->p->updatePersistentSession(
#$req,
#{
#_u2fKeyHandle =>
#$self->encode_base64url( $keyHandle, '' ),
#_u2fUserKey => $self->encode_base64url( $userKey, '' )
#}
#);
return [
200,
[
@ -165,7 +158,7 @@ sub run {
[$challenge]
];
}
elsif ( $action eq 'signature' ) {
$self->logger->debug('Verification response');
my ( $challenge, $resp );
@ -209,23 +202,24 @@ sub run {
[$challenge]
];
}
#elsif ( $action eq 'unregistration' ) {
#$self->p->updatePersistentSession(
#$req,
#{
#_u2fKeyHandle => '',
#_u2fUserKey => ''
#}
#);
#$self->userLogger->notice('U2F key unregistration succeed');
#return [
#200,
#[ 'Content-Type' => 'application/json', 'Content-Length' => 12, ],
#['{"result":1}']
#];
#my $err = Crypt::U2F::Server::Simple::lastError();
#$self->userLogger->warn("U2F Unregistration failed: $err");
#return $self->p->sendError( $req, $err, 200 );
#$self->p->updatePersistentSession(
#$req,
#{
#_u2fKeyHandle => '',
#_u2fUserKey => ''
#}
#);
#$self->userLogger->notice('U2F key unregistration succeed');
#return [
#200,
#[ 'Content-Type' => 'application/json', 'Content-Length' => 12, ],
#['{"result":1}']
#];
#my $err = Crypt::U2F::Server::Simple::lastError();
#$self->userLogger->warn("U2F Unregistration failed: $err");
#return $self->p->sendError( $req, $err, 200 );
#}
elsif ( $action eq 'delete' ) {
my $epoch = $req->param('epoch');
@ -247,13 +241,6 @@ sub run {
"Delete 2F Device : { type => 'U2F', epoch => $epoch }");
$self->p->updatePersistentSession( $req,
{ _2fDevices => to_json( \@keep ) } );
#$self->p->updatePersistentSession(
#$req,
#{
#_u2fKeyHandle => '',
#_u2fUserKey => ''
#}
#);
$self->userLogger->notice('U2F key unregistration succeed');
return [
200,
@ -273,49 +260,34 @@ sub loadUser {
$self->logger->debug("Loading user U2F Devices ...");
my $uid = $req->userData->{ $self->conf->{whatToTrace} };
my $session = $self->p->getPersistentSession($uid);
my $secret = '';
my $_2fDevices = eval {
$self->logger->debug("Loading 2F Devices ...");
# Read existing 2FDevices
from_json( $session->data->{_2fDevices}, { allow_nonref => 1 } );
};
unless ( $_2fDevices ) {
$self->logger->debug("No 2F Device found");
my $secret = '';
my $_2fDevices = eval {
$self->logger->debug("Loading 2F Devices ...");
# Set default value
@$_2fDevices = [];
}
#foreach (@$_2fDevices) {
#$self->logger->debug("Reading U2F keys if exists ...");
#if ( $_->{type} eq 'TOTP' ) {
#$secret = $_->{_secret};
#last;
#}
#}
my @U2Fs = grep { $_->{type} =~ /U2F/s } @$_2fDevices;
my $kh = $U2Fs[0]{_keyHandle};
my $uk = $self->decode_base64url( $U2Fs[0]{_userKey} );
# Read existing 2FDevices
from_json( $session->data->{_2fDevices}, { allow_nonref => 1 } );
};
unless ($_2fDevices) {
$self->logger->debug("No 2F Device found");
# Set default value
@$_2fDevices = [];
}
# Reading existing U2F keys
$self->logger->debug("Reading U2F keys if exists ...");
my @U2Fs = grep { $_->{type} =~ /U2F/s } @$_2fDevices;
my $kh = $U2Fs[0]{_keyHandle};
my $uk = $self->decode_base64url( $U2Fs[0]{_userKey} );
unless ( $kh and $uk ) {
$self->logger->debug("UTOP -> No U2F key found !!!");
$self->logger->debug("UTOP -> No U2F key found !!!");
return 0;
}
$self->logger->debug("_userKey = ".$uk);
$self->logger->debug( "_userKey = " . $uk );
$req->datas->{crypter} = $self->crypter(
#keyHandle => $self->decode_base64url($kh),
#publicKey => $self->decode_base64url($uk)
keyHandle => $kh,
publicKey => $uk
);

View File

@ -46,10 +46,6 @@ sub run {
if ( $otp
and length($otp) > $self->conf->{yubikey2fPublicIDSize} )
{
#my $keys = $req->userData->{_yubikeys} || '';
#$keys .= ( $keys ? ', ' : '' )
#. substr( $otp, 0, $self->conf->{yubikey2fPublicIDSize} );
my $key = substr( $otp, 0, $self->conf->{yubikey2fPublicIDSize} );
my $_2fDevices = eval {
$self->logger->debug("Looking for 2F Devices ...");
@ -112,7 +108,6 @@ sub run {
$self->p->updatePersistentSession( $req,
{ _2fDevices => to_json($_2fDevices) } );
#$self->p->updatePersistentSession( $req, { _yubikeys => $keys } );
return $self->p->sendHtml(
$req, 'error',
params => {

View File

@ -30,11 +30,8 @@ sub init {
if ( $self->conf->{totp2fSelfRegistration}
and $self->conf->{totp2fActivation} eq '1' )
{
#$self->conf->{totp2fActivation} = '$_totp2fSecret';
$self->conf->{totp2fActivation} = '$_2fDevices =~ /"type":\s*"TOTP"/s';
}
#$self->conf->{totp2fInterval} ||= 30;
#$self->conf->{totp2fRange} ||= 1;
return $self->SUPER::init();
}
@ -67,43 +64,29 @@ sub verify {
$self->userLogger->error('TOTP 2F: no code');
return PE_FORMEMPTY;
}
my $secret = '';
my $_2fDevices = eval {
$self->logger->debug("Loading 2F Devices ...");
# Read existing 2FDevices
from_json( $session->{_2fDevices}, { allow_nonref => 1 } );
};
unless ( $_2fDevices ) {
$self->logger->debug("No 2F Device found");
my $secret = '';
my $_2fDevices = eval {
$self->logger->debug("Loading 2F Devices ...");
# Set default value
@$_2fDevices = [];
}
foreach (@$_2fDevices) {
# Read existing 2FDevices
from_json( $session->{_2fDevices}, { allow_nonref => 1 } );
};
unless ($_2fDevices) {
$self->logger->debug("No 2F Device found");
# Set default value
@$_2fDevices = [];
}
foreach (@$_2fDevices) {
$self->logger->debug("Reading TOTP secret if exists ...");
if ( $_->{type} eq 'TOTP' ) {
$secret = $_->{_secret};
last;
}
}
#my @totp2f = grep { $_->{type} =~ /TOTP/s } @$_2fDevices;
}
my $r = $self->verifyCode(
$self->conf->{totp2fInterval},

View File

@ -36,7 +36,6 @@ sub init {
if ( $self->conf->{u2fSelfRegistration}
and $self->conf->{u2fActivation} eq '1' )
{
#$self->conf->{u2fActivation} = '$_u2fKeyHandle and $_u2fUserKey';
$self->conf->{u2fActivation} = '$_2fDevices =~ /"type":\s*"U2F"/s';
}
return 0
@ -87,9 +86,8 @@ sub verify {
$req->error(PE_ERROR);
return $self->fail($req);
}
$self->logger->debug("Get challenge: $challenge");
#eval { $challenge = JSON::from_json($challenge)->{challenge} };
$self->logger->debug("Get challenge: $challenge");
if ( not $req->datas->{crypter}->setChallenge($challenge) ) {
$self->logger->error(
$@ ? $@ : Crypt::U2F::Server::Simple::lastError() );
@ -138,57 +136,45 @@ sub fail {
sub loadUser {
my ( $self, $req, $session ) = @_;
my ( $kh, $uk );
my $_2fDevices = eval {
$self->logger->debug("Loading 2F Devices ...");
# Read existing 2FDevices
from_json( $session->{_2fDevices}, { allow_nonref => 1 } );
};
unless ( $_2fDevices ) {
$self->logger->debug("No 2F Device found");
my $_2fDevices = eval {
$self->logger->debug("Loading 2F Devices ...");
# Set default value
@$_2fDevices = [];
}
my @u2fs = ();
foreach ( @$_2fDevices ) {
# Read existing 2FDevices
from_json( $session->{_2fDevices}, { allow_nonref => 1 } );
};
unless ($_2fDevices) {
$self->logger->debug("No 2F Device found");
# Set default value
@$_2fDevices = [];
}
my @u2fs = ();
foreach (@$_2fDevices) {
$self->logger->debug("Reading U2F keys if exists ...");
if ( $_->{type} eq 'U2F' ) {
$self->logger->debug("_userKey = ".$_->{_userKey});
$self->logger->debug("_keyHandle = ".$_->{_keyHandle});
$_->{_userKey} = $self->decode_base64url( $_->{_userKey} );
$self->logger->debug( "_userKey = " . $_->{_userKey} );
$self->logger->debug( "_keyHandle = " . $_->{_keyHandle} );
$_->{_userKey} = $self->decode_base64url( $_->{_userKey} );
push @u2fs, $_;
}
}
#if ( ( $kh = $session->{_u2fKeyHandle} )
# and ( $uk = $session->{_u2fUserKey} ) )
}
if ( ( $kh = $u2fs[0]{_keyHandle} )
and ( $uk = $u2fs[0]{_userKey} ) )
{
$self->logger->debug("kh & uk -> OK");
$self->logger->debug("kh & uk -> OK");
$req->datas->{crypter} = $self->crypter(
#keyHandle => $self->decode_base64url($kh),
#publicKey => $self->decode_base64url($uk)
keyHandle => $kh,
publicKey => $uk
publicKey => $uk
);
unless ( $req->datas->{crypter} ) {
$self->logger->error(
'U2F error: ' . Crypt::U2F::Server::u2fclib_getError() );
return -1;
};
}
return 1;
}
else {

View File

@ -37,6 +37,7 @@ sub init {
)
{
$self->conf->{utotp2fActivation} =
#'$_totp2fSecret or $_u2fKeyHandle and $_u2fUserKey';
'$_2fDevices =~ /"type":\s*"(?:TOTP|U2F)"/s';
}

View File

@ -32,8 +32,8 @@ sub init {
if ( $self->conf->{yubikey2fSelfRegistration}
and $self->conf->{yubikey2fActivation} eq '1' )
{
#$self->conf->{yubikey2fActivation} = '$_yubikeys';
$self->conf->{yubikey2fActivation} = '$_2fDevices =~ /"type":\s*"UBK"/s';
$self->conf->{yubikey2fActivation} =
'$_2fDevices =~ /"type":\s*"UBK"/s';
}
unless ($self->conf->{yubikey2fClientID}
and $self->conf->{yubikey2fSecretKey} )