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:
Xavier Guimard 2018-03-08 06:48:53 +01:00
commit ec85664131
19 changed files with 257 additions and 229 deletions

2
.gitignore vendored
View File

@ -1,6 +1,6 @@
.gitignore
node_modules
e2e-tests/conf/
e2e-tests/conf
lemonldap-ng-common/MYMETA.json
lemonldap-ng-common/MYMETA.yml
lemonldap-ng-common/Makefile

View File

@ -52,7 +52,7 @@ sub delSession {
return $self->sendJSONresponse( $req, { result => 1 } );
}
sub delU2FKey {
sub deleteU2FKey {
my ( $self, $req ) = @_;
return $self->sendJSONresponse( $req, { result => 1 } )
if ( $self->{demoMode} );
@ -77,6 +77,56 @@ sub delU2FKey {
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 {
my ( $self, $req, $id, $skey ) = @_;
my ( %h, $res );

View File

@ -8,12 +8,12 @@ sub types {
'authParamsText' => {
'test' => sub {
1;
}
}
},
'blackWhiteList' => {
'test' => sub {
1;
}
}
},
'bool' => {
'msgFail' => '__notABoolean__',
@ -36,17 +36,17 @@ sub types {
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
}
}
},
'catAndAppList' => {
'test' => sub {
1;
}
}
},
'file' => {
'test' => sub {
1;
}
}
},
'hostname' => {
'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};
}
return 1, "__unknownAttrOrMacro__: $val";
}
}
},
'longtext' => {
'test' => sub {
1;
}
}
},
'menuApp' => {
'test' => sub {
1;
}
}
},
'menuCat' => {
'test' => sub {
1;
}
}
},
'oidcmetadatajson' => {
'test' => sub {
1;
}
}
},
'oidcmetadatajwks' => {
'test' => sub {
1;
}
}
},
'oidcOPMetaDataNode' => {
'test' => sub {
1;
}
}
},
'oidcRPMetaDataNode' => {
'test' => sub {
1;
}
}
},
'password' => {
'msgFail' => '__malformedValue__',
'test' => sub {
1;
}
}
},
'pcre' => {
'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;
}
}
},
'PerlModule' => {
'form' => 'text',
@ -142,17 +142,17 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
'portalskin' => {
'test' => sub {
1;
}
}
},
'portalskinbackground' => {
'test' => sub {
1;
}
}
},
'post' => {
'test' => sub {
1;
}
}
},
'RSAPrivateKey' => {
'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
? 1
: ( 1, '__badPemEncoding__' );
}
}
},
'RSAPublicKey' => {
'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
? 1
: ( 1, '__badPemEncoding__' );
}
}
},
'RSAPublicKeyOrCertificate' => {
'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
? 1
: ( 1, '__badPemEncoding__' );
}
}
},
'rule' => {
'test' => sub {
1;
}
}
},
'samlAssertion' => {
'test' => sub {
1;
}
}
},
'samlAttribute' => {
'test' => sub {
1;
}
}
},
'samlIDPMetaDataNode' => {
'test' => sub {
1;
}
}
},
'samlService' => {
'test' => sub {
1;
}
}
},
'samlSPMetaDataNode' => {
'test' => sub {
1;
}
}
},
'select' => {
'test' => sub {
@ -216,19 +216,19 @@ m[^(?:(?:\-+\s*BEGIN\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\
return $test
? 1
: ( 1, "Invalid value '$_[0]' for this select" );
}
}
},
'subContainer' => {
'keyTest' => qr/\w/,
'test' => sub {
1;
}
}
},
'text' => {
'msgFail' => '__malformedValue__',
'test' => sub {
1;
}
}
},
'trool' => {
'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 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
}
}
},
'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};
}
return 1, "__unknownAttrOrMacro__: $val";
}
}
},
'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 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
}
}
},
'type' => 'ruleContainer'
},
@ -2986,19 +2986,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

