Commit b0824190 authored by Antoine Rosier's avatar Antoine Rosier

Merge remote-tracking branch 'upstream/v2.0' into v2.0

parents ce8ca0ed 93ee1bcf
......@@ -15,3 +15,4 @@
--noopening-brace-on-new-line
--stack-opening-tokens
--format-skipping
--continuation-indentation=2
......@@ -119,8 +119,13 @@
"namespace" : "lemonldap-ng-sessions"
},
"locationRules" : {
"auth.example.com" : {
"(?#checkUser)^/checkuser": "$uid eq \"dwho\"",
"(?#errors)^/lmerror/": "accept",
"default" : "accept"
},
"manager.__DNSDOMAIN__" : {
"(?#Configuration)^/(manager\\.html|conf/)" : "$uid eq \"dwho\"",
"(?#Configuration)^/(manager\\.html|$)" : "$uid eq \"dwho\"",
"(?#Notifications)/notifications" : "$uid eq \"dwho\" or $uid eq \"rtyler\"",
"(?#Sessions)/sessions" : "$uid eq \"dwho\" or $uid eq \"rtyler\"",
"default" : "$uid eq \"dwho\" or $uid eq \"rtyler\""
......
......@@ -28,7 +28,6 @@ totp2fActivation = 1
totp2fSelfRegistration = 1
captcha_mail_enabled = 0
portalDisplayResetPassword = 1
translations = __pwd__/lemonldap-ng-portal/site/templates/localeTranslations.txt
[handler]
......@@ -38,8 +37,12 @@ useRedirectOnError = 0
[manager]
enabledModules = conf, sessions, notifications, 2ndFA
enabledModules = conf, sessions, notifications, 2ndFA, viewer
protection = manager
viewerHiddenPK = samlIDPMetaDataNodes samlSPMetaDataNodes portalDisplayLogout
viewerAllowBrowser = 1
staticPrefix = /static
languages = fr, en, vi, ar, de, it, zh
templateDir = __pwd__/lemonldap-ng-manager/site/templates
......
......@@ -147,7 +147,7 @@
"default" : "accept"
},
"manager.example.com": {
"(?#Configuration)^/(manager\\.html|conf/)": "$uid eq \"dwho\"",
"(?#Configuration)^/(manager\\.html|$)": "$uid eq \"dwho\"",
"(?#Notifications)^/notifications": "$uid eq \"dwho\" or $uid eq \"rtyler\"",
"(?#Sessions)^/sessions": "$uid eq \"dwho\" or $uid eq \"rtyler\"",
"default": "$uid eq \"dwho\" or $uid eq \"rtyler\""
......
......@@ -204,7 +204,6 @@ languages = en, fr, vi, it, ar
;useOldMenuItems=1
; Override error codes
;error_0 = You are well authenticated!
;translations = __PORTALTEMPLATESDIR__/localeTranslations.txt
; Custom template parameters
; For example to use <TMPL_VAR NAME="myparam">
;tpl_myparam = test
......@@ -360,7 +359,11 @@ languages = fr, en, vi, ar
; Manager modules enabled
; Set here the list of modules you want to see in manager interface
; The first will be used as default module displayed
enabledModules = conf, sessions, notifications, 2ndFA
enabledModules = conf, sessions, notifications, 2ndFA, viewer
; Viewer options - Default values
;viewerHiddenPK = samlIDPMetaDataNodes samlSPMetaDataNodes
;viewerAllowBrowser = 0
;[node-handler]
;
......
......@@ -4,7 +4,7 @@ use strict;
use Mouse;
use Lemonldap::NG::Common::Conf::ReConstants;
our $VERSION = '2.0.0';
our $VERSION = '2.0.3';
sub compactConf {
my ( $self, $conf ) = @_;
......@@ -24,6 +24,7 @@ sub compactConf {
s/^(\w+).*$/lc($1)/e;
s/OpenIDConnect/oidc/i;
$keep{$_} = 1;
if ( $_ eq "ad" ) { $keep{'ldap'} = 1; }
}
}
if ( $keep{choice} ) {
......@@ -33,6 +34,7 @@ sub compactConf {
s/^(\w+).*$/lc($1)/e;
s/OpenIDConnect/oidc/i;
$keep{$_} = 1;
if ( $_ eq "ad" ) { $keep{'ldap'} = 1; }
}
}
}
......
......@@ -296,13 +296,14 @@ sub defaultValues {
'useRedirectOnError' => 1,
'useSafeJail' => 1,
'utotp2fActivation' => 0,
'webIDAuthnLevel' => 1,
'webIDExportedVars' => {},
'whatToTrace' => 'uid',
'yubikey2fActivation' => 0,
'yubikey2fPublicIDSize' => 12,
'yubikey2fSelfRegistration' => 0,
'yubikey2fUserCanRemoveKey' => 1
'viewerHiddenPK' => 'samlIDPMetaDataNodes samlSPMetaDataNodes',
'webIDAuthnLevel' => 1,
'webIDExportedVars' => {},
'whatToTrace' => 'uid',
'yubikey2fActivation' => 0,
'yubikey2fPublicIDSize' => 12,
'yubikey2fSelfRegistration' => 0,
'yubikey2fUserCanRemoveKey' => 1
};
}
......
......@@ -21,6 +21,7 @@ lib/Lemonldap/NG/Manager/Conf/Tests.pm
lib/Lemonldap/NG/Manager/Conf/Zero.pm
lib/Lemonldap/NG/Manager/Notifications.pm
lib/Lemonldap/NG/Manager/Sessions.pm
lib/Lemonldap/NG/Manager/Viewer.pm
Makefile.PL
MANIFEST This list of files
META.json
......@@ -36,6 +37,7 @@ site/coffee/llApp.coffee
site/coffee/manager.coffee
site/coffee/notifications.coffee
site/coffee/sessions.coffee
site/coffee/viewer.coffee
site/htdocs/manager.fcgi
site/htdocs/manager.psgi
site/htdocs/static/bwr/angular-animate/angular-animate.js
......@@ -156,6 +158,8 @@ site/htdocs/static/js/notifications.js
site/htdocs/static/js/notifications.min.js
site/htdocs/static/js/sessions.js
site/htdocs/static/js/sessions.min.js
site/htdocs/static/js/viewer.js
site/htdocs/static/js/viewer.min.js
site/htdocs/static/languages/ar.json
site/htdocs/static/languages/de.json
site/htdocs/static/languages/en.json
......@@ -187,6 +191,7 @@ site/templates/notifications.tpl
site/templates/scripts.tpl
site/templates/sessions.tpl
site/templates/tree.tpl
site/templates/viewer.tpl
t/02-HTML-template.t
t/03-HTML-forms.t
t/05-rest-api.t
......
......@@ -23,6 +23,7 @@ extends 'Lemonldap::NG::Common::Conf::AccessLib',
'Lemonldap::NG::Handler::PSGI::Router';
has csp => ( is => 'rw' );
has brw => ( is => 'rw', default => 0 );
## @method boolean init($args)
# Launch initialization method
......@@ -86,7 +87,7 @@ sub init {
$self->csp(
"default-src 'self' $portal;frame-ancestors 'none';form-action 'self';"
);
$self->brw( $self->{viewerAllowBrowser} || $conf->{viewerAllowBrowser} );
$self->defaultRoute( $working[0]->defaultRoute );
# Find out more glyphicones at https://www.w3schools.com/icons/bootstrap_icons_glyphicons.asp
......@@ -94,7 +95,8 @@ sub init {
'conf' => 'cog',
'sessions' => 'duplicate',
'notifications' => 'bell',
'2ndFA' => 'wrench'
'2ndFA' => 'wrench',
'viewer' => 'eye-open',
};
$self->links( [] );
......@@ -132,13 +134,14 @@ sub init {
}
sub tplParams {
return ( VERSION => $VERSION, );
my ($self) = @_;
return ( VERSION => $VERSION, ALLOWBROWSER => $self->brw );
}
sub javascript {
my ($self) = @_;
return
'var formPrefix=staticPrefix+"forms/";var confPrefix=scriptname+"confs/";'
'var formPrefix=staticPrefix+"forms/";var confPrefix=scriptname+"confs/";var viewPrefix=scriptname+"view/";'
. ( $self->links ? 'var links=' . to_json( $self->links ) . ';' : '' )
. (
$self->menuLinks
......
......@@ -3558,6 +3558,14 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
],
'type' => 'select'
},
'viewerAllowBrowser' => {
'default' => 0,
'type' => 'bool'
},
'viewerHiddenPK' => {
'default' => 'samlIDPMetaDataNodes samlSPMetaDataNodes',
'type' => 'text'
},
'virtualHosts' => {
'type' => 'virtualHostContainer'
},
......
......@@ -915,6 +915,19 @@ sub attributes {
flags => 'hp',
},
# Viewer
viewerHiddenPK => {
type => 'text',
default => 'samlIDPMetaDataNodes samlSPMetaDataNodes',
documentation => 'ConfTree hidden primary keys',
flags => 'm',
},
viewerAllowBrowser => {
type => 'bool',
default => 0,
documentation => 'Allow configuration browser',
},
# Notification
oldNotifFormat => {
type => 'bool',
......
# This module implements all the methods that responds to '/confs/*' requests
# It contains 2 sections:
# - initialization methods
# - upload method
#
# Read methods are inherited from Lemonldap::NG::Common::Conf::RESTServer
package Lemonldap::NG::Manager::Viewer;
use 5.10.0;
use utf8;
use Mouse;
use Lemonldap::NG::Common::Conf::Constants;
use Lemonldap::NG::Common::UserAgent;
use URI::URL;
use feature 'state';
extends 'Lemonldap::NG::Manager::Conf';
our $VERSION = '2.0.3';
#############################
# I. INITIALIZATION METHODS #
#############################
use constant defaultRoute => 'viewer.html';
has ua => ( is => 'rw' );
sub addRoutes {
my ( $self, $conf ) = @_;
$self->ua( Lemonldap::NG::Common::UserAgent->new($conf) );
my $hiddenPK = '';
$hiddenPK = $self->{viewerHiddenPK} || $conf->{viewerHiddenPK};
my @enabledPK = ();
my @keys = qw(virtualHosts samlIDPMetaDataNodes samlSPMetaDataNodes
applicationList oidcOPMetaDataNodes oidcRPMetaDataNodes
casSrvMetaDataNodes casAppMetaDataNodes
authChoiceModules grantSessionRules combModules
openIdIDPList);
foreach (@keys) {
# Ignore hidden ConfTree Primary Keys
push @enabledPK, $_
unless ( $hiddenPK =~ /\b$_\b/ );
}
# HTML template
$self->addRoute( 'viewer.html', undef, ['GET'] )
# READ
# Special keys
->addRoute(
view => {
':cfgNum' => \@enabledPK
},
['GET']
);
foreach ( split /\s+/, $hiddenPK ) {
$self->addRoute(
view => { ':cfgNum' => { $_ => 'rejectKey' } },
['GET']
);
}
# Other keys
$self->addRoute( view => { ':cfgNum' => { '*' => 'getKey' } }, ['GET'] )
# Difference between confs
->addRoute( diff => { ':conf1' => { ':conf2' => 'diff' } } )
->addRoute( 'diff.html', undef, ['GET'] );
}
sub getConfByNum {
my ( $self, $cfgNum, @args ) = @_;
$self->SUPER::getConfByNum( $cfgNum, @args );
}
sub diff {
my ( $self, $req, @path ) = @_;
$self->SUPER::diff( $req, @path );
}
sub rejectKey {
my ( $self, $req ) = @_;
return $self->sendJSONresponse( $req, { 'value' => '_Hidden_' } );
}
1;
This diff is collapsed.
<div class="panel panel-default">
<div class="panel-heading">
<TMPL_IF NAME="ALLOWDIFF">
<h3 class="panel-title">
<span ng-if="!currentCfg.next" trspan="currentConfiguration"></span>
<span ng-if="currentCfg.next" trspan="loadedConfiguration"></span>
<i ng-if="currentCfg.prev">(<a trspan="diffWithPrevious" target="_blank" href="{{scriptname}}/diff.html#!/{{currentCfg.cfgNum}}" role="link"></a>)</i>
</h3>
</TMPL_IF>
</div>
<table class="table table-striped">
<tr>
......
This diff is collapsed.
(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 _download,_getAll,_stoggle,c,id,pathEvent,readError,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.viewPrefix=window.viewPrefix;$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};$scope.downloadConf=function(){return window.open($scope.viewPrefix+$scope.currentCfg.cfgNum+"?full=1")};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};_getAll=function(node){var d,d2;d=$q.defer();d2=$q.defer();if(node._nodes){_stoggle(node);d.resolve()}else if(node.cnodes){_download(node).then(function(){return d.resolve()})}else if(node.nodes||node.data){d.resolve()}else{$scope.getKey(node).then(function(){return d.resolve()})}d.promise.then(function(){var l,len,n,ref,t;t=[];if(node.nodes){ref=node.nodes;for(l=0,len=ref.length;l<len;l++){n=ref[l];t.push(_getAll(n))}}return $q.all(t).then(function(){return d2.resolve()})});return d2.promise};$scope.down=function(){var i,ind,l,len,n,p,ref,tmp;id=$scope.currentNode.id;p=$scope.currentScope.$parentNodeScope.$modelValue;ind=p.nodes.length;ref=p.nodes;for(i=l=0,len=ref.length;l<len;i=++l){n=ref[i];if(n.id===id){ind=i}}if(ind<p.nodes.length-1){tmp=p.nodes[ind];p.nodes[ind]=p.nodes[ind+1];p.nodes[ind+1]=tmp}return ind};$scope.up=function(){var i,ind,l,len,n,p,ref,tmp;id=$scope.currentNode.id;p=$scope.currentScope.$parentNodeScope.$modelValue;ind=-1;ref=p.nodes;for(i=l=0,len=ref.length;l<len;i=++l){n=ref[i];if(n.id===id){ind=i}}if(ind>0){tmp=p.nodes[ind];p.nodes[ind]=p.nodes[ind-1];p.nodes[ind-1]=tmp}return ind};$scope.inSelect=function(value){var l,len,n,ref;ref=$scope.currentNode.select;for(l=0,len=ref.length;l<len;l++){n=ref[l];if(n.k===value){return true}}return false};$scope.changeRuleTitle=function(node){return node.title=node.comment.length>0?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,l,len,len1,len2,m,n,o,ref,ref1,ref2;ref=["nodes","nodes_cond"];for(l=0,len=ref.length;l<len;l++){n=ref[l];if(node["_"+n]){node[n]=[];ref1=node["_"+n];for(m=0,len1=ref1.length;m<len1;m++){a=ref1[m];node[n].push(a)}delete node["_"+n]}}if(node._nodes_filter){if(node.nodes){ref2=node.nodes;for(o=0,len2=ref2.length;o<len2;o++){n=ref2[o];n.onChange=$scope.execFilters}}$scope.filters[node._nodes_filter]=node;return $scope.execFilters()}};$scope.toggle=function(scope){return scope.toggle()};$scope.download=function(scope){var node;node=scope.$modelValue;return _download(node)};_download=function(node){var d;d=$q.defer();d.notify("Trying to get datas");$scope.waiting=true;$http.get(""+window.viewPrefix+$scope.currentCfg.cfgNum+"/"+node.cnodes).then(function(response){var a,data,l,len;data=response.data;if(!data){d.reject("Empty response from server")}else if(data.error){if(data.error.match(/setDefault$/)){if(node["default"]){node.nodes=node["default"].slice(0)}else{node.nodes=[]}delete node.cnodes;d.resolve("Set data to default value")}else{d.reject("Server return an error: "+data.error)}}else{delete node.cnodes;if(!node.type){node.type="keyTextContainer"}node.nodes=[];for(l=0,len=data.length;l<len;l++){a=data[l];if(a.template){a._nodes=templates(a.template,a.title)}node.nodes.push(a)}d.resolve("OK")}return $scope.waiting=false},function(response){readError(response);return d.reject("")});return d.promise};$scope.openCnode=function(scope){return $scope.download(scope).then(function(){return scope.toggle()})};setHelp=function(scope){while(!scope.$modelValue.help&&scope.$parentNodeScope){scope=scope.$parentNodeScope}return $scope.helpUrl=scope.$modelValue.help||"start.html#configuration"};$scope.displayForm=function(scope){var f,l,len,n,node,ref;node=scope.$modelValue;if(node.cnodes){$scope.download(scope)}if(node._nodes){$scope.stoggle(scope)}$scope.currentNode=node;$scope.currentScope=scope;f=node.type?node.type:"text";if(node.nodes||node._nodes||node.cnodes){$scope.form=f!=="text"?f:"mini"}else{$scope.form=f;$scope.getKey(node)}if(node.type&&node.type==="simpleInputContainer"){ref=node.nodes;for(l=0,len=ref.length;l<len;l++){n=ref[l];$scope.getKey(n)}}$scope.showT=false;return setHelp(scope)};$scope.getKey=function(node){var d,i,l,len,n,ref,tmp;d=$q.defer();if(!node.data){$scope.waiting=true;if(node.get&&typeof node.get==="object"){node.data=[];tmp=[];ref=node.get;for(i=l=0,len=ref.length;l<len;i=++l){n=ref[i];node.data[i]={title:n,id:n};tmp.push($scope.getKey(node.data[i]))}$q.all(tmp).then(function(){return d.resolve(node.data)},function(response){d.reject(response.statusLine);return $scope.waiting=false})}else{$http.get(""+window.viewPrefix+$scope.currentCfg.cfgNum+"/"+(node.get?node.get:node.title)).then(function(response){var data;data=response.data;if((data.value===null||data.error&&data.error.match(/setDefault$/))&&node["default"]!==null){node.data=node["default"]}else{node.data=data.value}if(node.data.toString().match(/_Hidden_$/)){node.type="text";node.data="######"}if(node.type&&node.type.match(/^int$/)){node.data=parseInt(node.data,10)}else if(node.type&&node.type.match(/^(saml(Service|Assertion)|blackWhiteList)$/)&&!(typeof node.data==="object")){node.data=node.data.split(";")}$scope.waiting=false;return d.resolve(node.data)},function(response){readError(response);return d.reject(response.status)})}}else{if(node.data.toString().match(/_Hidden_$/)){node.type="text";node.data="######"}d.resolve(node.data)}return d.promise};pathEvent=function(event,next,current){var n;n=next.match(new RegExp("#!?/view/(latest|[0-9]+)"));if(n===null){return $location.path("/view/latest")}else{console.log("Trying to get cfg number "+n[1]);return $scope.getCfg(n[1])}};$scope.$on("$locationChangeSuccess",pathEvent);$scope.getCfg=function(n){if($scope.currentCfg.cfgNum!==n){return $http.get(""+window.viewPrefix+n).then(function(response){var d;$scope.currentCfg=response.data;d=new Date($scope.currentCfg.cfgDate*1e3);$scope.currentCfg.date=d.toLocaleString();console.log("Metadatas of cfg "+n+" loaded");$location.path("/view/"+n);return $scope.init()},function(response){return readError(response).then(function(){$scope.currentCfg.cfgNum=0;return $scope.init()})})}else{return $scope.waiting=false}};$scope.getLanguage=function(lang){$scope.lang=lang;$scope.form="white";$scope.init();return $scope.showM=false};$scope.init=function(){var tmp;tmp=null;$scope.waiting=true;$scope.data=[];$scope.confirmNeeded=false;$scope.forceSave=false;$q.all([$translator.init($scope.lang),$http.get(window.staticPrefix+"struct.json").then(function(response){tmp=response.data;return console.log("Structure loaded")})]).then(function(){console.log("Starting structure binding");$scope.data=tmp;tmp=null;if($scope.currentCfg.cfgNum!==0){setScopeVars($scope)}else{$scope.message={title:"emptyConf",message:"__zeroConfExplanations__"};$scope.showModal("message.html")}$scope.form="home";return $scope.waiting=false},readError);$scope.activeModule="viewer";return $scope.myStyle={color:"#ffb84d"}};c=$location.path().match(new RegExp("^/view/(latest|[0-9]+)"));if(!c){console.log("Redirecting to /view/latest");return $location.path("/view/latest")}}])}).call(this);
......@@ -648,6 +648,7 @@
"radiusSecret":"سر مشترك",
"radiusServer":"اسم الخادم",
"randomPasswordRegexp":"التعبير النمطي لتوليد كلمة المرور",
"readOnlyMode":"Read-Only mode",
"redirectFormMethod":"طريقة إعادة توجيه الإستمارة",
"redirection":"معالج إعادة التوجيه",
"reference":"مرجع",
......@@ -819,6 +820,7 @@
"vhostPort":"المنفذ",
"vhostType":"نوع",
"view":"عرض",
"viewer":"Viewer",
"virtualHost":"المضيف الإفتراضى ",
"virtualHostName":"اسم المضيف الافتراضي",
"virtualHosts":"المضيفين الإفتراضيين",
......
......@@ -648,6 +648,7 @@
"radiusSecret":"Shared secret",
"radiusServer":"Server hostname",
"randomPasswordRegexp":"Regexp for password generation",
"readOnlyMode":"Read-Only mode",
"redirectFormMethod":"Method for redirect form",
"redirection":"Handler redirections",
"reference":"Reference",
......@@ -819,6 +820,7 @@
"vhostPort":"Port",
"vhostType":"Type",
"view":"View",
"viewer":"Viewer",
"virtualHost":"Virtual Host",
"virtualHostName":"Virtual host hostname",
"virtualHosts":"Virtual Hosts",
......
......@@ -648,6 +648,7 @@
"radiusSecret":"Shared secret",
"radiusServer":"Server hostname",
"randomPasswordRegexp":"Regexp for password generation",
"readOnlyMode":"Read-Only mode",
"redirectFormMethod":"Method for redirect form",
"redirection":"Handler redirections",
"reference":"Reference",
......@@ -819,6 +820,7 @@
"vhostPort":"Port",
"vhostType":"Type",
"view":"View",
"viewer":"Viewer",
"virtualHost":"Virtual Host",
"virtualHostName":"Virtual host hostname",
"virtualHosts":"Virtual Hosts",
......
......@@ -648,6 +648,7 @@
"radiusSecret":"Secret partagé",
"radiusServer":"Nom d'hôte du serveur",
"randomPasswordRegexp":"Expression regulière pour la génération des mots de passe",
"readOnlyMode":"Mode lecture seule",
"redirectFormMethod":"Méthode du formulaire de redirection",
"redirection":"Redirections du Handler",
"reference":"Référence",
......@@ -819,6 +820,7 @@
"vhostPort":"Port",
"vhostType":"Type",
"view":"Aperçu",
"viewer":"Explorateur",
"virtualHost":"Hôte virtuel",
"virtualHostName":"Nom de l'hôte virtuel",
"virtualHosts":"Hôtes virtuels",
......
......@@ -648,6 +648,7 @@
"radiusSecret":"Segreto condiviso",
"radiusServer":"Nome host del server",
"randomPasswordRegexp":"Regex per la generazione di password",
"readOnlyMode":"Read-Only mode",
"redirectFormMethod":"Metodo per il modulo di reindirizzamento",
"redirection":"Redirezioni del gestore",
"reference":"Riferimento",
......@@ -819,6 +820,7 @@
"vhostPort":"Porta",
"vhostType":"Typo",
"view":"Visualizzazione",
"viewer":"Viewer",
"virtualHost":"Virtual Host",
"virtualHostName":"Hostname di Virtual host",
"virtualHosts":"Virtual Hosts",
......
......@@ -648,6 +648,7 @@
"radiusSecret":"Bí mật đã được chia sẻ",
"radiusServer":"Máy chủ lưu trữ",
"randomPasswordRegexp":"Regexp để tạo mật khẩu",
"readOnlyMode":"Read-Only mode",
"redirectFormMethod":"Phương pháp chuyển hướng mẫu",
"redirection":"chuyển hướng trình điều khiển",
"reference":"Tham khảo",
......@@ -819,6 +820,7 @@
"vhostPort":"Port",
"vhostType":"Loại",
"view":"Khung nhìn",
"viewer":"Viewer",
"virtualHost":"Máy chủ ảo",
"virtualHostName":"Tên máy chủ lưu trữ ảo",
"virtualHosts":"Máy chủ ảo",
......
......@@ -648,6 +648,7 @@
"radiusSecret":"Shared secret",
"radiusServer":"Server hostname",
"randomPasswordRegexp":"Regexp for password generation",
"readOnlyMode":"Read-Only mode",
"redirectFormMethod":"Method for redirect form",
"redirection":"Handler redirections",
"reference":"Reference",
......@@ -819,6 +820,7 @@
"vhostPort":"Port",
"vhostType":"Type",
"view":"View",
"viewer":"Viewer",
"virtualHost":"Virtual Host",
"virtualHostName":"Virtual host hostname",
"virtualHosts":"Virtual Hosts",
......
......@@ -21,7 +21,7 @@
<!-- Last buttons, available languages -->
</div>
<ul class="hidden-xs nav navbar-nav" role="grid">
<li ng-repeat="l in links" id="l in links"><a href="{{l.target}}" role="row" ng-mousedown="clickStyle={color: '#ffb84d'}"><strong><i ng-if="activeModule == l.title" ng-style="myStyle" class="glyphicon glyphicon-{{l.icon}}"></i><i ng-if="activeModule != l.title" class="glyphicon glyphicon-{{l.icon}}" ng-style="clickStyle"></i> <span ng-if="activeModule == l.title" ng-style="myStyle" ng-bind="translate(l.title)"></span><span ng-if="activeModule != l.title" ng-bind="translate(l.title)" ng-style="clickStyle"></span></strong></a></li>
<li ng-repeat="l in links" id="l in links"><a href="{{l.target}}" role="row" ng-mouseup="clickStyle={color: '#ffb84d'}"><strong><i ng-if="activeModule == l.title" ng-style="myStyle" class="glyphicon glyphicon-{{l.icon}}"></i><i ng-if="activeModule != l.title" class="glyphicon glyphicon-{{l.icon}}" ng-style="clickStyle"></i> <span ng-if="activeModule == l.title" ng-style="myStyle" ng-bind="translate(l.title)"></span><span ng-if="activeModule != l.title" ng-bind="translate(l.title)" ng-style="clickStyle"></span></strong></a></li>
</ul>
<ul class="hidden-xs nav navbar-nav navbar-right">
<li uib-dropdown>
......
This diff is collapsed.
......@@ -47,6 +47,8 @@ my @notManagedAttributes = (
# Loggers
'log4perlConfFile', 'userSyslogFacility', 'logger', 'sentryDsn',
'syslogFacility', 'userLogger', 'logLevel',
# Viewer
'viewerHiddenPK', 'viewerAllowBrowser',
# Other ini-only prms
'configStorage', 'status', 'localStorageOptions', 'localStorage',
......
......@@ -332,7 +332,6 @@ site/templates/bootstrap/customhead.tpl
site/templates/bootstrap/customheader.tpl
site/templates/bootstrap/customLoginFooter.tpl
site/templates/bootstrap/customLoginHeader.tpl
site/templates/bootstrap/error.json.example
site/templates/bootstrap/error.tpl
site/templates/bootstrap/ext2fcheck.tpl
site/templates/bootstrap/footer.tpl
......@@ -342,7 +341,6 @@ site/templates/bootstrap/idpchoice.tpl
site/templates/bootstrap/impersonation.tpl
site/templates/bootstrap/info.tpl
site/templates/bootstrap/ldapPpGrace.tpl
site/templates/bootstrap/login.json
site/templates/bootstrap/login.tpl
site/templates/bootstrap/mail.tpl
site/templates/bootstrap/menu.tpl
......@@ -400,8 +398,6 @@ site/templates/common/oidc_checksession.tpl
site/templates/common/redirect.tpl
site/templates/common/registerBrowser.tpl
site/templates/common/script.tpl
site/templates/common/trover.tpl
site/templates/localeTranslations.txt
t/01-AuthDemo.t
t/01-pdata.t
t/02-Password-Demo.t
......@@ -428,6 +424,7 @@ t/30-Auth-and-issuer-SAML-Artifact-with-SOAP-SLO-IdP-initiated.t
t/30-Auth-and-issuer-SAML-Artifact-with-SOAP-SLO.t
t/30-Auth-and-issuer-SAML-Metadata.t
t/30-Auth-and-issuer-SAML-POST-IdP-initiated.t
t/30-Auth-and-issuer-SAML-POST-Missing-SLO.t
t/30-Auth-and-issuer-SAML-POST.t
t/30-Auth-and-issuer-SAML-Redirect-IdP-initiated.t
t/30-Auth-and-issuer-SAML-Redirect.t
......@@ -461,8 +458,10 @@ t/36-Combination-Kerberos-or-Demo.t
t/36-Combination-with-over.t
t/36-Combination-with-token.t
t/36-Combination.t
t/37-CAS-App-to-SAML-IdP-POST-with-WAYF.t
t/37-CAS-App-to-SAML-IdP-POST.t
t/37-Logout-from-OIDC-RP-to-SAML-SP.t
t/37-OIDC-RP-to-SAML-IdP-GET-with-WAYF.t
t/37-OIDC-RP-to-SAML-IdP-GET.t
t/37-OIDC-RP-to-SAML-IdP-POST.t
t/37-SAML-SP-GET-to-OIDC-OP.t
......
......@@ -352,8 +352,7 @@ sub display {
# * Bad URL error
elsif ($req->{error} == PE_LOGOUT_OK
or $req->{error} == PE_WAIT
or $req->{error} == PE_BADURL
or $req->{error} == PE_BADCREDENTIALS )
or $req->{error} == PE_BADURL )
{
%templateParams = (
%templateParams,
......
......@@ -96,19 +96,7 @@ sub init {
}
);
# Load override messages from file and lemonldap-ng.ini
if ( $self->{localConfig}->{translations}
and -r $self->{localConfig}->{translations} )
{
open my $tr_file, '<', $self->{localConfig}->{translations}
or die "Can't open" . $self->{localConfig}->{translations} . " : $!";
while (<$tr_file>) {
chomp;
$_ =~ /^([\w_]+)\s+=\s+(.+)$/;
$self->{localConfig}->{$1} = $2;
}
close $tr_file or die "Can't close $tr_file : $!";
}
# Load override messages from lemonldap-ng.ini
foreach my $k ( keys %{ $self->localConfig } ) {
if ( $k =~ /tpl_(.*)/ ) {
$self->customParameters->{$1} = $self->localConfig->{$k};
......
......@@ -210,6 +210,12 @@ sub do {
if ( $err == PE_SENDRESPONSE ) {
return $req->response;
}
# Remove userData if authentication fails
if ( $err == PE_BADCREDENTIALS ) {
$req->userData( {} );
}
if ( !$self->conf->{noAjaxHook} and $req->wantJSON ) {
$self->logger->debug('Processing to JSON response');
if ( ( $err > 0 and !$req->id ) or $err eq PE_SESSIONNOTGRANTED ) {
......@@ -728,38 +734,39 @@ sub _dump {
sub sendHtml {
my ( $self, $req, $template, %args ) = @_;
$args{params}->{TROVER} = $self->trOver;
$args{templateDir} =
$self->conf->{templateDir} . '/' . $self->getSkin($req);
my $tmpl = $args{templateDir} . "/$template.tpl";
my $troverJson = $args{templateDir} . "/$template.json";
my $templateDir = $self->conf->{templateDir} . '/' . $self->getSkin($req);
# Check template
$args{templateDir} = $templateDir;
my $tmpl = $args{templateDir} . "/$template.tpl";
unless ( -f $tmpl ) {
$self->logger->debug("Template : $tmpl NOT found!!!");
$self->logger->debug("Template $tmpl not found");
$args{templateDir} = $self->conf->{templateDir} . '/bootstrap';
$tmpl = $args{templateDir} . "/$template.tpl";
$troverJson = $args{templateDir} . "/$template.json";
$tmpl = $args{templateDir} . "/$template.tpl";
$self->logger->debug("-> Trying to load $tmpl");
}
if ( -r $troverJson ) {
open my $tr_file, '<', $troverJson
or die "Can't open" . $troverJson . " : $!";
while (<$tr_file>) {
chomp;
$args{params}->{TROVERbyJSON} .= $_;
}
close $tr_file or die "Can't close $tr_file : $!";
eval { decode_json( $args{params}->{TROVERbyJSON} ) };
if ($@) {
$self->logger->debug("$troverJson is NOT a regular JSON file!!!");
$args{params}->{TROVERbyJSON} = '';
# Override messages
my $trOverMessages = JSON::from_json( $self->trOver );
opendir( DIR, $templateDir );
my @langfiles = grep( /\.json$/, readdir(DIR) );
close(DIR);
foreach my $file (@langfiles) {
my ($lang) = ( $file =~ /^(\w+)\.json/ );
$self->logger->debug("Use $file to override messages");
if ( open my $json, "<", $templateDir . "/" . $file ) {
local $/ = undef;
$trOverMessages->{$lang} = JSON::from_json(<$json>);
}
else {
$self->logger->debug(" -> Overriding messages with $troverJson");
$self->logger->debug(
" -> File content : $args{params}->{TROVERbyJSON}");
$self->logger->error("Unable to read $file");
}
}
$args{params}->{TROVER} = JSON::to_json($trOverMessages);
my $res = $self->SUPER::sendHtml( $req, $template, %args );
push @{ $res->[1] },
'X-XSS-Protection' => '1; mode=block',
......