WIP - 2ndFA manager module

This commit is contained in:
Christophe Maudoux 2018-03-11 23:33:55 +01:00
parent 703abd5c6a
commit 810b9f6a27
13 changed files with 381 additions and 128 deletions

View File

@ -77,6 +77,30 @@ sub deleteU2FKey {
return $self->sendJSONresponse( $req, { result => 1 } ); return $self->sendJSONresponse( $req, { result => 1 } );
} }
sub deleteTOTPKey {
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->{_totp2fSecret} = '';
$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 addU2FKey { sub addU2FKey {
my ( $self, $req ) = @_; my ( $self, $req ) = @_;
return $self->sendJSONresponse( $req, { result => 1 } ) return $self->sendJSONresponse( $req, { result => 1 } )

View File

@ -91,7 +91,7 @@ sub init {
# Find out more glyphicones at https://www.w3schools.com/icons/bootstrap_icons_glyphicons.asp # Find out more glyphicones at https://www.w3schools.com/icons/bootstrap_icons_glyphicons.asp
my $linksIcons = my $linksIcons =
{ 'conf' => 'cog', 'sessions' => 'duplicate', 'notifications' => 'bell', 'SFA' => 'wrench' }; { 'conf' => 'cog', 'sessions' => 'duplicate', 'notifications' => 'bell', '2ndFA' => 'wrench' };
$self->links( [] ); $self->links( [] );
for ( my $i = 0 ; $i < @links ; $i++ ) { for ( my $i = 0 ; $i < @links ; $i++ ) {

View File

@ -1,4 +1,4 @@
package Lemonldap::NG::Manager::SFA; package Lemonldap::NG::Manager::2ndFA;
use 5.10.0; use 5.10.0;
use utf8; use utf8;
@ -37,21 +37,21 @@ sub addRoutes {
['GET'] ['GET']
) )
# DELETE U2F KEY # DELETE 2FA KEY
->addRoute( ->addRoute(
sfa => { ':sessionType' => { ':sessionId' => 'deleteU2FKey' } }, sfa => { ':sessionType' => { ':sessionId' => 'delete2FAKey' } },
['DELETE'] ['DELETE']
) )
# ADD U2F KEY # ADD 2FA KEY
->addRoute( ->addRoute(
sfa => { ':sessionType' => { ':sessionId' => 'registerU2FKey' } }, sfa => { ':sessionType' => { ':sessionId' => 'add2FAKey' } },
['PUT'] ['PUT']
) )
# VERIFY U2F KEY # VERIFY 2FA KEY
->addRoute( ->addRoute(
sfa => { ':sessionType' => { ':sessionId' => 'verifyU2FKey' } }, sfa => { ':sessionType' => { ':sessionId' => 'verify2FAKey' } },
['POST'] ['POST']
); );
@ -63,23 +63,51 @@ sub addRoutes {
} }
############################ ###################
# II. REGISTRATION METHODS # # II. 2FA METHODS #
############################ ###################
sub registerU2FKey { sub delete2FAKey {
my ( $self, $req, $session, $skey ) = @_;
my $mod = $self->getMod($req)
or return $self->sendError( $req, undef, 400 );
my $params = $req->parameters();
my $Key = $params->{Key};
if ( $Key =~ /\bU2F\b/ ) {
return $self->deleteU2FKey( $req, $session, $skey );
}
elsif ( $Key =~ /\bTOTP\b/ ) {
return $self->deleteTOTPKey( $req, $session, $skey );
}
else {
return $self->sendError( $req, undef, 666 );
}
}
sub add2FAKey {
my ( $self, $req, $session, $skey ) = @_; my ( $self, $req, $session, $skey ) = @_;
eval 'use Crypt::U2F::Server::Simple'; eval 'use Crypt::U2F::Server::Simple';
if ($@) { if ($@) {
$self->error("Can't load U2F library: $@"); $self->error("Can't load U2F library: $@");
return 0; return 0;
} }
return $self->addU2FKey( $req, $session, $skey ); return $self->addU2FKey( $req, $session, $skey );
} }
sub verify2FAKey {
my ( $self, $req, $session, $skey ) = @_;
return $self->addU2FKey( $req, $session, $skey );
}
######################## ########################
# III. DISPLAY METHODS # # III. DISPLAY METHODS #
@ -90,6 +118,7 @@ sub sfa {
# Case 1: only one session is required # Case 1: only one session is required
if ($session) { if ($session) {
$self->error("Can't load U2F library: $session");
return $self->session( $req, $session, $skey ); return $self->session( $req, $session, $skey );
} }
@ -98,6 +127,7 @@ sub sfa {
my $params = $req->parameters(); my $params = $req->parameters();
my $type = delete $params->{sessionType}; my $type = delete $params->{sessionType};
$type = ucfirst($type); $type = ucfirst($type);
my $Key = $params->{sessionType};
my $res; my $res;
@ -106,7 +136,7 @@ sub sfa {
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, '_u2fKeyHandle' ); my @fields = ( '_httpSessionType', $self->{ipField}, $whatToTrace, '_u2fKeyHandle', '_totp2fSecret' );
if ( my $groupBy = $params->{groupBy} ) { if ( my $groupBy = $params->{groupBy} ) {
$groupBy =~ s/^substr\((\w+)(?:,\d+(?:,\d+)?)?\)$/$1/; $groupBy =~ s/^substr\((\w+)(?:,\d+(?:,\d+)?)?\)$/$1/;
$groupBy =~ s/^_whatToTrace$/$whatToTrace/o $groupBy =~ s/^_whatToTrace$/$whatToTrace/o
@ -195,7 +225,8 @@ sub sfa {
# Display sessions with registered U2F key only # Display sessions with registered U2F key only
foreach my $session ( keys %$res ) { foreach my $session ( keys %$res ) {
delete $res->{$session} delete $res->{$session}
unless ( defined $res->{$session}->{_u2fKeyHandle} and length $res->{$session}->{_u2fKeyHandle} ) unless ( ( defined $res->{$session}->{_u2fKeyHandle} and length $res->{$session}->{_u2fKeyHandle} )
or ( defined $res->{$session}->{_totp2fSecret} and length $res->{$session}->{_totp2fSecret} ) )
} }
my $total = ( keys %$res ); my $total = ( keys %$res );

View File

@ -2,6 +2,26 @@
# Session explorer # Session explorer
### ###
setMsg = (msg, level) ->
$('#msg').html window.translate msg
$('#color').removeClass 'message-positive message-warning alert-success alert-warning'
$('#color').addClass "message-#{level}"
level = 'success' if level == 'positive'
$('#color').addClass "alert-#{level}"
displayError = (j, status, err) ->
console.log 'Error', err
res = JSON.parse j.responseText
if res and res.error
res = res.error.replace /.* /, ''
console.log 'Returned error', res
setMsg res, 'warning'
# Max number of session to display (see overScheme) # Max number of session to display (see overScheme)
max = 25 max = 25
@ -16,23 +36,6 @@ schemes =
(t,v) -> (t,v) ->
"#{t}=#{v}" "#{t}=#{v}"
] ]
#~ ipAddr: [
#~ (t,v) ->
#~ "groupBy=net(#{t},16,1)"
#~ (t,v) ->
#~ v = v + '.' unless v.match /:/
#~ "#{t}=#{v}*&groupBy=net(#{t},32,2)"
#~ (t,v) ->
#~ v = v + '.' unless v.match /:/
#~ "#{t}=#{v}*&groupBy=net(#{t},48,3)"
#~ (t,v) ->
#~ v = v + '.' unless v.match /:/
#~ "#{t}=#{v}*&groupBy=net(#{t},128,4)"
#~ (t,v) ->
#~ "#{t}=#{v}&groupBy=_whatToTrace"
#~ (t,v,q) ->
#~ q.replace(/\&groupBy.*$/, '') + "&_whatToTrace=#{v}"
#~ ]
_startTime: [ _startTime: [
(t,v) -> (t,v) ->
"groupBy=substr(#{t},8)" "groupBy=substr(#{t},8)"
@ -50,14 +53,6 @@ schemes =
console.log q console.log q
q.replace(/\&groupBy.*$/, '') + "&_whatToTrace=#{v}" q.replace(/\&groupBy.*$/, '') + "&_whatToTrace=#{v}"
] ]
#doubleIp: [
#(t,v) ->
#t
#(t,v) ->
#"_whatToTrace=#{v}&groupBy=ipAddr"
#(t,v,q) ->
#q.replace(/\&groupBy.*$/, '') + "&ipAddr=#{v}"
#]
overScheme = overScheme =
_whatToTrace: (t,v,level,over) -> _whatToTrace: (t,v,level,over) ->
@ -71,9 +66,7 @@ overScheme =
else else
null null
#hiddenAttributes = '_password _u2fKeyHandle _u2fUserKey _totp2fSecret' hiddenAttributes = '_password'
hiddenAttributes = '_password _u2fKeyHandle _u2fUserKey _totp2fSecret'
# Attributes to group in session display # Attributes to group in session display
categories = categories =
@ -105,6 +98,14 @@ menu =
title: 'deleteTOTPKey' title: 'deleteTOTPKey'
icon: 'trash' icon: 'trash'
] ]
addTOTPKey: [
title: 'addTOTPKey'
icon: 'plus'
]
verifyTOTPKey: [
title: 'verifyTOTPKey'
icon: 'check'
]
home: [] home: []
### ###
@ -151,11 +152,10 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
$scope.showM = false $scope.showM = false
# SESSION MANAGEMENT # SESSION MANAGEMENT
# Delete U2F key # Delete U2F key
$scope.deleteU2FKey = -> $scope.deleteU2FKey = ->
$scope.waiting = true $scope.waiting = true
$http['delete']("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}/U2F").then (response) -> $http['delete']("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}?Key=U2F").then (response) ->
$scope.currentSession = null $scope.currentSession = null
$scope.currentScope.remove() $scope.currentScope.remove()
$scope.waiting = false $scope.waiting = false
@ -168,7 +168,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
# Delete TOTP key # Delete TOTP key
$scope.deleteTOTPKey = -> $scope.deleteTOTPKey = ->
$scope.waiting = true $scope.waiting = true
$http['delete']("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}/TOTP").then (response) -> $http['delete']("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}?Key=TOTP").then (response) ->
$scope.currentSession = null $scope.currentSession = null
$scope.currentScope.remove() $scope.currentScope.remove()
$scope.waiting = false $scope.waiting = false
@ -181,34 +181,54 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
# Add U2F key # Add U2F key
$scope.addU2FKey = -> $scope.addU2FKey = ->
$scope.waiting = true $scope.waiting = true
$http['put']("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}").then (response) -> $http['put']("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}?Key=U2F").then (response) ->
#$scope.currentSession = null $scope.currentSession = null
#$scope.currentScope.remove() $scope.currentScope.remove()
$scope.waiting = false $scope.waiting = false
, (resp) -> , (resp) ->
#$scope.currentSession = null $scope.currentSession = null
#$scope.currentScope.remove() $scope.currentScope.remove()
$scope.waiting = false $scope.waiting = false
$scope.showT = false $scope.showT = false
$http.get("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}").then (response) ->
$scope.currentSession = transformSession response.data # Add TOTP key
$scope.addTOTPKey = ->
$scope.waiting = true
$http['put']("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}?Key=TOTP").then (response) ->
$scope.currentSession = null
$scope.currentScope.remove()
$scope.waiting = false
, (resp) ->
$scope.currentSession = null
$scope.currentScope.remove()
$scope.waiting = false
$scope.showT = false $scope.showT = false
# Verify U2F key # Verify U2F key
$scope.verifyU2FKey = -> $scope.verifyU2FKey = ->
$scope.waiting = true $scope.waiting = true
$http['post']("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}").then (response) -> $http['post']("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}?Key=U2F").then (response) ->
#$scope.currentSession = null $scope.currentSession = null
#$scope.currentScope.remove() $scope.currentScope.remove()
$scope.waiting = false $scope.waiting = false
, (resp) -> , (resp) ->
#$scope.currentSession = null $scope.currentSession = null
#$scope.currentScope.remove() $scope.currentScope.remove()
$scope.waiting = false
$scope.showT = true
# Verify TOTP key
$scope.verifyTOTPKey = ->
$scope.waiting = true
$http['post']("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}?Key=TOTP").then (response) ->
$scope.currentSession = null
$scope.currentScope.remove()
$scope.waiting = false
, (resp) ->
$scope.currentSession = null
$scope.currentScope.remove()
$scope.waiting = false $scope.waiting = false
$scope.showT = true $scope.showT = true
$http.get("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}").then (response) ->
$scope.currentSession = transformSession response.data
$scope.showT = false
# Open node # Open node
$scope.stoggle = (scope) -> $scope.stoggle = (scope) ->
@ -256,6 +276,9 @@ 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|_totp2fSecret)$/
session[key] = '##########'
res = [] res = []
# 2. Push session keys in result, grouped by categories # 2. Push session keys in result, grouped by categories
@ -432,4 +455,48 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location',
# Default to '_whatToTrace' # Default to '_whatToTrace'
c = $location.path().match /^\/(\w+)/ c = $location.path().match /^\/(\w+)/
$scope.type = if c then c[1] else '_whatToTrace' $scope.type = if c then c[1] else '_whatToTrace'
# Unregistration function (launched by "unregister" button)
u2fcheck = ->
$scope.currentSession = null
$scope.currentScope.remove()
$scope.showT = false
$.ajax
type: "GET"
url: "https://manager.example.com:19876/sfa.html?U2FCheck=1"
data: {}
dataType: 'json'
error: displayError
success: (resp) ->
if resp.error
setMsg 'u2fFailed', 'warning'
else if resp.result
setMsg 'u2fUnregistered', 'positive'
error: displayError
totpcheck = ->
$scope.currentSession = null
$scope.currentScope.remove()
$scope.showT = false
$.ajax
type: "GET"
url: "https://manager.example.com:19876/sfa.html?U2FCheck=1"
data: {}
dataType: 'json'
error: displayError
success: (resp) ->
if resp.error
setMsg 'u2fFailed', 'warning'
else if resp.result
setMsg 'u2fUnregistered', 'positive'
error: displayError
# CheckBox "click" events
$(document).ready ->
$('#U2FCheck').on 'click', u2fcheck
$('#TOTPCheck').on 'click', totpcheck
] ]

View File

@ -5,7 +5,28 @@
*/ */
(function() { (function() {
var categories, hiddenAttributes, llapp, max, menu, overScheme, schemes; var categories, displayError, hiddenAttributes, llapp, max, menu, overScheme, schemes, setMsg;
setMsg = function(msg, level) {
$('#msg').html(window.translate(msg));
$('#color').removeClass('message-positive message-warning alert-success alert-warning');
$('#color').addClass("message-" + level);
if (level === 'positive') {
level = 'success';
}
return $('#color').addClass("alert-" + level);
};
displayError = function(j, status, err) {
var res;
console.log('Error', err);
res = JSON.parse(j.responseText);
if (res && res.error) {
res = res.error.replace(/.* /, '');
console.log('Returned error', res);
return setMsg(res, 'warning');
}
};
max = 25; max = 25;
@ -19,30 +40,6 @@
return t + "=" + v; return t + "=" + v;
} }
], ],
ipAddr: [
function(t, v) {
return "groupBy=net(" + t + ",16,1)";
}, function(t, v) {
if (!v.match(/:/)) {
v = v + '.';
}
return t + "=" + v + "*&groupBy=net(" + t + ",32,2)";
}, function(t, v) {
if (!v.match(/:/)) {
v = v + '.';
}
return t + "=" + v + "*&groupBy=net(" + t + ",48,3)";
}, function(t, v) {
if (!v.match(/:/)) {
v = v + '.';
}
return t + "=" + v + "*&groupBy=net(" + t + ",128,4)";
}, function(t, v) {
return t + "=" + v + "&groupBy=_whatToTrace";
}, function(t, v, q) {
return q.replace(/\&groupBy.*$/, '') + ("&_whatToTrace=" + v);
}
],
_startTime: [ _startTime: [
function(t, v) { function(t, v) {
return "groupBy=substr(" + t + ",8)"; return "groupBy=substr(" + t + ",8)";
@ -60,15 +57,6 @@
console.log(q); console.log(q);
return q.replace(/\&groupBy.*$/, '') + ("&_whatToTrace=" + v); return q.replace(/\&groupBy.*$/, '') + ("&_whatToTrace=" + v);
} }
],
doubleIp: [
function(t, v) {
return t;
}, function(t, v) {
return "_whatToTrace=" + v + "&groupBy=ipAddr";
}, function(t, v, q) {
return q.replace(/\&groupBy.*$/, '') + ("&ipAddr=" + v);
}
] ]
}; };
@ -122,6 +110,24 @@
icon: 'check' icon: 'check'
} }
], ],
delTOTPKey: [
{
title: 'deleteTOTPKey',
icon: 'trash'
}
],
addTOTPKey: [
{
title: 'addTOTPKey',
icon: 'plus'
}
],
verifyTOTPKey: [
{
title: 'verifyTOTPKey',
icon: 'check'
}
],
home: [] home: []
}; };
@ -134,7 +140,7 @@
llapp.controller('SessionsExplorerCtrl', [ llapp.controller('SessionsExplorerCtrl', [
'$scope', '$translator', '$location', '$q', '$http', function($scope, $translator, $location, $q, $http) { '$scope', '$translator', '$location', '$q', '$http', function($scope, $translator, $location, $q, $http) {
var autoId, c, pathEvent, sessionType; var autoId, c, pathEvent, sessionType, totpcheck, u2fcheck;
$scope.links = links; $scope.links = links;
$scope.menulinks = menulinks; $scope.menulinks = menulinks;
$scope.staticPrefix = staticPrefix; $scope.staticPrefix = staticPrefix;
@ -176,7 +182,20 @@
}; };
$scope.deleteU2FKey = function() { $scope.deleteU2FKey = function() {
$scope.waiting = true; $scope.waiting = true;
$http['delete'](scriptname + "sfa/" + sessionType + "/" + $scope.currentSession.id).then(function(response) { $http['delete'](scriptname + "sfa/" + sessionType + "/" + $scope.currentSession.id + "?Key=U2F").then(function(response) {
$scope.currentSession = null;
$scope.currentScope.remove();
return $scope.waiting = false;
}, function(resp) {
$scope.currentSession = null;
$scope.currentScope.remove();
return $scope.waiting = false;
});
return $scope.showT = false;
};
$scope.deleteTOTPKey = function() {
$scope.waiting = true;
$http['delete'](scriptname + "sfa/" + sessionType + "/" + $scope.currentSession.id + "?Key=TOTP").then(function(response) {
$scope.currentSession = null; $scope.currentSession = null;
$scope.currentScope.remove(); $scope.currentScope.remove();
return $scope.waiting = false; return $scope.waiting = false;
@ -189,29 +208,55 @@
}; };
$scope.addU2FKey = function() { $scope.addU2FKey = function() {
$scope.waiting = true; $scope.waiting = true;
$http['put'](scriptname + "sfa/" + sessionType + "/" + $scope.currentSession.id).then(function(response) { $http['put'](scriptname + "sfa/" + sessionType + "/" + $scope.currentSession.id + "?Key=U2F").then(function(response) {
$scope.currentSession = null;
$scope.currentScope.remove();
return $scope.waiting = false; return $scope.waiting = false;
}, function(resp) { }, function(resp) {
$scope.currentSession = null;
$scope.currentScope.remove();
return $scope.waiting = false; return $scope.waiting = false;
}); });
$scope.showT = false; return $scope.showT = false;
$http.get(scriptname + "sfa/" + sessionType + "/" + $scope.currentSession.id).then(function(response) { };
return $scope.currentSession = transformSession(response.data); $scope.addTOTPKey = function() {
$scope.waiting = true;
$http['put'](scriptname + "sfa/" + sessionType + "/" + $scope.currentSession.id + "?Key=TOTP").then(function(response) {
$scope.currentSession = null;
$scope.currentScope.remove();
return $scope.waiting = false;
}, function(resp) {
$scope.currentSession = null;
$scope.currentScope.remove();
return $scope.waiting = false;
}); });
return $scope.showT = false; return $scope.showT = false;
}; };
$scope.verifyU2FKey = function() { $scope.verifyU2FKey = function() {
$scope.waiting = true; $scope.waiting = true;
$http['post'](scriptname + "sfa/" + sessionType + "/" + $scope.currentSession.id).then(function(response) { $http['post'](scriptname + "sfa/" + sessionType + "/" + $scope.currentSession.id + "?Key=U2F").then(function(response) {
$scope.currentSession = null;
$scope.currentScope.remove();
return $scope.waiting = false; return $scope.waiting = false;
}, function(resp) { }, function(resp) {
$scope.currentSession = null;
$scope.currentScope.remove();
return $scope.waiting = false; return $scope.waiting = false;
}); });
$scope.showT = true; return $scope.showT = true;
$http.get(scriptname + "sfa/" + sessionType + "/" + $scope.currentSession.id).then(function(response) { };
return $scope.currentSession = transformSession(response.data); $scope.verifyTOTPKey = function() {
$scope.waiting = true;
$http['post'](scriptname + "sfa/" + sessionType + "/" + $scope.currentSession.id + "?Key=TOTP").then(function(response) {
$scope.currentSession = null;
$scope.currentScope.remove();
return $scope.waiting = false;
}, function(resp) {
$scope.currentSession = null;
$scope.currentScope.remove();
return $scope.waiting = false;
}); });
return $scope.showT = false; return $scope.showT = true;
}; };
$scope.stoggle = function(scope) { $scope.stoggle = function(scope) {
var node; var node;
@ -224,7 +269,7 @@
$scope.displaySession = function(scope) { $scope.displaySession = function(scope) {
var sessionId, transformSession; var sessionId, transformSession;
transformSession = function(session) { transformSession = function(session) {
var _insert, _stToStr, attr, attrs, category, i, id, j, k, key, l, len, len1, len2, ref, ref1, res, subres, time, tmp, value; var _insert, _stToStr, attr, attrs, category, i, id, k, key, l, len, len1, len2, m, ref, ref1, res, subres, time, tmp, value;
_stToStr = function(s) { _stToStr = function(s) {
return s; return s;
}; };
@ -266,6 +311,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|_totp2fSecret)$/)) {
session[key] = '##########';
} }
} }
} }
@ -297,8 +344,8 @@
tmp = []; tmp = [];
if (session._loginHistory.successLogin) { if (session._loginHistory.successLogin) {
ref = session._loginHistory.successLogin; ref = session._loginHistory.successLogin;
for (j = 0, len1 = ref.length; j < len1; j++) { for (k = 0, len1 = ref.length; k < len1; k++) {
l = ref[j]; l = ref[k];
tmp.push({ tmp.push({
t: l._utime, t: l._utime,
title: $scope.localeDate(l._utime), title: $scope.localeDate(l._utime),
@ -308,8 +355,8 @@
} }
if (session._loginHistory.failedLogin) { if (session._loginHistory.failedLogin) {
ref1 = session._loginHistory.failedLogin; ref1 = session._loginHistory.failedLogin;
for (k = 0, len2 = ref1.length; k < len2; k++) { for (m = 0, len2 = ref1.length; m < len2; m++) {
l = ref1[k]; l = ref1[m];
tmp.push({ tmp.push({
t: l._utime, t: l._utime,
title: $scope.localeDate(l._utime), title: $scope.localeDate(l._utime),
@ -442,7 +489,51 @@
}); });
}; };
c = $location.path().match(/^\/(\w+)/); c = $location.path().match(/^\/(\w+)/);
return $scope.type = c ? c[1] : '_whatToTrace'; $scope.type = c ? c[1] : '_whatToTrace';
u2fcheck = function() {
$scope.currentSession = null;
$scope.currentScope.remove();
$scope.showT = false;
return $.ajax({
type: "GET",
url: "https://manager.example.com:19876/sfa.html?U2FCheck=1",
data: {},
dataType: 'json',
error: displayError,
success: function(resp) {
if (resp.error) {
return setMsg('u2fFailed', 'warning');
} else if (resp.result) {
return setMsg('u2fUnregistered', 'positive');
}
},
error: displayError
});
};
totpcheck = function() {
$scope.currentSession = null;
$scope.currentScope.remove();
$scope.showT = false;
return $.ajax({
type: "GET",
url: "https://manager.example.com:19876/sfa.html?U2FCheck=1",
data: {},
dataType: 'json',
error: displayError,
success: function(resp) {
if (resp.error) {
return setMsg('u2fFailed', 'warning');
} else if (resp.result) {
return setMsg('u2fUnregistered', 'positive');
}
},
error: displayError
});
};
return $(document).ready(function() {
$('#U2FCheck').on('click', u2fcheck);
return $('#TOTPCheck').on('click', totpcheck);
});
} }
]); ]);

File diff suppressed because one or more lines are too long

View File

@ -34,6 +34,7 @@
"addSPSamlPartner":"إضافة SP SAML", "addSPSamlPartner":"إضافة SP SAML",
"addSrvCasPartner":"إضافة سرفر كاس", "addSrvCasPartner":"إضافة سرفر كاس",
"addU2FKey":"Add U2F key", "addU2FKey":"Add U2F key",
"addTOTPKey":"Add TOTP key",
"addVhost":"إضافة خادم افتراضي", "addVhost":"إضافة خادم افتراضي",
"adParams":"معاييرأكتيف ديريكتوري", "adParams":"معاييرأكتيف ديريكتوري",
"ADPwdExpireWarning":"تحذير انتهاء صلاحية كلمة المرور", "ADPwdExpireWarning":"تحذير انتهاء صلاحية كلمة المرور",
@ -203,6 +204,7 @@
"deleteNotification":"حذف", "deleteNotification":"حذف",
"deleteSession":"حذف الجلسة", "deleteSession":"حذف الجلسة",
"deleteU2FKey":"Delete U2F key", "deleteU2FKey":"Delete U2F key",
"deleteTOTPKey":"Delete TOTP key",
"demoExportedVars":"المتغيرات المصدرة", "demoExportedVars":"المتغيرات المصدرة",
"demoParams":"إثبات المعايير", "demoParams":"إثبات المعايير",
"description":"التفاصيل", "description":"التفاصيل",
@ -755,6 +757,7 @@
"variables":"المتغيرات", "variables":"المتغيرات",
"version":"الإصدار", "version":"الإصدار",
"verifyU2FKey":"Verify U2F key", "verifyU2FKey":"Verify U2F key",
"verifyTOTPKey":"Verify TOTP key",
"vhostAliases":"اسماء مستعارة", "vhostAliases":"اسماء مستعارة",
"vhostAuthnLevel":"مستوى إثبات الهوية واجب", "vhostAuthnLevel":"مستوى إثبات الهوية واجب",
"vhostHttps":"إتش تي تي بي س", "vhostHttps":"إتش تي تي بي س",

View File

@ -24,6 +24,7 @@
"_userDB":"User", "_userDB":"User",
"_url":"Origin URL", "_url":"Origin URL",
"_utime":"Session timestamp", "_utime":"Session timestamp",
"2faSessions":"2FA sessions explorer",
"actives":"Actives", "actives":"Actives",
"activeTimer":"Auto accept time", "activeTimer":"Auto accept time",
"addAppCasPartner":"Add CAS application", "addAppCasPartner":"Add CAS application",
@ -34,6 +35,7 @@
"addSPSamlPartner":"Add SAML SP", "addSPSamlPartner":"Add SAML SP",
"addSrvCasPartner":"Add CAS server", "addSrvCasPartner":"Add CAS server",
"addU2FKey":"Add U2F key", "addU2FKey":"Add U2F key",
"addTOTPKey":"Add TOTP key",
"addVhost":"Add virtualhost", "addVhost":"Add virtualhost",
"adParams":"Active Directory Parameters", "adParams":"Active Directory Parameters",
"ADPwdExpireWarning":"Password expire warning", "ADPwdExpireWarning":"Password expire warning",
@ -203,6 +205,7 @@
"deleteNotification":"Delete", "deleteNotification":"Delete",
"deleteSession":"Delete session", "deleteSession":"Delete session",
"deleteU2FKey":"Delete U2F key", "deleteU2FKey":"Delete U2F key",
"deleteTOTPKey":"Delete TOTP key",
"demoExportedVars":"Exported variables", "demoExportedVars":"Exported variables",
"demoParams":"Demonstration parameters", "demoParams":"Demonstration parameters",
"description":"Description", "description":"Description",
@ -729,7 +732,6 @@
"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",
@ -755,6 +757,7 @@
"variables":"Variables", "variables":"Variables",
"version":"Version", "version":"Version",
"verifyU2FKey":"Verify U2F key", "verifyU2FKey":"Verify U2F key",
"verifyTOTPKey":"Verify TOTP key",
"vhostAliases":"Aliases", "vhostAliases":"Aliases",
"vhostAuthnLevel":"Required authentication level", "vhostAuthnLevel":"Required authentication level",
"vhostHttps":"HTTPS", "vhostHttps":"HTTPS",

View File

@ -25,6 +25,7 @@
"_url":"URL d'origine", "_url":"URL d'origine",
"_utime":"Tampon de la session", "_utime":"Tampon de la session",
"actives":"Actives", "actives":"Actives",
"2faSessions":"Explorateur de sessions 2FA",
"activeTimer":"Délai d'acceptation automatique", "activeTimer":"Délai d'acceptation automatique",
"addAppCasPartner":"Ajouter une application CAS", "addAppCasPartner":"Ajouter une application CAS",
"addIDPSamlPartner":"Ajouter un IDP SAML", "addIDPSamlPartner":"Ajouter un IDP SAML",
@ -34,6 +35,7 @@
"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", "addU2FKey":"Ajouter une clef U2F",
"addTOTPKey":"Ajouter une clef TOTP",
"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",
@ -203,6 +205,7 @@
"deleteNotification":"Effacer", "deleteNotification":"Effacer",
"deleteSession":"Effacer la session", "deleteSession":"Effacer la session",
"deleteU2FKey":"Supprimer la clef U2F", "deleteU2FKey":"Supprimer la clef U2F",
"deleteTOTPKey":"Supprimer la clef TOTP",
"demoExportedVars":"Variables exportées", "demoExportedVars":"Variables exportées",
"demoParams":"Paramètres démonstration", "demoParams":"Paramètres démonstration",
"description":"Description", "description":"Description",
@ -729,7 +732,6 @@
"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",
@ -754,6 +756,7 @@
"values":"Valeurs", "values":"Valeurs",
"variables":"Variables", "variables":"Variables",
"verifyU2FKey":"Vérifier la clef U2F", "verifyU2FKey":"Vérifier la clef U2F",
"verifyTOTPKey":"Vérifier la clef TOTP",
"version":"Version", "version":"Version",
"vhostAliases":"Alias", "vhostAliases":"Alias",
"vhostAuthnLevel":"Niveau d'authentication requis", "vhostAuthnLevel":"Niveau d'authentication requis",

View File

@ -24,6 +24,7 @@
"_userDB":"Utente", "_userDB":"Utente",
"_url":"URL di origine", "_url":"URL di origine",
"_utime":"Sessione timestamp", "_utime":"Sessione timestamp",
"2faSessions":"2FA sessions explorer",
"actives":"Attivi", "actives":"Attivi",
"activeTimer":"Auto accettazione tempo", "activeTimer":"Auto accettazione tempo",
"addAppCasPartner":"Aggiungi applicazione CAS", "addAppCasPartner":"Aggiungi applicazione CAS",
@ -34,6 +35,7 @@
"addSPSamlPartner":"Aggiungi SAML SP", "addSPSamlPartner":"Aggiungi SAML SP",
"addSrvCasPartner":"Aggiungi server CAS", "addSrvCasPartner":"Aggiungi server CAS",
"addU2FKey":"Add U2F key", "addU2FKey":"Add U2F key",
"addTOTPKey":"Add TOTP 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",
@ -203,6 +205,7 @@
"deleteNotification":"Elimina", "deleteNotification":"Elimina",
"deleteSession":"Elimina sessione", "deleteSession":"Elimina sessione",
"deleteU2FKey":"Delete U2F key", "deleteU2FKey":"Delete U2F key",
"deleteTOTPKey":"Delete TOTP key",
"demoExportedVars":"Variabili esportate", "demoExportedVars":"Variabili esportate",
"demoParams":"Parametri di dimostrazione", "demoParams":"Parametri di dimostrazione",
"description":"Descrizione", "description":"Descrizione",
@ -729,7 +732,6 @@
"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",
@ -755,6 +757,7 @@
"variables":"Variabili", "variables":"Variabili",
"version":"Versioni", "version":"Versioni",
"verifyU2FKey":"Verify U2F key", "verifyU2FKey":"Verify U2F key",
"verifyTOTPKey":"Verify TOTP key",
"vhostAliases":"Alias", "vhostAliases":"Alias",
"vhostAuthnLevel":"Livello di autenticazione richiesto", "vhostAuthnLevel":"Livello di autenticazione richiesto",
"vhostHttps":"HTTPS", "vhostHttps":"HTTPS",

View File

@ -24,6 +24,7 @@
"_userDB":"Người dùng", "_userDB":"Người dùng",
"_url":"URL gốc", "_url":"URL gốc",
"_utime":"Dấu thời gian của phiên", "_utime":"Dấu thời gian của phiên",
"u2fSessions":"U2F sessions explorer",
"actives":"Hoạt động", "actives":"Hoạt động",
"activeTimer":"Tự động chấp nhận thời gian", "activeTimer":"Tự động chấp nhận thời gian",
"addAppCasPartner":"Thêm ứng dụng CAS", "addAppCasPartner":"Thêm ứng dụng CAS",
@ -34,6 +35,7 @@
"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", "addU2FKey":"Add U2F key",
"addTOTPKey":"Add TOTP 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",
@ -203,6 +205,7 @@
"deleteNotification":"Xóa", "deleteNotification":"Xóa",
"deleteSession":"Xóa phiên", "deleteSession":"Xóa phiên",
"deleteU2FKey":"Delete U2F key", "deleteU2FKey":"Delete U2F key",
"deleteTOTPKey":"Delete TOTP key",
"demoExportedVars":"Xuất khẩu biến", "demoExportedVars":"Xuất khẩu biến",
"demoParams":"Tham số trình diễn", "demoParams":"Tham số trình diễn",
"description":"Mô tả", "description":"Mô tả",
@ -729,7 +732,6 @@
"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",
@ -755,6 +757,7 @@
"variables":"biến", "variables":"biến",
"version":"Phiên bản", "version":"Phiên bản",
"verifyU2FKey":"Verify U2F key", "verifyU2FKey":"Verify U2F key",
"verifyTOTPKey":"Verify TOTP 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",

View File

@ -48,7 +48,7 @@
<!-- Right(main) div --> <!-- Right(main) div -->
<div id="right" class="col-lg-8 col-md-8 col-sm-7 col-xs-12 scrollable" ng-class="{'hidden-xs':showT&&!showM}"> <div id="right" class="col-lg-8 col-md-8 col-sm-7 col-xs-12 scrollable" ng-class="{'hidden-xs':showT&&!showM}">
<!-- Menu buttons --> <!-- Menu buttons -->
<div class="lmmenu navbar navbar-default" ng-class="{'hidden-xs':!showM}"> <div ng-if="currentSession" 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.session" ng-include="'menubutton.html'"></li>

View File

@ -12,10 +12,17 @@
<!-- Tree --> <!-- Tree -->
<aside id="left" class="col-lg-4 col-md-4 col-sm-5 col-xs-12 scrollable " ng-class="{'hidden-xs':!showT}" role="complementary"> <aside id="left" class="col-lg-4 col-md-4 col-sm-5 col-xs-12 scrollable " ng-class="{'hidden-xs':!showT}" role="complementary">
<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" role="row"><i class="glyphicon glyphicon-exclamation-sign"></i> {{translate('u2fSessions')}}</a></li> <li><a id="a-persistent" role="row"><i class="glyphicon glyphicon-exclamation-sign"></i> {{translate('2faSessions')}}</a></li>
<div class="form-check ">&nbsp;&nbsp;&nbsp;
<input type="checkbox" class="form-check-input" id="U2FCheck" value="1">
<label class="form-check-label" for="U2FCheck">U2F</label>&nbsp;&nbsp;
<input type="checkbox" class="form-check-input" id="TOTPCheck" value="1">
<label class="form-check-label" for="TOTPCheck">TOTP</label>
</div>
</ul> </ul>
</div> </div>
</div> </div>
@ -38,15 +45,13 @@
<!-- Right(main) div --> <!-- Right(main) div -->
<div id="right" class="col-lg-8 col-md-8 col-sm-7 col-xs-12 scrollable" ng-class="{'hidden-xs':showT&&!showM}"> <div id="right" class="col-lg-8 col-md-8 col-sm-7 col-xs-12 scrollable" ng-class="{'hidden-xs':showT&&!showM}">
<!-- Menu buttons --> <!-- Menu buttons -->
<div class="lmmenu navbar navbar-default" ng-class="{'hidden-xs':!showM}">
<div ng-if="currentSession" 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.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" ng-repeat="button in menu.delU2FKey" 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.addU2FKey" 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>
@ -59,6 +64,26 @@
</ul> </ul>
</div> </div>
</div> </div>
<div ng-if="currentSession" 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.delTOTPKey" ng-include="'menubutton.html'"></li>
<li ng-if="currentSession" ng-repeat="button in menu.verifyTOTPKey" ng-include="'menubutton.html'"></li>
<li ng-if="currentSession" ng-repeat="button in menu.addTOTPKey" 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>
<ul uib-dropdown-menu aria-labelled-by="langmenu" role="grid">
<li ng-repeat="link in links"><a href="{{link.target}}" role="row"><i ng-if="link.icon" class="glyphicon glyphicon-{{link.icon}}"></i> {{translate(link.title)}}</a></li>
<li ng-repeat="menulink in menulinks"><a href="{{menulink.target}}" role="row"><i ng-if="menulink.icon" class="glyphicon glyphicon-{{menulink.icon}}"></i> {{translate(menulink.title)}}</a></li>
<li ng-include="'languages.html'"></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="panel panel-default" ng-hide="currentSession===null"> <div class="panel panel-default" ng-hide="currentSession===null">
<div class="panel-heading"> <div class="panel-heading">
<h1 class="panel-title text-center">{{translate("sessionTitle")}} {{currentSession.id}}</h1> <h1 class="panel-title text-center">{{translate("sessionTitle")}} {{currentSession.id}}</h1>