diff --git a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/DefaultValues.pm b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/DefaultValues.pm index 1799ebe5c..9a1ca7ab1 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/DefaultValues.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/DefaultValues.pm @@ -17,7 +17,7 @@ sub defaultValues { }, 'authChoiceParam' => 'lmAuth', 'authentication' => 'Demo', - 'available2F' => 'UTOTP,TOTP,U2F,REST,Mail2F,Ext2F,Yubikey', + 'available2F' => 'UTOTP,TOTP,U2F,REST,Mail2F,Ext2F,Yubikey,Radius', 'available2FSelfRegistration' => 'TOTP,U2F,Yubikey', 'bruteForceProtectionMaxAge' => 300, 'bruteForceProtectionMaxFailed' => 3, @@ -220,6 +220,8 @@ sub defaultValues { 'portalSkin' => 'bootstrap', 'portalUserAttr' => '_user', 'proxyAuthnLevel' => 2, + 'radius2fActivation' => 0, + 'radius2fTimeout' => 20, 'radiusAuthnLevel' => 3, 'randomPasswordRegexp' => '[A-Z]{3}[a-z]{5}.\\d{2}', 'redirectFormMethod' => 'get', diff --git a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/RESTServer.pm b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/RESTServer.pm index 65f84611a..cf99ae226 100644 --- a/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/RESTServer.pm +++ b/lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/RESTServer.pm @@ -706,10 +706,11 @@ sub sfExtra { my $res = []; foreach my $mod ( keys %$val ) { my $tmp; - $tmp->{title} = $mod; - $tmp->{id} = "sfExtra/$mod"; - $tmp->{type} = 'sfExtra'; - $tmp->{data}->{$_} = $val->{$mod}->{$_} foreach (qw(type rule)); + $tmp->{title} = $mod; + $tmp->{id} = "sfExtra/$mod"; + $tmp->{type} = 'sfExtra'; + $tmp->{data}->{$_} = $val->{$mod}->{$_} + foreach (qw(type rule logo label)); my $over = $val->{$mod}->{over} // {}; $tmp->{data}->{over} = [ map { [ $_, $over->{$_} ] } keys %$over ]; push @$res, $tmp; diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm index b5e658292..8d4e6f83e 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Attributes.pm @@ -137,7 +137,7 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a- eval { do { qr/$_[0]/; - } + } }; return $@ ? ( 0, "__badRegexp__: $@" ) : 1; } @@ -218,8 +218,7 @@ m[^(?:(?:\-+\s*BEGIN\s+(?:PUBLIC\s+KEY|CERTIFICATE)\s*\-+\r?\n)?[a-zA-Z0-9/\+\r\ }, 'select' => { 'test' => sub { - my $test = - grep( { $_ eq $_[0]; } + my $test = grep( { $_ eq $_[0]; } map( { $_->{'k'}; } @{ $_[2]{'select'}; } ) ); return $test ? 1 @@ -599,7 +598,7 @@ sub attributes { 'type' => 'keyTextContainer' }, 'available2F' => { - 'default' => 'UTOTP,TOTP,U2F,REST,Mail2F,Ext2F,Yubikey', + 'default' => 'UTOTP,TOTP,U2F,REST,Mail2F,Ext2F,Yubikey,Radius', 'type' => 'text' }, 'available2FSelfRegistration' => { @@ -1146,6 +1145,9 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][ 'default' => '\\d{6}', 'type' => 'pcre' }, + 'ext2fLabel' => { + 'type' => 'text' + }, 'ext2fLogo' => { 'type' => 'text' }, @@ -1590,7 +1592,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][ eval { do { qr/$_[0]/; - } + } }; return $@ ? 0 : 1; }, @@ -1655,6 +1657,9 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][ 'default' => '\\d{6}', 'type' => 'pcre' }, + 'mail2fLabel' => { + 'type' => 'text' + }, 'mail2fLogo' => { 'type' => 'text' }, @@ -2425,6 +2430,32 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][ 'default' => 0, 'type' => 'bool' }, + 'radius2fActivation' => { + 'default' => 0, + 'type' => 'boolOrExpr' + }, + 'radius2fAuthnLevel' => { + 'type' => 'int' + }, + 'radius2fLabel' => { + 'type' => 'text' + }, + 'radius2fLogo' => { + 'type' => 'text' + }, + 'radius2fSecret' => { + 'type' => 'text' + }, + 'radius2fServer' => { + 'type' => 'text' + }, + 'radius2fTimeout' => { + 'default' => 20, + 'type' => 'int' + }, + 'radius2fUsernameSessionKey' => { + 'type' => 'text' + }, 'radiusAuthnLevel' => { 'default' => 3, 'type' => 'int' @@ -2542,6 +2573,9 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.] 'rest2fInitUrl' => { 'type' => 'url' }, + 'rest2fLabel' => { + 'type' => 'text' + }, 'rest2fLogo' => { 'type' => 'text' }, @@ -3253,6 +3287,10 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.] { 'k' => 'Ext2F', 'v' => 'External' + }, + { + 'k' => 'Radius', + 'v' => 'Radius' } ], 'test' => sub { @@ -3465,6 +3503,12 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a- 'totp2fIssuer' => { 'type' => 'text' }, + 'totp2fLabel' => { + 'type' => 'text' + }, + 'totp2fLogo' => { + 'type' => 'text' + }, 'totp2fRange' => { 'default' => 1, 'type' => 'int' @@ -3511,6 +3555,12 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a- 'u2fAuthnLevel' => { 'type' => 'int' }, + 'u2fLabel' => { + 'type' => 'text' + }, + 'u2fLogo' => { + 'type' => 'text' + }, 'u2fSelfRegistration' => { 'default' => 0, 'type' => 'boolOrExpr' @@ -3591,6 +3641,12 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a- 'utotp2fAuthnLevel' => { 'type' => 'int' }, + 'utotp2fLabel' => { + 'type' => 'text' + }, + 'utotp2fLogo' => { + 'type' => 'text' + }, 'vhostAliases' => { 'type' => 'text' }, @@ -3705,6 +3761,12 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a- 'yubikey2fClientID' => { 'type' => 'text' }, + 'yubikey2fLabel' => { + 'type' => 'text' + }, + 'yubikey2fLogo' => { + 'type' => 'text' + }, 'yubikey2fNonce' => { 'type' => 'text' }, diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm index 899210f0c..28b12edc2 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm @@ -1432,6 +1432,14 @@ sub attributes { documentation => 'Authentication level for users authentified by password+U2F' }, + u2fLabel => { + type => 'text', + documentation => 'Portal label for U2F' + }, + u2fLogo => { + type => 'text', + documentation => 'Custom logo for U2F', + }, u2fUserCanRemoveKey => { type => 'bool', default => 1, @@ -1458,6 +1466,14 @@ sub attributes { documentation => 'Authentication level for users authentified by password+TOTP' }, + totp2fLabel => { + type => 'text', + documentation => 'Portal label for TOTP 2F' + }, + totp2fLogo => { + type => 'text', + documentation => 'Custom logo for TOTP 2F', + }, totp2fIssuer => { type => 'text', documentation => 'TOTP Issuer', @@ -1509,6 +1525,14 @@ sub attributes { documentation => 'Authentication level for users authentified by password+(U2F or TOTP)' }, + utotp2fLabel => { + type => 'text', + documentation => 'Portal label for U2F+TOTP' + }, + utotp2fLogo => { + type => 'text', + documentation => 'Custom logo for U2F+TOTP', + }, # Mail second factor mail2fActivation => { @@ -1538,6 +1562,10 @@ sub attributes { documentation => 'Authentication level for users authenticated by Mail second factor' }, + mail2fLabel => { + type => 'text', + documentation => 'Portal label for Mail second factor' + }, mail2fLogo => { type => 'text', documentation => 'Custom logo for Mail 2F', @@ -1567,11 +1595,46 @@ sub attributes { documentation => 'Authentication level for users authentified by External second factor' }, + ext2fLabel => { + type => 'text', + documentation => 'Portal label for External second factor' + }, ext2fLogo => { type => 'text', documentation => 'Custom logo for External 2F', }, + # Radius second factor + radius2fActivation => { + type => 'boolOrExpr', + default => 0, + documentation => 'Radius second factor activation', + }, + radius2fSecret => { type => 'text', }, + radius2fServer => { type => 'text', }, + radius2fUsernameSessionKey => { + type => 'text', + documentation => 'Session key used as Radius login' + }, + radius2fTimeout => { + type => 'int', + default => 20, + documentation => 'Radius 2f verification timeout', + }, + radius2fAuthnLevel => { + type => 'int', + documentation => +'Authentication level for users authenticated by Radius second factor' + }, + radius2fLogo => { + type => 'text', + documentation => 'Custom logo for Radius 2F', + }, + radius2fLabel => { + type => 'text', + documentation => 'Portal label for Radius 2F' + }, + # REST External second factor rest2fActivation => { type => 'boolOrExpr', @@ -1607,6 +1670,10 @@ sub attributes { documentation => 'Authentication level for users authentified by REST second factor' }, + rest2fLabel => { + type => 'text', + documentation => 'Portal label for REST second factor' + }, rest2fLogo => { type => 'text', documentation => 'Custom logo for REST 2F', @@ -1628,6 +1695,14 @@ sub attributes { documentation => 'Authentication level for users authentified by Yubikey second factor' }, + yubikey2fLabel => { + type => 'text', + documentation => 'Portal label for Yubikey second factor' + }, + yubikey2fLogo => { + type => 'text', + documentation => 'Custom logo for Yubikey 2F', + }, yubikey2fClientID => { type => 'text', documentation => 'Yubico client ID', @@ -2677,7 +2752,7 @@ sub attributes { }, available2F => { type => 'text', - default => 'UTOTP,TOTP,U2F,REST,Mail2F,Ext2F,Yubikey', + default => 'UTOTP,TOTP,U2F,REST,Mail2F,Ext2F,Yubikey,Radius', documentation => 'Available second factor modules', }, available2FSelfRegistration => { @@ -3325,6 +3400,7 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?: { k => 'Mail2F', v => 'E-Mail' }, { k => 'REST', v => 'REST' }, { k => 'Ext2F', v => 'External' }, + { k => 'Radius', v => 'Radius' }, ], }, diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Tree.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Tree.pm index 15267208b..da25d7882 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Tree.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Tree.pm @@ -712,17 +712,18 @@ sub tree { title => 'utotp2f', help => 'utotp2f.html', form => 'simpleInputContainer', - nodes => - [ 'utotp2fActivation', 'utotp2fAuthnLevel' ] + nodes => [ + 'utotp2fActivation', 'utotp2fAuthnLevel', + 'utotp2fLabel', 'utotp2fLogo' + ] }, { - title => 'totp', + title => 'totp2f', help => 'totp2f.html', form => 'simpleInputContainer', nodes => [ 'totp2fActivation', 'totp2fSelfRegistration', - 'totp2fAuthnLevel', 'totp2fIssuer', 'totp2fInterval', 'totp2fRange', @@ -731,6 +732,9 @@ sub tree { 'totp2fUserCanChangeKey', 'totp2fUserCanRemoveKey', 'totp2fTTL', + 'totp2fAuthnLevel', + 'totp2fLabel', + 'totp2fLogo', ] }, { @@ -738,9 +742,10 @@ sub tree { help => 'u2f.html', form => 'simpleInputContainer', nodes => [ - 'u2fActivation', 'u2fSelfRegistration', - 'u2fAuthnLevel', 'u2fUserCanRemoveKey', - 'u2fTTL', + 'u2fActivation', 'u2fSelfRegistration', + 'u2fUserCanRemoveKey', 'u2fTTL', + 'u2fAuthnLevel', 'u2fLabel', + 'u2fLogo', ] }, { @@ -751,17 +756,33 @@ sub tree { 'mail2fActivation', 'mail2fCodeRegex', 'mail2fTimeout', 'mail2fSubject', 'mail2fBody', 'mail2fAuthnLevel', - 'mail2fLogo', + 'mail2fLabel', 'mail2fLogo', ] }, { - title => 'external2f', + title => 'ext2f', help => 'external2f.html', form => 'simpleInputContainer', nodes => [ 'ext2fActivation', 'ext2fCodeActivation', 'ext2FSendCommand', 'ext2FValidateCommand', - 'ext2fAuthnLevel', 'ext2fLogo', + 'ext2fAuthnLevel', 'ext2fLabel', + 'ext2fLogo', + ] + }, + { + title => 'radius2f', + help => 'radius2f.html', + form => 'simpleInputContainer', + nodes => [ + 'radius2fActivation', + 'radius2fServer', + 'radius2fSecret', + 'radius2fUsernameSessionKey', + 'radius2fTimeout', + 'radius2fAuthnLevel', + 'radius2fLogo', + 'radius2fLabel', ] }, { @@ -771,7 +792,7 @@ sub tree { 'rest2fActivation', 'rest2fInitUrl', 'rest2fInitArgs', 'rest2fVerifyUrl', 'rest2fVerifyArgs', 'rest2fAuthnLevel', - 'rest2fLogo', + 'rest2fLabel', 'rest2fLogo', ] }, { @@ -781,7 +802,6 @@ sub tree { nodes => [ 'yubikey2fActivation', 'yubikey2fSelfRegistration', - 'yubikey2fAuthnLevel', 'yubikey2fClientID', 'yubikey2fSecretKey', 'yubikey2fNonce', @@ -789,6 +809,9 @@ sub tree { 'yubikey2fPublicIDSize', 'yubikey2fUserCanRemoveKey', 'yubikey2fTTL', + 'yubikey2fAuthnLevel', + 'yubikey2fLabel', + 'yubikey2fLogo', ], }, 'sfExtra', diff --git a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf/Parser.pm b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf/Parser.pm index 7ac98dfd9..8ab4781e0 100644 --- a/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf/Parser.pm +++ b/lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Conf/Parser.pm @@ -799,7 +799,8 @@ sub _scanNodes { $self->newConf->{$name} = {}; foreach my $node ( @{ $leaf->{nodes} } ) { my $tmp; - $tmp->{$_} = $node->{data}->{$_} foreach (qw(type rule)); + $tmp->{$_} = $node->{data}->{$_} + foreach (qw(type rule logo label)); $tmp->{over} = {}; foreach ( @{ $node->{data}->{over} } ) { $tmp->{over}->{ $_->[0] } = $_->[1]; diff --git a/lemonldap-ng-manager/site/coffee/manager.coffee b/lemonldap-ng-manager/site/coffee/manager.coffee index 5d53bca9c..75ebb1a0b 100644 --- a/lemonldap-ng-manager/site/coffee/manager.coffee +++ b/lemonldap-ng-manager/site/coffee/manager.coffee @@ -337,6 +337,8 @@ llapp.controller 'TreeCtrl', [ data: type: '' rule: '' + logo: '' + label: '' over: [] diff --git a/lemonldap-ng-manager/site/htdocs/static/forms/sfExtra.html b/lemonldap-ng-manager/site/htdocs/static/forms/sfExtra.html index a17175895..56faa0bbe 100644 --- a/lemonldap-ng-manager/site/htdocs/static/forms/sfExtra.html +++ b/lemonldap-ng-manager/site/htdocs/static/forms/sfExtra.html @@ -5,9 +5,11 @@ - - - + + + + + @@ -21,6 +23,12 @@ + + diff --git a/lemonldap-ng-manager/site/htdocs/static/forms/sfExtraContainer.html b/lemonldap-ng-manager/site/htdocs/static/forms/sfExtraContainer.html index 78889181b..9d78ecf50 100644 --- a/lemonldap-ng-manager/site/htdocs/static/forms/sfExtraContainer.html +++ b/lemonldap-ng-manager/site/htdocs/static/forms/sfExtraContainer.html @@ -5,9 +5,11 @@
+ + + +
- - - + + + + + @@ -21,6 +23,12 @@ + + diff --git a/lemonldap-ng-manager/site/htdocs/static/js/manager.js b/lemonldap-ng-manager/site/htdocs/static/js/manager.js index 1ae7f1742..54994fc88 100644 --- a/lemonldap-ng-manager/site/htdocs/static/js/manager.js +++ b/lemonldap-ng-manager/site/htdocs/static/js/manager.js @@ -392,6 +392,8 @@ This file contains: data: { type: '', rule: '', + logo: '', + label: '', over: [] } }); diff --git a/lemonldap-ng-manager/site/htdocs/static/js/manager.min.js b/lemonldap-ng-manager/site/htdocs/static/js/manager.min.js index f6e4a0db9..77e7c4b2c 100644 --- a/lemonldap-ng-manager/site/htdocs/static/js/manager.min.js +++ b/lemonldap-ng-manager/site/htdocs/static/js/manager.min.js @@ -1 +1 @@ -(function(){var llapp;llapp=angular.module("llngManager",["ui.tree","ui.bootstrap","llApp","ngCookies"]);llapp.controller("TreeCtrl",["$scope","$http","$location","$q","$uibModal","$translator","$cookies","$htmlParams",function($scope,$http,$location,$q,$uibModal,$translator,$cookies,$htmlParams){var _checkSaveResponse,_download,_getAll,_stoggle,c,id,pathEvent,readError,setDefault,setHelp;$scope.links=window.links;$scope.menu=$htmlParams.menu;$scope.menulinks=window.menulinks;$scope.staticPrefix=window.staticPrefix;$scope.formPrefix=window.formPrefix;$scope.availableLanguages=window.availableLanguages;$scope.waiting=true;$scope.showM=false;$scope.showT=false;$scope.form="home";$scope.currentCfg={};$scope.confPrefix=window.confPrefix;$scope.message={};$scope.result="";$scope.translateTitle=function(node){return $translator.translateField(node,"title")};$scope.translateP=$translator.translateP;$scope.translate=$translator.translate;$scope.helpUrl="start.html#configuration";$scope.setShowHelp=function(val){var d;if(val==null){val=!$scope.showH}$scope.showH=val;d=new Date(Date.now());d.setFullYear(d.getFullYear()+1);return $cookies.put("showhelp",val?"true":"false",{expires:d})};$scope.showH=$cookies.get("showhelp")==="false"?false:true;if($scope.showH==null){$scope.setShowHelp(true)}readError=function(response){var e,j;e=response.status;j=response.statusLine;$scope.waiting=false;if(e===403){$scope.message={title:"forbidden",message:"",items:[]}}else if(e===401){console.log("Authentication needed");$scope.message={title:"authenticationNeeded",message:"__waitOrF5__",items:[]}}else if(e===400){$scope.message={title:"badRequest",message:j,items:[]}}else if(e>0){$scope.message={title:"badRequest",message:j,items:[]}}else{$scope.message={title:"networkProblem",message:"",items:[]}}return $scope.showModal("message.html")};$scope.showModal=function(tpl,init){var d,modalInstance;modalInstance=$uibModal.open({templateUrl:tpl,controller:"ModalInstanceCtrl",size:"lg",resolve:{elem:function(){return function(s){return $scope[s]}},set:function(){return function(f,s){return $scope[f]=s}},init:function(){return init}}});d=$q.defer();modalInstance.result.then(function(msgok){$scope.message={title:"",message:"",items:[]};return d.resolve(msgok)},function(msgnok){$scope.message={title:"",message:"",items:[]};return d.reject(msgnok)});return d.promise};$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.home=function(){$scope.form="home";return $scope.showM=false};_checkSaveResponse=function(data){var m;$scope.message={title:"",message:"",items:[],itemsE:[],itemsNC:[],itemsW:[]};if(data.needConfirm){$scope.confirmNeeded=true}if(data.message){$scope.message.message=data.message}if(data.details){for(m in data.details){if(m!=="__changes__"){if(m==="__needConfirmation__"){$scope.message.itemsNC.push({message:m,items:data.details[m]});console.log("NeedConfirmation:",$scope.message.itemsNC)}else if(m==="__warnings__"){$scope.message.itemsW.push({message:m,items:data.details[m]});console.log("Warnings:",$scope.message.itemsW)}else{$scope.message.itemsE.push({message:m,items:data.details[m]});console.log("Errors:",$scope.message.itemsE)}}}$scope.message.items=$scope.message.itemsE.concat($scope.message.itemsNC.concat($scope.message.itemsW))}$scope.waiting=false;if(data.result===1){$location.path("/confs/");$scope.message.title="successfullySaved"}else{$scope.message.title="saveReport"}return $scope.showModal("message.html")};$scope.downloadConf=function(){return window.open($scope.confPrefix+$scope.currentCfg.cfgNum+"?full=1")};$scope.save=function(){$scope.showModal("save.html").then(function(){$scope.waiting=true;$scope.data.push({id:"cfgLog",title:"cfgLog",data:$scope.result?$scope.result:""});return $http.post(window.confPrefix+"?cfgNum="+$scope.currentCfg.cfgNum+($scope.forceSave?"&force=1":""),$scope.data).then(function(response){$scope.data.pop();return _checkSaveResponse(response.data)},function(response){readError(response);return $scope.data.pop()})},function(){return console.log("Saving canceled")});return $scope.showM=false};$scope.saveRawConf=function($fileContent){$scope.waiting=true;return $http.post(window.confPrefix+"/raw",$fileContent).then(function(response){return _checkSaveResponse(response.data)},readError)};$scope.restore=function(){$scope.currentNode=null;return $scope.form="restore"};$scope.cancel=function(){$scope.currentNode.data=null;return $scope.getKey($scope.currentNode)};id=1;$scope._findContainer=function(){return $scope._findScopeContainer().$modelValue};$scope._findScopeContainer=function(){var cs;cs=$scope.currentScope;while(!cs.$modelValue.type.match(/Container$/)){cs=cs.$parentNodeScope}return cs};$scope._findScopeByKey=function(k){var cs;cs=$scope.currentScope;while(!(cs.$modelValue.title===k)){cs=cs.$parentNodeScope}return cs};$scope.newGrantRule=function(){var l,n,node;node=$scope._findContainer();l=node.nodes.length;n=l>0?l-1:0;return node.nodes.push({id:node.id+"/n"+id++,title:"New rule",re:"Message",comment:"New rule",data:"1",type:"grant"})};$scope.newRule=function(){var l,n,node;node=$scope._findContainer();l=node.nodes.length;n=l>0?l-1:0;return node.nodes.splice(n,0,{id:node.id+"/n"+id++,title:"New rule",re:"^/new",comment:"New rule",data:"accept",type:"rule"})};$scope.newPost=function(){var node;node=$scope._findContainer();return node.nodes.push({id:node.id+"/n"+id++,title:"/absolute/path/to/form",data:{},type:"post"})};$scope.newPostVar=function(){if($scope.currentNode.data.vars==null){$scope.currentNode.data.vars=[]}return $scope.currentNode.data.vars.push(["var1","$uid"])};$scope.newAuthChoice=function(){var node;node=$scope._findContainer();node.nodes.push({id:node.id+"/n"+id++,title:"1_Key",data:["Null","Null","Null"],type:"authChoice"});return $scope.execFilters($scope._findScopeByKey("authParams"))};$scope.newHashEntry=function(){var node;node=$scope._findContainer();return node.nodes.push({id:node.id+"/n"+id++,title:"new",data:"",type:"keyText"})};$scope.newCat=function(){var cs;cs=$scope.currentScope;if(cs.$modelValue.type==="menuApp"){cs=cs.$parentNodeScope}return cs.$modelValue.nodes.push({id:cs.$modelValue.id+"/n"+id++,title:"New category",type:"menuCat",nodes:[]})};$scope.newApp=function(){var cs;cs=$scope.currentScope;if(cs.$modelValue.type==="menuApp"){cs=cs.$parentNodeScope}return cs.$modelValue.nodes.push({id:cs.$modelValue.id+"/n"+id++,title:"New application",type:"menuApp",data:{description:"New app description",uri:"https://test.example.com/",logo:"network.png",display:"auto"}})};$scope.newCmbMod=function(){var node;node=$scope._findContainer();node.nodes.push({id:node.id+"/n"+id++,title:"new",type:"cmbModule",data:{type:"LDAP",for:"0",over:[]}});return $scope.execFilters($scope._findScopeByKey("authParams"))};$scope.newSfExtra=function(){var node;node=$scope._findContainer();return node.nodes.push({id:node.id+"/n"+id++,title:"new",type:"sfExtra",data:{type:"",rule:"",over:[]}})};$scope.newSfOver=function(){var d;d=$scope.currentNode.data;if(!d.over){d.over=[]}return d.over.push(["new"+id++,""])};$scope.newCmbOver=function(){var d;d=$scope.currentNode.data;if(!d.over){d.over=[]}return d.over.push(["new"+id++,""])};$scope.newChoiceOver=function(){var d;d=$scope.currentNode.data;console.log("data",d);if(!d[5]){d[5]=[]}return d[5].push(["new"+id++,""])};$scope.addHost=function(){var cn;cn=$scope.currentNode;if(!cn.data){cn.data=[]}return cn.data.push({k:"newHost",h:[{k:"key",v:"uid"}]})};$scope.addSamlAttribute=function(){var node;node=$scope._findContainer();return node.nodes.push({id:node.id+"/n"+id++,title:"new",type:"samlAttribute",data:["0","New","",""]})};$scope.addVhost=function(){var name;name=$scope.domain?"."+$scope.domain.data:".example.com";$scope.message={title:"virtualHostName",field:"hostname"};return $scope.showModal("prompt.html",name).then(function(){var n;n=$scope.result;if(n){return $scope.addTemplateNode(n,"virtualHost")}})};$scope.duplicateVhost=function(){var name;name=$scope.domain?"."+$scope.domain.data:".example.com";$scope.message={title:"virtualHostName",field:"hostname"};return $scope.showModal("prompt.html",name).then(function(){var n;n=$scope.result;return $scope.duplicateNode(n,"virtualHost",$scope.currentNode.title)})};$scope.addSamlIDP=function(){return $scope.newTemplateNode("samlIDPMetaDataNode","samlPartnerName","idp-example")};$scope.addSamlSP=function(){return $scope.newTemplateNode("samlSPMetaDataNode","samlPartnerName","sp-example")};$scope.addOidcOp=function(){return $scope.newTemplateNode("oidcOPMetaDataNode","oidcOPName","op-example")};$scope.addOidcRp=function(){return $scope.newTemplateNode("oidcRPMetaDataNode","oidcRPName","rp-example")};$scope.addCasSrv=function(){return $scope.newTemplateNode("casSrvMetaDataNode","casPartnerName","srv-example")};$scope.addCasApp=function(){return $scope.newTemplateNode("casAppMetaDataNode","casPartnerName","app-example")};$scope.newTemplateNode=function(type,title,init){$scope.message={title:title,field:"name"};return $scope.showModal("prompt.html",init).then(function(){var name;name=$scope.result;if(name){return $scope.addTemplateNode(name,type)}})};$scope.addTemplateNode=function(name,type){var cs,t;cs=$scope.currentScope;while(cs.$modelValue.title!==type+"s"){cs=cs.$parentNodeScope}t={id:type+"s/new__"+name,title:name,type:type,nodes:templates(type,"new__"+name)};setDefault(t.nodes);cs.$modelValue.nodes.push(t);cs.expand();return t};setDefault=function(node){var len,n,o;for(o=0,len=node.length;o0){tmp=p.nodes[ind];p.nodes[ind]=p.nodes[ind-1];p.nodes[ind-1]=tmp}return ind};$scope.inSelect=function(value){var len,n,o,ref;ref=$scope.currentNode.select;for(o=0,len=ref.length;o0?node.comment:node.re};$scope.filters={};$scope.execFilters=function(scope){var filter,func,ref;scope=scope?scope:$scope;ref=$scope.filters;for(filter in ref){func=ref[filter];if($scope.filters.hasOwnProperty(filter)){return window.filterFunctions[filter](scope,$q,func)}}return false};$scope.stoggle=function(scope){var node;node=scope.$modelValue;_stoggle(node);return scope.toggle()};_stoggle=function(node){var a,len,len1,len2,n,o,q,r,ref,ref1,ref2;ref=["nodes","nodes_cond"];for(o=0,len=ref.length;o0){$scope.message={title:"badRequest",message:j,items:[]}}else{$scope.message={title:"networkProblem",message:"",items:[]}}return $scope.showModal("message.html")};$scope.showModal=function(tpl,init){var d,modalInstance;modalInstance=$uibModal.open({templateUrl:tpl,controller:"ModalInstanceCtrl",size:"lg",resolve:{elem:function(){return function(s){return $scope[s]}},set:function(){return function(f,s){return $scope[f]=s}},init:function(){return init}}});d=$q.defer();modalInstance.result.then(function(msgok){$scope.message={title:"",message:"",items:[]};return d.resolve(msgok)},function(msgnok){$scope.message={title:"",message:"",items:[]};return d.reject(msgnok)});return d.promise};$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.home=function(){$scope.form="home";return $scope.showM=false};_checkSaveResponse=function(data){var m;$scope.message={title:"",message:"",items:[],itemsE:[],itemsNC:[],itemsW:[]};if(data.needConfirm){$scope.confirmNeeded=true}if(data.message){$scope.message.message=data.message}if(data.details){for(m in data.details){if(m!=="__changes__"){if(m==="__needConfirmation__"){$scope.message.itemsNC.push({message:m,items:data.details[m]});console.log("NeedConfirmation:",$scope.message.itemsNC)}else if(m==="__warnings__"){$scope.message.itemsW.push({message:m,items:data.details[m]});console.log("Warnings:",$scope.message.itemsW)}else{$scope.message.itemsE.push({message:m,items:data.details[m]});console.log("Errors:",$scope.message.itemsE)}}}$scope.message.items=$scope.message.itemsE.concat($scope.message.itemsNC.concat($scope.message.itemsW))}$scope.waiting=false;if(data.result===1){$location.path("/confs/");$scope.message.title="successfullySaved"}else{$scope.message.title="saveReport"}return $scope.showModal("message.html")};$scope.downloadConf=function(){return window.open($scope.confPrefix+$scope.currentCfg.cfgNum+"?full=1")};$scope.save=function(){$scope.showModal("save.html").then(function(){$scope.waiting=true;$scope.data.push({id:"cfgLog",title:"cfgLog",data:$scope.result?$scope.result:""});return $http.post(window.confPrefix+"?cfgNum="+$scope.currentCfg.cfgNum+($scope.forceSave?"&force=1":""),$scope.data).then(function(response){$scope.data.pop();return _checkSaveResponse(response.data)},function(response){readError(response);return $scope.data.pop()})},function(){return console.log("Saving canceled")});return $scope.showM=false};$scope.saveRawConf=function($fileContent){$scope.waiting=true;return $http.post(window.confPrefix+"/raw",$fileContent).then(function(response){return _checkSaveResponse(response.data)},readError)};$scope.restore=function(){$scope.currentNode=null;return $scope.form="restore"};$scope.cancel=function(){$scope.currentNode.data=null;return $scope.getKey($scope.currentNode)};id=1;$scope._findContainer=function(){return $scope._findScopeContainer().$modelValue};$scope._findScopeContainer=function(){var cs;cs=$scope.currentScope;while(!cs.$modelValue.type.match(/Container$/)){cs=cs.$parentNodeScope}return cs};$scope._findScopeByKey=function(k){var cs;cs=$scope.currentScope;while(!(cs.$modelValue.title===k)){cs=cs.$parentNodeScope}return cs};$scope.newGrantRule=function(){var l,n,node;node=$scope._findContainer();l=node.nodes.length;n=l>0?l-1:0;return node.nodes.push({id:node.id+"/n"+id++,title:"New rule",re:"Message",comment:"New rule",data:"1",type:"grant"})};$scope.newRule=function(){var l,n,node;node=$scope._findContainer();l=node.nodes.length;n=l>0?l-1:0;return node.nodes.splice(n,0,{id:node.id+"/n"+id++,title:"New rule",re:"^/new",comment:"New rule",data:"accept",type:"rule"})};$scope.newPost=function(){var node;node=$scope._findContainer();return node.nodes.push({id:node.id+"/n"+id++,title:"/absolute/path/to/form",data:{},type:"post"})};$scope.newPostVar=function(){if($scope.currentNode.data.vars==null){$scope.currentNode.data.vars=[]}return $scope.currentNode.data.vars.push(["var1","$uid"])};$scope.newAuthChoice=function(){var node;node=$scope._findContainer();node.nodes.push({id:node.id+"/n"+id++,title:"1_Key",data:["Null","Null","Null"],type:"authChoice"});return $scope.execFilters($scope._findScopeByKey("authParams"))};$scope.newHashEntry=function(){var node;node=$scope._findContainer();return node.nodes.push({id:node.id+"/n"+id++,title:"new",data:"",type:"keyText"})};$scope.newCat=function(){var cs;cs=$scope.currentScope;if(cs.$modelValue.type==="menuApp"){cs=cs.$parentNodeScope}return cs.$modelValue.nodes.push({id:cs.$modelValue.id+"/n"+id++,title:"New category",type:"menuCat",nodes:[]})};$scope.newApp=function(){var cs;cs=$scope.currentScope;if(cs.$modelValue.type==="menuApp"){cs=cs.$parentNodeScope}return cs.$modelValue.nodes.push({id:cs.$modelValue.id+"/n"+id++,title:"New application",type:"menuApp",data:{description:"New app description",uri:"https://test.example.com/",logo:"network.png",display:"auto"}})};$scope.newCmbMod=function(){var node;node=$scope._findContainer();node.nodes.push({id:node.id+"/n"+id++,title:"new",type:"cmbModule",data:{type:"LDAP",for:"0",over:[]}});return $scope.execFilters($scope._findScopeByKey("authParams"))};$scope.newSfExtra=function(){var node;node=$scope._findContainer();return node.nodes.push({id:node.id+"/n"+id++,title:"new",type:"sfExtra",data:{type:"",rule:"",logo:"",label:"",over:[]}})};$scope.newSfOver=function(){var d;d=$scope.currentNode.data;if(!d.over){d.over=[]}return d.over.push(["new"+id++,""])};$scope.newCmbOver=function(){var d;d=$scope.currentNode.data;if(!d.over){d.over=[]}return d.over.push(["new"+id++,""])};$scope.newChoiceOver=function(){var d;d=$scope.currentNode.data;console.log("data",d);if(!d[5]){d[5]=[]}return d[5].push(["new"+id++,""])};$scope.addHost=function(){var cn;cn=$scope.currentNode;if(!cn.data){cn.data=[]}return cn.data.push({k:"newHost",h:[{k:"key",v:"uid"}]})};$scope.addSamlAttribute=function(){var node;node=$scope._findContainer();return node.nodes.push({id:node.id+"/n"+id++,title:"new",type:"samlAttribute",data:["0","New","",""]})};$scope.addVhost=function(){var name;name=$scope.domain?"."+$scope.domain.data:".example.com";$scope.message={title:"virtualHostName",field:"hostname"};return $scope.showModal("prompt.html",name).then(function(){var n;n=$scope.result;if(n){return $scope.addTemplateNode(n,"virtualHost")}})};$scope.duplicateVhost=function(){var name;name=$scope.domain?"."+$scope.domain.data:".example.com";$scope.message={title:"virtualHostName",field:"hostname"};return $scope.showModal("prompt.html",name).then(function(){var n;n=$scope.result;return $scope.duplicateNode(n,"virtualHost",$scope.currentNode.title)})};$scope.addSamlIDP=function(){return $scope.newTemplateNode("samlIDPMetaDataNode","samlPartnerName","idp-example")};$scope.addSamlSP=function(){return $scope.newTemplateNode("samlSPMetaDataNode","samlPartnerName","sp-example")};$scope.addOidcOp=function(){return $scope.newTemplateNode("oidcOPMetaDataNode","oidcOPName","op-example")};$scope.addOidcRp=function(){return $scope.newTemplateNode("oidcRPMetaDataNode","oidcRPName","rp-example")};$scope.addCasSrv=function(){return $scope.newTemplateNode("casSrvMetaDataNode","casPartnerName","srv-example")};$scope.addCasApp=function(){return $scope.newTemplateNode("casAppMetaDataNode","casPartnerName","app-example")};$scope.newTemplateNode=function(type,title,init){$scope.message={title:title,field:"name"};return $scope.showModal("prompt.html",init).then(function(){var name;name=$scope.result;if(name){return $scope.addTemplateNode(name,type)}})};$scope.addTemplateNode=function(name,type){var cs,t;cs=$scope.currentScope;while(cs.$modelValue.title!==type+"s"){cs=cs.$parentNodeScope}t={id:type+"s/new__"+name,title:name,type:type,nodes:templates(type,"new__"+name)};setDefault(t.nodes);cs.$modelValue.nodes.push(t);cs.expand();return t};setDefault=function(node){var len,n,o;for(o=0,len=node.length;o0){tmp=p.nodes[ind];p.nodes[ind]=p.nodes[ind-1];p.nodes[ind-1]=tmp}return ind};$scope.inSelect=function(value){var len,n,o,ref;ref=$scope.currentNode.select;for(o=0,len=ref.length;o0?node.comment:node.re};$scope.filters={};$scope.execFilters=function(scope){var filter,func,ref;scope=scope?scope:$scope;ref=$scope.filters;for(filter in ref){func=ref[filter];if($scope.filters.hasOwnProperty(filter)){return window.filterFunctions[filter](scope,$q,func)}}return false};$scope.stoggle=function(scope){var node;node=scope.$modelValue;_stoggle(node);return scope.toggle()};_stoggle=function(node){var a,len,len1,len2,n,o,q,r,ref,ref1,ref2;ref=["nodes","nodes_cond"];for(o=0,len=ref.length;ologger->debug('Processing Extra 2F modules'); - foreach my $extraKey (sort keys %{ $self->conf->{sfExtra} } ) { + foreach my $extraKey ( sort keys %{ $self->conf->{sfExtra} } ) { my $moduleType = $self->conf->{sfExtra}->{$extraKey}->{type}; next unless ($moduleType); @@ -113,6 +113,12 @@ sub init { my $rule = $self->conf->{sfExtra}->{$extraKey}->{rule} || 1; my $prefix = $m->prefix; + # Overwrite logo and label from user configuration + $m->logo( $self->conf->{sfExtra}->{$extraKey}->{logo} ) + if $self->conf->{sfExtra}->{$extraKey}->{logo}; + $m->label( $self->conf->{sfExtra}->{$extraKey}->{label} ) + if $self->conf->{sfExtra}->{$extraKey}->{label}; + # Compile rule $rule = $self->p->HANDLER->substitute($rule); unless ( $rule = $self->p->HANDLER->buildSub($rule) ) { @@ -322,7 +328,14 @@ sub run { MAIN_LOGO => $self->conf->{portalMainLogo}, SKIN => $self->p->getSkin($req), TOKEN => $token, - MODULES => [ map { { CODE => $_->prefix, LOGO => $_->logo } } @am ], + MODULES => [ + map { { + CODE => $_->prefix, + LOGO => $_->logo, + LABEL => $_->label + } + } @am + ], CHECKLOGINS => $checkLogins } ); diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Ext2F.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Ext2F.pm index 6a1142bc7..43f4614e7 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Ext2F.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Ext2F.pm @@ -29,9 +29,7 @@ sub init { } } $self->prefix( $self->conf->{sfPrefix} ) - if ( $self->conf->{sfPrefix} ); - $self->logo( $self->conf->{ext2fLogo} ) - if ( $self->conf->{ext2fLogo} ); + if ( $self->conf->{sfPrefix} ); return $self->SUPER::init(); } if ( $self->conf->{ext2fCodeActivation} ) { @@ -41,9 +39,7 @@ sub init { } $self->random( Lemonldap::NG::Common::Crypto::srandom() ); $self->prefix( $self->conf->{sfPrefix} ) - if ( $self->conf->{sfPrefix} ); - $self->logo( $self->conf->{ext2fLogo} ) - if ( $self->conf->{ext2fLogo} ); + if ( $self->conf->{sfPrefix} ); return $self->SUPER::init(); } return 0; diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Mail2F.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Mail2F.pm index 75b413b14..dac558a55 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Mail2F.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Mail2F.pm @@ -45,8 +45,6 @@ sub init { $self->error("Missing 'mailSessionKey' parameter, aborting"); return 0; } - $self->logo( $self->conf->{mail2fLogo} ) - if ( $self->conf->{mail2fLogo} ); $self->prefix( $self->conf->{sfPrefix} ) if ( $self->conf->{sfPrefix} ); return $self->SUPER::init(); diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/REST.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/REST.pm index 096fbe62a..3b9e2b4f0 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/REST.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/REST.pm @@ -30,8 +30,7 @@ sub init { return 0; } $self->prefix( $self->conf->{sfPrefix} ) - if ( $self->conf->{sfPrefix} ); - $self->logo( $self->conf->{rest2fLogo} ) if ( $self->conf->{rest2fLogo} ); + if ( $self->conf->{sfPrefix} ); foreach my $k ( keys %{ $self->conf->{rest2fInitArgs} } ) { my $attr = $self->conf->{rest2fInitArgs}->{$k}; $attr =~ s/^$//; diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Radius.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Radius.pm new file mode 100644 index 000000000..283ec147c --- /dev/null +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Radius.pm @@ -0,0 +1,112 @@ +package Lemonldap::NG::Portal::2F::Radius; + +use strict; +use Mouse; +use Lemonldap::NG::Portal::Main::Constants qw( + PE_BADCREDENTIALS + PE_ERROR + PE_MALFORMEDUSER + PE_OK + PE_SENDRESPONSE +); + +our $VERSION = '2.0.0'; + +extends 'Lemonldap::NG::Portal::Main::SecondFactor'; + +# INITIALIZATION + +has prefix => ( is => 'rw', default => 'radius' ); + +has radius => ( is => 'rw' ); + +sub init { + my ($self) = @_; + + foreach (qw(radius2fSecret radius2fServer)) { + unless ( $self->conf->{$_} ) { + $self->error("Missing $_ parameter, aborting"); + return 0; + } + } + + eval { require Authen::Radius }; + if ($@) { + $self->error("Unable to load Authen::Radius: $@"); + return 0; + } + + unless ( + $self->radius( + Authen::Radius->new( + Host => $self->conf->{radius2fServer}, + Secret => $self->conf->{radius2fSecret}, + TimeOut => $self->conf->{radius2fTimeout}, + ) + ) + ) + { + $self->error('Radius connect failed'); + } + $self->prefix( $self->conf->{sfPrefix} ) + if ( $self->conf->{sfPrefix} ); + return $self->SUPER::init(); +} + +sub run { + my ( $self, $req, $token ) = @_; + + my $checkLogins = $req->param('checkLogins'); + $self->logger->debug("Radius2F checkLogins set") if ($checkLogins); + + # Prepare form + my $tmp = $self->p->sendHtml( + $req, + 'ext2fcheck', + params => { + MAIN_LOGO => $self->conf->{portalMainLogo}, + SKIN => $self->p->getSkin($req), + TOKEN => $token, + TARGET => '/' . $self->prefix . '2fcheck', + LEGEND => 'enterRadius2fCode', + CHECKLOGINS => $checkLogins + } + ); + $self->logger->debug("Prepare Radius 2F verification"); + + $req->response($tmp); + return PE_SENDRESPONSE; +} + +sub verify { + my ( $self, $req, $session ) = @_; + + # Some Radius Servers allow empty codes and perform + # out of band, interactive verification (InWebo...) + my $code = $req->param('code'); + + # Launch Radius request + my $userAttr = + $self->conf->{radius2fUsernameSessionKey} || $self->conf->{whatToTrace}; + my $username = $session->{$userAttr}; + unless ($username) { + $self->logger->error( + "Could not find Radius username from session attribute $userAttr"); + return PE_MALFORMEDUSER; + } + + $self->logger->debug("Checking Radius credentials $username:$code"); + + my $res = $self->radius->check_pwd( $username, $code ); + unless ( $res == 1 ) { + $self->userLogger->warn( "Radius second factor failed for " + . $session->{ $self->conf->{whatToTrace} } ); + $self->logger->warn( + "Radius server replied: " . $self->radius->get_error ); + return PE_BADCREDENTIALS; + } + $self->logger->debug("Radius server accepted 2F credentials"); + PE_OK; +} + +1; diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/Yubikey.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/Yubikey.pm index 6d9f4b6f9..db5a564a7 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/Yubikey.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/Register/Yubikey.pm @@ -103,8 +103,7 @@ sub run { my $maxSize = $self->conf->{max2FDevices}; $self->logger->debug("Nbr 2FDevices = $size / $maxSize"); if ( $size >= $maxSize ) { - $self->userLogger->warn( - "Max number of 2F devices is reached"); + $self->userLogger->warn("Max number of 2F devices is reached"); return $self->p->sendHtml( $req, 'error', params => { diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/U2F.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/U2F.pm index d00a1d317..36f521f25 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/U2F.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/2F/U2F.pm @@ -125,8 +125,7 @@ sub verify { unless ( $session->{__ch} and $session->{__ch} eq $challenge ) { $self->userLogger->error( -"U2F challenge changed by user: $session->{__ch} / $challenge" - ); + "U2F challenge changed by user: $session->{__ch} / $challenge"); $req->error(PE_BADCREDENTIALS); return $self->fail($req); } diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/Combination.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/Combination.pm index cc3bb48af..2808834b3 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/Combination.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/Combination.pm @@ -141,7 +141,7 @@ sub authLogout { $self->getStack( $req, 'extractFormInfo' ) or return PE_ERROR; # Avoid warning msg at first access - $req->userData->{_combinationTry} ||= ''; + $req->userData->{_combinationTry} ||= 0; my ( $res, $name ) = $req->data->{combinationStack}->[ $req->userData->{_combinationTry} ] ->[0]->( 'authLogout', $req ); diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SMTP.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SMTP.pm index 370767c18..7ca4f8001 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SMTP.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Lib/SMTP.pm @@ -100,7 +100,7 @@ sub translate { if ($langOver) { for my $k ( keys %{ $langOver->{all} || {} } ) { - $lang->{$k} = $langOver->{$lang_code}->{$k}; + $lang->{$k} = $langOver->{all}->{$k}; } for my $k ( keys %{ $langOver->{$lang_code} || {} } ) { $lang->{$k} = $langOver->{$lang_code}->{$k}; diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Init.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Init.pm index 36bd73ac3..2e244da77 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Init.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/Init.pm @@ -356,7 +356,8 @@ sub reloadConf { unless ( $_[0]->pdata->{keepPdata} ) { $self->logger->debug('Cleaning pdata'); $_[0]->pdata( {} ); - $self->userLogger->notice( $_[0]->user . ' connected' ) if $_[0]->user; + $self->userLogger->notice( $_[0]->user . ' connected' ) + if $_[0]->user; } return PE_OK; }; diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/SecondFactor.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/SecondFactor.pm index 0935ba305..b5dc610fb 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/SecondFactor.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Main/SecondFactor.pm @@ -31,10 +31,21 @@ has prefix => ( is => 'rw' ); has logo => ( is => 'rw', default => '2f.png' ); +has label => ( is => 'rw' ); + has noRoute => ( is => 'ro' ); sub init { my ($self) = @_; + + # Set logo if overriden + $self->logo( $self->conf->{ $self->prefix . "2fLogo" } ) + if ( $self->conf->{ $self->prefix . "2fLogo" } ); + + # Set label if provided, translation files will be used otherwise + $self->label( $self->conf->{ $self->prefix . "2fLabel" } ) + if ( $self->conf->{ $self->prefix . "2fLabel" } ); + unless ( $self->noRoute ) { $self->logger->debug( 'Adding ' . $self->prefix . '2fcheck routes' ); $self->addAuthRoute( diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/CheckUser.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/CheckUser.pm index c1a6b0ec1..8c9e1a807 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/CheckUser.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/CheckUser.pm @@ -458,7 +458,7 @@ sub _splitAttributes { } else { push @$spoofedAttrs, $element; - $self->logger->debug(' -> Spoofed attribute'); + #$self->logger->debug(' -> Spoofed attribute'); } } @$others = ( @$spoofedAttrs, @$realAttrs ); diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/ContextSwitching.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/ContextSwitching.pm index 2c197dc24..8e0091e5d 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/ContextSwitching.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/ContextSwitching.pm @@ -14,8 +14,11 @@ use Lemonldap::NG::Portal::Main::Constants qw( our $VERSION = '2.0.6'; -extends - qw(Lemonldap::NG::Portal::Main::Plugin Lemonldap::NG::Portal::Lib::_tokenRule); +extends qw( + Lemonldap::NG::Portal::Main::Plugin + Lemonldap::NG::Portal::Lib::_tokenRule + Lemonldap::NG::Portal::Lib::OtherSessions +); # INITIALIZATION @@ -35,8 +38,8 @@ has idRule => ( is => 'rw', default => sub { 1 } ); sub init { my ($self) = @_; my $hd = $self->p->HANDLER; - $self->addAuthRoute( switchcontext => 'run', ['POST'] ); - $self->addAuthRoute( switchcontext => 'display', ['GET'] ); + $self->addAuthRoute( switchcontext => 'run', ['POST'] ) + ->addAuthRoute( switchcontext => 'display', ['GET'] ); # Parse activation rule $self->logger->debug( diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Notifications.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Notifications.pm index 9d7438745..3384d8d1a 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Notifications.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Notifications.pm @@ -47,14 +47,17 @@ sub init { if ( $self->conf->{notificationServer} ) { $self->logger->debug('Notification server enable'); + $self->addUnauthRoute( notifications => 'notificationServer', ['POST'] ) if ( $self->conf->{notificationServerPOST} // 1 ); + $self->addUnauthRoute( notifications => { '*' => 'notificationServer' }, ['GET'] ) if ( $self->conf->{notificationServerGET} ); + $self->addUnauthRoute( notifications => { ':uid' => { ':reference' => 'notificationServer' } }, diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/RESTServer.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/RESTServer.pm index 0fb072148..dfe9e96b6 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/RESTServer.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/RESTServer.pm @@ -29,7 +29,9 @@ # n° # * GET /config// : get conf key value # * GET /config/?full : get the full configuration -# where is the session type ("global" for SSO session) +# where is the session type ("global" for SSO session or "persistent") +# * GET /error// : get message from .json +# Return all error messages if no specified # # - Authorizations for connected users (always): # * GET /mysession/?whoami : get "my" uid @@ -124,11 +126,14 @@ sub init { ] }, ['GET'], - ); - $self->addUnauthRoute( + ) + + ->addUnauthRoute( config => { ':cfgNum' => { '*' => 'getKey' } }, ['GET'] - ); + ) + + ->addUnauthRoute( error => { '*' => 'getError' }, ['GET'] ); } if ( $self->conf->{restSessionServer} ) { push @parents, 'Lemonldap::NG::Common::Session::REST'; @@ -144,44 +149,48 @@ sub init { ) }, ['GET'] - ); - $self->addUnauthRoute( + ) + + ->addUnauthRoute( sessions => { ':sessionType' => 'newSession' }, ['POST'] - ); + ) - # Methods written below - $self->addUnauthRoute( + # Methods written below + ->addUnauthRoute( sessions => { ':sessionType' => 'updateSession' }, ['PUT'] - ); - $self->addUnauthRoute( + ) + + ->addUnauthRoute( sessions => { ':sessionType' => 'delSession' }, ['DELETE'] - ); + ) - $self->addAuthRoute( + ->addAuthRoute( session => { my => { ':sessionType' => 'getMyKey' } }, [ 'GET', 'POST' ] - ); + ); } # Methods always available $self->addAuthRoute( mysession => { '*' => 'mysession' }, [ 'GET', 'POST' ] - ); - $self->addAuthRoute( + ) + + ->addAuthRoute( mysession => { ':sessionType' => { ':key' => 'delKeyInMySession', '*' => 'delMySession' } }, ['DELETE'] - ); - $self->addAuthRoute( + ) + + ->addAuthRoute( mysession => { ':sessionType' => 'updateMySession' }, ['PUT'] - ); + ); extends @parents if ($add); $self->setTypes( $self->conf ) if ( $self->conf->{restSessionServer} ); return 1; @@ -523,4 +532,47 @@ sub delKeyInMySession { { result => 1, count => $res, modifiedKeys => $dkey } ); } +sub getError { + my ( $self, $req, $lang, $errNum ) = @_; + my $json; + my $langsDir = + $self->conf->{templateDir} + . '/../htdocs' + . $self->conf->{staticPrefix} + . '/languages'; + $lang ||= 'en'; + + $errNum + ? $self->logger->debug("GET error: $errNum message from lang: $lang") + : $self->logger->debug("GET ALL error messages from lang: $lang"); + + if ( open my $file, "<", $langsDir . "/$lang.json" ) { + local $/ = undef; + $json = from_json(<$file>); + } + else { + $self->logger->error("Unable to read $langsDir/$lang.json"); + return $self->p->sendJSONresponse( $req, + { result => 0, lang => $lang, error => 'Unable to read language file' } ); + } + + %$json = map { $_ =~ /^PE\d+$/ ? ( $_ => $json->{$_} ) : () } + keys %$json + unless ($errNum); + + return $self->p->sendJSONresponse( + $req, + { + result => 1, + lang => $lang, + errorNum => $errNum ? $errNum : 'all', + errorMsg => ( + $errNum + ? $json->{"PE$errNum"} + : $json + ) + } + ); +} + 1; diff --git a/lemonldap-ng-portal/site/coffee/portal.coffee b/lemonldap-ng-portal/site/coffee/portal.coffee index 042756f2a..f731c82d4 100644 --- a/lemonldap-ng-portal/site/coffee/portal.coffee +++ b/lemonldap-ng-portal/site/coffee/portal.coffee @@ -266,8 +266,9 @@ $(document).ready -> if datas['login'] $("input[type=password]:first").focus() else - # Focus on first visible input - $("input[type!=hidden]:first").focus() + # If there are no auto-focused fields, focus on first visible input + if $("input[autofocus]").length == 0 + $("input[type!=hidden]:first").focus(); # Open links in new windows if required if datas['newwindow'] diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/portal.js b/lemonldap-ng-portal/site/htdocs/static/common/js/portal.js index b2486914a..62cfae94d 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/portal.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/portal.js @@ -256,7 +256,9 @@ LemonLDAP::NG Portal jQuery scripts if (datas['login']) { $("input[type=password]:first").focus(); } else { - $("input[type!=hidden]:first").focus(); + if ($("input[autofocus]").length === 0) { + $("input[type!=hidden]:first").focus(); + } } if (datas['newwindow']) { $('#appslist a').attr("target", "_blank"); diff --git a/lemonldap-ng-portal/site/htdocs/static/common/js/portal.min.js b/lemonldap-ng-portal/site/htdocs/static/common/js/portal.min.js index f720f3a56..684ce5559 100644 --- a/lemonldap-ng-portal/site/htdocs/static/common/js/portal.min.js +++ b/lemonldap-ng-portal/site/htdocs/static/common/js/portal.min.js @@ -1 +1 @@ -(function(){var datas,delKey,getCookie,getValues,isHiddenFormValueSet,ping,removeOidcConsent,restoreOrder,setCookie,setKey,setOrder,setSelector,translate,translatePage,translationFields,indexOf=[].indexOf||function(item){for(var i=0,l=this.length;i div.category",update:function(){return setOrder()}});restoreOrder();$("div.message").fadeIn("slow");$("input[name=timezone]").val(-((new Date).getTimezoneOffset()/60));menuTabs=$("#menu").tabs({active:0});menuIndex=$('#menu a[href="#'+datas["displaytab"]+'"]').parent().index();if(menuIndex<0){menuIndex=0}menuTabs.tabs("option","active",menuIndex);authMenuTabs=$("#authMenu").tabs({active:0});if(datas["choicetab"]){authMenuTabs.tabs("option","active",$('#authMenu a[href="#'+datas["choicetab"]+'"]').parent().index())}if(datas["login"]){$("input[type=password]:first").focus()}else{$("input[type!=hidden]:first").focus()}if(datas["newwindow"]){$("#appslist a").attr("target","_blank")}if($("p.removeOther").length){action=$("form.login").attr("action");method=$("form.login").attr("method");back_url="";if(action.indexOf("?")!==-1){action.substring(0,action.indexOf("?"))+"?"}else{back_url=action+"?"}$("form.login input[type=hidden]").each(function(index){return back_url+="&"+$(this).attr("name")+"="+$(this).val()});link=$("p.removeOther a").attr("href")+"&method="+method+"&url="+btoa(back_url);$("p.removeOther a").attr("href",link)}lang=getCookie("llnglanguage");if(!lang){if(navigator){langs=[];langs2=[];nlangs=[navigator.language];if(navigator.languages){nlangs=navigator.languages}ref=window.availableLanguages;for(i=0,len=ref.length;i '}for(l=0,len1=nlangs.length;l",lang);setCookie("llnglanguage",lang);translatePage(lang);langdiv="";ref2=window.availableLanguages;for(n=0,len3=ref2.length;n '}$("#languages").html(langdiv);$(".langicon").on("click",function(){lang=$(this).attr("title");setCookie("llnglanguage",lang);return translatePage(lang)});if(datas["pingInterval"]&&datas["pingInterval"]>0){window.setTimeout(ping,datas["pingInterval"])}$(".localeDate").each(function(){var s;s=new Date($(this).attr("val")*1e3);return $(this).text(s.toLocaleString())});return $(".oidcConsent").on("click",function(){return removeOidcConsent($(this).attr("partner"))})})}).call(this); +(function(){var datas,delKey,getCookie,getValues,isHiddenFormValueSet,ping,removeOidcConsent,restoreOrder,setCookie,setKey,setOrder,setSelector,translate,translatePage,translationFields,indexOf=[].indexOf||function(item){for(var i=0,l=this.length;i div.category",update:function(){return setOrder()}});restoreOrder();$("div.message").fadeIn("slow");$("input[name=timezone]").val(-((new Date).getTimezoneOffset()/60));menuTabs=$("#menu").tabs({active:0});menuIndex=$('#menu a[href="#'+datas["displaytab"]+'"]').parent().index();if(menuIndex<0){menuIndex=0}menuTabs.tabs("option","active",menuIndex);authMenuTabs=$("#authMenu").tabs({active:0});if(datas["choicetab"]){authMenuTabs.tabs("option","active",$('#authMenu a[href="#'+datas["choicetab"]+'"]').parent().index())}if(datas["login"]){$("input[type=password]:first").focus()}else{if($("input[autofocus]").length===0){$("input[type!=hidden]:first").focus()}}if(datas["newwindow"]){$("#appslist a").attr("target","_blank")}if($("p.removeOther").length){action=$("form.login").attr("action");method=$("form.login").attr("method");back_url="";if(action.indexOf("?")!==-1){action.substring(0,action.indexOf("?"))+"?"}else{back_url=action+"?"}$("form.login input[type=hidden]").each(function(index){return back_url+="&"+$(this).attr("name")+"="+$(this).val()});link=$("p.removeOther a").attr("href")+"&method="+method+"&url="+btoa(back_url);$("p.removeOther a").attr("href",link)}lang=getCookie("llnglanguage");if(!lang){if(navigator){langs=[];langs2=[];nlangs=[navigator.language];if(navigator.languages){nlangs=navigator.languages}ref=window.availableLanguages;for(i=0,len=ref.length;i '}for(l=0,len1=nlangs.length;l",lang);setCookie("llnglanguage",lang);translatePage(lang);langdiv="";ref2=window.availableLanguages;for(n=0,len3=ref2.length;n '}$("#languages").html(langdiv);$(".langicon").on("click",function(){lang=$(this).attr("title");setCookie("llnglanguage",lang);return translatePage(lang)});if(datas["pingInterval"]&&datas["pingInterval"]>0){window.setTimeout(ping,datas["pingInterval"])}$(".localeDate").each(function(){var s;s=new Date($(this).attr("val")*1e3);return $(this).text(s.toLocaleString())});return $(".oidcConsent").on("click",function(){return removeOidcConsent($(this).attr("partner"))})})}).call(this); diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/ar.json b/lemonldap-ng-portal/site/htdocs/static/languages/ar.json index 972a42b1e..49d5df595 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/ar.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/ar.json @@ -128,10 +128,12 @@ "enterCred":"الرجاء إدخال بيانات الاعتماد الخاصة بك", "enterExt2fCode":"تم إرسال رمز إليك. الرجاء إدخاله", "enterOpenIDLogin":"الرجاء إدخال تسجيل الدخول الأوبين إيدي الخاص بك", +"enterRadius2fCode":"Please enter your OTP code", "enterTotpCode":"Enter TOTP code", "enterYubikey":"يرجى استخدام يوبي كي الخاص بك", "errorMsg":"رسالة خاطئة", "expired2Fremoved":"%s expired 2F devices have been removed!", +"ext2f":"Verification code", "fillTheForm":"Fill the form", "firstName":"الاسم الاول", "forbidden":"Access FORBIDDEN", @@ -161,6 +163,7 @@ "logoutFromSP":"Logout from service providers ...", "macros":"MACROS", "mail":"البريد", +"mail2f":"Email code", "mailSent2":"تم إرسال رسالة إلى عنوان بريدك الإلكتروني.", "maintenanceMode":"هذا التطبيق في صيانة، يرجى محاولة الاتصال في وقت لاحق", "maxNumberof2FDevicesReached":"Maximum number of 2F devices reached!", @@ -193,6 +196,7 @@ "pwd":"كلمة المرور", "pwdResetAlreadyIssued":"تم إصدار طلب إعادة تعيين كلمة المرور من قبل", "pwdWillExpire":"٪ s من الأيام و٪ s من الساعات و٪ s من الدقائق و٪ s من الثواني قبل انتهاء صلاحية كلمة المرور، قم بتغييرها!", +"radius2f":"Radius", "redirectedFrom":"تمت إعادة توجيهك من", "redirectedIn":"ستتم إعادة توجيهك خلال 30 ثانية", "redirectionInProgress":"جار إعادة التوجيه قيد التقدم ...", @@ -207,6 +211,7 @@ "resentConfirm":"هل تريد إعادة إرسال رسالة التأكيد؟", "resetFavApps":"Reset my favorite Apps.", "resetPwd":"إعادة تعيين كلمة المرور الخاصة بي", +"rest2f":"Verification code", "rightsReloadNeedsLogout":" إعادة تحميل الحقوق تحتاج إلى تسجيل الخروج وتسجيل الدخول مرة أخرى", "scope":"نطاق", "search":"Search", @@ -222,10 +227,12 @@ "stayConnected":"ابق على اتصال على هذا الجهاز", "submit":"قدم", "switchContext":"Switch context", +"totp2f":"OTP App", "totpExistingKey":"A TOTP secret already exists", "touchU2fDevice":"يرجى لمس جهاز U2F وامض الآن.", "touchU2fDeviceOrEnterTotp":"Please touch the flashing U2F device or enter TOTP code.", "type":"نوع", +"u2f":"U2F Key", "u2fFailed":"فشل التحقق من U2F. أعد محاولة الاتصال بالمشرف أو اتصل به", "u2fPermission":"قد تتم مطالبتك بالسماح للموقع إذن الوصول إلى مفاتيح الأمان الخاصة بك.بعد منح الإذن، سيبدأ الجهاز في العملية.", "u2fWelcome":"U2F device management", @@ -236,6 +243,7 @@ "upgradeSession":"ترقية الجلسة", "user":"المستخدم", "useYubikey":"استخدم اليوبي كي الخاص بك", +"utotp2f":"TOTP-or-U2F", "value":"القيمة", "verify":"التحقق", "VHnotFound":"Virtual Host not found", @@ -257,5 +265,6 @@ "yourNewTotpKey":"Your new TOTP key, please test it and enter the code", "yourPhone":"رقم هاتفك", "yourProfile":"ملفك الشخصي", -"yourTotpKey":"Your TOTP key" +"yourTotpKey":"Your TOTP key", +"yubikey2f":"Yubikey" } diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/de.json b/lemonldap-ng-portal/site/htdocs/static/languages/de.json index 85879412d..0d9808315 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/de.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/de.json @@ -128,10 +128,12 @@ "enterCred":"Bitte geben deine Zugangsdaten ein", "enterExt2fCode":"Ein Code wurde an dich gesendet. Bitte gebe diesen ein", "enterOpenIDLogin":"Bitte geben deinen OpenID-Login ein", +"enterRadius2fCode":"Please enter your OTP code", "enterTotpCode":"Gebe den TOTP Code ein", "enterYubikey":"Benutze bitte deinen Yubikey", "errorMsg":"Fehlermeldung", "expired2Fremoved":"%s expired 2F devices have been removed!", +"ext2f":"Verification code", "fillTheForm":"Fülle das Formular aus", "firstName":"Vorname", "forbidden":"Access FORBIDDEN", @@ -161,6 +163,7 @@ "logoutFromSP":"Von Dienstanbietern abmelden ...", "macros":"MACROS", "mail":"E-Mail", +"mail2f":"Email code", "mailSent2":"Eine Nachricht wurde an deine E-Mail Adresse gesendet.", "maintenanceMode":"Diese Anwendung ist in Wartung, bitte versuche später eine Verbindung herzustellen", "maxNumberof2FDevicesReached":"Maximum number of 2F devices reached!", @@ -193,6 +196,7 @@ "pwd":"Passwort", "pwdResetAlreadyIssued":"Eine Anfrage zum Zurücksetzen des Passworts wurde bereits gestellt", "pwdWillExpire":"%s Tage, %s Stunden, %s Minuten und %s Sekunden bevor dein Passwort abläuft, bitte ändere es!", +"radius2f":"Radius", "redirectedFrom":"Du wurdest umgeleitet von", "redirectedIn":"Du wirst in 30 Sekunden umgeleitet", "redirectionInProgress":"Umleitung läuft ...", @@ -207,6 +211,7 @@ "resentConfirm":"Möchtest du, dass die Bestätigungsmail erneut gesendet wird ?", "resetFavApps":"Reset my favorite Apps.", "resetPwd":"Mein Passwort zurücksetzen", +"rest2f":"Verification code", "rightsReloadNeedsLogout":"Zum Neuladen der Rechte musst du dich ab- und wieder anmelden", "scope":"Scope", "search":"Search", @@ -222,10 +227,12 @@ "stayConnected":"Auf diesem Gerät verbunden bleiben", "submit":"Absenden", "switchContext":"Switch context", +"totp2f":"OTP App", "totpExistingKey":"Es existiert bereits ein TOTP-Secret", "touchU2fDevice":"Please touch the flashing U2F device now.", "touchU2fDeviceOrEnterTotp":"Please touch the flashing U2F device or enter TOTP code.", "type":"Typ", +"u2f":"U2F Key", "u2fFailed":"U2F-Überprüfung fehlgeschlagen. Versuchen Sie es erneut oder wenden Sie sich an Ihren Administrator", "u2fPermission":"You may be prompted to allow the site permission to access your security keys. After granting permission, the device will start to blink.", "u2fWelcome":"U2F - Geräteverwaltung", @@ -236,6 +243,7 @@ "upgradeSession":"Upgrade session", "user":"Benutzer", "useYubikey":"Benutze deinen Yubikey", +"utotp2f":"TOTP-or-U2F", "value":"Value", "verify":"Verify", "VHnotFound":"Virtual Host not found", @@ -257,5 +265,6 @@ "yourNewTotpKey":"Your new TOTP key, please test it and enter the code", "yourPhone":"Ihre Telefonnummer", "yourProfile":"Ihr Profil", -"yourTotpKey":"Your TOTP key" +"yourTotpKey":"Your TOTP key", +"yubikey2f":"Yubikey" } diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/en.json b/lemonldap-ng-portal/site/htdocs/static/languages/en.json index ebff9032d..4d2b768c1 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/en.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/en.json @@ -128,10 +128,12 @@ "enterCred":"Please enter your credentials", "enterExt2fCode":"A code has been sent to you. Please enter it", "enterOpenIDLogin":"Please enter your OpenID login", +"enterRadius2fCode":"Please enter your OTP code", "enterTotpCode":"Enter TOTP code", "enterYubikey":"Please use your Yubikey", "errorMsg":"Error Message", "expired2Fremoved":"%s expired 2F devices have been removed!", +"ext2f":"Verification code", "fillTheForm":"Fill the form", "firstName":"First name", "forbidden":"Access FORBIDDEN", @@ -161,6 +163,7 @@ "logoutFromSP":"Logout from service providers ...", "macros":"MACROS", "mail":"Mail", +"mail2f":"Email code", "mailSent2":"A message has been sent to your mail address.", "maintenanceMode":"This application is in maintenance, please try to connect later", "maxNumberof2FDevicesReached":"Maximum number of 2F devices reached!", @@ -193,6 +196,7 @@ "pwd":"Password", "pwdResetAlreadyIssued":"A password reset request was already issued on ", "pwdWillExpire":"%s days, %s hours, %s minutes and %s seconds before password expiration, change it!", +"radius2f":"Radius", "redirectedFrom":"You were redirect from ", "redirectedIn":"You'll be redirected in 30 seconds", "redirectionInProgress":"Redirection in progress...", @@ -207,6 +211,7 @@ "resentConfirm":"Do you want the confirmation mail to be resent?", "resetFavApps":"Reset my favorite Apps.", "resetPwd":"Reset my password", +"rest2f":"Verification code", "rightsReloadNeedsLogout": "Rights reloads need to logout and login again", "scope":"Scope", "search":"Search", @@ -222,10 +227,12 @@ "stayConnected": "Stay connected on this device", "submit":"Submit", "switchContext":"Switch context", +"totp2f":"OTP App", "totpExistingKey":"A TOTP secret already exists", "touchU2fDevice": "Please touch the flashing U2F device now.", "touchU2fDeviceOrEnterTotp": "Please touch the flashing U2F device or enter TOTP code.", "type":"Type", +"u2f":"U2F Key", "u2fFailed": "U2F verification failed. Retry or contact your administrator", "u2fPermission": "You may be prompted to allow the site permission to access your security keys. After granting permission, the device will start to blink.", "u2fWelcome": "U2F device management", @@ -236,6 +243,7 @@ "upgradeSession":"Upgrade session", "user":"User", "useYubikey":"use your Yubikey", +"utotp2f":"TOTP-or-U2F", "value":"Value", "verify": "Verify", "VHnotFound":"Virtual Host not found", @@ -257,5 +265,6 @@ "yourNewTotpKey":"Your new TOTP key, please test it and enter the code", "yourPhone":"Your phone number", "yourProfile":"Your profile", -"yourTotpKey":"Your TOTP key" +"yourTotpKey":"Your TOTP key", +"yubikey2f":"Yubikey" } diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/es.json b/lemonldap-ng-portal/site/htdocs/static/languages/es.json index d9734d70c..744884cf3 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/es.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/es.json @@ -128,10 +128,12 @@ "enterCred":"Please enter your credentials", "enterExt2fCode":"A code has been sent to you. Please enter it", "enterOpenIDLogin":"Please enter your OpenID login", +"enterRadius2fCode":"Please enter your OTP code", "enterTotpCode":"Enter TOTP code", "enterYubikey":"Please use your Yubikey", "errorMsg":"Error Message", "expired2Fremoved":"%s expired 2F devices have been removed!", +"ext2f":"Verification code", "fillTheForm":"Fill the form", "firstName":"First name", "forbidden":"Access FORBIDDEN", @@ -161,6 +163,7 @@ "logoutFromSP":"Logout from service providers ...", "macros":"MACROS", "mail":"Mail", +"mail2f":"Email code", "mailSent2":"A message has been sent to your mail address.", "maintenanceMode":"This application is in maintenance, please try to connect later", "maxNumberof2FDevicesReached":"Maximum number of 2F devices reached!", @@ -193,6 +196,7 @@ "pwd":"Password", "pwdResetAlreadyIssued":"A password reset request was already issued on ", "pwdWillExpire":"%s days, %s hours, %s minutes and %s seconds before password expiration, change it!", +"radius2f":"Radius", "redirectedFrom":"You were redirect from ", "redirectedIn":"You'll be redirected in 30 seconds", "redirectionInProgress":"Redirection in progress...", @@ -207,6 +211,7 @@ "resentConfirm":"Do you want the confirmation mail to be resent?", "resetFavApps":"Reset my favorite Apps.", "resetPwd":"Reset my password", +"rest2f":"Verification code", "rightsReloadNeedsLogout":"Rights reloads need to logout and login again", "scope":"Scope", "search":"Search", @@ -222,10 +227,12 @@ "stayConnected":"Stay connected on this device", "submit":"Submit", "switchContext":"Switch context", +"totp2f":"OTP App", "totpExistingKey":"A TOTP secret already exists", "touchU2fDevice":"Please touch the flashing U2F device now.", "touchU2fDeviceOrEnterTotp":"Please touch the flashing U2F device or enter TOTP code.", "type":"Type", +"u2f":"U2F Key", "u2fFailed":"U2F verification failed. Retry or contact your administrator", "u2fPermission":"You may be prompted to allow the site permission to access your security keys. After granting permission, the device will start to blink.", "u2fWelcome":"U2F device management", @@ -236,6 +243,7 @@ "upgradeSession":"Upgrade session", "user":"User", "useYubikey":"use your Yubikey", +"utotp2f":"TOTP-or-U2F", "value":"Value", "verify":"Verify", "VHnotFound":"Virtual Host not found", @@ -257,5 +265,6 @@ "yourNewTotpKey":"Your new TOTP key, please test it and enter the code", "yourPhone":"Your phone number", "yourProfile":"Your profile", -"yourTotpKey":"Your TOTP key" +"yourTotpKey":"Your TOTP key", +"yubikey2f":"Yubikey" } diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/fi.json b/lemonldap-ng-portal/site/htdocs/static/languages/fi.json index c2251c737..2924ffb6f 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/fi.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/fi.json @@ -128,10 +128,12 @@ "enterCred":"Syötä käyttäjätietosi", "enterExt2fCode":"A code has been sent to you. Please enter it", "enterOpenIDLogin":"Please enter your OpenID login", +"enterRadius2fCode":"Please enter your OTP code", "enterTotpCode":"Enter TOTP code", "enterYubikey":"Please use your Yubikey", "errorMsg":"Virhe viesti", "expired2Fremoved":"%s expired 2F devices have been removed!", +"ext2f":"Verification code", "fillTheForm":"Fill the form", "firstName":"Etunimi", "forbidden":"Access FORBIDDEN", @@ -161,6 +163,7 @@ "logoutFromSP":"Logout from service providers ...", "macros":"MACROS", "mail":"Sähköposti", +"mail2f":"Email code", "mailSent2":"Viesti on lähetetty sähköpostiisi.", "maintenanceMode":"This application is in maintenance, please try to connect later", "maxNumberof2FDevicesReached":"Maximum number of 2F devices reached!", @@ -193,6 +196,7 @@ "pwd":"Salasana", "pwdResetAlreadyIssued":"A password reset request was already issued on ", "pwdWillExpire":"%d päivää, %d tuntia, %d minuuttia ja %sekunttia jäljellä salasanan vanhentumiseen, vaihda salasana!", +"radius2f":"Radius", "redirectedFrom":"Olet uudelleenohjattu", "redirectedIn":"You'll be redirected in 30 seconds", "redirectionInProgress":"Redirection in progress...", @@ -207,6 +211,7 @@ "resentConfirm":"Do you want the confirmation mail to be resent?", "resetFavApps":"Reset my favorite Apps.", "resetPwd":"Palauta salasanani?", +"rest2f":"Verification code", "rightsReloadNeedsLogout":"Rights reloads need to logout and login again", "scope":"Scope", "search":"Search", @@ -222,10 +227,12 @@ "stayConnected":"Stay connected on this device", "submit":"Lähetä", "switchContext":"Switch context", +"totp2f":"OTP App", "totpExistingKey":"A TOTP secret already exists", "touchU2fDevice":"Please touch the flashing U2F device now.", "touchU2fDeviceOrEnterTotp":"Please touch the flashing U2F device or enter TOTP code.", "type":"Type", +"u2f":"U2F Key", "u2fFailed":"U2F verification failed. Retry or contact your administrator", "u2fPermission":"You may be prompted to allow the site permission to access your security keys. After granting permission, the device will start to blink.", "u2fWelcome":"U2F device management", @@ -236,6 +243,7 @@ "upgradeSession":"Upgrade session", "user":"Käyttäjä", "useYubikey":"Käytä Yubikeytä", +"utotp2f":"TOTP-or-U2F", "value":"Value", "verify":"Vahvista", "VHnotFound":"Virtual Host not found", @@ -257,5 +265,6 @@ "yourNewTotpKey":"Your new TOTP key, please test it and enter the code", "yourPhone":"Puhelinnumerosi", "yourProfile":"Profiilisi", -"yourTotpKey":"Your TOTP key" +"yourTotpKey":"Your TOTP key", +"yubikey2f":"Yubikey" } diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/fr.json b/lemonldap-ng-portal/site/htdocs/static/languages/fr.json index 7e8a2dbc6..788398c52 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/fr.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/fr.json @@ -128,10 +128,12 @@ "enterCred":"Merci de vous authentifier", "enterExt2fCode":"Un code vous a été envoyé, entrez-le ici", "enterOpenIDLogin":"Entrez votre identifiant OpenID", +"enterRadius2fCode":"Entrez votre code OTP", "enterTotpCode":"Entrez le code TOTP", "enterYubikey":"Utilisez votre Yubikey", "errorMsg":"Message d'erreur", "expired2Fremoved":"%s seconds facteurs expirés ont été supprimés !", +"ext2f":"Code de vérification", "fillTheForm":"Remplissez le formulaire", "forbidden":"Accès INTERDIT", "firstName":"Prénom", @@ -161,6 +163,7 @@ "logoutFromSP":"Déconnexion des services ...", "macros":"MACROS", "mail":"Adresse mail", +"mail2f":"Code par mail", "mailSent2":"Un message a été envoyé à votre adresse mail.", "maintenanceMode":"Cette application est en maintenance, merci de réessayer plus tard", "maxNumberof2FDevicesReached":"Nombre maximum de seconds facteurs atteint !", @@ -193,6 +196,7 @@ "pwd":"Mot de passe", "pwdResetAlreadyIssued":"Une demande de réinitialisation de mot de passe a déjà été faite le ", "pwdWillExpire":"%s jours, %s heures, %s minutes et %s secondes avant expiration de votre mot de passe, pensez à le changer !", +"radius2f":"Radius", "redirectedFrom":"Vous avez été redirigé depuis ", "redirectedIn":"Vous allez être redirigé(e) automatiquement dans 30 secondes", "redirectionInProgress":"Redirection en cours ...", @@ -207,6 +211,7 @@ "resentConfirm":"Voulez-vous que le message de confirmation soit renvoyé ?", "resetFavApps":"Réinitialiser mes applications favorites", "resetPwd":"Réinitialiser mon mot de passe", +"rest2f":"Code de vérification", "rightsReloadNeedsLogout": "Le rechargement des droits nécessite une déconnexion", "scope": "Informations", "search":"Chercher", @@ -222,10 +227,12 @@ "stayConnected": "Rester connecté sur cet appareil", "submit":"Envoyer", "switchContext":"Changer de contexte", +"totp2f":"Application OTP", "totpExistingKey":"Un secret TOTP existe déjà !", "touchU2fDevice": "Posez votre doigt sur le périphérique U2F", "touchU2fDeviceOrEnterTotp": "Posez votre doigt sur le périphérique U2F ou entrez le code TOTP", "type":"Type", +"u2f":"Clé U2F", "u2fFailed": "La vérification U2F a échoué. Réessayez ou contactez votre administrateur", "u2fPermission": "Il est possible qu'on vous demande d'autoriser le site à accéder à votre clef. Après votre accord, la clef clignotera.", "u2fWelcome": "Gestion du périphérique U2F", @@ -236,6 +243,7 @@ "upgradeSession":"Se réauthentifier", "user":"Utilisateur", "useYubikey":"Utilisez votre Yubikey", +"utotp2f":"TOTP-ou-U2F", "value":"Valeur", "verify": "Vérifier", "VHnotFound":"Hôte virtuel erroné ou inexistant", @@ -257,5 +265,6 @@ "yourNewTotpKey":"Votre nouvelle clef TOTP. Testez-la et entrez le code", "yourPhone":"Votre numéro de téléphone", "yourProfile":"Vos informations personnelles", -"yourTotpKey":"Votre clef TOTP" +"yourTotpKey":"Votre clef TOTP", +"yubikey2f":"Yubikey" } diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/it.json b/lemonldap-ng-portal/site/htdocs/static/languages/it.json index 63ef361c4..27fd90cbf 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/it.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/it.json @@ -128,10 +128,12 @@ "enterCred":"Inserisci le tue credenziali", "enterExt2fCode":"Un codice vi é stato inviato. Inseritelo", "enterOpenIDLogin":"Inserisci il tuo login OpenID", +"enterRadius2fCode":"Please enter your OTP code", "enterTotpCode":"Inserisci il codice TOTP", "enterYubikey":"Utilizza il tuo Yubikey", "errorMsg":"Messaggio di errore", "expired2Fremoved":"%s expired 2F devices have been removed!", +"ext2f":"Verification code", "fillTheForm":"Compila il modulo", "firstName":"Nome", "forbidden":"Accesso VIETATO", @@ -161,6 +163,7 @@ "logoutFromSP":"Disconnessione dai fornitori di servizi ...", "macros":"MACROS", "mail":"Mail", +"mail2f":"Email code", "mailSent2":"Vi é stato inviato un messaggio via mail", "maintenanceMode":"Questa applicazione è in manutenzione, prova a connetterti più tardi", "maxNumberof2FDevicesReached":"Raggiunto il numero massimo di dispositivi 2F !", @@ -193,6 +196,7 @@ "pwd":"Password", "pwdResetAlreadyIssued":"Una richiesta di ripristino della password é già stata rilasciata", "pwdWillExpire":"%s giorni, %s ore, %s minuti e %s secondi prima della scadenza della password, cambiala!", +"radius2f":"Radius", "redirectedFrom":"Sei stato reindirizzato da", "redirectedIn":"Sarai reindirizzato in 30 secondi", "redirectionInProgress":"Reindirizzamento in corso ...", @@ -207,6 +211,7 @@ "resentConfirm":"Vuoi inviare di nuovo la mail di conferma?", "resetFavApps":"Reset my favorite Apps.", "resetPwd":"Reimpostare la password", +"rest2f":"Verification code", "rightsReloadNeedsLogout":"Le ricariche dei diritti necessitano di disconnettersi e di riconnettersi", "scope":"Ambito", "search":"Ricerca", @@ -222,10 +227,12 @@ "stayConnected":"Resta connesso su questo dispositivo", "submit":"Invia", "switchContext":"Switch context", +"totp2f":"OTP App", "totpExistingKey":"Un segreto TOTP esiste già", "touchU2fDevice":"Adesso tocca il dispositivo U2F lampeggiante.", "touchU2fDeviceOrEnterTotp":"Tocca il dispositivo U2F lampeggiante o inserisci il codice TOTP.", "type":"Tipo", +"u2f":"U2F Key", "u2fFailed":"Verifica U2F non riuscita. Riprovare o contattare l'amministratore", "u2fPermission":"È possibile che venga richiesto di consentire il permesso del sito per accedere alle chiavi di sicurezza. Dopo aver concesso il permesso, il dispositivo inizierà a lampeggiare.", "u2fWelcome":"Gestione dei dispositivi U2F", @@ -236,6 +243,7 @@ "upgradeSession":"Sessione di aggiornamento", "user":"Utente", "useYubikey":"Usa la tua Yubikey", +"utotp2f":"TOTP-or-U2F", "value":"Valore", "verify":"Verifica", "VHnotFound":"Host virtuale non trovato", @@ -257,5 +265,6 @@ "yourNewTotpKey":"La tua nuova chiave TOTP, per favore provala e inserisci il codice", "yourPhone":"Numero di telefono", "yourProfile":"Il tuo profilo", -"yourTotpKey":"La tua chiave TOTP" +"yourTotpKey":"La tua chiave TOTP", +"yubikey2f":"Yubikey" } diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/nl.json b/lemonldap-ng-portal/site/htdocs/static/languages/nl.json index 3357f1746..590b88f84 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/nl.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/nl.json @@ -128,10 +128,12 @@ "enterCred":"Please enter your credentials", "enterExt2fCode":"A code has been sent to you. Please enter it", "enterOpenIDLogin":"Please enter your OpenID login", +"enterRadius2fCode":"Please enter your OTP code", "enterTotpCode":"Enter TOTP code", "enterYubikey":"Please use your Yubikey", "errorMsg":"Error Message", "expired2Fremoved":"%s expired 2F devices have been removed!", +"ext2f":"Verification code", "fillTheForm":"Fill the form", "firstName":"First name", "forbidden":"Access FORBIDDEN", @@ -161,6 +163,7 @@ "logoutFromSP":"Logout from service providers ...", "macros":"MACROS", "mail":"Mail", +"mail2f":"Email code", "mailSent2":"A message has been sent to your mail address.", "maintenanceMode":"This application is in maintenance, please try to connect later", "maxNumberof2FDevicesReached":"Maximum number of 2F devices reached!", @@ -193,6 +196,7 @@ "pwd":"Password", "pwdResetAlreadyIssued":"A password reset request was already issued on ", "pwdWillExpire":"%s days, %s hours, %s minutes and %s seconds before password expiration, change it!", +"radius2f":"Radius", "redirectedFrom":"You were redirect from ", "redirectedIn":"You'll be redirected in 30 seconds", "redirectionInProgress":"Redirection in progress...", @@ -207,6 +211,7 @@ "resentConfirm":"Do you want the confirmation mail to be resent?", "resetFavApps":"Reset my favorite Apps.", "resetPwd":"Reset my password", +"rest2f":"Verification code", "rightsReloadNeedsLogout":"Rights reloads need to logout and login again", "scope":"Scope", "search":"Search", @@ -222,10 +227,12 @@ "stayConnected":"Stay connected on this device", "submit":"Submit", "switchContext":"Switch context", +"totp2f":"OTP App", "totpExistingKey":"A TOTP secret already exists", "touchU2fDevice":"Please touch the flashing U2F device now.", "touchU2fDeviceOrEnterTotp":"Please touch the flashing U2F device or enter TOTP code.", "type":"Type", +"u2f":"U2F Key", "u2fFailed":"U2F verification failed. Retry or contact your administrator", "u2fPermission":"You may be prompted to allow the site permission to access your security keys. After granting permission, the device will start to blink.", "u2fWelcome":"U2F device management", @@ -236,6 +243,7 @@ "upgradeSession":"Upgrade session", "user":"User", "useYubikey":"use your Yubikey", +"utotp2f":"TOTP-or-U2F", "value":"Value", "verify":"Verify", "VHnotFound":"Virtual Host not found", @@ -257,5 +265,6 @@ "yourNewTotpKey":"Your new TOTP key, please test it and enter the code", "yourPhone":"Your phone number", "yourProfile":"Your profile", -"yourTotpKey":"Your TOTP key" +"yourTotpKey":"Your TOTP key", +"yubikey2f":"Yubikey" } diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/pt.json b/lemonldap-ng-portal/site/htdocs/static/languages/pt.json index d2b1980ce..ddd8e522e 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/pt.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/pt.json @@ -128,10 +128,12 @@ "enterCred":"Please enter your credentials", "enterExt2fCode":"A code has been sent to you. Please enter it", "enterOpenIDLogin":"Please enter your OpenID login", +"enterRadius2fCode":"Please enter your OTP code", "enterTotpCode":"Enter TOTP code", "enterYubikey":"Please use your Yubikey", "errorMsg":"Error Message", "expired2Fremoved":"%s expired 2F devices have been removed!", +"ext2f":"Verification code", "fillTheForm":"Fill the form", "firstName":"First name", "forbidden":"Access FORBIDDEN", @@ -161,6 +163,7 @@ "logoutFromSP":"Logout from service providers ...", "macros":"MACROS", "mail":"Mail", +"mail2f":"Email code", "mailSent2":"A message has been sent to your mail address.", "maintenanceMode":"This application is in maintenance, please try to connect later", "maxNumberof2FDevicesReached":"Maximum number of 2F devices reached!", @@ -193,6 +196,7 @@ "pwd":"Password", "pwdResetAlreadyIssued":"A password reset request was already issued on ", "pwdWillExpire":"%s days, %s hours, %s minutes and %s seconds before password expiration, change it!", +"radius2f":"Radius", "redirectedFrom":"You were redirect from ", "redirectedIn":"You'll be redirected in 30 seconds", "redirectionInProgress":"Redirection in progress...", @@ -207,6 +211,7 @@ "resentConfirm":"Do you want the confirmation mail to be resent?", "resetFavApps":"Reset my favorite Apps.", "resetPwd":"Reset my password", +"rest2f":"Verification code", "rightsReloadNeedsLogout":"Rights reloads need to logout and login again", "scope":"Scope", "search":"Search", @@ -222,10 +227,12 @@ "stayConnected":"Stay connected on this device", "submit":"Submit", "switchContext":"Switch context", +"totp2f":"OTP App", "totpExistingKey":"A TOTP secret already exists", "touchU2fDevice":"Please touch the flashing U2F device now.", "touchU2fDeviceOrEnterTotp":"Please touch the flashing U2F device or enter TOTP code.", "type":"Type", +"u2f":"U2F Key", "u2fFailed":"U2F verification failed. Retry or contact your administrator", "u2fPermission":"You may be prompted to allow the site permission to access your security keys. After granting permission, the device will start to blink.", "u2fWelcome":"U2F device management", @@ -236,6 +243,7 @@ "upgradeSession":"Upgrade session", "user":"User", "useYubikey":"use your Yubikey", +"utotp2f":"TOTP-or-U2F", "value":"Value", "verify":"Verify", "VHnotFound":"Virtual Host not found", @@ -257,5 +265,6 @@ "yourNewTotpKey":"Your new TOTP key, please test it and enter the code", "yourPhone":"Your phone number", "yourProfile":"Your profile", -"yourTotpKey":"Your TOTP key" +"yourTotpKey":"Your TOTP key", +"yubikey2f":"Yubikey" } diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/ro.json b/lemonldap-ng-portal/site/htdocs/static/languages/ro.json index 79d3a7646..3b0a4f8dc 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/ro.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/ro.json @@ -128,10 +128,12 @@ "enterCred":"Please enter your credentials", "enterExt2fCode":"A code has been sent to you. Please enter it", "enterOpenIDLogin":"Please enter your OpenID login", +"enterRadius2fCode":"Please enter your OTP code", "enterTotpCode":"Enter TOTP code", "enterYubikey":"Please use your Yubikey", "errorMsg":"Error Message", "expired2Fremoved":"%s expired 2F devices have been removed!", +"ext2f":"Verification code", "fillTheForm":"Fill the form", "firstName":"First name", "forbidden":"Access FORBIDDEN", @@ -161,6 +163,7 @@ "logoutFromSP":"Logout from service providers ...", "macros":"MACROS", "mail":"Mail", +"mail2f":"Email code", "mailSent2":"A message has been sent to your mail address.", "maintenanceMode":"This application is in maintenance, please try to connect later", "maxNumberof2FDevicesReached":"Maximum number of 2F devices reached!", @@ -193,6 +196,7 @@ "pwd":"Password", "pwdResetAlreadyIssued":"A password reset request was already issued on ", "pwdWillExpire":"%s days, %s hours, %s minutes and %s seconds before password expiration, change it!", +"radius2f":"Radius", "redirectedFrom":"You were redirect from ", "redirectedIn":"You'll be redirected in 30 seconds", "redirectionInProgress":"Redirection in progress...", @@ -207,6 +211,7 @@ "resentConfirm":"Do you want the confirmation mail to be resent?", "resetFavApps":"Reset my favorite Apps.", "resetPwd":"Reset my password", +"rest2f":"Verification code", "rightsReloadNeedsLogout":"Rights reloads need to logout and login again", "scope":"Scope", "search":"Search", @@ -222,10 +227,12 @@ "stayConnected":"Stay connected on this device", "submit":"Submit", "switchContext":"Switch context", +"totp2f":"OTP App", "totpExistingKey":"A TOTP secret already exists", "touchU2fDevice":"Please touch the flashing U2F device now.", "touchU2fDeviceOrEnterTotp":"Please touch the flashing U2F device or enter TOTP code.", "type":"Type", +"u2f":"U2F Key", "u2fFailed":"U2F verification failed. Retry or contact your administrator", "u2fPermission":"You may be prompted to allow the site permission to access your security keys. After granting permission, the device will start to blink.", "u2fWelcome":"U2F device management", @@ -236,6 +243,7 @@ "upgradeSession":"Upgrade session", "user":"User", "useYubikey":"use your Yubikey", +"utotp2f":"TOTP-or-U2F", "value":"Value", "verify":"Verify", "VHnotFound":"Virtual Host not found", @@ -257,5 +265,6 @@ "yourNewTotpKey":"Your new TOTP key, please test it and enter the code", "yourPhone":"Your phone number", "yourProfile":"Your profile", -"yourTotpKey":"Your TOTP key" +"yourTotpKey":"Your TOTP key", +"yubikey2f":"Yubikey" } diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/vi.json b/lemonldap-ng-portal/site/htdocs/static/languages/vi.json index 8df30610e..3c8b803f4 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/vi.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/vi.json @@ -128,10 +128,12 @@ "enterCred":"Vui lòng nhập thông tin đăng nhập của bạn", "enterExt2fCode":"Một mã đã được gửi cho bạn. Hãy nhập nó", "enterOpenIDLogin":"Hãy nhập thông tin đăng nhập OpenID của bạn", +"enterRadius2fCode":"Please enter your OTP code", "enterTotpCode":"Enter TOTP code", "enterYubikey":"Vui lòng sử dụng Yubikey của bạn", "errorMsg":"Thông báo lỗi", "expired2Fremoved":"%s expired 2F devices have been removed!", +"ext2f":"Verification code", "fillTheForm":"Fill the form", "firstName":"Tên", "forbidden":"Access FORBIDDEN", @@ -161,6 +163,7 @@ "logoutFromSP":"Logout from service providers ...", "macros":"MACROS", "mail":"Thư", +"mail2f":"Email code", "mailSent2":"Một tin nhắn đã được gửi đến địa chỉ thư của bạn.", "maintenanceMode":"Ứng dụng này đang trong quá trình bảo trì, hãy thử kết nối sau", "maxNumberof2FDevicesReached":"Maximum number of 2F devices reached!", @@ -193,6 +196,7 @@ "pwd":"Mật khẩu", "pwdResetAlreadyIssued":"Yêu cầu đặt lại mật khẩu đã được ban hành", "pwdWillExpire":"%s ngày, %s giờ, %s phút và %s giây trước khi hết hạn mật khẩu, hãy thay đổi nó!", +"radius2f":"Radius", "redirectedFrom":"Bạn đã được chuyển hướng từ", "redirectedIn":"Bạn sẽ được chuyển hướng trong 30 giây", "redirectionInProgress":"Đang tiến hành chuyển hướng...", @@ -207,6 +211,7 @@ "resentConfirm":"Bạn có muốn gửi lại thư xác nhận không?", "resetFavApps":"Reset my favorite Apps.", "resetPwd":"Đặt lại mật khẩu của tôi", +"rest2f":"Verification code", "rightsReloadNeedsLogout":"Tải lại quyền cần đăng xuất và đăng nhập lại", "scope":"Phạm vi", "search":"Search", @@ -222,10 +227,12 @@ "stayConnected":"Giữ kết nối trên thiết bị này", "submit":"Gửi", "switchContext":"Switch context", +"totp2f":"OTP App", "totpExistingKey":"A TOTP secret already exists", "touchU2fDevice":"Vui lòng chạm vào thiết bị U2F nhấp nháy ngay bây giờ.", "touchU2fDeviceOrEnterTotp":"Please touch the flashing U2F device or enter TOTP code.", "type":"Loại", +"u2f":"U2F Key", "u2fFailed":"Xác minh U2F thất bại. Thử lại hoặc liên hệ với quản trị viên của bạn ", "u2fPermission":"Bạn có thể được nhắc cho phép trang web được phép truy cập vào các khóa bảo mật của bạn. Sau khi cho phép, thiết bị sẽ bắt đầu nhấp nháy. ", "u2fWelcome":"U2F device management", @@ -236,6 +243,7 @@ "upgradeSession":"Phiên nâng cấp", "user":"Người dùng", "useYubikey":"sử dụng Yubikey của bạn", +"utotp2f":"TOTP-or-U2F", "value":"Giá trị", "verify":"Xác minh", "VHnotFound":"Virtual Host not found", @@ -257,5 +265,6 @@ "yourNewTotpKey":"Your new TOTP key, please test it and enter the code", "yourPhone":"Số điện thoại của bạn", "yourProfile":"Profile của bạn", -"yourTotpKey":"Your TOTP key" +"yourTotpKey":"Your TOTP key", +"yubikey2f":"Yubikey" } diff --git a/lemonldap-ng-portal/site/htdocs/static/languages/zh.json b/lemonldap-ng-portal/site/htdocs/static/languages/zh.json index 407da417f..4998e88de 100644 --- a/lemonldap-ng-portal/site/htdocs/static/languages/zh.json +++ b/lemonldap-ng-portal/site/htdocs/static/languages/zh.json @@ -128,10 +128,12 @@ "enterCred":"请输入您的认证信息", "enterExt2fCode":"验证法已发送,请输入", "enterOpenIDLogin":"请输入您的 OpenID 认证", +"enterRadius2fCode":"Please enter your OTP code", "enterTotpCode":"Enter TOTP code", "enterYubikey":"请使用您的Yubikey", "errorMsg":"错误消息", "expired2Fremoved":"%s expired 2F devices have been removed!", +"ext2f":"Verification code", "fillTheForm":"Fill the form", "firstName":"名", "forbidden":"Access FORBIDDEN", @@ -161,6 +163,7 @@ "logoutFromSP":"Logout from service providers ...", "macros":"宏", "mail":"邮件", +"mail2f":"Email code", "mailSent2":"已经发送一封邮件到您的邮箱", "maintenanceMode":"程序维护中,请稍后再尝试连接。", "maxNumberof2FDevicesReached":"Maximum number of 2F devices reached!", @@ -193,6 +196,7 @@ "pwd":"密码", "pwdResetAlreadyIssued":"A password reset request was already issued on ", "pwdWillExpire":"距离密码失效还有 %d 天, %d 小时, %d 分钟, %d 秒, 请修改!", +"radius2f":"Radius", "redirectedFrom":"您重定向自", "redirectedIn":"您将30秒后重定向", "redirectionInProgress":"重定向进行中", @@ -207,6 +211,7 @@ "resentConfirm":"您想确认邮件被重新发送吗?", "resetFavApps":"Reset my favorite Apps.", "resetPwd":"重置我的密码", +"rest2f":"Verification code", "rightsReloadNeedsLogout":"重新加载权限需要登出并且再次登录", "scope":"Scope", "search":"搜索", @@ -222,10 +227,12 @@ "stayConnected":"在该项设备上保持连接", "submit":"提交", "switchContext":"Switch context", +"totp2f":"OTP App", "totpExistingKey":"A TOTP secret already exists", "touchU2fDevice":"Please touch the flashing U2F device now.", "touchU2fDeviceOrEnterTotp":"Please touch the flashing U2F device or enter TOTP code.", "type":"Type", +"u2f":"U2F Key", "u2fFailed":"U2F verification failed. Retry or contact your administrator", "u2fPermission":"You may be prompted to allow the site permission to access your security keys. After granting permission, the device will start to blink.", "u2fWelcome":"U2F device management", @@ -236,6 +243,7 @@ "upgradeSession":"升级会话", "user":"用户", "useYubikey":"使用您的 Yubikey", +"utotp2f":"TOTP-or-U2F", "value":"Value", "verify":"验证", "VHnotFound":"Virtual Host not found", @@ -257,5 +265,6 @@ "yourNewTotpKey":"Your new TOTP key, please test it and enter the code", "yourPhone":"您的电话号码", "yourProfile":"您的档案", -"yourTotpKey":"Your TOTP key" +"yourTotpKey":"Your TOTP key", +"yubikey2f":"Yubikey" } diff --git a/lemonldap-ng-portal/site/templates/bootstrap/2fchoice.tpl b/lemonldap-ng-portal/site/templates/bootstrap/2fchoice.tpl index 594282385..d0ca66862 100644 --- a/lemonldap-ng-portal/site/templates/bootstrap/2fchoice.tpl +++ b/lemonldap-ng-portal/site/templates/bootstrap/2fchoice.tpl @@ -9,6 +9,13 @@ " /> diff --git a/lemonldap-ng-portal/site/templates/bootstrap/yubikey2fregister.tpl b/lemonldap-ng-portal/site/templates/bootstrap/yubikey2fregister.tpl index 196254fd3..ddb837a38 100644 --- a/lemonldap-ng-portal/site/templates/bootstrap/yubikey2fregister.tpl +++ b/lemonldap-ng-portal/site/templates/bootstrap/yubikey2fregister.tpl @@ -20,9 +20,9 @@
- +
- + diff --git a/lemonldap-ng-portal/t/35-REST-config-backend.t b/lemonldap-ng-portal/t/35-REST-config-backend.t index 142779bb9..7e6384b2a 100644 --- a/lemonldap-ng-portal/t/35-REST-config-backend.t +++ b/lemonldap-ng-portal/t/35-REST-config-backend.t @@ -127,9 +127,79 @@ ok( $res->{_session_id} eq $spId, ' Good ID' ) or explain( $res, "_session_id => $spId" ); ok( $res->{uid} eq 'french', ' Uid is french' ) or explain( $res, 'uid => french' ); -ok( $res->{cn} eq 'Frédéric Accents', 'UTF-8 values' ); +ok( $res->{cn} eq 'Frédéric Accents', ' UTF-8 values' ); count(5); +# Retrieve error messages +ok( + $res = $issuer->_get("/error/zz/9"), + 'Retrieve error message: 9 from lang: zz' +); +expectOK($res); +ok( $res = eval { JSON::from_json( $res->[2]->[0] ) }, ' GET JSON' ) + or print STDERR $@; +ok( $res->{result} eq '0', ' Error returned' ) + or explain( $res, 'result => 0' ); +ok( $res->{lang} eq 'zz', ' Goog lang' ) + or explain( $res, 'lang => zz' ); +ok( $res->{error} eq 'Unable to read language file', + ' Unable to read lang file' ) + or explain( $res, 'Unable to read lang file' ); +count(5); + +ok( + $res = $issuer->_get("/error/fr/9"), + 'Retrieve error message: 9 from lang: fr' +); +expectOK($res); +ok( $res = eval { JSON::from_json( $res->[2]->[0] ) }, ' GET JSON' ) + or print STDERR $@; +ok( $res->{lang} eq 'fr', ' Good lang' ) + or explain( $res, 'lang => fr' ); +ok( $res->{errorNum} eq '9', ' Good errorNum' ) + or explain( $res, 'errorNum => 9' ); +ok( $res->{errorMsg} eq 'Veuillez vous authentifier', ' Good errorMsg' ) + or explain( $res, 'errorMsg => Veuillez vous authentifier' ); +ok( $res->{result} eq '1', ' Good result' ) + or explain( $res, 'result => 1' ); +count(6); + +ok( + $res = $issuer->_get("/error/es"), + 'Retrieve ALL error messages from lang: es' +); +expectOK($res); +ok( $res = eval { JSON::from_json( $res->[2]->[0] ) }, ' GET JSON' ) + or print STDERR $@; +ok( $res->{lang} eq 'es', ' Good lang' ) + or explain( $res, 'lang => es' ); +ok( $res->{errorNum} eq 'all', ' Good all errorNum' ) + or explain( $res, 'errorNum => all' ); +ok( $res->{errorMsg}->{PE4} eq 'Usuario no reconocido', ' Good errorMsg' ) + or explain( $res, 'errorMsg PE4 => Usuario no reconocido' ); +ok( keys %{ $res->{errorMsg} } eq 84, ' Good number of error messages found' ) + or explain( $res, 'Number of error messages' ); +ok( $res->{result} eq '1', ' Good result' ) + or explain( $res, 'result => 1' ); +count(7); + +ok( $res = $issuer->_get("/error"), + 'Retrieve ALL error messages from lang: en (default)' ); +expectOK($res); +ok( $res = eval { JSON::from_json( $res->[2]->[0] ) }, ' GET JSON' ) + or print STDERR $@; +ok( $res->{lang} eq 'en', ' Good lang' ) + or explain( $res, 'lang => en' ); +ok( $res->{errorNum} eq 'all', ' Good all errorNum' ) + or explain( $res, 'errorNum => all' ); +ok( $res->{errorMsg}->{PE4} eq 'User not found in directory', ' Good errorMsg' ) + or explain( $res, 'errorMsg PE4 => User not found in directory' ); +ok( keys %{ $res->{errorMsg} } eq 84, ' Good number of error messages found' ) + or explain( $res, 'Number of error messages' ); +ok( $res->{result} eq '1', ' Good result' ) + or explain( $res, 'result => 1' ); +count(7); + # Logout switch ('sp'); ok( diff --git a/lemonldap-ng-portal/t/36-Combination-with-TOTP.t b/lemonldap-ng-portal/t/36-Combination-with-TOTP.t new file mode 100644 index 000000000..9afd19a47 --- /dev/null +++ b/lemonldap-ng-portal/t/36-Combination-with-TOTP.t @@ -0,0 +1,156 @@ +use Test::More; +use strict; +use IO::String; + +require 't/test-lib.pm'; +my $maintests = 16; + +SKIP: { + eval { require Convert::Base32 }; + if ($@) { + skip 'Convert::Base32 is missing', $maintests; + } + require Lemonldap::NG::Common::TOTP; + + my $client = LLNG::Manager::Test->new( { + ini => { + logLevel => 'error', + loginHistoryEnabled => 0, + useSafeJail => 1, + totp2fSelfRegistration => 1, + totp2fActivation => 1, + requireToken => 1, + formTimeout => 2, + loginHistoryEnabled => 0, + authentication => 'Combination', + userDB => 'Same', + combination => '[Dm1] or [Dm2]', + combModules => { + Dm1 => { + for => 0, + type => 'Demo', + }, + Dm2 => { + for => 0, + type => 'Demo', + }, + }, + } + } + ); + my $res; + + ## Try to authenticate + ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); + my ( $host, $url, $query ) = + expectForm( $res, '#', undef, 'user', 'password', 'token' ); + + $query =~ s/user=/user=dwho/; + $query =~ s/password=/password=dwho/; + ok( + $res = $client->_post( + '/', + IO::String->new($query), + length => length($query), + accept => 'text/html', + ), + 'Auth query' + ); + count(1); + my $id = expectCookie($res); + expectRedirection( $res, 'http://auth.example.com/' ); + + # TOTP form + ok( + $res = $client->_get( + '/2fregisters/totp', + cookie => "lemonldap=$id", + accept => 'text/html', + ), + 'Form registration' + ); + ok( $res->[2]->[0] =~ /totpregistration\.(?:min\.)?js/, 'Found TOTP js' ); + + # JS query + ok( + $res = $client->_post( + '/2fregisters/totp/getkey', IO::String->new(''), + cookie => "lemonldap=$id", + length => 0, + ), + 'Get new key' + ); + eval { $res = JSON::from_json( $res->[2]->[0] ) }; + ok( not($@), 'Content is JSON' ) + or explain( $res->[2]->[0], 'JSON content' ); + my ( $key, $token ); + ok( $key = $res->{secret}, 'Found secret' ); + ok( $token = $res->{token}, 'Found token' ); + $key = Convert::Base32::decode_base32($key); + + # Post code + my $code; + ok( $code = Lemonldap::NG::Common::TOTP::_code( undef, $key, 0, 30, 6 ), + 'Code' ); + ok( $code =~ /^\d{6}$/, 'Code contains 6 digits' ); + my $s = "code=$code&token=$token"; + ok( + $res = $client->_post( + '/2fregisters/totp/verify', + IO::String->new($s), + length => length($s), + cookie => "lemonldap=$id", + ), + 'Post code' + ); + eval { $res = JSON::from_json( $res->[2]->[0] ) }; + ok( not($@), 'Content is JSON' ) + or explain( $res->[2]->[0], 'JSON content' ); + ok( $res->{result} == 1, 'Key is registered' ); + $client->logout($id); + + # Try to sign-in + ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); + ( $host, $url, $query ) = + expectForm( $res, '#', undef, 'user', 'password', 'token' ); + + $query =~ s/user=/user=dwho/; + $query =~ s/password=/password=dwho/; + ok( + $res = $client->_post( + '/', + IO::String->new($query), + length => length($query), + accept => 'text/html', + ), + 'Auth query' + ); + + ( $host, $url, $query ) = + expectForm( $res, undef, '/totp2fcheck', 'token', 'checkLogins' ); + ok( $code = Lemonldap::NG::Common::TOTP::_code( undef, $key, 0, 30, 6 ), + 'Code' ); + $query =~ s/code=/code=$code/; + + # Expired token -->> TO BE FIXED + #diag 'Waiting'; + #sleep 3; + ok( + $res = $client->_post( + '/totp2fcheck', IO::String->new($query), + length => length($query), + accept => 'text/html', + ), + 'Post code' + ); + expectRedirection( $res, 'http://auth.example.com/' ); + $id = expectCookie($res); + + $client->logout($id); +} +count($maintests); + +clean_sessions(); + +done_testing( count() ); + diff --git a/lemonldap-ng-portal/t/40-Notifications-JSON-File.t b/lemonldap-ng-portal/t/40-Notifications-JSON-File.t index f85420693..32b09b266 100644 --- a/lemonldap-ng-portal/t/40-Notifications-JSON-File.t +++ b/lemonldap-ng-portal/t/40-Notifications-JSON-File.t @@ -76,7 +76,7 @@ ok( ); my $c = getCookies($res); -ok( not( %$c{'lemonldap'} ), 'Cookie expired' ) or print STDERR Dumper($c); +ok( not( $c->{'lemonldap'} ), 'Cookie expired' ) or print STDERR Dumper($c); count(2); expectRedirection( $res, 'http://auth.example.com/' ); diff --git a/lemonldap-ng-portal/t/40-Notifications-XML-DBI.t b/lemonldap-ng-portal/t/40-Notifications-XML-DBI.t index 341851176..aa87806ac 100644 --- a/lemonldap-ng-portal/t/40-Notifications-XML-DBI.t +++ b/lemonldap-ng-portal/t/40-Notifications-XML-DBI.t @@ -3,7 +3,11 @@ use strict; use IO::String; my $res; -my $maintests = 6; +my $file = 't/notifications.db'; +my $maintests = 7; +#my $maintests = 8; + +eval { unlink $file }; require 't/test-lib.pm'; my $file = tempdb(); @@ -69,7 +73,18 @@ qq{INSERT INTO notifications VALUES ('dwho','testref2','2016-05-30 00:00:00','[2]->[0] =~ + //gs ); + ok( @refs == 2, 'Two notification references found' ) + or print STDERR Dumper( $res->[2]->[0] ); + + ### TO BE FIXED + # ok( $refs[0] eq 'testref2', '1st reference found is "testref2"' ) + # or print STDERR Dumper( $res->[2]->[0] ); + # ok( $refs[1] eq 'testref', '2nd reference found is "testref"' ) + # or print STDERR Dumper( $res->[2]->[0] ); + ok( $res->[2]->[0] =~ /1x1x1/, ' Found ref' ); expectForm( $res, undef, '/notifback', 'reference1x1', 'url' ); diff --git a/lemonldap-ng-portal/t/40-Notifications-XML-File.t b/lemonldap-ng-portal/t/40-Notifications-XML-File.t index e24c3bba9..293773fb2 100644 --- a/lemonldap-ng-portal/t/40-Notifications-XML-File.t +++ b/lemonldap-ng-portal/t/40-Notifications-XML-File.t @@ -81,7 +81,7 @@ SKIP: { ); my $c = getCookies($res); - ok( not( %$c{'lemonldap'} ), 'Cookie expired' ) or print STDERR Dumper($c); + ok( not( $c->{'lemonldap'} ), 'Cookie expired' ) or print STDERR Dumper($c); count(2); expectRedirection( $res, 'http://auth.example.com/' ); diff --git a/lemonldap-ng-portal/t/67-CheckUser-with-Global-token.t b/lemonldap-ng-portal/t/67-CheckUser-with-Global-token.t index 42b9b7450..eb2f210f4 100644 --- a/lemonldap-ng-portal/t/67-CheckUser-with-Global-token.t +++ b/lemonldap-ng-portal/t/67-CheckUser-with-Global-token.t @@ -15,7 +15,6 @@ my $client = LLNG::Manager::Test->new( { userDB => 'Same', loginHistoryEnabled => 0, brutForceProtection => 0, - portalMainLogo => 'common/logos/logo_llng_old.png', checkUser => 1, requireToken => 1, tokenUseGlobalStorage => 1, diff --git a/lemonldap-ng-portal/t/67-CheckUser-with-token.t b/lemonldap-ng-portal/t/67-CheckUser-with-token.t index 92696e7fa..d386a28a7 100644 --- a/lemonldap-ng-portal/t/67-CheckUser-with-token.t +++ b/lemonldap-ng-portal/t/67-CheckUser-with-token.t @@ -15,7 +15,6 @@ my $client = LLNG::Manager::Test->new( { userDB => 'Same', loginHistoryEnabled => 0, brutForceProtection => 0, - portalMainLogo => 'common/logos/logo_llng_old.png', checkUser => 1, requireToken => 1, tokenUseGlobalStorage => 0, diff --git a/lemonldap-ng-portal/t/67-CheckUser.t b/lemonldap-ng-portal/t/67-CheckUser.t index 098e999ba..3aa878dca 100644 --- a/lemonldap-ng-portal/t/67-CheckUser.t +++ b/lemonldap-ng-portal/t/67-CheckUser.t @@ -15,7 +15,6 @@ my $client = LLNG::Manager::Test->new( { userDB => 'Same', loginHistoryEnabled => 0, brutForceProtection => 0, - portalMainLogo => 'common/logos/logo_llng_old.png', checkUser => 1, requireToken => 0, checkUserIdRule => '$uid ne "msmith"', diff --git a/lemonldap-ng-portal/t/77-2F-Extra.t b/lemonldap-ng-portal/t/77-2F-Extra.t index 20e3d2f09..fb3531f4d 100644 --- a/lemonldap-ng-portal/t/77-2F-Extra.t +++ b/lemonldap-ng-portal/t/77-2F-Extra.t @@ -11,23 +11,23 @@ count(1); my $client = LLNG::Manager::Test->new( { ini => { - logLevel => 'error', - authentication => 'Demo', - userDB => 'Same', - 'sfExtra' => { + logLevel => 'error', + authentication => 'Demo', + userDB => 'Same', + 'sfExtra' => { 'home' => { 'over' => { - mail2fCodeRegex => '\w{4}', - mail2fLogo => 'home.jpg', + mail2fCodeRegex => '\w{4}', }, + 'logo' => 'home.jpg', 'rule' => '$uid eq "dwho" or $uid eq "msmith"', 'type' => 'Mail2F' }, 'work' => { 'over' => { - mail2fLogo => 'work.jpg', - mail2fCodeRegex => '\d{8}', + mail2fCodeRegex => '\d{8}', }, + 'logo' => 'work.jpg', 'rule' => '$uid eq "dwho" or $uid eq "rtyler"', 'type' => 'Mail2F' } @@ -95,7 +95,6 @@ ok( ); count(1); - # Expect choice page my ( $host, $url, $query ) = expectForm( $res, undef, '/2fchoice', 'token', 'checkLogins' ); @@ -103,14 +102,14 @@ my ( $host, $url, $query ) = ok( $res->[2]->[0] =~ qq%work2F%, - 'Found work.png' + 'Found work.jpg' ) or print STDERR Dumper( $res->[2]->[0] ); count(1); ok( $res->[2]->[0] =~ qq%home2F%, - 'Found home.png' + 'Found home.jpg' ) or print STDERR Dumper( $res->[2]->[0] ); count(1);
+ + + +