@ -4,12 +4,14 @@ use 5.10.0;
use utf8;
use strict;
use Mouse;
use MIME::Base64 qw(encode_base64 decode_base64);
use Crypt::U2F::Server::Simple;
use Lemonldap::NG::Common::Session;
use Lemonldap::NG::Common::Conf::Constants;
use Lemonldap::NG::Common::PSGI::Constants;
use Lemonldap::NG::Common::Conf::ReConstants;
use Lemonldap::NG::Common::IPv6;
#use Lemonldap::NG::Common::IPv6;
use feature 'state';
@ -33,21 +35,27 @@ sub addRoutes {
# READ
->addRoute(
u2f => { ':sessionType' => 'sessions' },
u2f => { ':sessionType' => 'u2f' },
['GET']
)
# DELETE U2F KEY ATTRIBUTS
# DELETE U2F KEY
->addRoute(
u2f => { ':sessionType' => { ':sessionId' => 'delU2FKey' } },
u2f => { ':sessionType' => { ':sessionId' => 'deleteU2FKey' } },
['DELETE']
);
)
# UPDATE U2F KEY ATTRIBUTS
# ->addRoute(
# u2f => { ':sessionType' => { ':sessionId' => { ':updateSession' } },
# ['PUT']
#);
# ADD U2F KEY
->addRoute(
u2f => { ':sessionType' => { ':sessionId' => 'registerU2FKey' } },
['PUT']
)
# VERIFY U2F KEY
->addRoute(
u2f => { ':sessionType' => { ':sessionId' => 'verifyU2FKey' } },
['POST']
);
$self->setTypes($conf);
@ -56,9 +64,28 @@ sub addRoutes {
$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 {
my ( $self, $req, $session, $skey ) = @_;
@ -72,27 +99,21 @@ sub u2f {
or return $self->sendError( $req, undef, 400 );
my $params = $req->parameters();
my $type = delete $params->{sessionType};
$type = $type eq 'global' ? 'SSO' : ucfirst($type);
$type = ucfirst($type);
my $res;
# Case 2: list of sessions
my $whatToTrace = Lemonldap::NG::Handler::PSGI::Main->tsv->{whatToTrace};
# 2.1 Get fields to require
my @fields = ( '_httpSessionType', $self->{ipField}, $whatToTrace );
my @fields = ( '_httpSessionType', $self->{ipField}, $whatToTrace, '_u2fKeyHandle' );
if ( my $groupBy = $params->{groupBy} ) {
$groupBy =~ s/^substr\((\w+)(?:,\d+(?:,\d+)?)?\)$/$1/
or $groupBy =~ s/^net(?:4|6|)\(([\w:]+),\d+(?:,\d+)?\)$/$1/;
$groupBy =~ s/^substr\((\w+)(?:,\d+(?:,\d+)?)?\)$/$1/;
$groupBy =~ s/^_whatToTrace$/$whatToTrace/o
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 {
push @fields, '_utime';
}
@ -109,10 +130,12 @@ sub u2f {
: ( $s => $params->{$_} );
} keys %$params;
$filters{_session_kind} = $type;
# $filters{_u2fKeyHandle} = '';
push @fields, keys(%filters);
{
my %seen;
@fields = grep { !$seen{$_}++ } @fields;
# @fields = grep { !/\w+/ } @fields;
}
# 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 );
# 2.4 Special case doubleIp (users connected from more than 1 IP)
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') ) {
if ( my $group = $req->params('groupBy') ) {
my $r;
$group =~ s/\b_whatToTrace\b/$whatToTrace/o;
@ -243,46 +219,6 @@ sub u2f {
$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
elsif ( $group =~ /^\w+$/ ) {
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:
# { session => <sessionId>, date => <timestamp> }
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;

View File

@ -196,6 +196,8 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
session[key] = $scope.localeDate value
else if key.match /^(_startTime|_updateTime)$/
session[key] = _stToStr value
else if key.match /^(_u2fKeyHandle|_u2fUserKey)$/
session[key] = '########'
res = []
# 2. Push session keys in reuslt, grouped by categories

View File

@ -87,10 +87,18 @@ categories =
# Menu entries
menu =
session: [
delU2FKey: [
title: 'deleteU2FKey'
icon: 'trash'
]
addU2FKey: [
title: 'addU2FKey'
icon: 'plus'
]
verifyU2FKey: [
title: 'verifyU2FKey'
icon: 'check'
]
home: []
###
@ -138,7 +146,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
# SESSION MANAGEMENT
# Delete U2F key attributs
# Delete U2F key
$scope.deleteU2FKey = ->
$scope.waiting = true
$http['delete']("#{scriptname}u2f/#{sessionType}/#{$scope.currentSession.id}").then (response) ->
@ -151,6 +159,32 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
$scope.waiting = false
$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
$scope.stoggle = (scope) ->
node = scope.$modelValue
@ -197,6 +231,8 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
session[key] = $scope.localeDate value
else if key.match /^(_startTime|_updateTime)$/
session[key] = _stToStr value
else if key.match /^(_u2fKeyHandle|_u2fUserKey)$/
session[key] = '########'
res = []
# 2. Push session keys in result, grouped by categories
@ -261,7 +297,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
$scope.currentScope = scope
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.showT = false
@ -325,7 +361,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
over = 0
# Launch HTTP query
$http.get("#{scriptname}sessions/#{sessionType}?#{query}").then (response) ->
$http.get("#{scriptname}u2f/#{sessionType}?#{query}").then (response) ->
data = response.data
if data.result
for n in data.values

View File

@ -227,6 +227,8 @@
session[key] = $scope.localeDate(value);
} else if (key.match(/^(_startTime|_updateTime)$/)) {
session[key] = _stToStr(value);
} else if (key.match(/^(_u2fKeyHandle|_u2fUserKey)$/)) {
session[key] = '########';
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -104,12 +104,24 @@
};
menu = {
session: [
delU2FKey: [
{
title: 'deleteU2FKey',
icon: 'trash'
}
],
addU2FKey: [
{
title: 'addU2FKey',
icon: 'plus'
}
],
verifyU2FKey: [
{
title: 'verifyU2FKey',
icon: 'check'
}
],
home: []
};
@ -173,6 +185,28 @@
});
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) {
var node;
node = scope.$modelValue;
@ -226,6 +260,8 @@
session[key] = $scope.localeDate(value);
} else if (key.match(/^(_startTime|_updateTime)$/)) {
session[key] = _stToStr(value);
} else if (key.match(/^(_u2fKeyHandle|_u2fUserKey)$/)) {
session[key] = '########';
}
}
}
@ -315,7 +351,7 @@
};
$scope.currentScope = scope;
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.showT = false;
@ -363,7 +399,7 @@
} else {
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;
data = response.data;
if (data.result) {

File diff suppressed because one or more lines are too long

View File

@ -33,6 +33,7 @@
"addSamlAttribute":"إضافة صفة",
"addSPSamlPartner":"إضافة SP SAML",
"addSrvCasPartner":"إضافة سرفر كاس",
"addU2FKey":"Add U2F key",
"addVhost":"إضافة خادم افتراضي",
"adParams":"معاييرأكتيف ديريكتوري",
"ADPwdExpireWarning":"تحذير انتهاء صلاحية كلمة المرور",
@ -728,6 +729,7 @@
"u2fActivation":"تفعيل",
"u2fAuthnLevel":"U2F مستوى إثبات الهوية",
"u2fSelfRegistration":"التسجيل الذاتي",
"u2fSessions":"U2F sessions explorer",
"uid":"المعرف",
"unknownAttrOrMacro":"سمة غير معروفة أو ماكرو",
"unknownError":"خطأ غير معروف",
@ -752,6 +754,7 @@
"values":"القيم",
"variables":"المتغيرات",
"version":"الإصدار",
"verifyU2FKey":"Verify U2F key",
"vhostAliases":"اسماء مستعارة",
"vhostAuthnLevel":"مستوى إثبات الهوية واجب",
"vhostHttps":"إتش تي تي بي س",

View File

@ -33,6 +33,7 @@
"addSamlAttribute":"Add attribute",
"addSPSamlPartner":"Add SAML SP",
"addSrvCasPartner":"Add CAS server",
"addU2FKey":"Add U2F key",
"addVhost":"Add virtualhost",
"adParams":"Active Directory Parameters",
"ADPwdExpireWarning":"Password expire warning",
@ -728,6 +729,7 @@
"u2fActivation":"Activation",
"u2fAuthnLevel":"U2F authentication level",
"u2fSelfRegistration":"Self registration",
"u2fSessions":"U2F sessions explorer",
"uid":"Identifier",
"unknownAttrOrMacro":"Unknown attribute or macro",
"unknownError":"Unknown error",
@ -752,6 +754,7 @@
"values":"Values",
"variables":"Variables",
"version":"Version",
"verifyU2FKey":"Verify U2F key",
"vhostAliases":"Aliases",
"vhostAuthnLevel":"Required authentication level",
"vhostHttps":"HTTPS",

View File

@ -33,6 +33,7 @@
"addSamlAttribute":"Ajouter un attribut",
"addSPSamlPartner":"Ajouter un SP SAML",
"addSrvCasPartner":"Ajouter un serveur CAS",
"addU2FKey":"Ajouter une clef U2F",
"addVhost":"Ajouter un hôte virtuel",
"adParams":"Paramètres Active Directory",
"ADPwdExpireWarning":"Avertissement avant expiration du mot de passe",
@ -728,6 +729,7 @@
"u2fActivation":"Activation",
"u2fAuthnLevel":"Niveau d'authentification U2F",
"u2fSelfRegistration":"Auto-enregistrement",
"u2fSessions":"Explorateur de sessions U2F",
"uid":"Identifiant",
"unknownAttrOrMacro":"Attribut ou macro inconnu",
"unknownError":"Erreur inconnue",
@ -751,6 +753,7 @@
"value":"Valeur",
"values":"Valeurs",
"variables":"Variables",
"verifyU2FKey":"Vérifier la clef U2F",
"version":"Version",
"vhostAliases":"Alias",
"vhostAuthnLevel":"Niveau d'authentication requis",

View File

@ -33,6 +33,7 @@
"addSamlAttribute":"Aggiungi attributo",
"addSPSamlPartner":"Aggiungi SAML SP",
"addSrvCasPartner":"Aggiungi server CAS",
"addU2FKey":"Add U2F key",
"addVhost":"Aggiungi virtualhost",
"adParams":"Parametri di Active Directory",
"ADPwdExpireWarning":"Avviso di scadenza password",
@ -728,6 +729,7 @@
"u2fActivation":"Attivazione",
"u2fAuthnLevel":"Livello di autenticazione U2F",
"u2fSelfRegistration":"Auto-registrazione",
"u2fSessions":"U2F sessions explorer",
"uid":"Identificatore",
"unknownAttrOrMacro":"Attributo o macro sconosciuti",
"unknownError":"Errore sconosciuto",
@ -752,6 +754,7 @@
"values":"Valori",
"variables":"Variabili",
"version":"Versioni",
"verifyU2FKey":"Verify U2F key",
"vhostAliases":"Alias",
"vhostAuthnLevel":"Livello di autenticazione richiesto",
"vhostHttps":"HTTPS",

View File

@ -33,6 +33,7 @@
"addSamlAttribute":"Thêm thuộc tính",
"addSPSamlPartner":"Thêm SAML SP",
"addSrvCasPartner":"Thêm máy chủ CAS",
"addU2FKey":"Add U2F key",
"addVhost":"Thêm host ảo",
"adParams":"Tham số của Active Directory",
"ADPwdExpireWarning":"Cảnh báo mật khẩu hết hạn",
@ -728,6 +729,7 @@
"u2fActivation":"Kích hoạt",
"u2fAuthnLevel":"Mức xác thực U2F",
"u2fSelfRegistration":"Tự đăng ký ",
"u2fSessions":"U2F sessions explorer",
"uid":"Trình định danh",
"unknownAttrOrMacro":"Thuộc tính hoặc macro chưa xác định",
"unknownError":"Lỗi không xác định",
@ -752,6 +754,7 @@
"values":"Giá trị",
"variables":"biến",
"version":"Phiên bản",
"verifyU2FKey":"Verify U2F key",
"vhostAliases":"Bí danh",
"vhostAuthnLevel":"Mức xác thực bắt buộc",
"vhostHttps":"HTTPS",

View File

@ -15,7 +15,7 @@
<div class="navbar navbar-default">
<div class="navbar-collapse">
<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>
</div>
</div>
@ -40,8 +40,13 @@
<!-- Menu buttons -->
<div class="lmmenu navbar navbar-default" ng-class="{'hidden-xs':!showM}">
<div class="navbar-collapse" ng-class="{'collapse':!showM}" id="formmenu">
<ul class="nav navbar-nav">
<li ng-if="currentSession" ng-repeat="button in menu.session" ng-include="'menubutton.html'"></li>
<ul class="nav navbar-nav">
<!--
<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 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>

View File

@ -116,7 +116,7 @@ sub run {
elsif ( $err == 0 ) {
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] ];
}
if ( $action eq 'signature' ) {
@ -133,7 +133,7 @@ sub run {
return $self->p->sendError( $req, "noU2FKeyFound" );
}
my $res =
( $req->data->{crypter}->authenticationVerify($resp) ? 1 : 0 );
( $req->datas->{crypter}->authenticationVerify($resp) ? 1 : 0 );
return [
200, [ 'Content-Type' => 'application/json' ],
[qq'{"result":$res}']
@ -150,11 +150,11 @@ sub loadUser {
unless ( $kh and $uk ) {
return 0;
}
$req->data->{crypter} = $self->crypter(
$req->datas->{crypter} = $self->crypter(
keyHandle => $self->decode_base64url($kh),
publicKey => $self->decode_base64url($uk)
);
unless ( $req->data->{crypter} ) {
unless ( $req->datas->{crypter} ) {
my $error = Crypt::U2F::Server::Simple::lastError();
return ( -1, $error );
}

View File

@ -197,7 +197,7 @@
"touchU2fDevice": "Please touch the flashing U2F device now.",
"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.",
"u2fRegistered": "Your key is registered. Click to verify.",
"u2fRegistered": "Your key has been registered.",
"u2fUnregistered": "Your key has been unregistered.",
"u2fSuccess": "Your key is successfully tested",
"u2fWelcome": "U2F device management",

View File

@ -197,7 +197,7 @@
"touchU2fDevice": "Poser votre doigt sur le périphérique U2F",
"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.",
"u2fRegistered": "Votre clef est enregistrée. Cliquez sur vérifier",
"u2fRegistered": "Votre clef a été enregistrée.",
"u2fUnregistered": "Votre clef a été supprimée.",
"u2fSuccess": "Votre clef est vérifiée",
"u2fWelcome": "Gestion du périphérique U2F",
@ -206,7 +206,7 @@
"upgradeSession":"Se réauthentifier",
"user":"Utilisateur",
"useYubikey":"utilisez votre Yubikey",
"verify": "Verifier",
"verify": "Vérifier",
"wait":"Attendre",
"warning":"Attention",
"welcomeOnPortal":"Bienvenue sur votre portail d'authentification sécurisée.",