diff --git a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Session/REST.pm b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Session/REST.pm index 9ddbf1e0e..94c8b561a 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Session/REST.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Session/REST.pm @@ -3,6 +3,7 @@ package Lemonldap::NG::Common::Session::REST; use strict; use Mouse; use Lemonldap::NG::Common::Conf::Constants; +use JSON qw(from_json to_json); our $VERSION = '2.0.0'; @@ -44,15 +45,17 @@ sub delSession { my $id = $req->params('sessionId') or return $self->sendError( $req, 'sessionId is missing', 400 ); my $session = $self->getApacheSession( $mod, $id ); + $self->logger->debug("Delete session : $id"); $session->remove; 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 deleteU2FKey { +sub delete2F { my ( $self, $req ) = @_; return $self->sendJSONresponse( $req, { result => 1 } ) if ( $self->{demoMode} ); @@ -62,12 +65,51 @@ sub deleteU2FKey { or return $self->sendError( $req, 'sessionId is missing', 400 ); # Try to read session + $self->logger->debug("Loading session : $id"); my $session = $self->getApacheSession( $mod, $id ) or return $self->sendError( $req, undef, 400 ); - # Delete U2F key attributs and update session - $session->data->{_u2fKeyHandle} = ''; - $session->data->{_u2fUserKey} = ''; + # Try to read 2F parameters + $self->logger->debug("Reading parameters ..."); + my $params = $req->parameters(); + my $type = $params->{type} + or return $self->sendError( $req, '2F device Type is missing', 400 ); + my $epoch = $params->{epoch} + or return $self->sendError( $req, '2F device Epoch is missing', 400 ); + + # Try to load 2F Device(s) from session + $self->logger->debug("Looking for 2F Device(s) ..."); + my $_2fDevices; + if ( $session->data->{_2fDevices} ) { + $_2fDevices = eval { + from_json( $session->data->{_2fDevices}, { allow_nonref => 1 } ); + }; + if ($@) { + $self->logger->error("Corrupted session (_2fDevices) : $@"); + return $self->p->sendError( $req, "Corrupted session", 500 ); + } + } + else { + $self->logger->debug("No 2F Device found"); + $_2fDevices = []; + } + + # Delete 2F device + $self->logger->debug("Reading 2F device(s) ..."); + my @keep = (); + while (@$_2fDevices) { + my $element = shift @$_2fDevices; + $self->logger->debug( + "Searching 2F device to delete -> $type / $epoch ..."); + push @keep, $element + unless ( ( $element->{type} eq $type ) + and ( $element->{epoch} eq $epoch ) ); + } + + # Update session + $self->logger->debug("Saving 2F Devices ..."); + $session->data->{_2fDevices} = to_json( \@keep ); + $self->logger->debug("Updating session ..."); $session->update( \%{ $session->data } ); Lemonldap::NG::Handler::PSGI::Main->localUnlog( $req, $id ); @@ -77,79 +119,55 @@ sub deleteU2FKey { 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 ); +#sub add2F { +#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 ); +## 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 } ); +## 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 } ); -} +#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 { - 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 ); +#sub verify2F { +#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 ); +## 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 } ); +## 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 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 } ); -} +#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 ) = @_; diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/2ndFA.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/2ndFA.pm index d408664c0..e6f204075 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/2ndFA.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/2ndFA.pm @@ -27,7 +27,7 @@ use constant defaultRoute => '2ndfa.html#/persistent'; sub addRoutes { my ( $self, $conf ) = @_; - # Remote Procedure Call are defined in Lemonldap::NG::Common::Session::REST + # Remote Procedure are defined in Lemonldap::NG::Common::Session::REST # HTML template $self->addRoute( '2ndfa.html', undef, ['GET'] ) @@ -36,24 +36,24 @@ sub addRoutes { ['GET'] ) - # DELETE 2FA KEY + # DELETE 2FA DEVICE ->addRoute( - sfa => { ':sessionType' => { ':sessionId' => 'delete2FAKey' } }, + sfa => { ':sessionType' => { ':sessionId' => 'delete2FA' } }, ['DELETE'] - ) - - # ADD 2FA KEY - ->addRoute( - sfa => { ':sessionType' => { ':sessionId' => 'add2FAKey' } }, - ['PUT'] - ) - - # VERIFY 2FA KEY - ->addRoute( - sfa => { ':sessionType' => { ':sessionId' => 'verify2FAKey' } }, - ['POST'] ); + ## ADD 2FA DEVICE + #->addRoute( + #sfa => { ':sessionType' => { ':sessionId' => 'add2FA' } }, + #['PUT'] + #) + + ## VERIFY 2FA DEVICE + #->addRoute( + #sfa => { ':sessionType' => { ':sessionId' => 'verify2FA' } }, + #['POST'] + #); + $self->setTypes($conf); $self->{ipField} ||= 'ipAddr'; @@ -61,54 +61,60 @@ sub addRoutes { $self->{hiddenAttributes} //= "_password"; $self->{TOTPCheck} = '1'; $self->{U2FCheck} = '1'; + $self->{UBKCheck} = '1'; } ################### # II. 2FA METHODS # ################### -sub delete2FAKey { +sub delete2FA { 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}; + my $params = $req->parameters(); + my $type = $params->{type}; + my $epoch = $params->{epoch}; - if ( $Key =~ /\bU2F\b/ ) { - $self->logger->debug("Call procedure deleteU2FKey"); - return $self->deleteU2FKey( $req, $session, $skey ); - } - elsif ( $Key =~ /\bTOTP\b/ ) { - $self->logger->debug("Call procedure deleteTOTPKey"); - return $self->deleteTOTPKey( $req, $session, $skey ); + if ( $type =~ /\b(?:U2F|TOTP|UBK)\b/ and $epoch ) { + $self->logger->debug("Call procedure delete2F with type=$type and epoch=$epoch"); + return $self->delete2F( $req, $session, $skey ); } + #elsif ( $type =~ /\bTOTP\b/ ) { + #$self->logger->debug("Call procedure deleteTOTP"); + #return $self->deleteTOTP( $req, $session, $skey ); + #} + #elsif ( $type =~ /\bUBK\b/ ) { + #$self->logger->debug("Call procedure deleteUBK"); + #return $self->deleteUBK( $req, $session, $skey ); + #} else { return $self->sendError( $req, undef, 400 ); } } -sub add2FAKey { +#sub add2FA { - my ( $self, $req, $session, $skey ) = @_; + #my ( $self, $req, $session, $skey ) = @_; - eval 'use Crypt::U2F::Server::Simple'; - if ($@) { - $self->error("Can't load U2F library: $@"); - return 0; - } + #eval 'use Crypt::U2F::Server::Simple'; + #if ($@) { + #$self->error("Can't load U2F library: $@"); + #return 0; + #} - return $self->addU2FKey( $req, $session, $skey ); -} + #return $self->addU2FKey( $req, $session, $skey ); +#} -sub verify2FAKey { +#sub verify2FA { - my ( $self, $req, $session, $skey ) = @_; + #my ( $self, $req, $session, $skey ) = @_; - return $self->addU2FKey( $req, $session, $skey ); -} + #return $self->addU2FKey( $req, $session, $skey ); +#} ######################## # III. DISPLAY METHODS # @@ -137,8 +143,7 @@ sub sfa { # 2.1 Get fields to require my @fields = ( '_httpSessionType', $self->{ipField}, - $whatToTrace, '_u2fKeyHandle', - '_totp2fSecret' + $whatToTrace, '_2fDevices' ); if ( my $groupBy = $params->{groupBy} ) { $groupBy =~ s/^substr\((\w+)(?:,\d+(?:,\d+)?)?\)$/$1/; @@ -155,9 +160,10 @@ sub sfa { $moduleOptions->{backend} = $mod->{module}; # Select 2FA sessions to display - if ( defined $params->{TOTPCheck} and defined $params->{TOTPCheck} ) { + if ( defined $params->{TOTPCheck} or defined $params->{U2FCheck} or defined $params->{UBKCheck}) { $self->{TOTPCheck} = delete $params->{TOTPCheck}; $self->{U2FCheck} = delete $params->{U2FCheck}; + $self->{UBKCheck} = delete $params->{UBKCheck}; } my %filters = map { @@ -236,15 +242,22 @@ sub sfa { if ( $self->{U2FCheck} eq '2' ) { foreach my $session ( keys %$res ) { delete $res->{$session} - unless ( defined $res->{$session}->{_u2fKeyHandle} - and length $res->{$session}->{_u2fKeyHandle} ); + unless ( defined $res->{$session}->{_2fDevices} + and $res->{$session}->{_2fDevices} =~ /"type":\s*"U2F"/s ); } } if ( $self->{TOTPCheck} eq '2' ) { foreach my $session ( keys %$res ) { delete $res->{$session} - unless ( defined $res->{$session}->{_totp2fSecret} - and length $res->{$session}->{_totp2fSecret} ); + unless ( defined $res->{$session}->{_2fDevices} + and $res->{$session}->{_2fDevices} =~ /"type":\s*"TOTP"/s ); + } + } + if ( $self->{UBKCheck} eq '2' ) { + foreach my $session ( keys %$res ) { + delete $res->{$session} + unless ( defined $res->{$session}->{_2fDevices} + and $res->{$session}->{_2fDevices} =~ /"type":\s*"UBK"/s ); } } diff --git a/lemonldap-ng-manager/site/coffee/2ndfa.coffee b/lemonldap-ng-manager/site/coffee/2ndfa.coffee index 341bdc23d..632cc224d 100644 --- a/lemonldap-ng-manager/site/coffee/2ndfa.coffee +++ b/lemonldap-ng-manager/site/coffee/2ndfa.coffee @@ -19,9 +19,6 @@ displayError = (j, status, err) -> setMsg res, 'warning' - - - # Max number of session to display (see overScheme) max = 25 @@ -72,40 +69,34 @@ hiddenAttributes = '_password' categories = dateTitle: ['_utime', '_startTime', '_updateTime', '_lastAuthnUTime', '_lastSeen'] connectionTitle: ['ipAddr', '_timezone', '_url'] - authenticationTitle:['_session_id', '_user', '_password', 'authenticationLevel'] - modulesTitle: ['_auth', '_userDB', '_passwordDB', '_issuerDB', '_authChoice', '_authMulti', '_userDBMulti'] - saml: ['_idp', '_idpConfKey', '_samlToken', '_lassoSessionDump', '_lassoIdentityDump'] - groups: ['groups', 'hGroups'] - ldap: ['dn'] - BrowserID: ['_browserIdAnswer', '_browserIdAnswerRaw'] - OpenIDConnect: ['_oidc_id_token', '_oidc_OP', '_oidc_access_token'] + sfaTitle: ['_2fDevices'] # Menu entries menu = - delU2FKey: [ - title: 'deleteU2FKey' - icon: 'trash' - ] - addU2FKey: [ - title: 'addU2FKey' - icon: 'plus' - ] - verifyU2FKey: [ - title: 'verifyU2FKey' - icon: 'check' - ] - delTOTPKey: [ - title: 'deleteTOTPKey' - icon: 'trash' - ] - addTOTPKey: [ - title: 'addTOTPKey' - icon: 'plus' - ] - verifyTOTPKey: [ - title: 'verifyTOTPKey' - icon: 'check' - ] + #delU2FKey: [ + #title: 'deleteU2FKey' + #icon: 'trash' + #] + #addU2FKey: [ + #title: 'addU2FKey' + #icon: 'plus' + #] + #verifyU2FKey: [ + #title: 'verifyU2FKey' + #icon: 'check' + #] + #delTOTPKey: [ + #title: 'deleteTOTPKey' + #icon: 'trash' + #] + #addTOTPKey: [ + #title: 'addTOTPKey' + #icon: 'plus' + #] + #verifyTOTPKey: [ + #title: 'verifyTOTPKey' + #icon: 'check' + #] home: [] ### @@ -146,6 +137,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', switch typeof button.action when 'function' button.action $scope.currentNode, $scope + $scope[button.action]() when 'string' $scope[button.action]() else @@ -161,83 +153,49 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', $scope.data = [] $scope.updateTree2 '', $scope.data, 0, 0 - # Delete U2F key - $scope.deleteU2FKey = -> + # Delete 2FA device + $scope.delete2FA = (type, epoch) -> + item = angular.element("#data-#{epoch}") + item.remove() $scope.waiting = true - $http['delete']("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}?Key=U2F").then (response) -> - $scope.currentSession = null - $scope.currentScope.remove() + $http['delete']("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}?type=#{type}&epoch=#{epoch}").then (response) -> + #$scope.currentSession = null + #$scope.currentScope.remove() + #$scope.data = [] $scope.waiting = false , (resp) -> - $scope.currentSession = null - $scope.currentScope.remove() - $scope.waiting = false - $scope.showT = false - - # Delete TOTP key - $scope.deleteTOTPKey = -> - $scope.waiting = true - $http['delete']("#{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.currentSession = null + #$scope.currentScope.remove() $scope.waiting = false $scope.showT = false + #$scope.data = [] - # Add U2F key - $scope.addU2FKey = -> - $scope.waiting = true - $http['put']("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}?Key=U2F").then (response) -> - $scope.currentSession = null - $scope.currentScope.remove() - $scope.waiting = false - , (resp) -> - $scope.currentSession = null - $scope.currentScope.remove() - $scope.waiting = false - $scope.showT = false - - # 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 + ## Add 2FA device + #$scope.add2FA (type) = -> + #$scope.waiting = true + #$http['put']("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}?Key=U2F").then (response) -> + #$scope.currentSession = null + #$scope.currentScope.remove() + #$scope.waiting = false + #, (resp) -> + #$scope.currentSession = null + #$scope.currentScope.remove() + #$scope.waiting = false + #$scope.showT = false - # Verify U2F key - $scope.verifyU2FKey = -> - $scope.waiting = true - $http['post']("#{scriptname}sfa/#{sessionType}/#{$scope.currentSession.id}?Key=U2F").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 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.showT = true + ## Verify 2FA device + #$scope.verify2FA (epoch) = -> + #$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.showT = true # Open node $scope.stoggle = (scope) -> @@ -284,66 +242,46 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', else if key.match /^(_utime|_lastAuthnUTime|_lastSeen|notification)$/ session[key] = $scope.localeDate value else if key.match /^(_startTime|_updateTime)$/ - session[key] = _stToStr value - #else if key.match /^(_u2fKeyHandle|_u2fUserKey|_totp2fSecret)$/ - # session[key] = '##########' - + session[key] = _stToStr value res = [] # 2. Push session keys in result, grouped by categories for category, attrs of categories subres = [] for attr in attrs - if session[attr] - subres.push - title: attr - value: session[attr] - delete session[attr] + if session[attr] and session[attr].match(/\w+/) + if session[attr].match(/"type":\s*"(?:TOTP|U2F|UBK)"/) + subres.push + title: "type" + value: "name" + sdate: "date" + array = JSON.parse(session[attr]); + for sfDevice in array + for key, value of sfDevice + if key == 'type' + title = value + if key == 'name' + name = value + if key == 'epoch' + epoch = value + newDate = new Date(value * 1000) + myDate = newDate.toLocaleString() + subres.push + title: title + value: name + epoch: epoch + sdate: myDate + delete session[attr] + else + subres.push + title: attr + value: session[attr] + delete session[attr] + if subres.length >0 res.push title: "__#{category}__" nodes: subres - - # 3. Add OpenID and notifications already notified - _insert '^openid', 'OpenID' - _insert '^notification_(.+)', '__notificationsDone__' - - # 4. Add session history if exists - if session._loginHistory - tmp = [] - if session._loginHistory.successLogin - for l in session._loginHistory.successLogin - tmp.push - t: l._utime - title: $scope.localeDate l._utime - value: "Success (IP #{l.ipAddr})" - if session._loginHistory.failedLogin - for l in session._loginHistory.failedLogin - tmp.push - t: l._utime - title: $scope.localeDate l._utime - value: "#{l.error} (IP #{l.ipAddr})" - delete session._loginHistory - tmp.sort (a,b) -> - a.t - b.t - res.push - title: '__loginHistory__' - nodes: tmp - - # 5. Other keys (attributes and macros) - tmp = [] - for key, value of session - tmp.push - title: key - value: value - tmp.sort (a,b) -> - if a.title > b.title then 1 - else if a.title < b.title then -1 - else 0 - - res.push - title: '__attributesAndMacros__' - nodes: tmp return { _utime: time id: id @@ -478,7 +416,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', over = 0 # Launch HTTP - $http.get("#{scriptname}sfa/#{sessionType}?_session_uid=#{$scope.searchString}*&groupBy=substr(_session_uid,#{$scope.searchString.length})&U2FCheck=#{$scope.U2FCheck}&TOTPCheck=#{$scope.TOTPCheck}").then (response) -> + $http.get("#{scriptname}sfa/#{sessionType}?_session_uid=#{$scope.searchString}*&groupBy=substr(_session_uid,#{$scope.searchString.length})&U2FCheck=#{$scope.U2FCheck}&TOTPCheck=#{$scope.TOTPCheck}&UBKCheck=#{$scope.UBKCheck}").then (response) -> data = response.data if data.result for n in data.values @@ -528,3 +466,5 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', $scope.type = if c then c[1] else '_whatToTrace' ] + + diff --git a/lemonldap-ng-manager/site/coffee/sessions.coffee b/lemonldap-ng-manager/site/coffee/sessions.coffee index 589f03a79..bd3dbb65d 100644 --- a/lemonldap-ng-manager/site/coffee/sessions.coffee +++ b/lemonldap-ng-manager/site/coffee/sessions.coffee @@ -77,7 +77,7 @@ hiddenAttributes = '_password' categories = dateTitle: ['_utime', '_startTime', '_updateTime', '_lastAuthnUTime', '_lastSeen'] connectionTitle: ['ipAddr', '_timezone', '_url'] - authenticationTitle:['_session_id', '_user', '_password', 'authenticationLevel'] + authenticationTitle:['_session_id', '_user', '_password', 'authenticationLevel', '_2fDevices'] modulesTitle: ['_auth', '_userDB', '_passwordDB', '_issuerDB', '_authChoice', '_authMulti', '_userDBMulti'] saml: ['_idp', '_idpConfKey', '_samlToken', '_lassoSessionDump', '_lassoIdentityDump'] groups: ['groups', 'hGroups'] @@ -196,8 +196,7 @@ 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|_totp2fSecret)$/ - # session[key] = '##########' + res = [] # 2. Push session keys in result, grouped by categories diff --git a/lemonldap-ng-manager/site/htdocs/static/js/2ndfa.js b/lemonldap-ng-manager/site/htdocs/static/js/2ndfa.js index b9675000c..b43d64756 100644 --- a/lemonldap-ng-manager/site/htdocs/static/js/2ndfa.js +++ b/lemonldap-ng-manager/site/htdocs/static/js/2ndfa.js @@ -82,52 +82,10 @@ categories = { dateTitle: ['_utime', '_startTime', '_updateTime', '_lastAuthnUTime', '_lastSeen'], connectionTitle: ['ipAddr', '_timezone', '_url'], - authenticationTitle: ['_session_id', '_user', '_password', 'authenticationLevel'], - modulesTitle: ['_auth', '_userDB', '_passwordDB', '_issuerDB', '_authChoice', '_authMulti', '_userDBMulti'], - saml: ['_idp', '_idpConfKey', '_samlToken', '_lassoSessionDump', '_lassoIdentityDump'], - groups: ['groups', 'hGroups'], - ldap: ['dn'], - BrowserID: ['_browserIdAnswer', '_browserIdAnswerRaw'], - OpenIDConnect: ['_oidc_id_token', '_oidc_OP', '_oidc_access_token'] + sfaTitle: ['_2fDevices'] }; menu = { - delU2FKey: [ - { - title: 'deleteU2FKey', - icon: 'trash' - } - ], - addU2FKey: [ - { - title: 'addU2FKey', - icon: 'plus' - } - ], - verifyU2FKey: [ - { - title: 'verifyU2FKey', - icon: 'check' - } - ], - delTOTPKey: [ - { - title: 'deleteTOTPKey', - icon: 'trash' - } - ], - addTOTPKey: [ - { - title: 'addTOTPKey', - icon: 'plus' - } - ], - verifyTOTPKey: [ - { - title: 'verifyTOTPKey', - icon: 'check' - } - ], home: [] }; @@ -171,6 +129,7 @@ switch (typeof button.action) { case 'function': button.action($scope.currentNode, $scope); + $scope[button.action](); break; case 'string': $scope[button.action](); @@ -189,84 +148,18 @@ $scope.data = []; return $scope.updateTree2('', $scope.data, 0, 0); }; - $scope.deleteU2FKey = function() { + $scope.delete2FA = function(type, epoch) { + var item; + item = angular.element("#data-" + epoch); + item.remove(); $scope.waiting = true; - $http['delete'](scriptname + "sfa/" + sessionType + "/" + $scope.currentSession.id + "?Key=U2F").then(function(response) { - $scope.currentSession = null; - $scope.currentScope.remove(); + $http['delete'](scriptname + "sfa/" + sessionType + "/" + $scope.currentSession.id + "?type=" + type + "&epoch=" + epoch).then(function(response) { 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.currentScope.remove(); - return $scope.waiting = false; - }, function(resp) { - $scope.currentSession = null; - $scope.currentScope.remove(); - return $scope.waiting = false; - }); - return $scope.showT = false; - }; - $scope.addU2FKey = function() { - $scope.waiting = true; - $http['put'](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.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; - }; - $scope.verifyU2FKey = function() { - $scope.waiting = true; - $http['post'](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 = true; - }; - $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 = true; - }; $scope.stoggle = function(scope) { var node; node = scope.$modelValue; @@ -278,7 +171,7 @@ $scope.displaySession = function(scope) { var sessionId, transformSession; transformSession = function(session) { - var _insert, _stToStr, attr, attrs, category, i, id, k, key, l, len, len1, len2, m, ref, ref1, res, subres, time, tmp, value; + var _insert, _stToStr, array, attr, attrs, category, epoch, i, id, k, key, len, len1, myDate, name, newDate, res, sfDevice, subres, time, title, value; _stToStr = function(s) { return s; }; @@ -330,12 +223,45 @@ subres = []; for (i = 0, len = attrs.length; i < len; i++) { attr = attrs[i]; - if (session[attr]) { - subres.push({ - title: attr, - value: session[attr] - }); - delete session[attr]; + if (session[attr] && session[attr].match(/\w+/)) { + if (session[attr].match(/"type":\s*"(?:TOTP|U2F|UBK)"/)) { + subres.push({ + title: "type", + value: "name", + sdate: "date" + }); + array = JSON.parse(session[attr]); + for (k = 0, len1 = array.length; k < len1; k++) { + sfDevice = array[k]; + for (key in sfDevice) { + value = sfDevice[key]; + if (key === 'type') { + title = value; + } + if (key === 'name') { + name = value; + } + if (key === 'epoch') { + epoch = value; + newDate = new Date(value * 1000); + myDate = newDate.toLocaleString(); + } + } + subres.push({ + title: title, + value: name, + epoch: epoch, + sdate: myDate + }); + } + delete session[attr]; + } else { + subres.push({ + title: attr, + value: session[attr] + }); + delete session[attr]; + } } } if (subres.length > 0) { @@ -345,62 +271,6 @@ }); } } - _insert('^openid', 'OpenID'); - _insert('^notification_(.+)', '__notificationsDone__'); - if (session._loginHistory) { - tmp = []; - if (session._loginHistory.successLogin) { - ref = session._loginHistory.successLogin; - for (k = 0, len1 = ref.length; k < len1; k++) { - l = ref[k]; - tmp.push({ - t: l._utime, - title: $scope.localeDate(l._utime), - value: "Success (IP " + l.ipAddr + ")" - }); - } - } - if (session._loginHistory.failedLogin) { - ref1 = session._loginHistory.failedLogin; - for (m = 0, len2 = ref1.length; m < len2; m++) { - l = ref1[m]; - tmp.push({ - t: l._utime, - title: $scope.localeDate(l._utime), - value: l.error + " (IP " + l.ipAddr + ")" - }); - } - } - delete session._loginHistory; - tmp.sort(function(a, b) { - return a.t - b.t; - }); - res.push({ - title: '__loginHistory__', - nodes: tmp - }); - } - tmp = []; - for (key in session) { - value = session[key]; - tmp.push({ - title: key, - value: value - }); - } - tmp.sort(function(a, b) { - if (a.title > b.title) { - return 1; - } else if (a.title < b.title) { - return -1; - } else { - return 0; - } - }); - res.push({ - title: '__attributesAndMacros__', - nodes: tmp - }); return { _utime: time, id: id, @@ -502,7 +372,7 @@ } else { over = 0; } - return $http.get(scriptname + "sfa/" + sessionType + "?_session_uid=" + $scope.searchString + "*&groupBy=substr(_session_uid," + $scope.searchString.length + ")&U2FCheck=" + $scope.U2FCheck + "&TOTPCheck=" + $scope.TOTPCheck).then(function(response) { + return $http.get(scriptname + "sfa/" + sessionType + "?_session_uid=" + $scope.searchString + "*&groupBy=substr(_session_uid," + $scope.searchString.length + ")&U2FCheck=" + $scope.U2FCheck + "&TOTPCheck=" + $scope.TOTPCheck + "&UBKCheck=" + $scope.UBKCheck).then(function(response) { var data, i, len, n, ref; data = response.data; if (data.result) { diff --git a/lemonldap-ng-manager/site/htdocs/static/js/2ndfa.min.js b/lemonldap-ng-manager/site/htdocs/static/js/2ndfa.min.js index 247dd71cf..fccf5beff 100644 --- a/lemonldap-ng-manager/site/htdocs/static/js/2ndfa.min.js +++ b/lemonldap-ng-manager/site/htdocs/static/js/2ndfa.min.js @@ -1 +1 @@ -(function(){var c,d,f,g,h,a,e,i,b;b=function(j,k){$("#msg").html(window.translate(j));$("#color").removeClass("message-positive message-warning alert-success alert-warning");$("#color").addClass("message-"+k);if(k==="positive"){k="success"}return $("#color").addClass("alert-"+k)};d=function(l,k,n){var m;console.log("Error",n);m=JSON.parse(l.responseText);if(m&&m.error){m=m.error.replace(/.* /,"");console.log("Returned error",m);return b(m,"warning")}};h=25;i={_whatToTrace:[function(k,j){return"groupBy=substr("+k+",1)"},function(k,j){return k+"="+j+"*&groupBy="+k},function(k,j){return k+"="+j}],_startTime:[function(k,j){return"groupBy=substr("+k+",8)"},function(k,j){return k+"="+j+"*&groupBy=substr("+k+",10)"},function(k,j){return k+"="+j+"*&groupBy=substr("+k+",11)"},function(k,j){return k+"="+j+"*&groupBy=substr("+k+",12)"},function(k,j){return k+"="+j+"*&groupBy=_whatToTrace"},function(k,j,l){console.log(k);console.log(j);console.log(l);return l.replace(/\&groupBy.*$/,"")+("&_whatToTrace="+j)}]};e={_whatToTrace:function(k,j,m,l){if(m===1){return k+"="+j+"*&groupBy=substr("+k+","+(m+l+1)+")"}else{return null}},ipAddr:function(k,j,m,l){if(m>0&&m<4){return k+"="+j+"*&groupBy=net("+k+","+(16*m+4*(l+1))+",2)"}else{return null}}};f="_password";c={dateTitle:["_utime","_startTime","_updateTime","_lastAuthnUTime","_lastSeen"],connectionTitle:["ipAddr","_timezone","_url"],authenticationTitle:["_session_id","_user","_password","authenticationLevel"],modulesTitle:["_auth","_userDB","_passwordDB","_issuerDB","_authChoice","_authMulti","_userDBMulti"],saml:["_idp","_idpConfKey","_samlToken","_lassoSessionDump","_lassoIdentityDump"],groups:["groups","hGroups"],ldap:["dn"],BrowserID:["_browserIdAnswer","_browserIdAnswerRaw"],OpenIDConnect:["_oidc_id_token","_oidc_OP","_oidc_access_token"]};a={delU2FKey:[{title:"deleteU2FKey",icon:"trash"}],addU2FKey:[{title:"addU2FKey",icon:"plus"}],verifyU2FKey:[{title:"verifyU2FKey",icon:"check"}],delTOTPKey:[{title:"deleteTOTPKey",icon:"trash"}],addTOTPKey:[{title:"addTOTPKey",icon:"plus"}],verifyTOTPKey:[{title:"verifyTOTPKey",icon:"check"}],home:[]};g=angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]);g.controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(r,j,k,l,o){var p,n,m,q;r.links=links;r.menulinks=menulinks;r.staticPrefix=staticPrefix;r.scriptname=scriptname;r.formPrefix=formPrefix;r.availableLanguages=availableLanguages;r.waiting=true;r.showM=false;r.showT=true;r.data=[];r.currentScope=null;r.currentSession=null;r.menu=a;r.searchString="";r.translateP=j.translateP;r.translate=j.translate;r.translateTitle=function(s){return j.translateField(s,"title")};q="global";r.menuClick=function(s){if(s.popup){window.open(s.popup)}else{if(!s.action){s.action=s.title}switch(typeof s.action){case"function":s.action(r.currentNode,r);break;case"string":r[s.action]();break;default:console.log(typeof s.action)}}return r.showM=false};r.search2FA=function(s){if(s){r.searchString=""}r.currentSession=null;r.data=[];return r.updateTree2("",r.data,0,0)};r.deleteU2FKey=function(){r.waiting=true;o["delete"](scriptname+"sfa/"+q+"/"+r.currentSession.id+"?Key=U2F").then(function(s){r.currentSession=null;r.currentScope.remove();return r.waiting=false},function(s){r.currentSession=null;r.currentScope.remove();return r.waiting=false});return r.showT=false};r.deleteTOTPKey=function(){r.waiting=true;o["delete"](scriptname+"sfa/"+q+"/"+r.currentSession.id+"?Key=TOTP").then(function(s){r.currentSession=null;r.currentScope.remove();return r.waiting=false},function(s){r.currentSession=null;r.currentScope.remove();return r.waiting=false});return r.showT=false};r.addU2FKey=function(){r.waiting=true;o.put(scriptname+"sfa/"+q+"/"+r.currentSession.id+"?Key=U2F").then(function(s){r.currentSession=null;r.currentScope.remove();return r.waiting=false},function(s){r.currentSession=null;r.currentScope.remove();return r.waiting=false});return r.showT=false};r.addTOTPKey=function(){r.waiting=true;o.put(scriptname+"sfa/"+q+"/"+r.currentSession.id+"?Key=TOTP").then(function(s){r.currentSession=null;r.currentScope.remove();return r.waiting=false},function(s){r.currentSession=null;r.currentScope.remove();return r.waiting=false});return r.showT=false};r.verifyU2FKey=function(){r.waiting=true;o.post(scriptname+"sfa/"+q+"/"+r.currentSession.id+"?Key=U2F").then(function(s){r.currentSession=null;r.currentScope.remove();return r.waiting=false},function(s){r.currentSession=null;r.currentScope.remove();return r.waiting=false});return r.showT=true};r.verifyTOTPKey=function(){r.waiting=true;o.post(scriptname+"sfa/"+q+"/"+r.currentSession.id+"?Key=TOTP").then(function(s){r.currentSession=null;r.currentScope.remove();return r.waiting=false},function(s){r.currentSession=null;r.currentScope.remove();return r.waiting=false});return r.showT=true};r.stoggle=function(s){var t;t=s.$modelValue;if(t.nodes.length===0){r.updateTree(t.value,t.nodes,t.level,t.over,t.query,t.count)}return s.toggle()};r.displaySession=function(t){var u,s;s=function(v){var A,C,G,E,J,L,D,K,Q,I,M,z,y,H,w,B,P,O,x,N,F;C=function(R){return R};A=function(U,W){var S,T,R,V;R=[];T=new RegExp(U);for(S in v){V=v[S];if(S.match(T)&&V){R.push({title:S,value:V});delete v[S]}}if(R.length>0){return P.push({title:W,nodes:R})}};x=v._utime;D=v._session_id;for(Q in v){F=v[Q];if(!F){delete v[Q]}else{if(typeof v==="string"&&F.match(/; /)){v[Q]=F.split("; ")}if(typeof v[Q]!=="object"){if(f.match(new RegExp("\b"+Q+"\b"))){v[Q]="********"}else{if(Q.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)){v[Q]=r.localeDate(F)}else{if(Q.match(/^(_startTime|_updateTime)$/)){v[Q]=C(F)}}}}}}P=[];for(J in c){E=c[J];O=[];for(L=0,M=E.length;L0){P.push({title:"__"+J+"__",nodes:O})}}A("^openid","OpenID");A("^notification_(.+)","__notificationsDone__");if(v._loginHistory){N=[];if(v._loginHistory.successLogin){w=v._loginHistory.successLogin;for(K=0,z=w.length;KR.title){return 1}else{if(S.titleh&&e[r.type]){if(v=e[r.type](r.type,A,s,x,z)){x++;y=v;s=s-1}else{x=0}}else{x=0}return o.get(scriptname+"sfa/"+q+"?"+y+"&U2FCheck="+r.U2FCheck+"&TOTPCheck="+r.TOTPCheck).then(function(C){var F,D,B,G,E;F=C.data;if(F.result){E=F.values;for(D=0,B=E.length;Dh&&e[r.type]){if(v=e[r.type](r.type,A,s,x,z)){x++;y=v;s=s-1}else{x=0}}else{x=0}return o.get(scriptname+"sfa/"+q+"?_session_uid="+r.searchString+"*&groupBy=substr(_session_uid,"+r.searchString.length+")&U2FCheck="+r.U2FCheck+"&TOTPCheck="+r.TOTPCheck).then(function(C){var F,D,B,G,E;F=C.data;if(F.result){E=F.values;for(D=0,B=E.length;D0&&m<4){return k+"="+j+"*&groupBy=net("+k+","+(16*m+4*(l+1))+",2)"}else{return null}}};f="_password";c={dateTitle:["_utime","_startTime","_updateTime","_lastAuthnUTime","_lastSeen"],connectionTitle:["ipAddr","_timezone","_url"],sfaTitle:["_2fDevices"]};a={home:[]};g=angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]);g.controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(r,j,k,l,o){var p,n,m,q;r.links=links;r.menulinks=menulinks;r.staticPrefix=staticPrefix;r.scriptname=scriptname;r.formPrefix=formPrefix;r.availableLanguages=availableLanguages;r.waiting=true;r.showM=false;r.showT=true;r.data=[];r.currentScope=null;r.currentSession=null;r.menu=a;r.searchString="";r.translateP=j.translateP;r.translate=j.translate;r.translateTitle=function(s){return j.translateField(s,"title")};q="global";r.menuClick=function(s){if(s.popup){window.open(s.popup)}else{if(!s.action){s.action=s.title}switch(typeof s.action){case"function":s.action(r.currentNode,r);r[s.action]();break;case"string":r[s.action]();break;default:console.log(typeof s.action)}}return r.showM=false};r.search2FA=function(s){if(s){r.searchString=""}r.currentSession=null;r.data=[];return r.updateTree2("",r.data,0,0)};r.delete2FA=function(s,u){var t;t=angular.element("#data-"+u);t.remove();r.waiting=true;o["delete"](scriptname+"sfa/"+q+"/"+r.currentSession.id+"?type="+s+"&epoch="+u).then(function(v){return r.waiting=false},function(v){return r.waiting=false});return r.showT=false};r.stoggle=function(s){var t;t=s.$modelValue;if(t.nodes.length===0){r.updateTree(t.value,t.nodes,t.level,t.over,t.query,t.count)}return s.toggle()};r.displaySession=function(t){var u,s;s=function(v){var B,D,z,H,F,I,M,K,E,J,Q,L,A,w,R,y,P,C,N,x,O,G;D=function(S){return S};B=function(V,X){var T,U,S,W;S=[];U=new RegExp(V);for(T in v){W=v[T];if(T.match(U)&&W){S.push({title:T,value:W});delete v[T]}}if(S.length>0){return P.push({title:X,nodes:S})}};x=v._utime;E=v._session_id;for(Q in v){G=v[Q];if(!G){delete v[Q]}else{if(typeof v==="string"&&G.match(/; /)){v[Q]=G.split("; ")}if(typeof v[Q]!=="object"){if(f.match(new RegExp("\b"+Q+"\b"))){v[Q]="********"}else{if(Q.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)){v[Q]=r.localeDate(G)}else{if(Q.match(/^(_startTime|_updateTime)$/)){v[Q]=D(G)}}}}}}P=[];for(I in c){F=c[I];N=[];for(K=0,L=F.length;K0){P.push({title:"__"+I+"__",nodes:N})}}return{_utime:x,id:E,nodes:P}};r.currentScope=t;u=t.$modelValue.session;o.get(scriptname+"sfa/"+q+"/"+u).then(function(v){return r.currentSession=s(v.data)});return r.showT=false};r.localeDate=function(t){var u;u=new Date(t*1000);return u.toLocaleString()};r.getLanguage=function(s){r.lang=s;r.form="white";r.init();return r.showM=false};m=function(t,s,u){var v;v=s.match(/#\/(\w+)/);q="global";if(v===null){r.type="_whatToTrace"}else{if(v[1].match(/^(persistent)$/)){q=RegExp.$1;r.type="_session_uid"}else{r.type=v[1]}}return r.init()};r.$on("$locationChangeSuccess",m);p=0;r.updateTree=function(A,u,s,x,z,w){var y,t,v;r.waiting=true;t=i[r.type]?i[r.type]:r.type==="_updateTime"?i._startTime:i._whatToTrace;y=t[s](r.type,A,z);if(w>h&&e[r.type]){if(v=e[r.type](r.type,A,s,x,z)){x++;y=v;s=s-1}else{x=0}}else{x=0}return o.get(scriptname+"sfa/"+q+"?"+y+"&U2FCheck="+r.U2FCheck+"&TOTPCheck="+r.TOTPCheck).then(function(C){var F,D,B,G,E;F=C.data;if(F.result){E=F.values;for(D=0,B=E.length;Dh&&e[r.type]){if(v=e[r.type](r.type,A,s,x,z)){x++;y=v;s=s-1}else{x=0}}else{x=0}return o.get(scriptname+"sfa/"+q+"?_session_uid="+r.searchString+"*&groupBy=substr(_session_uid,"+r.searchString.length+")&U2FCheck="+r.U2FCheck+"&TOTPCheck="+r.TOTPCheck+"&UBKCheck="+r.UBKCheck).then(function(C){var F,D,B,G,E;F=C.data;if(F.result){E=F.values;for(D=0,B=E.length;D0&&k<4){return i+"="+h+"*&groupBy=net("+i+","+(16*k+4*(j+1))+",2)"}else{return null}}};e="_password";c={dateTitle:["_utime","_startTime","_updateTime","_lastAuthnUTime","_lastSeen"],connectionTitle:["ipAddr","_timezone","_url"],authenticationTitle:["_session_id","_user","_password","authenticationLevel"],modulesTitle:["_auth","_userDB","_passwordDB","_issuerDB","_authChoice","_authMulti","_userDBMulti"],saml:["_idp","_idpConfKey","_samlToken","_lassoSessionDump","_lassoIdentityDump"],groups:["groups","hGroups"],ldap:["dn"],BrowserID:["_browserIdAnswer","_browserIdAnswerRaw"],OpenIDConnect:["_oidc_id_token","_oidc_OP","_oidc_access_token"]};g={session:[{title:"deleteSession",icon:"trash"}],home:[]};d=angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]);d.controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(p,h,i,j,m){var n,l,k,o;p.links=links;p.menulinks=menulinks;p.staticPrefix=staticPrefix;p.scriptname=scriptname;p.formPrefix=formPrefix;p.availableLanguages=availableLanguages;p.waiting=true;p.showM=false;p.showT=true;p.data=[];p.currentScope=null;p.currentSession=null;p.menu=g;p.translateP=h.translateP;p.translate=h.translate;p.translateTitle=function(q){return h.translateField(q,"title")};o="global";p.menuClick=function(q){if(q.popup){window.open(q.popup)}else{if(!q.action){q.action=q.title}switch(typeof q.action){case"function":q.action(p.currentNode,p);break;case"string":p[q.action]();break;default:console.log(typeof q.action)}}return p.showM=false};p.deleteSession=function(){p.waiting=true;return m["delete"](scriptname+"sessions/"+o+"/"+p.currentSession.id).then(function(q){p.currentSession=null;p.currentScope.remove();return p.waiting=false},function(q){p.currentSession=null;p.currentScope.remove();return p.waiting=false})};p.stoggle=function(q){var r;r=q.$modelValue;if(r.nodes.length===0){p.updateTree(r.value,r.nodes,r.level,r.over,r.query,r.count)}return q.toggle()};p.displaySession=function(r){var s,q;q=function(t){var y,A,E,C,G,J,B,I,H,O,F,K,x,w,u,z,N,M,v,L,D;A=function(P){return P};y=function(S,U){var Q,R,P,T;P=[];R=new RegExp(S);for(Q in t){T=t[Q];if(Q.match(R)&&T){P.push({title:Q,value:T});delete t[Q]}}if(P.length>0){return N.push({title:U,nodes:P})}};v=t._utime;B=t._session_id;for(O in t){D=t[O];if(!D){delete t[O]}else{if(typeof t==="string"&&D.match(/; /)){t[O]=D.split("; ")}if(typeof t[O]!=="object"){if(e.match(new RegExp("\b"+O+"\b"))){t[O]="********"}else{if(O.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)){t[O]=p.localeDate(D)}else{if(O.match(/^(_startTime|_updateTime)$/)){t[O]=A(D)}}}}}}N=[];for(G in c){C=c[G];M=[];for(J=0,K=C.length;J0){N.push({title:"__"+G+"__",nodes:M})}}y("^openid","OpenID");y("^notification_(.+)","__notificationsDone__");if(t._loginHistory){L=[];if(t._loginHistory.successLogin){u=t._loginHistory.successLogin;for(I=0,x=u.length;IP.title){return 1}else{if(Q.titleb&&f[p.type]){if(t=f[p.type](p.type,y,q,v,x)){v++;w=t;q=q-1}else{v=0}}else{v=0}return m.get(scriptname+"sessions/"+o+"?"+w).then(function(A){var D,B,z,E,C;D=A.data;if(D.result){C=D.values;for(B=0,z=C.length;B0&&k<4){return i+"="+h+"*&groupBy=net("+i+","+(16*k+4*(j+1))+",2)"}else{return null}}};e="_password";c={dateTitle:["_utime","_startTime","_updateTime","_lastAuthnUTime","_lastSeen"],connectionTitle:["ipAddr","_timezone","_url"],authenticationTitle:["_session_id","_user","_password","authenticationLevel","_2fDevices"],modulesTitle:["_auth","_userDB","_passwordDB","_issuerDB","_authChoice","_authMulti","_userDBMulti"],saml:["_idp","_idpConfKey","_samlToken","_lassoSessionDump","_lassoIdentityDump"],groups:["groups","hGroups"],ldap:["dn"],BrowserID:["_browserIdAnswer","_browserIdAnswerRaw"],OpenIDConnect:["_oidc_id_token","_oidc_OP","_oidc_access_token"]};g={session:[{title:"deleteSession",icon:"trash"}],home:[]};d=angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]);d.controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(p,h,i,j,m){var n,l,k,o;p.links=links;p.menulinks=menulinks;p.staticPrefix=staticPrefix;p.scriptname=scriptname;p.formPrefix=formPrefix;p.availableLanguages=availableLanguages;p.waiting=true;p.showM=false;p.showT=true;p.data=[];p.currentScope=null;p.currentSession=null;p.menu=g;p.translateP=h.translateP;p.translate=h.translate;p.translateTitle=function(q){return h.translateField(q,"title")};o="global";p.menuClick=function(q){if(q.popup){window.open(q.popup)}else{if(!q.action){q.action=q.title}switch(typeof q.action){case"function":q.action(p.currentNode,p);break;case"string":p[q.action]();break;default:console.log(typeof q.action)}}return p.showM=false};p.deleteSession=function(){p.waiting=true;return m["delete"](scriptname+"sessions/"+o+"/"+p.currentSession.id).then(function(q){p.currentSession=null;p.currentScope.remove();return p.waiting=false},function(q){p.currentSession=null;p.currentScope.remove();return p.waiting=false})};p.stoggle=function(q){var r;r=q.$modelValue;if(r.nodes.length===0){p.updateTree(r.value,r.nodes,r.level,r.over,r.query,r.count)}return q.toggle()};p.displaySession=function(r){var s,q;q=function(t){var y,A,E,C,G,J,B,I,H,O,F,K,x,w,u,z,N,M,v,L,D;A=function(P){return P};y=function(S,U){var Q,R,P,T;P=[];R=new RegExp(S);for(Q in t){T=t[Q];if(Q.match(R)&&T){P.push({title:Q,value:T});delete t[Q]}}if(P.length>0){return N.push({title:U,nodes:P})}};v=t._utime;B=t._session_id;for(O in t){D=t[O];if(!D){delete t[O]}else{if(typeof t==="string"&&D.match(/; /)){t[O]=D.split("; ")}if(typeof t[O]!=="object"){if(e.match(new RegExp("\b"+O+"\b"))){t[O]="********"}else{if(O.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)){t[O]=p.localeDate(D)}else{if(O.match(/^(_startTime|_updateTime)$/)){t[O]=A(D)}}}}}}N=[];for(G in c){C=c[G];M=[];for(J=0,K=C.length;J0){N.push({title:"__"+G+"__",nodes:M})}}y("^openid","OpenID");y("^notification_(.+)","__notificationsDone__");if(t._loginHistory){L=[];if(t._loginHistory.successLogin){u=t._loginHistory.successLogin;for(I=0,x=u.length;IP.title){return 1}else{if(Q.titleb&&f[p.type]){if(t=f[p.type](p.type,y,q,v,x)){v++;w=t;q=q-1}else{v=0}}else{v=0}return m.get(scriptname+"sessions/"+o+"?"+w).then(function(A){var D,B,z,E,C;D=A.data;if(D.result){C=D.values;for(B=0,z=C.length;B
    -    + +    +    + +
@@ -54,49 +58,7 @@ - - diff --git a/lemonldap-ng-portal/site/templates/bootstrap/totp2fregister.tpl b/lemonldap-ng-portal/site/templates/bootstrap/totp2fregister.tpl index 5fd4d79d6..7a6f56848 100644 --- a/lemonldap-ng-portal/site/templates/bootstrap/totp2fregister.tpl +++ b/lemonldap-ng-portal/site/templates/bootstrap/totp2fregister.tpl @@ -49,6 +49,6 @@ //else --> - +