Merge branch 'manager-u2f-module_add-u2f-key' into 'master'
Manager u2f module add u2f key See merge request lemonldap-ng/lemonldap-ng!16
This commit is contained in:
commit
ec85664131
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,6 +1,6 @@
|
|||||||
.gitignore
|
.gitignore
|
||||||
node_modules
|
node_modules
|
||||||
e2e-tests/conf/
|
e2e-tests/conf
|
||||||
lemonldap-ng-common/MYMETA.json
|
lemonldap-ng-common/MYMETA.json
|
||||||
lemonldap-ng-common/MYMETA.yml
|
lemonldap-ng-common/MYMETA.yml
|
||||||
lemonldap-ng-common/Makefile
|
lemonldap-ng-common/Makefile
|
||||||
|
@ -52,7 +52,7 @@ sub delSession {
|
|||||||
return $self->sendJSONresponse( $req, { result => 1 } );
|
return $self->sendJSONresponse( $req, { result => 1 } );
|
||||||
}
|
}
|
||||||
|
|
||||||
sub delU2FKey {
|
sub deleteU2FKey {
|
||||||
my ( $self, $req ) = @_;
|
my ( $self, $req ) = @_;
|
||||||
return $self->sendJSONresponse( $req, { result => 1 } )
|
return $self->sendJSONresponse( $req, { result => 1 } )
|
||||||
if ( $self->{demoMode} );
|
if ( $self->{demoMode} );
|
||||||
@ -77,6 +77,56 @@ sub delU2FKey {
|
|||||||
return $self->sendJSONresponse( $req, { result => 1 } );
|
return $self->sendJSONresponse( $req, { result => 1 } );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub addU2FKey {
|
||||||
|
my ( $self, $req ) = @_;
|
||||||
|
return $self->sendJSONresponse( $req, { result => 1 } )
|
||||||
|
if ( $self->{demoMode} );
|
||||||
|
my $mod = $self->getMod($req)
|
||||||
|
or return $self->sendError( $req, undef, 400 );
|
||||||
|
my $id = $req->params('sessionId')
|
||||||
|
or return $self->sendError( $req, 'sessionId is missing', 400 );
|
||||||
|
|
||||||
|
# Try to read session
|
||||||
|
my $session = $self->getApacheSession( $mod, $id )
|
||||||
|
or return $self->sendError( $req, undef, 400 );
|
||||||
|
|
||||||
|
# Delete U2F key attributs and update session
|
||||||
|
$session->data->{_u2fKeyHandle} = 'TOF';
|
||||||
|
$session->data->{_u2fUserKey} = 'TOF';
|
||||||
|
$session->update( \%{ $session->data } );
|
||||||
|
|
||||||
|
Lemonldap::NG::Handler::PSGI::Main->localUnlog( $req, $id );
|
||||||
|
if ( $session->error ) {
|
||||||
|
return $self->sendError( $req, $session->error, 200 );
|
||||||
|
}
|
||||||
|
return $self->sendJSONresponse( $req, { result => 1 } );
|
||||||
|
}
|
||||||
|
|
||||||
|
sub verifyU2FKey {
|
||||||
|
my ( $self, $req ) = @_;
|
||||||
|
return $self->sendJSONresponse( $req, { result => 1 } )
|
||||||
|
if ( $self->{demoMode} );
|
||||||
|
my $mod = $self->getMod($req)
|
||||||
|
or return $self->sendError( $req, undef, 400 );
|
||||||
|
my $id = $req->params('sessionId')
|
||||||
|
or return $self->sendError( $req, 'sessionId is missing', 400 );
|
||||||
|
|
||||||
|
# Try to read session
|
||||||
|
my $session = $self->getApacheSession( $mod, $id )
|
||||||
|
or return $self->sendError( $req, undef, 400 );
|
||||||
|
|
||||||
|
# Delete U2F key attributs and update session
|
||||||
|
$session->data->{_u2fKeyHandle} = 'OK';
|
||||||
|
$session->data->{_u2fUserKey} = 'OK';
|
||||||
|
$session->update( \%{ $session->data } );
|
||||||
|
|
||||||
|
Lemonldap::NG::Handler::PSGI::Main->localUnlog( $req, $id );
|
||||||
|
if ( $session->error ) {
|
||||||
|
return $self->sendError( $req, $session->error, 200 );
|
||||||
|
}
|
||||||
|
return $self->sendJSONresponse( $req, { result => 1 } );
|
||||||
|
}
|
||||||
|
|
||||||
sub session {
|
sub session {
|
||||||
my ( $self, $req, $id, $skey ) = @_;
|
my ( $self, $req, $id, $skey ) = @_;
|
||||||
my ( %h, $res );
|
my ( %h, $res );
|
||||||
|
@ -8,12 +8,12 @@ sub types {
|
|||||||
'authParamsText' => {
|
'authParamsText' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'blackWhiteList' => {
|
'blackWhiteList' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'bool' => {
|
'bool' => {
|
||||||
'msgFail' => '__notABoolean__',
|
'msgFail' => '__notABoolean__',
|
||||||
@ -36,17 +36,17 @@ sub types {
|
|||||||
split( /\n/, $@, 0 ) )
|
split( /\n/, $@, 0 ) )
|
||||||
);
|
);
|
||||||
return $err ? ( 1, "__badExpression__: $err" ) : 1;
|
return $err ? ( 1, "__badExpression__: $err" ) : 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'catAndAppList' => {
|
'catAndAppList' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'file' => {
|
'file' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'hostname' => {
|
'hostname' => {
|
||||||
'form' => 'text',
|
'form' => 'text',
|
||||||
@ -80,48 +80,48 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
|
|||||||
if $_ =~ /exportedvars$/i and defined $conf->{$_}{$val};
|
if $_ =~ /exportedvars$/i and defined $conf->{$_}{$val};
|
||||||
}
|
}
|
||||||
return 1, "__unknownAttrOrMacro__: $val";
|
return 1, "__unknownAttrOrMacro__: $val";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'longtext' => {
|
'longtext' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'menuApp' => {
|
'menuApp' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'menuCat' => {
|
'menuCat' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'oidcmetadatajson' => {
|
'oidcmetadatajson' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'oidcmetadatajwks' => {
|
'oidcmetadatajwks' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'oidcOPMetaDataNode' => {
|
'oidcOPMetaDataNode' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'oidcRPMetaDataNode' => {
|
'oidcRPMetaDataNode' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'password' => {
|
'password' => {
|
||||||
'msgFail' => '__malformedValue__',
|
'msgFail' => '__malformedValue__',
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'pcre' => {
|
'pcre' => {
|
||||||
'form' => 'text',
|
'form' => 'text',
|
||||||
@ -132,7 +132,7 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
return $@ ? ( 0, "__badRegexp__: $@" ) : 1;
|
return $@ ? ( 0, "__badRegexp__: $@" ) : 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'PerlModule' => {
|
'PerlModule' => {
|
||||||
'form' => 'text',
|
'form' => 'text',
|
||||||
@ -142,17 +142,17 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
|
|||||||
'portalskin' => {
|
'portalskin' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'portalskinbackground' => {
|
'portalskinbackground' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'post' => {
|
'post' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'RSAPrivateKey' => {
|
'RSAPrivateKey' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
@ -160,7 +160,7 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
|
|||||||
m[^(?:(?:\-+\s*BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+(?:RSA\s+)PRIVATE\s+KEY\s*\-+)?[\r\n]*)?$]s
|
m[^(?:(?:\-+\s*BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+(?:RSA\s+)PRIVATE\s+KEY\s*\-+)?[\r\n]*)?$]s
|
||||||
? 1
|
? 1
|
||||||
: ( 1, '__badPemEncoding__' );
|
: ( 1, '__badPemEncoding__' );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'RSAPublicKey' => {
|
'RSAPublicKey' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
@ -168,7 +168,7 @@ m[^(?:(?:\-+\s*BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+=
|
|||||||
m[^(?:(?:\-+\s*BEGIN\s+PUBLIC\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+PUBLIC\s+KEY\s*\-+)?[\r\n]*)?$]s
|
m[^(?:(?:\-+\s*BEGIN\s+PUBLIC\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+PUBLIC\s+KEY\s*\-+)?[\r\n]*)?$]s
|
||||||
? 1
|
? 1
|
||||||
: ( 1, '__badPemEncoding__' );
|
: ( 1, '__badPemEncoding__' );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'RSAPublicKeyOrCertificate' => {
|
'RSAPublicKeyOrCertificate' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
@ -176,37 +176,37 @@ m[^(?:(?:\-+\s*BEGIN\s+PUBLIC\s+KEY\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\
|
|||||||
m[^(?:(?:\-+\s*BEGIN\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+)?[\r\n]*)?$]s
|
m[^(?:(?:\-+\s*BEGIN\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\n]+={0,2}(?:\r?\n\-+\s*END\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+)?[\r\n]*)?$]s
|
||||||
? 1
|
? 1
|
||||||
: ( 1, '__badPemEncoding__' );
|
: ( 1, '__badPemEncoding__' );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'rule' => {
|
'rule' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'samlAssertion' => {
|
'samlAssertion' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'samlAttribute' => {
|
'samlAttribute' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'samlIDPMetaDataNode' => {
|
'samlIDPMetaDataNode' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'samlService' => {
|
'samlService' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'samlSPMetaDataNode' => {
|
'samlSPMetaDataNode' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'select' => {
|
'select' => {
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
@ -216,19 +216,19 @@ m[^(?:(?:\-+\s*BEGIN\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\
|
|||||||
return $test
|
return $test
|
||||||
? 1
|
? 1
|
||||||
: ( 1, "Invalid value '$_[0]' for this select" );
|
: ( 1, "Invalid value '$_[0]' for this select" );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'subContainer' => {
|
'subContainer' => {
|
||||||
'keyTest' => qr/\w/,
|
'keyTest' => qr/\w/,
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'text' => {
|
'text' => {
|
||||||
'msgFail' => '__malformedValue__',
|
'msgFail' => '__malformedValue__',
|
||||||
'test' => sub {
|
'test' => sub {
|
||||||
1;
|
1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'trool' => {
|
'trool' => {
|
||||||
'msgFail' => '__authorizedValues__: -1, 0, 1',
|
'msgFail' => '__authorizedValues__: -1, 0, 1',
|
||||||
@ -1036,7 +1036,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
|
|||||||
split( /\n/, $@, 0 ) )
|
split( /\n/, $@, 0 ) )
|
||||||
);
|
);
|
||||||
return $err ? ( 1, "__badExpression__: $err" ) : 1;
|
return $err ? ( 1, "__badExpression__: $err" ) : 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'type' => 'keyTextContainer'
|
'type' => 'keyTextContainer'
|
||||||
},
|
},
|
||||||
@ -1208,7 +1208,7 @@ qr/^(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-
|
|||||||
and defined $conf->{$_}{$val};
|
and defined $conf->{$_}{$val};
|
||||||
}
|
}
|
||||||
return 1, "__unknownAttrOrMacro__: $val";
|
return 1, "__unknownAttrOrMacro__: $val";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'type' => 'doubleHash'
|
'type' => 'doubleHash'
|
||||||
},
|
},
|
||||||
@ -1490,7 +1490,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
|
|||||||
split( /\n/, $@, 0 ) )
|
split( /\n/, $@, 0 ) )
|
||||||
);
|
);
|
||||||
return $err ? ( 1, "__badExpression__: $err" ) : 1;
|
return $err ? ( 1, "__badExpression__: $err" ) : 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'type' => 'ruleContainer'
|
'type' => 'ruleContainer'
|
||||||
},
|
},
|
||||||
@ -2986,19 +2986,19 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
|
|||||||
'default' => 0,
|
'default' => 0,
|
||||||
'select' => [
|
'select' => [
|
||||||
{
|
{
|
||||||
'k' => '0',
|
'k' => 0,
|
||||||
'v' => 'unsecuredCookie'
|
'v' => 'unsecuredCookie'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'k' => '1',
|
'k' => 1,
|
||||||
'v' => 'securedCookie'
|
'v' => 'securedCookie'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'k' => '2',
|
'k' => 2,
|
||||||
'v' => 'doubleCookie'
|
'v' => 'doubleCookie'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'k' => '3',
|
'k' => 3,
|
||||||
'v' => 'doubleCookieForSingleSession'
|
'v' => 'doubleCookieForSingleSession'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -4,12 +4,14 @@ use 5.10.0;
|
|||||||
use utf8;
|
use utf8;
|
||||||
use strict;
|
use strict;
|
||||||
use Mouse;
|
use Mouse;
|
||||||
|
use MIME::Base64 qw(encode_base64 decode_base64);
|
||||||
|
use Crypt::U2F::Server::Simple;
|
||||||
|
|
||||||
use Lemonldap::NG::Common::Session;
|
use Lemonldap::NG::Common::Session;
|
||||||
use Lemonldap::NG::Common::Conf::Constants;
|
use Lemonldap::NG::Common::Conf::Constants;
|
||||||
use Lemonldap::NG::Common::PSGI::Constants;
|
use Lemonldap::NG::Common::PSGI::Constants;
|
||||||
use Lemonldap::NG::Common::Conf::ReConstants;
|
use Lemonldap::NG::Common::Conf::ReConstants;
|
||||||
use Lemonldap::NG::Common::IPv6;
|
#use Lemonldap::NG::Common::IPv6;
|
||||||
|
|
||||||
use feature 'state';
|
use feature 'state';
|
||||||
|
|
||||||
@ -33,21 +35,27 @@ sub addRoutes {
|
|||||||
|
|
||||||
# READ
|
# READ
|
||||||
->addRoute(
|
->addRoute(
|
||||||
u2f => { ':sessionType' => 'sessions' },
|
u2f => { ':sessionType' => 'u2f' },
|
||||||
['GET']
|
['GET']
|
||||||
)
|
)
|
||||||
|
|
||||||
# DELETE U2F KEY ATTRIBUTS
|
# DELETE U2F KEY
|
||||||
->addRoute(
|
->addRoute(
|
||||||
u2f => { ':sessionType' => { ':sessionId' => 'delU2FKey' } },
|
u2f => { ':sessionType' => { ':sessionId' => 'deleteU2FKey' } },
|
||||||
['DELETE']
|
['DELETE']
|
||||||
);
|
)
|
||||||
|
|
||||||
# UPDATE U2F KEY ATTRIBUTS
|
# ADD U2F KEY
|
||||||
# ->addRoute(
|
->addRoute(
|
||||||
# u2f => { ':sessionType' => { ':sessionId' => { ':updateSession' } },
|
u2f => { ':sessionType' => { ':sessionId' => 'registerU2FKey' } },
|
||||||
# ['PUT']
|
['PUT']
|
||||||
#);
|
)
|
||||||
|
|
||||||
|
# VERIFY U2F KEY
|
||||||
|
->addRoute(
|
||||||
|
u2f => { ':sessionType' => { ':sessionId' => 'verifyU2FKey' } },
|
||||||
|
['POST']
|
||||||
|
);
|
||||||
|
|
||||||
$self->setTypes($conf);
|
$self->setTypes($conf);
|
||||||
|
|
||||||
@ -56,9 +64,28 @@ sub addRoutes {
|
|||||||
$self->{hiddenAttributes} //= "_password";
|
$self->{hiddenAttributes} //= "_password";
|
||||||
}
|
}
|
||||||
|
|
||||||
#######################
|
|
||||||
# II. DISPLAY METHODS #
|
############################
|
||||||
#######################
|
# II. REGISTRATION METHODS #
|
||||||
|
############################
|
||||||
|
|
||||||
|
sub registerU2FKey {
|
||||||
|
|
||||||
|
my ( $self, $req, $session, $skey ) = @_;
|
||||||
|
|
||||||
|
eval 'use Crypt::U2F::Server::Simple';
|
||||||
|
if ($@) {
|
||||||
|
$self->error("Can't load U2F library: $@");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $self->addU2FKey( $req, $session, $skey );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
########################
|
||||||
|
# III. DISPLAY METHODS #
|
||||||
|
########################
|
||||||
|
|
||||||
sub u2f {
|
sub u2f {
|
||||||
my ( $self, $req, $session, $skey ) = @_;
|
my ( $self, $req, $session, $skey ) = @_;
|
||||||
@ -72,27 +99,21 @@ sub u2f {
|
|||||||
or return $self->sendError( $req, undef, 400 );
|
or return $self->sendError( $req, undef, 400 );
|
||||||
my $params = $req->parameters();
|
my $params = $req->parameters();
|
||||||
my $type = delete $params->{sessionType};
|
my $type = delete $params->{sessionType};
|
||||||
$type = $type eq 'global' ? 'SSO' : ucfirst($type);
|
$type = ucfirst($type);
|
||||||
|
|
||||||
my $res;
|
my $res;
|
||||||
|
|
||||||
# Case 2: list of sessions
|
# Case 2: list of sessions
|
||||||
|
|
||||||
my $whatToTrace = Lemonldap::NG::Handler::PSGI::Main->tsv->{whatToTrace};
|
my $whatToTrace = Lemonldap::NG::Handler::PSGI::Main->tsv->{whatToTrace};
|
||||||
|
|
||||||
# 2.1 Get fields to require
|
# 2.1 Get fields to require
|
||||||
my @fields = ( '_httpSessionType', $self->{ipField}, $whatToTrace );
|
my @fields = ( '_httpSessionType', $self->{ipField}, $whatToTrace, '_u2fKeyHandle' );
|
||||||
if ( my $groupBy = $params->{groupBy} ) {
|
if ( my $groupBy = $params->{groupBy} ) {
|
||||||
$groupBy =~ s/^substr\((\w+)(?:,\d+(?:,\d+)?)?\)$/$1/
|
$groupBy =~ s/^substr\((\w+)(?:,\d+(?:,\d+)?)?\)$/$1/;
|
||||||
or $groupBy =~ s/^net(?:4|6|)\(([\w:]+),\d+(?:,\d+)?\)$/$1/;
|
|
||||||
$groupBy =~ s/^_whatToTrace$/$whatToTrace/o
|
$groupBy =~ s/^_whatToTrace$/$whatToTrace/o
|
||||||
or push @fields, $groupBy;
|
or push @fields, $groupBy;
|
||||||
}
|
}
|
||||||
elsif ( my $order = $params->{orderBy} ) {
|
|
||||||
$order =~ s/^net(?:4|6|)\(([\w:]+)\)$/$1/;
|
|
||||||
$order =~ s/^_whatToTrace$/$whatToTrace/o
|
|
||||||
or push @fields, split( /, /, $order );
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
push @fields, '_utime';
|
push @fields, '_utime';
|
||||||
}
|
}
|
||||||
@ -109,10 +130,12 @@ sub u2f {
|
|||||||
: ( $s => $params->{$_} );
|
: ( $s => $params->{$_} );
|
||||||
} keys %$params;
|
} keys %$params;
|
||||||
$filters{_session_kind} = $type;
|
$filters{_session_kind} = $type;
|
||||||
|
# $filters{_u2fKeyHandle} = '';
|
||||||
push @fields, keys(%filters);
|
push @fields, keys(%filters);
|
||||||
{
|
{
|
||||||
my %seen;
|
my %seen;
|
||||||
@fields = grep { !$seen{$_}++ } @fields;
|
@fields = grep { !$seen{$_}++ } @fields;
|
||||||
|
# @fields = grep { !/\w+/ } @fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
# For now, only one argument can be passed to
|
# For now, only one argument can be passed to
|
||||||
@ -172,62 +195,15 @@ sub u2f {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Display sessions with U2F key registered only
|
||||||
|
foreach my $session ( keys %$res ) {
|
||||||
|
delete $res->{$session}
|
||||||
|
unless ( defined $res->{$session}->{_u2fKeyHandle} and length $res->{$session}->{_u2fKeyHandle} )
|
||||||
|
}
|
||||||
|
|
||||||
my $total = ( keys %$res );
|
my $total = ( keys %$res );
|
||||||
|
|
||||||
# 2.4 Special case doubleIp (users connected from more than 1 IP)
|
if ( my $group = $req->params('groupBy') ) {
|
||||||
if ( defined $params->{doubleIp} ) {
|
|
||||||
my %r;
|
|
||||||
|
|
||||||
# 2.4.1 Store user IP addresses in %r
|
|
||||||
foreach my $id ( keys %$res ) {
|
|
||||||
my $entry = $res->{$id};
|
|
||||||
next if ( $entry->{_httpSessionType} );
|
|
||||||
$r{ $entry->{$whatToTrace} }->{ $entry->{ $self->{ipField} } }++;
|
|
||||||
}
|
|
||||||
|
|
||||||
# 2.4.2 Store sessions owned by users that has more than one IP address in $r
|
|
||||||
my $r;
|
|
||||||
$total = 0;
|
|
||||||
foreach my $k ( keys %$res ) {
|
|
||||||
my @tmp = keys %{ $r{ $res->{$k}->{$whatToTrace} } };
|
|
||||||
if ( @tmp > 1 ) {
|
|
||||||
$total += 1;
|
|
||||||
$res->{$k}->{_sessionId} = $k;
|
|
||||||
push @{ $r->{ $res->{$k}->{$whatToTrace} } }, $res->{$k};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# 2.4.3 Store these session in an array. Array elements are :
|
|
||||||
# {
|
|
||||||
# uid => whatToTraceFieldValue,
|
|
||||||
# sessions => [
|
|
||||||
# { session => <session-id-1>, date => <_utime> },
|
|
||||||
# { session => <session-id-2>, date => <_utime> },
|
|
||||||
# ]
|
|
||||||
# }
|
|
||||||
$res = [];
|
|
||||||
foreach my $uid ( sort keys %$r ) {
|
|
||||||
push @$res, {
|
|
||||||
value => $uid,
|
|
||||||
count => scalar( @{ $r->{$uid} } ),
|
|
||||||
sessions => [
|
|
||||||
map {
|
|
||||||
{
|
|
||||||
session => $_->{_sessionId},
|
|
||||||
date => $_->{_utime}
|
|
||||||
}
|
|
||||||
} @{ $r->{$uid} }
|
|
||||||
]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# 2.4 Order and group by
|
|
||||||
# $res will become an array ref here (except for doubleIp, already done below).
|
|
||||||
|
|
||||||
# If "groupBy" is asked, elements will be like:
|
|
||||||
# { uid => 'foo.bar', count => 3 }
|
|
||||||
elsif ( my $group = $req->params('groupBy') ) {
|
|
||||||
my $r;
|
my $r;
|
||||||
$group =~ s/\b_whatToTrace\b/$whatToTrace/o;
|
$group =~ s/\b_whatToTrace\b/$whatToTrace/o;
|
||||||
|
|
||||||
@ -243,46 +219,6 @@ sub u2f {
|
|||||||
$group = $field;
|
$group = $field;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Subnets IPv4
|
|
||||||
elsif ( $group =~ /^net4\((\w+),(\d)\)$/ ) {
|
|
||||||
my $field = $1;
|
|
||||||
my $nb = $2 - 1;
|
|
||||||
foreach my $k ( keys %$res ) {
|
|
||||||
if ( $res->{$k}->{$field} =~ /^((((\d+)\.\d+)\.\d+)\.\d+)$/ ) {
|
|
||||||
my @d = ( $4, $3, $2, $1 );
|
|
||||||
$r->{ $d[$nb] }++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$group = $field;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Subnets IPv6
|
|
||||||
elsif ( $group =~ /^net6\(([\w:]+),(\d)\)$/ ) {
|
|
||||||
my $field = $1;
|
|
||||||
my $bits = $2;
|
|
||||||
foreach my $k ( keys %$res ) {
|
|
||||||
$r->{ net6( $res->{$k}->{$field}, $bits ) . "/$bits" }++
|
|
||||||
if ( isIPv6( $res->{$k}->{$field} ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Both IPv4 and IPv6
|
|
||||||
elsif ( $group =~ /^net\(([\w:]+),(\d+),(\d+)\)$/ ) {
|
|
||||||
my $field = $1;
|
|
||||||
my $bits = $2;
|
|
||||||
my $nb = $3 - 1;
|
|
||||||
foreach my $k ( keys %$res ) {
|
|
||||||
if ( isIPv6( $res->{$k}->{$field} ) ) {
|
|
||||||
$r->{ net6( $res->{$k}->{$field}, $bits ) . "/$bits" }++;
|
|
||||||
}
|
|
||||||
elsif ( $res->{$k}->{$field} =~ /^((((\d+)\.\d+)\.\d+)\.\d+)$/ )
|
|
||||||
{
|
|
||||||
my @d = ( $4, $3, $2, $1 );
|
|
||||||
$r->{ $d[$nb] }++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Simple field groupBy query
|
# Simple field groupBy query
|
||||||
elsif ( $group =~ /^\w+$/ ) {
|
elsif ( $group =~ /^\w+$/ ) {
|
||||||
eval {
|
eval {
|
||||||
@ -316,47 +252,6 @@ qq{Use of an uninitialized attribute "$group" to group sessions},
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
# Else if "orderBy" is asked, $res elements will be like:
|
|
||||||
# { uid => 'foo.bar', session => <sessionId> }
|
|
||||||
elsif ( my $f = $req->params('orderBy') ) {
|
|
||||||
my @fields = split /,/, $f;
|
|
||||||
my @r = map {
|
|
||||||
my $tmp = { session => $_ };
|
|
||||||
foreach my $f (@fields) {
|
|
||||||
my $s = $f;
|
|
||||||
$s =~ s/^net(?:4|6|)\(([\w:]+)\)$/$1/;
|
|
||||||
$tmp->{$s} = $res->{$_}->{$s};
|
|
||||||
}
|
|
||||||
$tmp
|
|
||||||
} keys %$res;
|
|
||||||
while ( my $f = pop @fields ) {
|
|
||||||
if ( $f =~ s/^net4\((\w+)\)$/$1/ ) {
|
|
||||||
@r = sort { cmpIPv4( $a->{$f}, $b->{$f} ); } @r;
|
|
||||||
}
|
|
||||||
elsif ( $f =~ s/^net6\(([:\w]+)\)$/$1/ ) {
|
|
||||||
@r = sort { expand6( $a->{$f} ) cmp expand6( $b->{$f} ); } @r;
|
|
||||||
}
|
|
||||||
elsif ( $f =~ s/^net\(([:\w]+)\)$/$1/ ) {
|
|
||||||
@r = sort {
|
|
||||||
my $ip1 = $a->{$f};
|
|
||||||
my $ip2 = $b->{$f};
|
|
||||||
isIPv6($ip1)
|
|
||||||
? (
|
|
||||||
isIPv6($ip2)
|
|
||||||
? expand6($ip1) cmp expand6($ip2)
|
|
||||||
: -1
|
|
||||||
)
|
|
||||||
: isIPv6($ip2) ? 1
|
|
||||||
: cmpIPv4( $ip1, $ip2 );
|
|
||||||
} @r;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
@r = sort { $a->{$f} cmp $b->{$f} } @r;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$res = [@r];
|
|
||||||
}
|
|
||||||
|
|
||||||
# Else, $res elements will be like:
|
# Else, $res elements will be like:
|
||||||
# { session => <sessionId>, date => <timestamp> }
|
# { session => <sessionId>, date => <timestamp> }
|
||||||
else {
|
else {
|
||||||
@ -378,17 +273,4 @@ qq{Use of an uninitialized attribute "$group" to group sessions},
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub cmpIPv4 {
|
|
||||||
my @a = split /\./, $_[0];
|
|
||||||
my @b = split /\./, $_[1];
|
|
||||||
my $cmp = 0;
|
|
||||||
F: for ( my $i = 0 ; $i < 4 ; $i++ ) {
|
|
||||||
if ( $a[$i] != $b[$i] ) {
|
|
||||||
$cmp = $a[$i] <=> $b[$i];
|
|
||||||
last F;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$cmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -196,6 +196,8 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
|
|||||||
session[key] = $scope.localeDate value
|
session[key] = $scope.localeDate value
|
||||||
else if key.match /^(_startTime|_updateTime)$/
|
else if key.match /^(_startTime|_updateTime)$/
|
||||||
session[key] = _stToStr value
|
session[key] = _stToStr value
|
||||||
|
else if key.match /^(_u2fKeyHandle|_u2fUserKey)$/
|
||||||
|
session[key] = '########'
|
||||||
res = []
|
res = []
|
||||||
|
|
||||||
# 2. Push session keys in reuslt, grouped by categories
|
# 2. Push session keys in reuslt, grouped by categories
|
||||||
|
@ -87,10 +87,18 @@ categories =
|
|||||||
|
|
||||||
# Menu entries
|
# Menu entries
|
||||||
menu =
|
menu =
|
||||||
session: [
|
delU2FKey: [
|
||||||
title: 'deleteU2FKey'
|
title: 'deleteU2FKey'
|
||||||
icon: 'trash'
|
icon: 'trash'
|
||||||
]
|
]
|
||||||
|
addU2FKey: [
|
||||||
|
title: 'addU2FKey'
|
||||||
|
icon: 'plus'
|
||||||
|
]
|
||||||
|
verifyU2FKey: [
|
||||||
|
title: 'verifyU2FKey'
|
||||||
|
icon: 'check'
|
||||||
|
]
|
||||||
home: []
|
home: []
|
||||||
|
|
||||||
###
|
###
|
||||||
@ -138,7 +146,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
|
|||||||
|
|
||||||
# SESSION MANAGEMENT
|
# SESSION MANAGEMENT
|
||||||
|
|
||||||
# Delete U2F key attributs
|
# Delete U2F key
|
||||||
$scope.deleteU2FKey = ->
|
$scope.deleteU2FKey = ->
|
||||||
$scope.waiting = true
|
$scope.waiting = true
|
||||||
$http['delete']("#{scriptname}u2f/#{sessionType}/#{$scope.currentSession.id}").then (response) ->
|
$http['delete']("#{scriptname}u2f/#{sessionType}/#{$scope.currentSession.id}").then (response) ->
|
||||||
@ -151,6 +159,32 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
|
|||||||
$scope.waiting = false
|
$scope.waiting = false
|
||||||
$scope.showT = true
|
$scope.showT = true
|
||||||
|
|
||||||
|
# Add U2F key
|
||||||
|
$scope.addU2FKey = ->
|
||||||
|
$scope.waiting = true
|
||||||
|
$http['put']("#{scriptname}u2f/#{sessionType}/#{$scope.currentSession.id}").then (response) ->
|
||||||
|
$scope.currentSession = null
|
||||||
|
#$scope.currentScope.remove()
|
||||||
|
$scope.waiting = false
|
||||||
|
, (resp) ->
|
||||||
|
$scope.currentSession = null
|
||||||
|
#$scope.currentScope.remove()
|
||||||
|
$scope.waiting = false
|
||||||
|
$scope.showT = true
|
||||||
|
|
||||||
|
# Verify U2F key
|
||||||
|
$scope.verifyU2FKey = ->
|
||||||
|
$scope.waiting = true
|
||||||
|
$http['post']("#{scriptname}u2f/#{sessionType}/#{$scope.currentSession.id}").then (response) ->
|
||||||
|
$scope.currentSession = null
|
||||||
|
#$scope.currentScope.remove()
|
||||||
|
$scope.waiting = false
|
||||||
|
, (resp) ->
|
||||||
|
$scope.currentSession = null
|
||||||
|
#$scope.currentScope.remove()
|
||||||
|
$scope.waiting = false
|
||||||
|
$scope.showT = true
|
||||||
|
|
||||||
# Open node
|
# Open node
|
||||||
$scope.stoggle = (scope) ->
|
$scope.stoggle = (scope) ->
|
||||||
node = scope.$modelValue
|
node = scope.$modelValue
|
||||||
@ -197,6 +231,8 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
|
|||||||
session[key] = $scope.localeDate value
|
session[key] = $scope.localeDate value
|
||||||
else if key.match /^(_startTime|_updateTime)$/
|
else if key.match /^(_startTime|_updateTime)$/
|
||||||
session[key] = _stToStr value
|
session[key] = _stToStr value
|
||||||
|
else if key.match /^(_u2fKeyHandle|_u2fUserKey)$/
|
||||||
|
session[key] = '########'
|
||||||
res = []
|
res = []
|
||||||
|
|
||||||
# 2. Push session keys in result, grouped by categories
|
# 2. Push session keys in result, grouped by categories
|
||||||
@ -261,7 +297,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
|
|||||||
|
|
||||||
$scope.currentScope = scope
|
$scope.currentScope = scope
|
||||||
sessionId = scope.$modelValue.session
|
sessionId = scope.$modelValue.session
|
||||||
$http.get("#{scriptname}sessions/#{sessionType}/#{sessionId}").then (response) ->
|
$http.get("#{scriptname}u2f/#{sessionType}/#{sessionId}").then (response) ->
|
||||||
$scope.currentSession = transformSession response.data
|
$scope.currentSession = transformSession response.data
|
||||||
$scope.showT = false
|
$scope.showT = false
|
||||||
|
|
||||||
@ -325,7 +361,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
|
|||||||
over = 0
|
over = 0
|
||||||
|
|
||||||
# Launch HTTP query
|
# Launch HTTP query
|
||||||
$http.get("#{scriptname}sessions/#{sessionType}?#{query}").then (response) ->
|
$http.get("#{scriptname}u2f/#{sessionType}?#{query}").then (response) ->
|
||||||
data = response.data
|
data = response.data
|
||||||
if data.result
|
if data.result
|
||||||
for n in data.values
|
for n in data.values
|
||||||
|
@ -227,6 +227,8 @@
|
|||||||
session[key] = $scope.localeDate(value);
|
session[key] = $scope.localeDate(value);
|
||||||
} else if (key.match(/^(_startTime|_updateTime)$/)) {
|
} else if (key.match(/^(_startTime|_updateTime)$/)) {
|
||||||
session[key] = _stToStr(value);
|
session[key] = _stToStr(value);
|
||||||
|
} else if (key.match(/^(_u2fKeyHandle|_u2fUserKey)$/)) {
|
||||||
|
session[key] = '########';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because one or more lines are too long
@ -104,12 +104,24 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
menu = {
|
menu = {
|
||||||
session: [
|
delU2FKey: [
|
||||||
{
|
{
|
||||||
title: 'deleteU2FKey',
|
title: 'deleteU2FKey',
|
||||||
icon: 'trash'
|
icon: 'trash'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
addU2FKey: [
|
||||||
|
{
|
||||||
|
title: 'addU2FKey',
|
||||||
|
icon: 'plus'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
verifyU2FKey: [
|
||||||
|
{
|
||||||
|
title: 'verifyU2FKey',
|
||||||
|
icon: 'check'
|
||||||
|
}
|
||||||
|
],
|
||||||
home: []
|
home: []
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -173,6 +185,28 @@
|
|||||||
});
|
});
|
||||||
return $scope.showT = true;
|
return $scope.showT = true;
|
||||||
};
|
};
|
||||||
|
$scope.addU2FKey = function() {
|
||||||
|
$scope.waiting = true;
|
||||||
|
$http['put'](scriptname + "u2f/" + sessionType + "/" + $scope.currentSession.id).then(function(response) {
|
||||||
|
$scope.currentSession = null;
|
||||||
|
return $scope.waiting = false;
|
||||||
|
}, function(resp) {
|
||||||
|
$scope.currentSession = null;
|
||||||
|
return $scope.waiting = false;
|
||||||
|
});
|
||||||
|
return $scope.showT = true;
|
||||||
|
};
|
||||||
|
$scope.verifyU2FKey = function() {
|
||||||
|
$scope.waiting = true;
|
||||||
|
$http['post'](scriptname + "u2f/" + sessionType + "/" + $scope.currentSession.id).then(function(response) {
|
||||||
|
$scope.currentSession = null;
|
||||||
|
return $scope.waiting = false;
|
||||||
|
}, function(resp) {
|
||||||
|
$scope.currentSession = null;
|
||||||
|
return $scope.waiting = false;
|
||||||
|
});
|
||||||
|
return $scope.showT = true;
|
||||||
|
};
|
||||||
$scope.stoggle = function(scope) {
|
$scope.stoggle = function(scope) {
|
||||||
var node;
|
var node;
|
||||||
node = scope.$modelValue;
|
node = scope.$modelValue;
|
||||||
@ -226,6 +260,8 @@
|
|||||||
session[key] = $scope.localeDate(value);
|
session[key] = $scope.localeDate(value);
|
||||||
} else if (key.match(/^(_startTime|_updateTime)$/)) {
|
} else if (key.match(/^(_startTime|_updateTime)$/)) {
|
||||||
session[key] = _stToStr(value);
|
session[key] = _stToStr(value);
|
||||||
|
} else if (key.match(/^(_u2fKeyHandle|_u2fUserKey)$/)) {
|
||||||
|
session[key] = '########';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -315,7 +351,7 @@
|
|||||||
};
|
};
|
||||||
$scope.currentScope = scope;
|
$scope.currentScope = scope;
|
||||||
sessionId = scope.$modelValue.session;
|
sessionId = scope.$modelValue.session;
|
||||||
$http.get(scriptname + "sessions/" + sessionType + "/" + sessionId).then(function(response) {
|
$http.get(scriptname + "u2f/" + sessionType + "/" + sessionId).then(function(response) {
|
||||||
return $scope.currentSession = transformSession(response.data);
|
return $scope.currentSession = transformSession(response.data);
|
||||||
});
|
});
|
||||||
return $scope.showT = false;
|
return $scope.showT = false;
|
||||||
@ -363,7 +399,7 @@
|
|||||||
} else {
|
} else {
|
||||||
over = 0;
|
over = 0;
|
||||||
}
|
}
|
||||||
return $http.get(scriptname + "sessions/" + sessionType + "?" + query).then(function(response) {
|
return $http.get(scriptname + "u2f/" + sessionType + "?" + query).then(function(response) {
|
||||||
var data, i, len, n, ref;
|
var data, i, len, n, ref;
|
||||||
data = response.data;
|
data = response.data;
|
||||||
if (data.result) {
|
if (data.result) {
|
||||||
|
File diff suppressed because one or more lines are too long
@ -33,6 +33,7 @@
|
|||||||
"addSamlAttribute":"إضافة صفة",
|
"addSamlAttribute":"إضافة صفة",
|
||||||
"addSPSamlPartner":"إضافة SP SAML",
|
"addSPSamlPartner":"إضافة SP SAML",
|
||||||
"addSrvCasPartner":"إضافة سرفر كاس",
|
"addSrvCasPartner":"إضافة سرفر كاس",
|
||||||
|
"addU2FKey":"Add U2F key",
|
||||||
"addVhost":"إضافة خادم افتراضي",
|
"addVhost":"إضافة خادم افتراضي",
|
||||||
"adParams":"معاييرأكتيف ديريكتوري",
|
"adParams":"معاييرأكتيف ديريكتوري",
|
||||||
"ADPwdExpireWarning":"تحذير انتهاء صلاحية كلمة المرور",
|
"ADPwdExpireWarning":"تحذير انتهاء صلاحية كلمة المرور",
|
||||||
@ -728,6 +729,7 @@
|
|||||||
"u2fActivation":"تفعيل",
|
"u2fActivation":"تفعيل",
|
||||||
"u2fAuthnLevel":"U2F مستوى إثبات الهوية",
|
"u2fAuthnLevel":"U2F مستوى إثبات الهوية",
|
||||||
"u2fSelfRegistration":"التسجيل الذاتي",
|
"u2fSelfRegistration":"التسجيل الذاتي",
|
||||||
|
"u2fSessions":"U2F sessions explorer",
|
||||||
"uid":"المعرف",
|
"uid":"المعرف",
|
||||||
"unknownAttrOrMacro":"سمة غير معروفة أو ماكرو",
|
"unknownAttrOrMacro":"سمة غير معروفة أو ماكرو",
|
||||||
"unknownError":"خطأ غير معروف",
|
"unknownError":"خطأ غير معروف",
|
||||||
@ -752,6 +754,7 @@
|
|||||||
"values":"القيم",
|
"values":"القيم",
|
||||||
"variables":"المتغيرات",
|
"variables":"المتغيرات",
|
||||||
"version":"الإصدار",
|
"version":"الإصدار",
|
||||||
|
"verifyU2FKey":"Verify U2F key",
|
||||||
"vhostAliases":"اسماء مستعارة",
|
"vhostAliases":"اسماء مستعارة",
|
||||||
"vhostAuthnLevel":"مستوى إثبات الهوية واجب",
|
"vhostAuthnLevel":"مستوى إثبات الهوية واجب",
|
||||||
"vhostHttps":"إتش تي تي بي س",
|
"vhostHttps":"إتش تي تي بي س",
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
"addSamlAttribute":"Add attribute",
|
"addSamlAttribute":"Add attribute",
|
||||||
"addSPSamlPartner":"Add SAML SP",
|
"addSPSamlPartner":"Add SAML SP",
|
||||||
"addSrvCasPartner":"Add CAS server",
|
"addSrvCasPartner":"Add CAS server",
|
||||||
|
"addU2FKey":"Add U2F key",
|
||||||
"addVhost":"Add virtualhost",
|
"addVhost":"Add virtualhost",
|
||||||
"adParams":"Active Directory Parameters",
|
"adParams":"Active Directory Parameters",
|
||||||
"ADPwdExpireWarning":"Password expire warning",
|
"ADPwdExpireWarning":"Password expire warning",
|
||||||
@ -728,6 +729,7 @@
|
|||||||
"u2fActivation":"Activation",
|
"u2fActivation":"Activation",
|
||||||
"u2fAuthnLevel":"U2F authentication level",
|
"u2fAuthnLevel":"U2F authentication level",
|
||||||
"u2fSelfRegistration":"Self registration",
|
"u2fSelfRegistration":"Self registration",
|
||||||
|
"u2fSessions":"U2F sessions explorer",
|
||||||
"uid":"Identifier",
|
"uid":"Identifier",
|
||||||
"unknownAttrOrMacro":"Unknown attribute or macro",
|
"unknownAttrOrMacro":"Unknown attribute or macro",
|
||||||
"unknownError":"Unknown error",
|
"unknownError":"Unknown error",
|
||||||
@ -752,6 +754,7 @@
|
|||||||
"values":"Values",
|
"values":"Values",
|
||||||
"variables":"Variables",
|
"variables":"Variables",
|
||||||
"version":"Version",
|
"version":"Version",
|
||||||
|
"verifyU2FKey":"Verify U2F key",
|
||||||
"vhostAliases":"Aliases",
|
"vhostAliases":"Aliases",
|
||||||
"vhostAuthnLevel":"Required authentication level",
|
"vhostAuthnLevel":"Required authentication level",
|
||||||
"vhostHttps":"HTTPS",
|
"vhostHttps":"HTTPS",
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
"addSamlAttribute":"Ajouter un attribut",
|
"addSamlAttribute":"Ajouter un attribut",
|
||||||
"addSPSamlPartner":"Ajouter un SP SAML",
|
"addSPSamlPartner":"Ajouter un SP SAML",
|
||||||
"addSrvCasPartner":"Ajouter un serveur CAS",
|
"addSrvCasPartner":"Ajouter un serveur CAS",
|
||||||
|
"addU2FKey":"Ajouter une clef U2F",
|
||||||
"addVhost":"Ajouter un hôte virtuel",
|
"addVhost":"Ajouter un hôte virtuel",
|
||||||
"adParams":"Paramètres Active Directory",
|
"adParams":"Paramètres Active Directory",
|
||||||
"ADPwdExpireWarning":"Avertissement avant expiration du mot de passe",
|
"ADPwdExpireWarning":"Avertissement avant expiration du mot de passe",
|
||||||
@ -728,6 +729,7 @@
|
|||||||
"u2fActivation":"Activation",
|
"u2fActivation":"Activation",
|
||||||
"u2fAuthnLevel":"Niveau d'authentification U2F",
|
"u2fAuthnLevel":"Niveau d'authentification U2F",
|
||||||
"u2fSelfRegistration":"Auto-enregistrement",
|
"u2fSelfRegistration":"Auto-enregistrement",
|
||||||
|
"u2fSessions":"Explorateur de sessions U2F",
|
||||||
"uid":"Identifiant",
|
"uid":"Identifiant",
|
||||||
"unknownAttrOrMacro":"Attribut ou macro inconnu",
|
"unknownAttrOrMacro":"Attribut ou macro inconnu",
|
||||||
"unknownError":"Erreur inconnue",
|
"unknownError":"Erreur inconnue",
|
||||||
@ -751,6 +753,7 @@
|
|||||||
"value":"Valeur",
|
"value":"Valeur",
|
||||||
"values":"Valeurs",
|
"values":"Valeurs",
|
||||||
"variables":"Variables",
|
"variables":"Variables",
|
||||||
|
"verifyU2FKey":"Vérifier la clef U2F",
|
||||||
"version":"Version",
|
"version":"Version",
|
||||||
"vhostAliases":"Alias",
|
"vhostAliases":"Alias",
|
||||||
"vhostAuthnLevel":"Niveau d'authentication requis",
|
"vhostAuthnLevel":"Niveau d'authentication requis",
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
"addSamlAttribute":"Aggiungi attributo",
|
"addSamlAttribute":"Aggiungi attributo",
|
||||||
"addSPSamlPartner":"Aggiungi SAML SP",
|
"addSPSamlPartner":"Aggiungi SAML SP",
|
||||||
"addSrvCasPartner":"Aggiungi server CAS",
|
"addSrvCasPartner":"Aggiungi server CAS",
|
||||||
|
"addU2FKey":"Add U2F key",
|
||||||
"addVhost":"Aggiungi virtualhost",
|
"addVhost":"Aggiungi virtualhost",
|
||||||
"adParams":"Parametri di Active Directory",
|
"adParams":"Parametri di Active Directory",
|
||||||
"ADPwdExpireWarning":"Avviso di scadenza password",
|
"ADPwdExpireWarning":"Avviso di scadenza password",
|
||||||
@ -728,6 +729,7 @@
|
|||||||
"u2fActivation":"Attivazione",
|
"u2fActivation":"Attivazione",
|
||||||
"u2fAuthnLevel":"Livello di autenticazione U2F",
|
"u2fAuthnLevel":"Livello di autenticazione U2F",
|
||||||
"u2fSelfRegistration":"Auto-registrazione",
|
"u2fSelfRegistration":"Auto-registrazione",
|
||||||
|
"u2fSessions":"U2F sessions explorer",
|
||||||
"uid":"Identificatore",
|
"uid":"Identificatore",
|
||||||
"unknownAttrOrMacro":"Attributo o macro sconosciuti",
|
"unknownAttrOrMacro":"Attributo o macro sconosciuti",
|
||||||
"unknownError":"Errore sconosciuto",
|
"unknownError":"Errore sconosciuto",
|
||||||
@ -752,6 +754,7 @@
|
|||||||
"values":"Valori",
|
"values":"Valori",
|
||||||
"variables":"Variabili",
|
"variables":"Variabili",
|
||||||
"version":"Versioni",
|
"version":"Versioni",
|
||||||
|
"verifyU2FKey":"Verify U2F key",
|
||||||
"vhostAliases":"Alias",
|
"vhostAliases":"Alias",
|
||||||
"vhostAuthnLevel":"Livello di autenticazione richiesto",
|
"vhostAuthnLevel":"Livello di autenticazione richiesto",
|
||||||
"vhostHttps":"HTTPS",
|
"vhostHttps":"HTTPS",
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
"addSamlAttribute":"Thêm thuộc tính",
|
"addSamlAttribute":"Thêm thuộc tính",
|
||||||
"addSPSamlPartner":"Thêm SAML SP",
|
"addSPSamlPartner":"Thêm SAML SP",
|
||||||
"addSrvCasPartner":"Thêm máy chủ CAS",
|
"addSrvCasPartner":"Thêm máy chủ CAS",
|
||||||
|
"addU2FKey":"Add U2F key",
|
||||||
"addVhost":"Thêm host ảo",
|
"addVhost":"Thêm host ảo",
|
||||||
"adParams":"Tham số của Active Directory",
|
"adParams":"Tham số của Active Directory",
|
||||||
"ADPwdExpireWarning":"Cảnh báo mật khẩu hết hạn",
|
"ADPwdExpireWarning":"Cảnh báo mật khẩu hết hạn",
|
||||||
@ -728,6 +729,7 @@
|
|||||||
"u2fActivation":"Kích hoạt",
|
"u2fActivation":"Kích hoạt",
|
||||||
"u2fAuthnLevel":"Mức xác thực U2F",
|
"u2fAuthnLevel":"Mức xác thực U2F",
|
||||||
"u2fSelfRegistration":"Tự đăng ký ",
|
"u2fSelfRegistration":"Tự đăng ký ",
|
||||||
|
"u2fSessions":"U2F sessions explorer",
|
||||||
"uid":"Trình định danh",
|
"uid":"Trình định danh",
|
||||||
"unknownAttrOrMacro":"Thuộc tính hoặc macro chưa xác định",
|
"unknownAttrOrMacro":"Thuộc tính hoặc macro chưa xác định",
|
||||||
"unknownError":"Lỗi không xác định",
|
"unknownError":"Lỗi không xác định",
|
||||||
@ -752,6 +754,7 @@
|
|||||||
"values":"Giá trị",
|
"values":"Giá trị",
|
||||||
"variables":"biến",
|
"variables":"biến",
|
||||||
"version":"Phiên bản",
|
"version":"Phiên bản",
|
||||||
|
"verifyU2FKey":"Verify U2F key",
|
||||||
"vhostAliases":"Bí danh",
|
"vhostAliases":"Bí danh",
|
||||||
"vhostAuthnLevel":"Mức xác thực bắt buộc",
|
"vhostAuthnLevel":"Mức xác thực bắt buộc",
|
||||||
"vhostHttps":"HTTPS",
|
"vhostHttps":"HTTPS",
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<div class="navbar navbar-default">
|
<div class="navbar navbar-default">
|
||||||
<div class="navbar-collapse">
|
<div class="navbar-collapse">
|
||||||
<ul class="nav navbar-nav" role="grid">
|
<ul class="nav navbar-nav" role="grid">
|
||||||
<li><a id="a-persistent" href="#/persistent" role="row"><i class="glyphicon glyphicon-exclamation-sign"></i> {{translate('persistentSessions')}}</a></li>
|
<li><a id="a-persistent" href="#/persistent" role="row"><i class="glyphicon glyphicon-exclamation-sign"></i> {{translate('u2fSessions')}}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -40,8 +40,13 @@
|
|||||||
<!-- Menu buttons -->
|
<!-- Menu buttons -->
|
||||||
<div class="lmmenu navbar navbar-default" ng-class="{'hidden-xs':!showM}">
|
<div class="lmmenu navbar navbar-default" ng-class="{'hidden-xs':!showM}">
|
||||||
<div class="navbar-collapse" ng-class="{'collapse':!showM}" id="formmenu">
|
<div class="navbar-collapse" ng-class="{'collapse':!showM}" id="formmenu">
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<li ng-if="currentSession" ng-repeat="button in menu.session" ng-include="'menubutton.html'"></li>
|
<!--
|
||||||
|
<li ng-if="currentSession" ng-repeat="button in menu.addU2FKey" ng-include="'menubutton.html'"></li>
|
||||||
|
<li ng-if="currentSession" ng-repeat="button in menu.verifyU2FKey" ng-include="'menubutton.html'"></li>
|
||||||
|
-->
|
||||||
|
<li ng-if="currentSession" ng-repeat="button in menu.delU2FKey" ng-include="'menubutton.html'"></li>
|
||||||
|
|
||||||
<li ng-if="currentSession===null" ng-repeat="button in menu.home" ng-include="'menubutton.html'"></li>
|
<li ng-if="currentSession===null" ng-repeat="button in menu.home" ng-include="'menubutton.html'"></li>
|
||||||
<li uib-dropdown class="visible-xs">
|
<li uib-dropdown class="visible-xs">
|
||||||
<a id="langmenu" name="menu" uib-dropdown-toggle data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Menu <span class="caret"></span></a>
|
<a id="langmenu" name="menu" uib-dropdown-toggle data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Menu <span class="caret"></span></a>
|
||||||
|
@ -116,7 +116,7 @@ sub run {
|
|||||||
elsif ( $err == 0 ) {
|
elsif ( $err == 0 ) {
|
||||||
return $self->p->sendError( $req, "noU2FKeyFound" );
|
return $self->p->sendError( $req, "noU2FKeyFound" );
|
||||||
}
|
}
|
||||||
my $challenge = $req->data->{crypter}->authenticationChallenge;
|
my $challenge = $req->datas->{crypter}->authenticationChallenge;
|
||||||
return [ 200, [ 'Content-Type' => 'application/json' ], [$challenge] ];
|
return [ 200, [ 'Content-Type' => 'application/json' ], [$challenge] ];
|
||||||
}
|
}
|
||||||
if ( $action eq 'signature' ) {
|
if ( $action eq 'signature' ) {
|
||||||
@ -133,7 +133,7 @@ sub run {
|
|||||||
return $self->p->sendError( $req, "noU2FKeyFound" );
|
return $self->p->sendError( $req, "noU2FKeyFound" );
|
||||||
}
|
}
|
||||||
my $res =
|
my $res =
|
||||||
( $req->data->{crypter}->authenticationVerify($resp) ? 1 : 0 );
|
( $req->datas->{crypter}->authenticationVerify($resp) ? 1 : 0 );
|
||||||
return [
|
return [
|
||||||
200, [ 'Content-Type' => 'application/json' ],
|
200, [ 'Content-Type' => 'application/json' ],
|
||||||
[qq'{"result":$res}']
|
[qq'{"result":$res}']
|
||||||
@ -150,11 +150,11 @@ sub loadUser {
|
|||||||
unless ( $kh and $uk ) {
|
unless ( $kh and $uk ) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
$req->data->{crypter} = $self->crypter(
|
$req->datas->{crypter} = $self->crypter(
|
||||||
keyHandle => $self->decode_base64url($kh),
|
keyHandle => $self->decode_base64url($kh),
|
||||||
publicKey => $self->decode_base64url($uk)
|
publicKey => $self->decode_base64url($uk)
|
||||||
);
|
);
|
||||||
unless ( $req->data->{crypter} ) {
|
unless ( $req->datas->{crypter} ) {
|
||||||
my $error = Crypt::U2F::Server::Simple::lastError();
|
my $error = Crypt::U2F::Server::Simple::lastError();
|
||||||
return ( -1, $error );
|
return ( -1, $error );
|
||||||
}
|
}
|
||||||
|
@ -197,7 +197,7 @@
|
|||||||
"touchU2fDevice": "Please touch the flashing U2F device now.",
|
"touchU2fDevice": "Please touch the flashing U2F device now.",
|
||||||
"u2fFailed": "U2F verification failed. Retry or contact your administrator",
|
"u2fFailed": "U2F verification failed. Retry or contact your administrator",
|
||||||
"u2fPermission": "You may be prompted to allow the site permission to access your security keys. After granting permission, the device will start to blink.",
|
"u2fPermission": "You may be prompted to allow the site permission to access your security keys. After granting permission, the device will start to blink.",
|
||||||
"u2fRegistered": "Your key is registered. Click to verify.",
|
"u2fRegistered": "Your key has been registered.",
|
||||||
"u2fUnregistered": "Your key has been unregistered.",
|
"u2fUnregistered": "Your key has been unregistered.",
|
||||||
"u2fSuccess": "Your key is successfully tested",
|
"u2fSuccess": "Your key is successfully tested",
|
||||||
"u2fWelcome": "U2F device management",
|
"u2fWelcome": "U2F device management",
|
||||||
|
@ -197,7 +197,7 @@
|
|||||||
"touchU2fDevice": "Poser votre doigt sur le périphérique U2F",
|
"touchU2fDevice": "Poser votre doigt sur le périphérique U2F",
|
||||||
"u2fFailed": "La vérification U2F a échoué, réessayez ou contactez votre administrateur",
|
"u2fFailed": "La vérification U2F a échoué, réessayez ou contactez votre administrateur",
|
||||||
"u2fPermission": "Il est possible qu'on vous demande d'autoriser le site à accéder à votre clef. Après votre accord, la clef clignotera.",
|
"u2fPermission": "Il est possible qu'on vous demande d'autoriser le site à accéder à votre clef. Après votre accord, la clef clignotera.",
|
||||||
"u2fRegistered": "Votre clef est enregistrée. Cliquez sur vérifier",
|
"u2fRegistered": "Votre clef a été enregistrée.",
|
||||||
"u2fUnregistered": "Votre clef a été supprimée.",
|
"u2fUnregistered": "Votre clef a été supprimée.",
|
||||||
"u2fSuccess": "Votre clef est vérifiée",
|
"u2fSuccess": "Votre clef est vérifiée",
|
||||||
"u2fWelcome": "Gestion du périphérique U2F",
|
"u2fWelcome": "Gestion du périphérique U2F",
|
||||||
@ -206,7 +206,7 @@
|
|||||||
"upgradeSession":"Se réauthentifier",
|
"upgradeSession":"Se réauthentifier",
|
||||||
"user":"Utilisateur",
|
"user":"Utilisateur",
|
||||||
"useYubikey":"utilisez votre Yubikey",
|
"useYubikey":"utilisez votre Yubikey",
|
||||||
"verify": "Verifier",
|
"verify": "Vérifier",
|
||||||
"wait":"Attendre",
|
"wait":"Attendre",
|
||||||
"warning":"Attention",
|
"warning":"Attention",
|
||||||
"welcomeOnPortal":"Bienvenue sur votre portail d'authentification sécurisée.",
|
"welcomeOnPortal":"Bienvenue sur votre portail d'authentification sécurisée.",
|
||||||
|
Loading…
Reference in New Issue
Block a user