From 9dfce47dfb59f795220c44c93dcce7813d556378 Mon Sep 17 00:00:00 2001 From: Christophe Maudoux Date: Thu, 1 Mar 2018 00:07:31 +0100 Subject: [PATCH] WIP - Append U2F module to manage users U2F Key (delete only at the moment) --- .gitignore | 24 +++++++++++++++++++ e2e-tests/lemonldap-ng-ldap.ini | 1 + .../lib/Lemonldap/NG/Common/Session/REST.pm | 23 +++++++++--------- .../lib/Lemonldap/NG/Manager.pm | 2 +- .../lib/Lemonldap/NG/Manager/U2F.pm | 20 ++++++++-------- lemonldap-ng-manager/site/coffee/u2f.coffee | 8 +++---- .../site/htdocs/static/js/sessions.js | 2 +- .../site/htdocs/static/js/u2f.js | 6 ++--- .../site/htdocs/static/js/u2f.min.js | 2 +- lemonldap-ng-manager/site/templates/u2f.tpl | 4 +--- 10 files changed, 57 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index 3c3629e64..8b59be3fb 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,25 @@ node_modules +e2e-tests/conf/ +lemonldap-ng-common/MYMETA.json +lemonldap-ng-common/MYMETA.yml +lemonldap-ng-common/Makefile +lemonldap-ng-common/blib/ +lemonldap-ng-common/pm_to_blib +lemonldap-ng-handler/MYMETA.json +lemonldap-ng-handler/MYMETA.yml +lemonldap-ng-handler/Makefile +lemonldap-ng-handler/blib/ +lemonldap-ng-handler/pm_to_blib +lemonldap-ng-manager/MYMETA.json +lemonldap-ng-manager/MYMETA.yml +lemonldap-ng-manager/Makefile +lemonldap-ng-manager/blib/ +lemonldap-ng-manager/pm_to_blib +lemonldap-ng-portal/MYMETA.json +lemonldap-ng-portal/MYMETA.yml +lemonldap-ng-portal/Makefile +lemonldap-ng-portal/blib/ +lemonldap-ng-portal/t/ +.gitignore +lemonldap-ng-portal/pm_to_blib +e2e-tests/lemonldap-ng.ini diff --git a/e2e-tests/lemonldap-ng-ldap.ini b/e2e-tests/lemonldap-ng-ldap.ini index 06ec231b2..128765aff 100644 --- a/e2e-tests/lemonldap-ng-ldap.ini +++ b/e2e-tests/lemonldap-ng-ldap.ini @@ -32,6 +32,7 @@ useRedirectOnError = 0 [manager] +enabledModules = conf, sessions, notifications, U2F protection = manager staticPrefix = /static languages = fr, en, vi, ar 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 382d4d8d4..de21cb766 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Session/REST.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Session/REST.pm @@ -33,6 +33,8 @@ sub hAttr { $_[0]->{hiddenAttributes} || $_[0]->conf->{hiddenAttributes}; } +### SEE LEMONLDAP::NG::COMMON::SESSION FOR AVAILABLE FUNCTIONS + sub delSession { my ( $self, $req ) = @_; return $self->sendJSONresponse( $req, { result => 1 } ) @@ -61,20 +63,17 @@ sub delU2FKey { # Try to read session - my $apacheSession = $self->getApacheSession( $mod, $id ) + my $session = $self->getApacheSession( $mod, $id ) or return $self->sendError( $req, undef, 400 ); - - my %session = %{ $apacheSession->data }; - $session{_session_uid} = 'TOTO'; - - $apacheSession->update(\%session); - - #return $self->sendError( $req, $session->data->{_session_uid}, 666 ); - - + + # 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 ( $apacheSession->error ) { - return $self->sendError( $req, $apacheSession->error, 200 ); + if ( $session->error ) { + return $self->sendError( $req, $session->error, 200 ); } return $self->sendJSONresponse( $req, { result => 1 } ); } diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager.pm index 22c6114bb..ad89c8d1c 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager.pm @@ -90,7 +90,7 @@ sub init { $self->defaultRoute( $working[0]->defaultRoute ); my $linksIcons = - { 'conf' => 'cog', 'sessions' => 'duplicate', 'notifications' => 'bell' }; + { 'conf' => 'cog', 'sessions' => 'duplicate', 'notifications' => 'bell', 'U2F' => 'wrench' }; $self->links( [] ); for ( my $i = 0 ; $i < @links ; $i++ ) { diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/U2F.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/U2F.pm index aa7fe4088..4281902e0 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/U2F.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/U2F.pm @@ -31,19 +31,19 @@ sub addRoutes { $self->addRoute( 'u2f.html', undef, ['GET'] ) # READ - ->addRoute( sessions => { ':sessionType' => 'sessions' }, ['GET'] ) + ->addRoute( u2f => { ':sessionType' => 'sessions' }, ['GET'] ) - # DELETEU2FKey + # DELETE U2F KEY ATTRIBUTS ->addRoute( - sessions => { ':sessionType' => { ':sessionId' => 'delU2FKey' } }, - ['POST'] + u2f => { ':sessionType' => { ':sessionId' => 'delU2FKey' } }, + ['DELETE'] ); - # DELETE - #~ ->addRoute( - #~ sessions => { ':sessionType' => { ':sessionId' => 'delSession' } }, - #~ ['DELETE'] - #); + # UPDATE U2F KEY ATTRIBUTS + # ->addRoute( + # u2f => { ':sessionType' => { ':sessionId' => { ':updateSession' } }, + # ['PUT'] + #); $self->setTypes($conf); @@ -56,7 +56,7 @@ sub addRoutes { # II. DISPLAY METHODS # ####################### -sub sessions { +sub u2f { my ( $self, $req, $session, $skey ) = @_; # Case 1: only one session is required diff --git a/lemonldap-ng-manager/site/coffee/u2f.coffee b/lemonldap-ng-manager/site/coffee/u2f.coffee index 885c8d9be..97a1270e5 100644 --- a/lemonldap-ng-manager/site/coffee/u2f.coffee +++ b/lemonldap-ng-manager/site/coffee/u2f.coffee @@ -1,5 +1,5 @@ ### -# U2F manager +# Session explorer ### # Max number of session to display (see overScheme) @@ -119,7 +119,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', $scope.translate = $translator.translate $scope.translateTitle = (node) -> $translator.translateField node, 'title' - sessionType = 'Persistent' + sessionType = 'global' # Handle menu items $scope.menuClick = (button) -> @@ -138,10 +138,10 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', # SESSION MANAGEMENT - # Delete U2F Key + # Delete $scope.deleteU2FKey = -> $scope.waiting = true - $http['post']("#{scriptname}sessions/#{sessionType}/#{$scope.currentSession.id}").then (response) -> + $http['delete']("#{scriptname}u2f/#{sessionType}/#{$scope.currentSession.id}").then (response) -> $scope.currentSession = null $scope.currentScope.remove() $scope.waiting = false diff --git a/lemonldap-ng-manager/site/htdocs/static/js/sessions.js b/lemonldap-ng-manager/site/htdocs/static/js/sessions.js index b1d8b493e..ccc91c467 100644 --- a/lemonldap-ng-manager/site/htdocs/static/js/sessions.js +++ b/lemonldap-ng-manager/site/htdocs/static/js/sessions.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.10.0 +// Generated by CoffeeScript 1.9.3 /* * Session explorer diff --git a/lemonldap-ng-manager/site/htdocs/static/js/u2f.js b/lemonldap-ng-manager/site/htdocs/static/js/u2f.js index de225761e..c6c94a852 100644 --- a/lemonldap-ng-manager/site/htdocs/static/js/u2f.js +++ b/lemonldap-ng-manager/site/htdocs/static/js/u2f.js @@ -1,7 +1,7 @@ // Generated by CoffeeScript 1.9.3 /* - * U2F manager + * Session explorer */ (function() { @@ -141,7 +141,7 @@ $scope.translateTitle = function(node) { return $translator.translateField(node, 'title'); }; - sessionType = 'Persistent'; + sessionType = 'global'; $scope.menuClick = function(button) { if (button.popup) { window.open(button.popup); @@ -164,7 +164,7 @@ }; $scope.deleteU2FKey = function() { $scope.waiting = true; - return $http['post'](scriptname + "sessions/" + sessionType + "/" + $scope.currentSession.id).then(function(response) { + return $http['delete'](scriptname + "u2f/" + sessionType + "/" + $scope.currentSession.id).then(function(response) { $scope.currentSession = null; $scope.currentScope.remove(); return $scope.waiting = false; diff --git a/lemonldap-ng-manager/site/htdocs/static/js/u2f.min.js b/lemonldap-ng-manager/site/htdocs/static/js/u2f.min.js index 0dcd94866..4ec44f125 100644 --- a/lemonldap-ng-manager/site/htdocs/static/js/u2f.min.js +++ b/lemonldap-ng-manager/site/htdocs/static/js/u2f.min.js @@ -1 +1 @@ -(function(){var c,e,d,b,g,f,a;b=25;a={_whatToTrace:[function(i,h){return"groupBy=substr("+i+",1)"},function(i,h){return i+"="+h+"*&groupBy="+i},function(i,h){return i+"="+h}],ipAddr:[function(i,h){return"groupBy=net("+i+",16,1)"},function(i,h){if(!h.match(/:/)){h=h+"."}return i+"="+h+"*&groupBy=net("+i+",32,2)"},function(i,h){if(!h.match(/:/)){h=h+"."}return i+"="+h+"*&groupBy=net("+i+",48,3)"},function(i,h){if(!h.match(/:/)){h=h+"."}return i+"="+h+"*&groupBy=net("+i+",128,4)"},function(i,h){return i+"="+h+"&groupBy=_whatToTrace"},function(i,h,j){return j.replace(/\&groupBy.*$/,"")+("&_whatToTrace="+h)}],_startTime:[function(i,h){return"groupBy=substr("+i+",8)"},function(i,h){return i+"="+h+"*&groupBy=substr("+i+",10)"},function(i,h){return i+"="+h+"*&groupBy=substr("+i+",11)"},function(i,h){return i+"="+h+"*&groupBy=substr("+i+",12)"},function(i,h){return i+"="+h+"*&groupBy=_whatToTrace"},function(i,h,j){console.log(i);console.log(h);console.log(j);return j.replace(/\&groupBy.*$/,"")+("&_whatToTrace="+h)}],doubleIp:[function(i,h){return i},function(i,h){return"_whatToTrace="+h+"&groupBy=ipAddr"},function(i,h,j){return j.replace(/\&groupBy.*$/,"")+("&ipAddr="+h)}]};f={_whatToTrace:function(i,h,k,j){if(k===1){return i+"="+h+"*&groupBy=substr("+i+","+(k+j+1)+")"}else{return null}},ipAddr:function(i,h,k,j){if(k>0&&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:"deleteU2FKey",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="Persistent";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.deleteU2FKey=function(){p.waiting=true;return m.post(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"],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:"deleteU2FKey",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.deleteU2FKey=function(){p.waiting=true;return m["delete"](scriptname+"u2f/"+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 - LemonLDAP::NG U2F manager + LemonLDAP::NG sessions explorer @@ -15,7 +15,6 @@