diff --git a/lemonldap-ng-common/lib/Lemonldap/NG/Common/PSGI/Router.pm b/lemonldap-ng-common/lib/Lemonldap/NG/Common/PSGI/Router.pm index 1c622fb9d..28a32190b 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/PSGI/Router.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/PSGI/Router.pm @@ -56,7 +56,7 @@ sub genRoute { else { $dest ||= $word; } - if ( $dest =~ /^(.+)\.html$/ ) { + if ( $word =~ /^(.+)\.html$/ and $word eq $dest ) { my $tpl = $1 or die; $self->logger->debug("route $dest will use $tpl"); $routes->{$word} = sub { $self->sendHtml( $_[1], $tpl ) }; @@ -305,8 +305,8 @@ the subroutine will be called with the word of path_info as second argument =item 'something.html': -if $word finishes with '.html', then sendHtml() will be called with -'something.tpl' as template name. In this case, $dest is not used. +if $word finishes with '.html', and $dest is undef, then sendHtml() will be +called with 'something.tpl' as template name. =back diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/2ndFA.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/2ndFA.pm index c95fdd703..80e8e5b74 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/2ndFA.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/2ndFA.pm @@ -15,7 +15,6 @@ extends qw( Lemonldap::NG::Common::Conf::AccessLib ); -use constant _2FTYPES => [ "UBK", "U2F", "TOTP", "WebAuthn" ]; our $VERSION = '2.0.10'; ############################# @@ -29,7 +28,7 @@ sub init { # Remote Procedure are defined in Lemonldap::NG::Common::Session::REST # HTML template - $self->addRoute( '2ndfa.html', undef, ['GET'] ) + $self->addRoute( '2ndfa.html', 'sfaView', ['GET'] ) ->addRoute( sfa => { ':sessionType' => 'sfa' }, @@ -47,8 +46,11 @@ sub init { $self->{hiddenAttributes} //= "_password"; $self->{hiddenAttributes} .= ' _session_id' unless $conf->{displaySessionId}; - $self->{TOTPCheck} = $self->{U2FCheck} = $self->{UBKCheck} = - $self->{WebAuthnCheck} = '1'; + + $self->{regSfaTypes} = [ + sort map { s/^Yubikey$/UBK/r } split /[\s,]+/, + $conf->{available2FSelfRegistration} + ]; return 1; } @@ -69,14 +71,9 @@ sub del2F { my $epoch = $params->{epoch} or return $self->sendError( $req, 'Missing "epoch" parameter', 400 ); - if ( grep { $_ eq $type } @{ _2FTYPES() } ) { - $self->logger->debug( - "Call procedure delete2F with type=$type and epoch=$epoch"); - return $self->delete2F( $req, $session, $skey ); - } - else { - return $self->sendError( $req, 'Bad value "type" parameter', 400 ); - } + $self->logger->debug( + "Call procedure delete2F with type=$type and epoch=$epoch"); + return $self->delete2F( $req, $session, $skey ); } ######################## @@ -118,11 +115,8 @@ sub sfa { my $moduleOptions = $mod->{options}; $moduleOptions->{backend} = $mod->{module}; - # Select 2FA sessions to display - foreach ( @{ _2FTYPES() } ) { - $self->{ $_ . 'Check' } = delete $params->{ $_ . 'Check' } - if ( defined $params->{ $_ . 'Check' } ); - } + my @display_types = $params->get_all('type'); + $params->remove('type'); my %filters = map { my $s = $_; @@ -190,19 +184,18 @@ sub sfa { # Remove sessions without at least one 2F device(s) $self->logger->debug( "Removing sessions without at least one 2F device(s)..."); - my $_2f_types_re = join( '|', @{ _2FTYPES() } ); foreach my $session ( keys %$res ) { delete $res->{$session} unless ( defined $res->{$session}->{_2fDevices} - and $res->{$session}->{_2fDevices} =~ - /"type":\s*"(?:$_2f_types_re)"/s ); + and $res->{$session}->{_2fDevices} =~ /"type"/s ); } - # Filter 2FA sessions if needed - $self->logger->debug("Filtering 2F sessions..."); my $all = ( keys %$res ); - foreach ( @{ _2FTYPES() } ) { - if ( $self->{ $_ . 'Check' } eq '2' ) { + + # Filter 2FA sessions if needed + if (@display_types) { + $self->logger->debug("Filtering 2F sessions..."); + foreach (@display_types) { foreach my $session ( keys %$res ) { delete $res->{$session} unless ( defined $res->{$session}->{_2fDevices} @@ -286,4 +279,14 @@ qq{Use of an uninitialized attribute "$group" to group sessions}, ); } +sub sfaView { + my ( $self, $req ) = @_; + return $self->p->sendHtml( + $req, "2ndfa", + params => { + SFATYPES => [ map { { SFATYPE => $_ } } @{ $self->{regSfaTypes} } ], + } + ); +} + 1; diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api.pm index 6b7427677..9e7b291cd 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api.pm @@ -228,7 +228,6 @@ sub init { $self->setTypes($conf); $self->{multiValuesSeparator} ||= '; '; $self->{hiddenAttributes} //= "_password"; - $self->{TOTPCheck} = $self->{U2FCheck} = $self->{UBKCheck} = '1'; return 1; } diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api/2F.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api/2F.pm index fa3fb25b9..918339607 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api/2F.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Api/2F.pm @@ -139,11 +139,6 @@ sub _get2F { my ( $self, $uid, $type, $id ) = @_; my ( $res, $psessions, @secondFactors ); - if ( defined $type ) { - $res = $self->_checkType($type); - return $res if ( $res->{res} ne 'ok' ); - } - $psessions = $self->_getSessions2F( $self->_getPersistentMod, 'Persistent', '_session_uid', $uid ); @@ -279,10 +274,6 @@ sub _delete2FFromSessions { sub _delete2F { my ( $self, $uid, $type, $id ) = @_; my ( $res, $removed, $count ); - if ( defined $type ) { - $res = $self->_checkType($type); - return $res if ( $res->{res} ne 'ok' ); - } $res = $self->_delete2FFromSessions( $uid, $type, $id, $self->_getPersistentMod, @@ -331,18 +322,4 @@ sub _getDevicesFromSessionData { return []; } -sub _checkType { - my ( $self, $type ) = @_; - - return { - res => "ko", - code => 400, - msg => -"Invalid input: Type \"$type\" does not exist. Allowed values for type are: \"U2F\", \"TOTP\", \"WebAuthn\" or \"UBK\"" - } - unless ( $type =~ /\b(?:U2F|TOTP|UBK|WebAuthn)\b/i ); - - return { res => "ok" }; -} - 1; diff --git a/lemonldap-ng-manager/site/coffee/2ndfa.coffee b/lemonldap-ng-manager/site/coffee/2ndfa.coffee index f1ba0ac2a..9e2198d3d 100644 --- a/lemonldap-ng-manager/site/coffee/2ndfa.coffee +++ b/lemonldap-ng-manager/site/coffee/2ndfa.coffee @@ -70,10 +70,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', $scope.currentSession = null $scope.menu = menu $scope.searchString = '' - $scope.U2FCheck = "1" - $scope.TOTPCheck = "1" - $scope.UBKCheck = "1" - $scope.WebAuthnCheck = "1" + $scope.sfatypes = {} # Import translations functions $scope.translateP = $translator.translateP @@ -202,24 +199,26 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', subres = [] for attr in attrs if session[attr] - if session[attr].toString().match(/"type":\s*"(?:TOTP|U2F|UBK|WebAuthn)"/) - subres.push - title: "type" - value: "name" - epoch: "date" + if attr == "_2fDevices" && session[attr] 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 + if array.length > 0 subres.push - title: title - value: name - epoch: epoch + title: "type" + value: "name" + epoch: "date" + for sfDevice in array + for key, value of sfDevice + if key == 'type' + title = value + if key == 'name' + name = value + if key == 'epoch' + epoch = value + subres.push + title: title + value: name + epoch: epoch + sfrow: true delete session[attr] else if session[attr].toString().match(/\w+/) subres.push @@ -296,7 +295,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', over = 0 # Launch HTTP query - $http.get("#{scriptname}sfa/#{sessionType}?#{query}&U2FCheck=#{$scope.U2FCheck}&TOTPCheck=#{$scope.TOTPCheck}&UBKCheck=#{$scope.UBKCheck}&WebAuthnCheck=#{$scope.WebAuthnCheck}").then (response) -> + $http.get("#{scriptname}sfa/#{sessionType}?#{query}"+Object.entries($scope.sfatypes).map((x) -> if x[1] then "&type=" + x[0] else "").join("")).then (response) -> data = response.data if data.result for n in data.values @@ -347,7 +346,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}&UBKCheck=#{$scope.UBKCheck}&WebAuthnCheck=#{$scope.WebAuthnCheck}").then (response) -> + $http.get("#{scriptname}sfa/#{sessionType}?_session_uid=#{$scope.searchString}*&groupBy=substr(_session_uid,#{$scope.searchString.length})"+Object.entries($scope.sfatypes).map((x) -> if x[1] then "&type=" + x[0] else "").join("")).then (response) -> data = response.data if data.result for n in data.values diff --git a/lemonldap-ng-manager/site/coffee/sessions.coffee b/lemonldap-ng-manager/site/coffee/sessions.coffee index ad0e2aa7b..b10c920da 100644 --- a/lemonldap-ng-manager/site/coffee/sessions.coffee +++ b/lemonldap-ng-manager/site/coffee/sessions.coffee @@ -254,26 +254,27 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', subres = [] for attr in attrs if session[attr] - if session[attr].toString().match(/"type":\s*"(?:TOTP|U2F|UBK|WebAuthn)"/) - subres.push - title: "type" - value: "name" - epoch: "date" - td: "0" + if attr == "_2fDevices" && session[attr] 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 + if array.length > 0 subres.push - title: title - value: name - epoch: epoch - td: "1" + title: "type" + value: "name" + epoch: "date" + td: "0" + for sfDevice in array + for key, value of sfDevice + if key == 'type' + title = value + if key == 'name' + name = value + if key == 'epoch' + epoch = value + subres.push + title: title + value: name + epoch: epoch + td: "1" delete session[attr] else if session[attr].toString().match(/"rp":\s*"[\w-]+"/) subres.push diff --git a/lemonldap-ng-manager/site/htdocs/static/js/2ndfa.js b/lemonldap-ng-manager/site/htdocs/static/js/2ndfa.js index 06857b174..b023164be 100644 --- a/lemonldap-ng-manager/site/htdocs/static/js/2ndfa.js +++ b/lemonldap-ng-manager/site/htdocs/static/js/2ndfa.js @@ -86,10 +86,7 @@ $scope.currentSession = null; $scope.menu = menu; $scope.searchString = ''; - $scope.U2FCheck = "1"; - $scope.TOTPCheck = "1"; - $scope.UBKCheck = "1"; - $scope.WebAuthnCheck = "1"; + $scope.sfatypes = {}; $scope.translateP = $translator.translateP; $scope.translate = $translator.translate; $scope.translateTitle = function(node) { @@ -206,32 +203,35 @@ for (i = 0, len = attrs.length; i < len; i++) { attr = attrs[i]; if (session[attr]) { - if (session[attr].toString().match(/"type":\s*"(?:TOTP|U2F|UBK|WebAuthn)"/)) { - subres.push({ - title: "type", - value: "name", - epoch: "date" - }); + if (attr === "_2fDevices" && session[attr]) { 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; - } - } + if (array.length > 0) { subres.push({ - title: title, - value: name, - epoch: epoch + title: "type", + value: "name", + epoch: "date" }); + 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; + } + } + subres.push({ + title: title, + value: name, + epoch: epoch, + sfrow: true + }); + } } delete session[attr]; } else if (session[attr].toString().match(/\w+/)) { @@ -304,7 +304,13 @@ } else { over = 0; } - return $http.get(scriptname + "sfa/" + sessionType + "?" + query + "&U2FCheck=" + $scope.U2FCheck + "&TOTPCheck=" + $scope.TOTPCheck + "&UBKCheck=" + $scope.UBKCheck + "&WebAuthnCheck=" + $scope.WebAuthnCheck).then(function(response) { + return $http.get((scriptname + "sfa/" + sessionType + "?" + query) + Object.entries($scope.sfatypes).map(function(x) { + if (x[1]) { + return "&type=" + x[0]; + } else { + return ""; + } + }).join("")).then(function(response) { var data, i, len, n, ref; data = response.data; if (data.result) { @@ -346,7 +352,13 @@ } 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 + "&UBKCheck=" + $scope.UBKCheck + "&WebAuthnCheck=" + $scope.WebAuthnCheck).then(function(response) { + return $http.get((scriptname + "sfa/" + sessionType + "?_session_uid=" + $scope.searchString + "*&groupBy=substr(_session_uid," + $scope.searchString.length + ")") + Object.entries($scope.sfatypes).map(function(x) { + if (x[1]) { + return "&type=" + x[0]; + } else { + return ""; + } + }).join("")).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 32a45b1b7..857e6fcca 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 a={_whatToTrace:[function(e,t){return"groupBy=substr("+e+",1)"},function(e,t){return e+"="+t+"*"}]},d={_whatToTrace:function(e,t,n,r){return console.log("overSchema => level",n,"over",r),1===n&&t.length>r?e+"="+t+"*&groupBy=substr("+e+","+(n+r+1)+")":null}},v={dateTitle:["_utime","_startTime","_updateTime"],sfaTitle:["_2fDevices"]},i={home:[]};angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]).controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(y,t,e,n,h){var p,r,f;return y.links=links,y.menulinks=menulinks,y.staticPrefix=staticPrefix,y.scriptname=scriptname,y.formPrefix=formPrefix,y.availableLanguages=availableLanguages,y.waiting=!0,y.showM=!1,y.showT=!0,y.data=[],y.currentScope=null,y.currentSession=null,y.menu=i,y.searchString="",y.U2FCheck="1",y.TOTPCheck="1",y.UBKCheck="1",y.WebAuthnCheck="1",y.translateP=t.translateP,y.translate=t.translate,y.translateTitle=function(e){return t.translateField(e,"title")},f="persistent",y.menuClick=function(e){if(e.popup)window.open(e.popup);else switch(e.action||(e.action=e.title),typeof e.action){case"function":e.action(y.currentNode,y),y[e.action]();break;case"string":y[e.action]();break;default:console.log(typeof e.action)}return y.showM=!1},y.search2FA=function(e){return e&&(y.searchString=""),y.currentSession=null,y.data=[],y.updateTree2("",y.data,0,0)},y.delete2FA=function(e,t){for(var n=document.querySelectorAll(".data-"+t),r=0,a=n.length;r level",n,"over",r),1===n&&t.length>r?e+"="+t+"*&groupBy=substr("+e+","+(n+r+1)+")":null}},_={dateTitle:["_utime","_startTime","_updateTime"],sfaTitle:["_2fDevices"]},i={home:[]};angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]).controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(v,t,e,n,p){var f,r,h;return v.links=links,v.menulinks=menulinks,v.staticPrefix=staticPrefix,v.scriptname=scriptname,v.formPrefix=formPrefix,v.availableLanguages=availableLanguages,v.waiting=!0,v.showM=!1,v.showT=!0,v.data=[],v.currentScope=null,v.currentSession=null,v.menu=i,v.searchString="",v.sfatypes={},v.translateP=t.translateP,v.translate=t.translate,v.translateTitle=function(e){return t.translateField(e,"title")},h="persistent",v.menuClick=function(e){if(e.popup)window.open(e.popup);else switch(e.action||(e.action=e.title),typeof e.action){case"function":e.action(v.currentNode,v),v[e.action]();break;case"string":v[e.action]();break;default:console.log(typeof e.action)}return v.showM=!1},v.search2FA=function(e){return e&&(v.searchString=""),v.currentSession=null,v.data=[],v.updateTree2("",v.data,0,0)},v.delete2FA=function(e,t){for(var n=document.querySelectorAll(".data-"+t),r=0,a=n.length;r 0) { subres.push({ - title: title, - value: name, - epoch: epoch, - td: "1" + title: "type", + value: "name", + epoch: "date", + td: "0" }); + for (j = 0, len1 = array.length; j < len1; j++) { + sfDevice = array[j]; + for (key in sfDevice) { + value = sfDevice[key]; + if (key === 'type') { + title = value; + } + if (key === 'name') { + name = value; + } + if (key === 'epoch') { + epoch = value; + } + } + subres.push({ + title: title, + value: name, + epoch: epoch, + td: "1" + }); + } } delete session[attr]; } else if (session[attr].toString().match(/"rp":\s*"[\w-]+"/)) { diff --git a/lemonldap-ng-manager/site/htdocs/static/js/sessions.min.js b/lemonldap-ng-manager/site/htdocs/static/js/sessions.min.js index ad8a2f878..037ae827c 100644 --- a/lemonldap-ng-manager/site/htdocs/static/js/sessions.min.js +++ b/lemonldap-ng-manager/site/htdocs/static/js/sessions.min.js @@ -1 +1 @@ -!function(){var f={_whatToTrace:[function(e,t){return"groupBy=substr("+e+",1)"},function(e,t){return e+"="+t+"*&groupBy="+e},function(e,t){return e+"="+t}],ipAddr:[function(e,t){return"groupBy=net("+e+",16,1)"},function(e,t){return t.match(/:/)||(t+="."),e+"="+t+"*&groupBy=net("+e+",32,2)"},function(e,t){return t.match(/:/)||(t+="."),e+"="+t+"*&groupBy=net("+e+",48,3)"},function(e,t){return t.match(/:/)||(t+="."),e+"="+t+"*&groupBy=net("+e+",128,4)"},function(e,t){return e+"="+t+"&groupBy=_whatToTrace"},function(e,t,n){return n.replace(/\&groupBy.*$/,"")+"&_whatToTrace="+t}],_startTime:[function(e,t){return"groupBy=substr("+e+",8)"},function(e,t){return e+"="+t+"*&groupBy=substr("+e+",10)"},function(e,t){return e+"="+t+"*&groupBy=substr("+e+",11)"},function(e,t){return e+"="+t+"*&groupBy=substr("+e+",12)"},function(e,t){return e+"="+t+"*&groupBy=_whatToTrace"},function(e,t,n){return console.log(e),console.log(t),console.log(n),n.replace(/\&groupBy.*$/,"")+"&_whatToTrace="+t}],doubleIp:[function(e,t){return e},function(e,t){return"_whatToTrace="+t+"&groupBy=ipAddr"},function(e,t,n){return n.replace(/\&groupBy.*$/,"")+"&ipAddr="+t}],_session_uid:[function(e,t){return"groupBy=substr("+e+",1)"},function(e,t){return e+"="+t+"*&groupBy="+e},function(e,t){return e+"="+t}]},g={_whatToTrace:function(e,t,n,o){return console.log("overScheme => level",n,"over",o),1===n&&t.length>o?e+"="+t+"*&groupBy=substr("+e+","+(n+o+1)+")":null},ipAddr:function(e,t,n,o){return console.log("overScheme => level",n,"over",o),0 level",n,"over",o),3 level",n,"over",o),1===n&&t.length>o?e+"="+t+"*&groupBy=substr("+e+","+(n+o+1)+")":null}},M={dateTitle:["_utime","_startTime","_updateTime","_lastAuthnUTime","_lastSeen"],connectionTitle:["ipAddr","_timezone","_url"],authenticationTitle:["_session_id","_user","_password","authenticationLevel"],modulesTitle:["_auth","_userDB","_passwordDB","_issuerDB","_authChoice","_authMulti","_userDBMulti","_2f"],saml:["_idp","_idpConfKey","_samlToken","_lassoSessionDump","_lassoIdentityDump"],groups:["groups","hGroups"],ldap:["dn"],OpenIDConnect:["_oidc_id_token","_oidc_OP","_oidc_access_token","_oidc_refresh_token","_oidc_access_token_eol"],sfaTitle:["_2fDevices"],oidcConsents:["_oidcConsents"]},i={session:[{title:"deleteSession",icon:"trash"}],home:[]};angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]).controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(H,t,r,e,o){var p,n,d;return H.links=links,H.menulinks=menulinks,H.staticPrefix=staticPrefix,H.scriptname=scriptname,H.formPrefix=formPrefix,H.impPrefix=impPrefix,H.sessionTTL=sessionTTL,H.availableLanguages=availableLanguages,H.waiting=!0,H.showM=!1,H.showT=!0,H.data=[],H.currentScope=null,H.currentSession=null,H.menu=i,H.translateP=t.translateP,H.translate=t.translate,H.translateTitle=function(e){return t.translateField(e,"title")},d="global",H.menuClick=function(e){if(e.popup)window.open(e.popup);else switch(e.action||(e.action=e.title),typeof e.action){case"function":e.action(H.currentNode,H);break;case"string":H[e.action]();break;default:console.log(typeof e.action)}return H.showM=!1},H.deleteOIDCConsent=function(e,t){var i=document.querySelectorAll(".data-"+t);return H.waiting=!0,o.delete(scriptname+"sessions/OIDCConsent/"+d+"/"+H.currentSession.id+"?rp="+e+"&epoch="+t).then(function(e){var t,n,o,r;for(H.waiting=!1,r=[],n=0,o=i.length;nt.title?1:e.title real attribute"),A.push(c)):k.push(c);return s=k.concat(A),d.push({title:"__attributesAndMacros__",nodes:s}),{_utime:E,nodes:d}};return H.currentScope=e,t=e.$modelValue.session,o.get(scriptname+"sessions/"+d+"/"+t).then(function(e){return H.currentSession=n(e.data),H.currentSession.id=t}),H.showT=!1},H.localeDate=function(e){return new Date(1e3*e).toLocaleString()},H.isValid=function(e,t){var n=r.path(),o=Date.now()/1e3;return console.log("Path",n),console.log("Session epoch",e),console.log("Current date",o),console.log("Session TTL",sessionTTL),n=o-e level",n,"over",o),1===n&&t.length>o?e+"="+t+"*&groupBy=substr("+e+","+(n+o+1)+")":null},ipAddr:function(e,t,n,o){return console.log("overScheme => level",n,"over",o),0 level",n,"over",o),3 level",n,"over",o),1===n&&t.length>o?e+"="+t+"*&groupBy=substr("+e+","+(n+o+1)+")":null}},O={dateTitle:["_utime","_startTime","_updateTime","_lastAuthnUTime","_lastSeen"],connectionTitle:["ipAddr","_timezone","_url"],authenticationTitle:["_session_id","_user","_password","authenticationLevel"],modulesTitle:["_auth","_userDB","_passwordDB","_issuerDB","_authChoice","_authMulti","_userDBMulti","_2f"],saml:["_idp","_idpConfKey","_samlToken","_lassoSessionDump","_lassoIdentityDump"],groups:["groups","hGroups"],ldap:["dn"],OpenIDConnect:["_oidc_id_token","_oidc_OP","_oidc_access_token","_oidc_refresh_token","_oidc_access_token_eol"],sfaTitle:["_2fDevices"],oidcConsents:["_oidcConsents"]},i={session:[{title:"deleteSession",icon:"trash"}],home:[]};angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]).controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function(M,t,r,e,o){var p,n,d;return M.links=links,M.menulinks=menulinks,M.staticPrefix=staticPrefix,M.scriptname=scriptname,M.formPrefix=formPrefix,M.impPrefix=impPrefix,M.sessionTTL=sessionTTL,M.availableLanguages=availableLanguages,M.waiting=!0,M.showM=!1,M.showT=!0,M.data=[],M.currentScope=null,M.currentSession=null,M.menu=i,M.translateP=t.translateP,M.translate=t.translate,M.translateTitle=function(e){return t.translateField(e,"title")},d="global",M.menuClick=function(e){if(e.popup)window.open(e.popup);else switch(e.action||(e.action=e.title),typeof e.action){case"function":e.action(M.currentNode,M);break;case"string":M[e.action]();break;default:console.log(typeof e.action)}return M.showM=!1},M.deleteOIDCConsent=function(e,t){var i=document.querySelectorAll(".data-"+t);return M.waiting=!0,o.delete(scriptname+"sessions/OIDCConsent/"+d+"/"+M.currentSession.id+"?rp="+e+"&epoch="+t).then(function(e){var t,n,o,r;for(M.waiting=!1,r=[],n=0,o=i.length;nt.title?1:e.title real attribute"),B.push(i)):P.push(i);return I=P.concat(B),L.push({title:"__attributesAndMacros__",nodes:I}),{_utime:H,nodes:L}};return M.currentScope=e,t=e.$modelValue.session,o.get(scriptname+"sessions/"+d+"/"+t).then(function(e){return M.currentSession=n(e.data),M.currentSession.id=t}),M.showT=!1},M.localeDate=function(e){return new Date(1e3*e).toLocaleString()},M.isValid=function(e,t){var n=r.path(),o=Date.now()/1e3;return console.log("Path",n),console.log("Session epoch",e),console.log("Current date",o),console.log("Session TTL",sessionTTL),e=o-e @@ -107,17 +101,14 @@
- {{translate(node.title)}} - {{node.title}} - {{translate(node.value)}} - {{node.value}} - {{translate(node.epoch)}} - {{localeDate(node.epoch)}} + {{translate(node.title)}} + {{node.title}} + {{translate(node.value)}} + {{node.value}} + {{translate(node.epoch)}} + {{localeDate(node.epoch)}} - - +
diff --git a/lemonldap-ng-manager/site/templates/sessions.tpl b/lemonldap-ng-manager/site/templates/sessions.tpl index db561bb10..90a6f5b49 100644 --- a/lemonldap-ng-manager/site/templates/sessions.tpl +++ b/lemonldap-ng-manager/site/templates/sessions.tpl @@ -107,9 +107,6 @@ {{localeDate(node.epoch)}} - diff --git a/lemonldap-ng-manager/t/04-2F-api.t b/lemonldap-ng-manager/t/04-2F-api.t index 364647435..7167c8ded 100644 --- a/lemonldap-ng-manager/t/04-2F-api.t +++ b/lemonldap-ng-manager/t/04-2F-api.t @@ -135,14 +135,6 @@ sub checkGetList { return $ret; } -sub checkGetBadType { - my ( $uid, $type ) = splice @_; - my ( $test, $res ); - $test = "Get for uid $uid and type \"$type\" should get rejected."; - $res = get( $test, $uid, $type ); - check400( $test, $res ); -} - sub checkGetOnIds { my ( $uid, $ret ) = splice @_; foreach (@$ret) { @@ -313,7 +305,7 @@ checkGetList( 1, 'dwho', 'U2F' ); checkGetList( 1, 'dwho', 'TOTP' ); checkGetList( 1, 'dwho', 'UBK' ); checkGetList( 1, 'dwho', 'WebAuthn' ); -checkGetBadType( 'dwho', 'UBKIKI' ); +checkGetList( 0, 'dwho', 'UBKIKI' ); $ret = checkGetList( 4, 'dwho' ); checkGetOnIds( 'dwho', $ret ); checkDelete( 'dwho', @$ret[0]->{id} ); diff --git a/lemonldap-ng-manager/t/60-2ndfa.t b/lemonldap-ng-manager/t/60-2ndfa.t index fff93623c..0ecd12ad8 100644 --- a/lemonldap-ng-manager/t/60-2ndfa.t +++ b/lemonldap-ng-manager/t/60-2ndfa.t @@ -147,8 +147,7 @@ ok( ( $res->{_2fDevices} and $res->{_2fDevices} =~ /"type":\s*"UBK"/s ), count(5); ## "All" query -$res = &client->jsonResponse( '/sfa/persistent', - 'groupBy=substr(uid,1)&U2FCheck=1&TOTPCheck=1&UBKCheck=1' ); +$res = &client->jsonResponse( '/sfa/persistent', 'groupBy=substr(uid,1)' ); ok( $res->{result} == 1, 'Search * - Result code = 1' ); ok( $res->{count} == 3, 'Found 3 results' ) or print STDERR Dumper($res); ok( @{ $res->{values} } == 3, 'List 3 results' ); @@ -168,8 +167,8 @@ count(9); ## "Search by UID" query # uid=d* -$res = &client->jsonResponse( '/sfa/persistent', - 'uid=d*&groupBy=substr(uid,1)&U2FCheck=1&TOTPCheck=1&UBKCheck=1' ); +$res = + &client->jsonResponse( '/sfa/persistent', 'uid=d*&groupBy=substr(uid,1)' ); ok( $res->{result} == 1, 'Search "uid"=d* - Result code = 1' ); ok( $res->{count} == 1, 'Found 1 result' ) or print STDERR Dumper($res); ok( @{ $res->{values} } == 1, 'List 1 result' ); @@ -180,8 +179,8 @@ ok( $res->{values}->[0]->{count} == 2, 'Found 2 sessions starting with "d"' ); count(5); # uid=dw* -$res = &client->jsonResponse( '/sfa/persistent', - 'uid=dw*&groupBy=substr(uid,2)&U2FCheck=1&TOTPCheck=1&UBKCheck=1' ); +$res = + &client->jsonResponse( '/sfa/persistent', 'uid=dw*&groupBy=substr(uid,2)' ); ok( $res->{result} == 1, 'Search "uid"=dw* - Result code = 1' ); ok( $res->{count} == 1, 'Found 1 result' ) or print STDERR Dumper($res); ok( @{ $res->{values} } == 1, 'List 1 result' ); @@ -193,7 +192,7 @@ count(5); # uid=d* & UBK $res = &client->jsonResponse( '/sfa/persistent', - 'uid=d*&groupBy=substr(uid,1)&U2FCheck=1&TOTPCheck=1&UBKCheck=2' ); + 'uid=d*&groupBy=substr(uid,1)&type=UBK' ); ok( $res->{result} == 1, 'Search "uid"=d* & UBK - Result code = 1' ); ok( $res->{count} == 1, 'Found 1 result' ) or print STDERR Dumper($res); ok( @{ $res->{values} } == 1, 'List 1 result' ); @@ -208,7 +207,7 @@ count(5); # uid=dw* & UBK $res = &client->jsonResponse( '/sfa/persistent', - 'uid=dw*&groupBy=substr(uid,2)&U2FCheck=1&TOTPCheck=1&UBKCheck=2' ); + 'uid=dw*&groupBy=substr(uid,2)&type=UBK' ); ok( $res->{result} == 1, 'Search "uid"=dw* & UBK - Result code = 1' ); ok( $res->{count} == 1, 'Found 1 result' ) or print STDERR Dumper($res); ok( @{ $res->{values} } == 1, 'List 1 result' ); @@ -223,7 +222,7 @@ count(5); # uid=da* & UBK $res = &client->jsonResponse( '/sfa/persistent', - 'uid=da*&groupBy=substr(uid,2)&U2FCheck=1&TOTPCheck=1&UBKCheck=2' ); + 'uid=da*&groupBy=substr(uid,2)&type=UBK' ); ok( $res->{result} == 1, 'Search "uid"=da* & UBK - Result code = 1' ); ok( $res->{count} == 0, 'Found 0 session with "da" & UBK' ) or print STDERR Dumper($res); @@ -232,7 +231,7 @@ count(3); ## "Filtered by U2F" query $res = &client->jsonResponse( '/sfa/persistent', - 'uid=*&groupBy=substr(uid,0)&U2FCheck=2&TOTPCheck=1&UBKCheck=1' ); + 'uid=*&groupBy=substr(uid,0)&type=U2F' ); ok( $res->{result} == 1, 'Search "uid"=* & UBK - Result code = 1' ); ok( $res->{count} == 3, 'Found 3 results' ) or print STDERR Dumper($res); ok( @{ $res->{values} } == 3, 'List 3 results' ); @@ -261,7 +260,7 @@ count(9); ## "Filtered by U2F & TOTP" query $res = &client->jsonResponse( '/sfa/persistent', - 'uid=*&groupBy=substr(uid,0)&U2FCheck=2&TOTPCheck=2&UBKCheck=1' ); + 'uid=*&groupBy=substr(uid,0)&type=U2F&type=TOTP' ); ok( $res->{result} == 1, 'Search "uid"=* & UBK & TOTP - Result code = 1' ); ok( $res->{count} == 1, 'Found 1 result' ) or print STDERR Dumper($res); ok( @{ $res->{values} } == 1, 'List 1 result' ); @@ -274,7 +273,7 @@ count(5); ## "Filtered by U2F & TOTP & UBK" query $res = &client->jsonResponse( '/sfa/persistent', - 'uid=*&groupBy=substr(uid,0)&U2FCheck=2&TOTPCheck=2&UBKCheck=2' ); + 'uid=*&groupBy=substr(uid,0)&type=U2F&type=TOTP&type=UBK' ); ok( $res->{result} == 1, 'Search "uid"=* & UBK & TOTP & UBK - Result code = 1' ); ok( $res->{count} == 1, 'Found 1 result' ) or print STDERR Dumper($res); @@ -288,7 +287,7 @@ count(5); ## "Filtered by U2F & UBK" query $res = &client->jsonResponse( '/sfa/persistent', - 'uid=*&groupBy=substr(uid,0)&U2FCheck=2&TOTPCheck=1&UBKCheck=2' ); + 'uid=*&groupBy=substr(uid,0)&type=U2F&type=UBK' ); ok( $res->{result} == 1, 'Search "uid"=* & UBK & UBK - Result code = 1' ); ok( $res->{count} == 2, 'Found 2 results' ) or print STDERR Dumper($res); ok( @{ $res->{values} } == 2, 'List 2 results' ); @@ -345,14 +344,18 @@ foreach ( 2 .. 3 ) { } ## Check than all devices have been deleted with "All" query -$res = &client->jsonResponse( '/sfa/persistent', - 'groupBy=substr(uid,1)&U2FCheck=1&TOTPCheck=1&UBKCheck=1' ); +$res = &client->jsonResponse( '/sfa/persistent', 'groupBy=substr(uid,1)' ); ok( $res->{result} == 1, 'Result code = 1' ); ok( $res->{count} == 0, 'Found 0 session with 2F device' ) or print STDERR Dumper($res); ok( @{ $res->{values} } == 0, 'List 0 result' ); count(3); +ok( $res = &client->_get('/2ndfa.html'), 'Succeed to get /2ndfa.html' ); +like( $res->[2]->[0], + qr,, ); +count(2); + done_testing( count() ); # Remove sessions directory