diff --git a/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/ApacheMP2/Request.pm b/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/ApacheMP2/Request.pm index 8f501b02d..20388d9c7 100644 --- a/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/ApacheMP2/Request.pm +++ b/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/ApacheMP2/Request.pm @@ -67,4 +67,11 @@ sub data { return $self->{data} ||= {}; } +sub wantJSON { + return 1 + if ( defined $_[0]->accept + and $_[0]->accept =~ m#(?:application|text)/json# ); + return 0; +} + 1; diff --git a/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Lib/OAuth2.pm b/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Lib/OAuth2.pm index 30d152769..c5c587406 100644 --- a/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Lib/OAuth2.pm +++ b/lemonldap-ng-handler/lib/Lemonldap/NG/Handler/Lib/OAuth2.pm @@ -2,7 +2,7 @@ package Lemonldap::NG::Handler::Lib::OAuth2; use strict; -our $VERSION = '2.0.4'; +our $VERSION = '2.1.0'; sub fetchId { my ( $class, $req ) = @_; diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager.pm index 63d83da08..1d441bd13 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager.pm @@ -141,9 +141,12 @@ sub tplParams { sub javascript { my ( $self, $req ) = @_; my $res = $self->diffRule->( $req, $req->{userData} ) || 0; + my $impPrefix = $self->{impersonationPrefix}; + return 'var formPrefix=staticPrefix+"forms/";var confPrefix=scriptname+"confs/";var viewPrefix=scriptname+"view/";' . 'var allowDiff=' . "$res;" + . 'var impPrefix=' . "'" . $impPrefix . "'" . ';' . ( $self->links ? 'var links=' . to_json( $self->links ) . ';' : '' ) . ( $self->menuLinks diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf/Tests.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf/Tests.pm index 57a4be48d..9512880db 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf/Tests.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf/Tests.pm @@ -288,7 +288,7 @@ sub tests { return 1; }, - # Error if session Activity Timeout is equal or lower than one minute + # Error if activity timeout interval is higher than session activity timeout timeoutActivityInterval => sub { return 1 unless ( defined $conf->{timeoutActivityInterval} ); return ( 0, @@ -404,6 +404,16 @@ sub tests { return ( $res, join( ', ', @msg ) ); }, + # Test if SAML private and public keys signature keys are set + samlSecretKeys => sub { + return 1 unless ( $conf->{issuerDBSAMLActivation} ); + return ( 0, + 'SAML service private and public keys signature must be set' ) + unless ( $conf->{samlServicePrivateKeySig} + && $conf->{samlServicePublicKeySig} ); + return 1; + }, + # Try to parse combination with declared modules checkCombinations => sub { return 1 unless ( $conf->{authentication} eq 'Combination' ); @@ -632,17 +642,6 @@ sub tests { # Return return 1; }, - - ## Warn if IdSpoofing plugin is enabled - # checkIdSpoofing => sub { - # return ( -1, - # '"IdSpoofing" plugin is enabled!!!' - # ) - # if ( $conf->{idSpoofingRule} ); - - # # Return - # return 1; - # }, }; } diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Sessions.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Sessions.pm index 330027f3d..ce888864d 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Sessions.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Sessions.pm @@ -53,6 +53,7 @@ sub addRoutes { $self->{ipField} ||= 'ipAddr'; $self->{multiValuesSeparator} ||= '; '; + $self->{impersonationPrefix} = $conf->{impersonationPrefix} || 'real_'; $self->{hiddenAttributes} //= "_password"; } diff --git a/lemonldap-ng-manager/site/coffee/sessions.coffee b/lemonldap-ng-manager/site/coffee/sessions.coffee index fe1da5d89..f972e7aa3 100644 --- a/lemonldap-ng-manager/site/coffee/sessions.coffee +++ b/lemonldap-ng-manager/site/coffee/sessions.coffee @@ -107,6 +107,7 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', $scope.staticPrefix = staticPrefix $scope.scriptname = scriptname $scope.formPrefix = formPrefix + $scope.impPrefix = impPrefix $scope.availableLanguages = availableLanguages $scope.waiting = true $scope.showM = false @@ -320,6 +321,17 @@ llapp.controller 'SessionsExplorerCtrl', ['$scope', '$translator', '$location', if a.title > b.title then 1 else if a.title < b.title then -1 else 0 + # Sort by real and spoofed attributes + real = [] + spoof = [] + for element in tmp + if element.title.match(new RegExp('^' + $scope.impPrefix + '.+$')) + console.log element, '-> real attribute' + real.push element + else + console.log element, '-> spoofed attribute' + spoof.push element + tmp = spoof.concat real res.push title: '__attributesAndMacros__' diff --git a/lemonldap-ng-manager/site/htdocs/static/js/sessions.js b/lemonldap-ng-manager/site/htdocs/static/js/sessions.js index 0550d21b7..2bcae4d65 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.12.8 +// Generated by CoffeeScript 1.12.7 /* * Sessions explorer @@ -130,6 +130,7 @@ $scope.staticPrefix = staticPrefix; $scope.scriptname = scriptname; $scope.formPrefix = formPrefix; + $scope.impPrefix = impPrefix; $scope.availableLanguages = availableLanguages; $scope.waiting = true; $scope.showM = false; @@ -199,7 +200,7 @@ $scope.displaySession = function(scope) { var sessionId, transformSession; transformSession = function(session) { - var _insert, array, attr, attrs, category, cv, epoch, i, id, j, k, key, l, len, len1, len2, len3, len4, m, name, o, oidcConsent, ref, ref1, res, sfDevice, subres, time, title, tmp, value; + var _insert, array, attr, attrs, category, cv, element, epoch, i, id, j, k, key, l, len, len1, len2, len3, len4, len5, m, name, o, oidcConsent, p, real, ref, ref1, res, sfDevice, spoof, subres, time, title, tmp, value; _insert = function(re, title) { var key, reg, tmp, value; tmp = []; @@ -396,6 +397,19 @@ return 0; } }); + real = []; + spoof = []; + for (p = 0, len5 = tmp.length; p < len5; p++) { + element = tmp[p]; + if (element.title.match(new RegExp('^' + $scope.impPrefix + '.+$'))) { + console.log(element, '-> real attribute'); + real.push(element); + } else { + console.log(element, '-> spoofed attribute'); + spoof.push(element); + } + } + tmp = spoof.concat(real); res.push({ title: '__attributesAndMacros__', nodes: tmp 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 ef1110650..5179d4a1e 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 categories,hiddenAttributes,llapp,max,menu,overScheme,schemes;max=25;schemes={_whatToTrace:[function(t,v){return"groupBy=substr("+t+",1)"},function(t,v){return t+"="+v+"*&groupBy="+t},function(t,v){return t+"="+v}],ipAddr:[function(t,v){return"groupBy=net("+t+",16,1)"},function(t,v){if(!v.match(/:/)){v=v+"."}return t+"="+v+"*&groupBy=net("+t+",32,2)"},function(t,v){if(!v.match(/:/)){v=v+"."}return t+"="+v+"*&groupBy=net("+t+",48,3)"},function(t,v){if(!v.match(/:/)){v=v+"."}return t+"="+v+"*&groupBy=net("+t+",128,4)"},function(t,v){return t+"="+v+"&groupBy=_whatToTrace"},function(t,v,q){return q.replace(/\&groupBy.*$/,"")+("&_whatToTrace="+v)}],_startTime:[function(t,v){return"groupBy=substr("+t+",8)"},function(t,v){return t+"="+v+"*&groupBy=substr("+t+",10)"},function(t,v){return t+"="+v+"*&groupBy=substr("+t+",11)"},function(t,v){return t+"="+v+"*&groupBy=substr("+t+",12)"},function(t,v){return t+"="+v+"*&groupBy=_whatToTrace"},function(t,v,q){console.log(t);console.log(v);console.log(q);return q.replace(/\&groupBy.*$/,"")+("&_whatToTrace="+v)}],doubleIp:[function(t,v){return t},function(t,v){return"_whatToTrace="+v+"&groupBy=ipAddr"},function(t,v,q){return q.replace(/\&groupBy.*$/,"")+("&ipAddr="+v)}]};overScheme={_whatToTrace:function(t,v,level,over){if(level===1&&v.length>over){return t+"="+v+"*&groupBy=substr("+t+","+(level+over+1)+")"}else{return null}},ipAddr:function(t,v,level,over){if(level>0&&level<4){return t+"="+v+"*&groupBy=net("+t+","+(16*level+4*(over+1))+",2)"}else{return null}}};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"],oidcConsents:["_oidcConsents"]};menu={session:[{title:"deleteSession",icon:"trash"}],home:[]};llapp=angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]);llapp.controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function($scope,$translator,$location,$q,$http){var autoId,c,pathEvent,sessionType;$scope.links=links;$scope.menulinks=menulinks;$scope.staticPrefix=staticPrefix;$scope.scriptname=scriptname;$scope.formPrefix=formPrefix;$scope.availableLanguages=availableLanguages;$scope.waiting=true;$scope.showM=false;$scope.showT=true;$scope.data=[];$scope.currentScope=null;$scope.currentSession=null;$scope.menu=menu;$scope.translateP=$translator.translateP;$scope.translate=$translator.translate;$scope.translateTitle=function(node){return $translator.translateField(node,"title")};sessionType="global";$scope.menuClick=function(button){if(button.popup){window.open(button.popup)}else{if(!button.action){button.action=button.title}switch(typeof button.action){case"function":button.action($scope.currentNode,$scope);break;case"string":$scope[button.action]();break;default:console.log(typeof button.action)}}return $scope.showM=false};$scope.deleteOIDCConsent=function(rp,epoch){var item;item=angular.element(".data-"+epoch);item.remove();$scope.waiting=true;$http["delete"](scriptname+"sessions/OIDCConsent/"+sessionType+"/"+$scope.currentSession.id+"?rp="+rp+"&epoch="+epoch).then(function(response){return $scope.waiting=false},function(resp){return $scope.waiting=false});return $scope.showT=false};$scope.deleteSession=function(){$scope.waiting=true;return $http["delete"](scriptname+"sessions/"+sessionType+"/"+$scope.currentSession.id).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})};$scope.stoggle=function(scope){var node;node=scope.$modelValue;if(node.nodes.length===0){$scope.updateTree(node.value,node.nodes,node.level,node.over,node.query,node.count)}return scope.toggle()};$scope.displaySession=function(scope){var sessionId,transformSession;transformSession=function(session){var _insert,array,attr,attrs,category,cv,epoch,i,id,j,k,key,l,len,len1,len2,len3,len4,m,name,o,oidcConsent,ref,ref1,res,sfDevice,subres,time,title,tmp,value;_insert=function(re,title){var key,reg,tmp,value;tmp=[];reg=new RegExp(re);for(key in session){value=session[key];if(key.match(reg)&&value){tmp.push({title:key,value:value});delete session[key]}}if(tmp.length>0){return res.push({title:title,nodes:tmp})}};time=session._utime;id=session._session_id;for(key in session){value=session[key];if(!value){delete session[key]}else{if(typeof session==="string"&&value.match(/; /)){session[key]=value.split("; ")}if(typeof session[key]!=="object"){if(hiddenAttributes.match(new RegExp("\b"+key+"\b"))){session[key]="********"}else if(key.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)){session[key]=$scope.localeDate(value)}else if(key.match(/^(_startTime|_updateTime)$/)){session[key]=$scope.strToLocaleDate(value)}}}}res=[];for(category in categories){attrs=categories[category];subres=[];for(i=0,len=attrs.length;i0){res.push({title:"__"+category+"__",nodes:subres})}}_insert("^openid","OpenID");_insert("^notification_(.+)","__notificationsDone__");if(session._loginHistory){tmp=[];if(session._loginHistory.successLogin){ref=session._loginHistory.successLogin;for(m=0,len3=ref.length;mb.title){return 1}else if(a.titlemax&&overScheme[$scope.type]){if(tmp=overScheme[$scope.type]($scope.type,value,level,over,currentQuery)){over++;query=tmp;level=level-1}else{over=0}}else{over=0}return $http.get(scriptname+"sessions/"+sessionType+"?"+query).then(function(response){var data,i,len,n,ref;data=response.data;if(data.result){ref=data.values;for(i=0,len=ref.length;i0&&level<4){return t+"="+v+"*&groupBy=net("+t+","+(16*level+4*(over+1))+",2)"}else{return null}}};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"],oidcConsents:["_oidcConsents"]};menu={session:[{title:"deleteSession",icon:"trash"}],home:[]};llapp=angular.module("llngSessionsExplorer",["ui.tree","ui.bootstrap","llApp"]);llapp.controller("SessionsExplorerCtrl",["$scope","$translator","$location","$q","$http",function($scope,$translator,$location,$q,$http){var autoId,c,pathEvent,sessionType;$scope.links=links;$scope.menulinks=menulinks;$scope.staticPrefix=staticPrefix;$scope.scriptname=scriptname;$scope.formPrefix=formPrefix;$scope.impPrefix=impPrefix;$scope.availableLanguages=availableLanguages;$scope.waiting=true;$scope.showM=false;$scope.showT=true;$scope.data=[];$scope.currentScope=null;$scope.currentSession=null;$scope.menu=menu;$scope.translateP=$translator.translateP;$scope.translate=$translator.translate;$scope.translateTitle=function(node){return $translator.translateField(node,"title")};sessionType="global";$scope.menuClick=function(button){if(button.popup){window.open(button.popup)}else{if(!button.action){button.action=button.title}switch(typeof button.action){case"function":button.action($scope.currentNode,$scope);break;case"string":$scope[button.action]();break;default:console.log(typeof button.action)}}return $scope.showM=false};$scope.deleteOIDCConsent=function(rp,epoch){var item;item=angular.element(".data-"+epoch);item.remove();$scope.waiting=true;$http["delete"](scriptname+"sessions/OIDCConsent/"+sessionType+"/"+$scope.currentSession.id+"?rp="+rp+"&epoch="+epoch).then(function(response){return $scope.waiting=false},function(resp){return $scope.waiting=false});return $scope.showT=false};$scope.deleteSession=function(){$scope.waiting=true;return $http["delete"](scriptname+"sessions/"+sessionType+"/"+$scope.currentSession.id).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})};$scope.stoggle=function(scope){var node;node=scope.$modelValue;if(node.nodes.length===0){$scope.updateTree(node.value,node.nodes,node.level,node.over,node.query,node.count)}return scope.toggle()};$scope.displaySession=function(scope){var sessionId,transformSession;transformSession=function(session){var _insert,array,attr,attrs,category,cv,element,epoch,i,id,j,k,key,l,len,len1,len2,len3,len4,len5,m,name,o,oidcConsent,p,real,ref,ref1,res,sfDevice,spoof,subres,time,title,tmp,value;_insert=function(re,title){var key,reg,tmp,value;tmp=[];reg=new RegExp(re);for(key in session){value=session[key];if(key.match(reg)&&value){tmp.push({title:key,value:value});delete session[key]}}if(tmp.length>0){return res.push({title:title,nodes:tmp})}};time=session._utime;id=session._session_id;for(key in session){value=session[key];if(!value){delete session[key]}else{if(typeof session==="string"&&value.match(/; /)){session[key]=value.split("; ")}if(typeof session[key]!=="object"){if(hiddenAttributes.match(new RegExp("\b"+key+"\b"))){session[key]="********"}else if(key.match(/^(_utime|_lastAuthnUTime|_lastSeen|notification)$/)){session[key]=$scope.localeDate(value)}else if(key.match(/^(_startTime|_updateTime)$/)){session[key]=$scope.strToLocaleDate(value)}}}}res=[];for(category in categories){attrs=categories[category];subres=[];for(i=0,len=attrs.length;i0){res.push({title:"__"+category+"__",nodes:subres})}}_insert("^openid","OpenID");_insert("^notification_(.+)","__notificationsDone__");if(session._loginHistory){tmp=[];if(session._loginHistory.successLogin){ref=session._loginHistory.successLogin;for(m=0,len3=ref.length;mb.title){return 1}else if(a.title real attribute");real.push(element)}else{console.log(element,"-> spoofed attribute");spoof.push(element)}}tmp=spoof.concat(real);res.push({title:"__attributesAndMacros__",nodes:tmp});return{_utime:time,id:id,nodes:res}};$scope.currentScope=scope;sessionId=scope.$modelValue.session;$http.get(scriptname+"sessions/"+sessionType+"/"+sessionId).then(function(response){return $scope.currentSession=transformSession(response.data)});return $scope.showT=false};$scope.localeDate=function(s){var d;d=new Date(s*1e3);return d.toLocaleString()};$scope.strToLocaleDate=function(s){var arrayDate,d;arrayDate=s.match(/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/);if(!arrayDate.length){return s}d=new Date(arrayDate[1]+"-"+arrayDate[2]+"-"+arrayDate[3]+"T"+arrayDate[4]+":"+arrayDate[5]+":"+arrayDate[6]);return d.toLocaleString()};$scope.getLanguage=function(lang){$scope.lang=lang;$scope.form="white";$scope.init();return $scope.showM=false};pathEvent=function(event,next,current){var n;n=next.match(/#!?\/(\w+)/);sessionType="global";if(n===null){$scope.type="_whatToTrace"}else if(n[1].match(/^(persistent)$/)){sessionType=RegExp.$1;$scope.type="_session_uid"}else{$scope.type=n[1]}return $scope.init()};$scope.$on("$locationChangeSuccess",pathEvent);autoId=0;$scope.updateTree=function(value,node,level,over,currentQuery,count){var query,scheme,tmp;$scope.waiting=true;scheme=schemes[$scope.type]?schemes[$scope.type]:$scope.type==="_updateTime"?schemes._startTime:schemes._whatToTrace;query=scheme[level]($scope.type,value,currentQuery);if(count>max&&overScheme[$scope.type]){if(tmp=overScheme[$scope.type]($scope.type,value,level,over,currentQuery)){over++;query=tmp;level=level-1}else{over=0}}else{over=0}return $http.get(scriptname+"sessions/"+sessionType+"?"+query).then(function(response){var data,i,len,n,ref;data=response.data;if(data.result){ref=data.values;for(i=0,len=ref.length;iconf->{oidcRPMetaDataOptions}->{$rp} ->{oidcRPMetaDataOptionsClientSecret}; + unless ($client_secret) { + $self->logger->error( + "Algorithm $alg needs a Client Secret to sign JWT"); + return; + } my $digest; @@ -1194,6 +1199,12 @@ sub createJWT { # Get signing private key my $priv_key = $self->conf->{oidcServicePrivateKeySig}; + unless ($priv_key) { + $self->logger->error( + "Algorithm $alg needs a Private Key to sign JWT"); + return; + } + my $rsa_priv = Crypt::OpenSSL::RSA->new_private_key($priv_key); if ( $alg eq "RS256" ) { diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/_tokenRule.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/_tokenRule.pm index e2b679234..70cd56c24 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/_tokenRule.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/_tokenRule.pm @@ -3,7 +3,7 @@ package Lemonldap::NG::Portal::Lib::_tokenRule; use strict; use Mouse; -our $VERSION = '2.0.3'; +our $VERSION = '2.1.0'; has ottRule => ( is => 'rw',