Commit 6453a04a authored by Xavier Guimard's avatar Xavier Guimard

Merge branch 'v2.0'

parents 1cf89af0 408a2157
Pipeline #6736 passed with stages
in 21 minutes and 1 second
......@@ -541,10 +541,15 @@ sub authChoiceModules {
my @res;
foreach my $k ( sort keys %$value ) {
my $data = [ split /;/, $value->{$k} ];
eval { $data->[5] = from_json( $data->[5] ) if $data->[5] };
if ($@) {
$self->logger->error(
"Bad value in choice over parameters, deleted ($@)");
if ( $data->[5] ) {
my $over;
eval { $over = from_json( $data->[5] ) };
if ($@) {
$self->logger->error(
"Bad value in choice over parameters, deleted ($@)");
} else {
$data->[5] = [ map { [ $_, $over->{$_} ] } keys %{$over} ];
}
}
push @res,
{
......
......@@ -27,9 +27,9 @@ sub new {
if ( $self->env->{X_ORIGINAL_URI} );
$self->env->{PATH_INFO} =~ s|//+|/|g;
if ( my $tmp = $self->script_name ) {
$self->env->{PATH_INFO} =~ s|^$tmp|/|;
}
#if ( my $tmp = $self->script_name ) {
# $self->env->{PATH_INFO} =~ s|^$tmp|/|;
#}
$self->env->{PATH_INFO} ||= '/';
$self->env->{REQUEST_URI} =~ s|^//+|/|g;
$self->{uri} = uri_unescape( $self->env->{REQUEST_URI} );
......@@ -49,7 +49,10 @@ sub uri { $_[0]->{uri} }
sub userData {
my ( $self, $v ) = @_;
return $self->{userData} = $v if ($v);
return $self->{userData} || { _whatToTrace => $self->{user}, };
return $self->{userData}
|| {
( $Lemonldap::NG::Handler::Main::tsv->{whatToTrace}
|| '_whatToTrace' ) => $self->{user}, };
}
sub respHeaders {
......
......@@ -252,7 +252,7 @@ sub newConf {
if ( $cfgNum ne $req->params('cfgNum') ) { $parser->confChanged(1); }
my $res = { result => $parser->check };
my $res = { result => $parser->check($self) };
# "message" fields: note that words enclosed by "__" (__word__) will be
# translated
......
......@@ -94,12 +94,14 @@ sub hdebug {
# Main method
#@return result
sub check {
my $self = shift;
my $self = shift;
my $localConf = shift;
hdebug("# check()");
unless ( $self->newConf ) {
return 0 unless ( $self->scanTree );
}
unless ( $self->testNewConf ) {
unless ( $self->testNewConf($localConf) ) {
hdebug(" testNewConf() failed");
return 0;
}
......@@ -846,9 +848,11 @@ sub _scanNodes {
# authChoiceModules
if ( $name eq 'authChoiceModules' ) {
hdebug(' combModules');
hdebug(' authChoiceModules');
$n->{data}->[5] ||= {};
$n->{data}->[5] = to_json( $n->{data}->[5] );
$n->{data}->[5] =
to_json( { map { @$_ } @{ $n->{data}->[5] } } )
if ref( $n->{data}->[5] ) eq 'ARRAY';
}
$n->{data} = join ';', @{ $n->{data} };
......@@ -1078,9 +1082,12 @@ sub defaultValue {
#
#@return true if tests succeed
sub testNewConf {
my $self = shift;
my $self = shift;
my $localConf = shift;
hdebug('# testNewConf()');
return $self->_unitTest( $self->newConf(), '' ) && $self->_globalTest();
return $self->_unitTest( $self->newConf(), $localConf )
&& $self->_globalTest($localConf);
}
##@method private boolean _unitTest()
......@@ -1088,23 +1095,24 @@ sub testNewConf {
#
#@return true if tests succeed
sub _unitTest {
my ( $self, $conf ) = @_;
my ( $self, $conf, $localConf ) = @_;
hdebug('# _unitTest()');
my $types = &Lemonldap::NG::Manager::Attributes::types();
my $attrs = &Lemonldap::NG::Manager::Attributes::attributes();
my $res = 1;
foreach my $key ( keys %$conf ) {
if ( $self->{skippedUnitTests}
and $self->{skippedUnitTests} =~ /\b$key\b/ )
if ( $localConf->{skippedUnitTests}
and $localConf->{skippedUnitTests} =~ /\b$key\b/ )
{
$self->logger->debug("Ignore test for $key");
$localConf->logger->debug("-> Ignore test for $key\n");
next;
}
hdebug("Testing $key");
my $attr = $attrs->{$key};
my $type = $types->{ $attr->{type} };
unless ( $type or $attr->{test} ) {
print STDERR "Unknown attribute $key, deleting it\n";
$localConf->logger->debug("Unknown attribute $key, deleting it\n");
delete $conf->{$key};
next;
}
......@@ -1227,16 +1235,19 @@ sub _execTest {
#
#@return true if tests succeed
sub _globalTest {
my $self = shift;
my $self = shift;
my $localConf = shift;
require Lemonldap::NG::Manager::Conf::Tests;
hdebug('# _globalTest()');
my $result = 1;
my $tests = &Lemonldap::NG::Manager::Conf::Tests::tests( $self->newConf );
foreach my $name ( keys %$tests ) {
if ( $self->{skippedGlobalTests}
and $self->{skippedGlobalTests} =~ /\b$name\b/ )
if ( $localConf->{skippedGlobalTests}
and $localConf->{skippedGlobalTests} =~ /\b$name\b/ )
{
$self->logger->debug("Ignore test for $name");
$localConf->logger->debug("-> Ignore test for $name\n");
next;
}
my $sub = $tests->{$name};
......@@ -1258,7 +1269,7 @@ sub _globalTest {
};
if ($@) {
push @{ $self->warnings }, "Test $name failed: $@";
print STDERR "Test $name failed: $@\n";
$localConf->logger->debug("Test $name failed: $@\n");
}
}
return $result;
......
......@@ -2,7 +2,7 @@
diff.html script
###
llapp = angular.module 'llngConfDiff', ['ui.tree', 'ui.bootstrap', 'llApp', 'ngCookies'] , ($rootScopeProvider) -> $rootScopeProvider.digestTtl(15)
llapp = angular.module 'llngConfDiff', ['ui.tree', 'ui.bootstrap', 'llApp', 'ngCookies'] , ['$rootScopeProvider', ($rootScopeProvider) -> $rootScopeProvider.digestTtl(15)]
llapp.controller 'DiffCtrl', [ '$scope', '$http', '$q', '$translator', '$location', ($scope, $http, $q, $translator, $location) ->
$scope.links = links
$scope.menulinks = menulinks
......
......@@ -2,7 +2,7 @@
diff.html script
###
llapp = angular.module 'llngConfDiff', ['ui.tree', 'ui.bootstrap', 'llApp', 'ngCookies'] , ($rootScopeProvider) -> $rootScopeProvider.digestTtl(15)
llapp = angular.module 'llngConfDiff', ['ui.tree', 'ui.bootstrap', 'llApp', 'ngCookies'] , ['$rootScopeProvider', ($rootScopeProvider) -> $rootScopeProvider.digestTtl(15)]
llapp.controller 'DiffCtrl', [ '$scope', '$http', '$q', '$translator', '$location', ($scope, $http, $q, $translator, $location) ->
$scope.links = links
$scope.menulinks = menulinks
......
......@@ -42,8 +42,9 @@
<input class="form-control" ng-model="t[1]" />
</td>
<td>
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.data.over,$index)"/>
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign" ng-click="menuClick({title:'newCmbOver'})"/>
<span class="link text-danger glyphicon glyphicon-minus-sign" ng-click="del(currentNode.data[5],$index)"/>
<span ng-if="$last" class="link text-success glyphicon glyphicon-plus-sign"
ng-click="menuClick({title:'newCmbOver', action:'newChoiceOver'})" />
</td>
</tr>
</table>
......
// Generated by CoffeeScript 1.12.8
// Generated by CoffeeScript 1.12.7
/*
* 2ndFA Session explorer
......
......@@ -7,9 +7,11 @@ diff.html script
(function() {
var llapp;
llapp = angular.module('llngConfDiff', ['ui.tree', 'ui.bootstrap', 'llApp', 'ngCookies'], function($rootScopeProvider) {
return $rootScopeProvider.digestTtl(15);
});
llapp = angular.module('llngConfDiff', ['ui.tree', 'ui.bootstrap', 'llApp', 'ngCookies'], [
'$rootScopeProvider', function($rootScopeProvider) {
return $rootScopeProvider.digestTtl(15);
}
]);
llapp.controller('DiffCtrl', [
'$scope', '$http', '$q', '$translator', '$location', function($scope, $http, $q, $translator, $location) {
......
(function(){angular.module("llngConfDiff",["ui.tree","ui.bootstrap","llApp","ngCookies"],function(t){return t.digestTtl(15)}).controller("DiffCtrl",["$scope","$http","$q","$translator","$location",function(p,o,l,a,u){var n,i,c,t,s,h,f;return p.links=links,p.menulinks=menulinks,p.staticPrefix=staticPrefix,p.scriptname=scriptname,p.availableLanguages=availableLanguages,p.waiting=!0,p.showM=!1,p.cfg=[],p.data={},p.currentNode=null,p.translateTitle=function(t){return a.translateField(t,"title")},p.translateP=a.translateP,p.translate=a.translate,p.toggle=function(t){return t.toggle()},p.stoggle=function(t,e){return p.currentNode=e,t.toggle()},p.menuClick=function(t){if(t.popup)window.open(t.popup);else switch(t.action||(t.action=t.title),typeof t.action){case"function":t.action(p.currentNode,p);break;case"string":p[t.action]();break;default:console.log(typeof t.action)}return p.showM=!1},p.getLanguage=function(t){return p.lang=t,c(),p.showM=!1},i=function(n,r){var a;return a=l.defer(),null==p.cfg[n]||p.cfg[n]!==r?o.get(""+confPrefix+r).then(function(t){var e;return t&&t.data?(p.cfg[n]=t.data,e=new Date(1e3*t.data.cfgDate),p.cfg[n].date=e.toLocaleString(),console.log("Metadatas of cfg "+r+" loaded"),a.resolve("OK")):a.reject(t)},function(t){return console.log(t),a.reject("NOK")}):a.resolve(),a.promise},c=function(){return p.message=null,p.currentNode=null,l.all([a.init(p.lang),o.get(staticPrefix+"reverseTree.json").then(function(t){return t.data,console.log("Structure loaded")})]).then(function(){return l.defer(),o.get(scriptname+"diff/"+p.cfg[0].cfgNum+"/"+p.cfg[1].cfgNum).then(function(t){var e;return[],e=s(t.data[0],t.data[1]),p.data=n(e),p.message="",p.waiting=!1},function(t){return p.message=p.translate("error")+" : "+t.statusLine})}),p.activeModule="conf",p.myStyle={color:"#ffb84d"}},s=function(t,e,n){var r,a,o,l;for(r in null==n&&(n=!0),a=[],t)l=t[r],o=n?{title:p.translate(r),id:r}:{title:r},r.match(/^cfg(?:Num|Log|Author(?:IP)?|Date)$/)||(null!=l&&"object"==typeof l?"array"===l.constructor?(o.oldvalue=l,o.newvalue=e[r]):"object"==typeof e[r]?o.nodes=s(t[r],e[r],!1):o.oldnodes=f(l,"old"):(o.oldvalue=l,o.newvalue=e[r]),a.push(o));for(r in e)l=e[r],r.match(/^cfg(?:Num|Log|Author(?:IP)?|Date)$/)||null!=t[r]||(o=n?{title:p.translate(r),id:r}:{title:r},null!=l&&"object"==typeof l?"array"===l.constructor?o.newvalue=l:(console.log("Iteration"),o.newnodes=f(l,"new")):o.newvalue=l,a.push(o));return a},f=function(t,e){var n,r,a,o;for(n in r=[],t)a={title:n},"object"==typeof(o=t[n])?"array"===o.constructor?a[e+"value"]=o:a[e+"nodes"]=f(t[n],e):a[e+"value"]=o,r.push(a);return r},h=[],n=function(t){var e,n,r,a,o,l,u,i,c,s,f,g,d;if(null==h)return t;for(d=[],a=0,l=t.length;a<l;a++){for(e=t[a],f=d,o=0,u=(g=null!=h[e.id]?h[e.id].split("/"):"").length;o<u;o++)if(0<(s=g[o]).length)if(f.length){for(n=-1,r=c=0,i=f.length;c<i;r=++c)f[r].id===s&&(n=r);f=-1!==n?f[n].nodes:(f.push({id:s,title:p.translate(s),nodes:[]}),f[f.length-1].nodes)}else f.push({id:s,title:p.translate(s),nodes:[]}),f=f[0].nodes;f.push(e)}return d},p.newDiff=function(){return u.path("/"+p.cfg[0].cfgNum+"/"+p.cfg[1].cfgNum)},t=function(t,e,n){var r;return null===(r=e.match(new RegExp("#!?/(latest|[0-9]+)(?:/(latest|[0-9]+))?$")))?u.path("/latest"):(p.waiting=!0,l.all([a.init(p.lang),o.get(staticPrefix+"reverseTree.json").then(function(t){return h=t.data,console.log("Structure loaded")}),i(0,r[1]),null!=r[2]?i(1,r[2]):void 0]).then(function(){return null!=r[2]?c():p.cfg[0].prev?(p.cfg[1]=p.cfg[0],i(0,p.cfg[1].prev).then(function(){return c()})):(p.data=[],p.waiting=!1)},function(){return p.message=p.translate("error"),p.waiting=!1})),!0},p.$on("$locationChangeSuccess",t)}])}).call(this);
\ No newline at end of file
(function(){angular.module("llngConfDiff",["ui.tree","ui.bootstrap","llApp","ngCookies"],["$rootScopeProvider",function(t){return t.digestTtl(15)}]).controller("DiffCtrl",["$scope","$http","$q","$translator","$location",function(p,a,l,o,u){var n,i,c,t,s,h,f;return p.links=links,p.menulinks=menulinks,p.staticPrefix=staticPrefix,p.scriptname=scriptname,p.availableLanguages=availableLanguages,p.waiting=!0,p.showM=!1,p.cfg=[],p.data={},p.currentNode=null,p.translateTitle=function(t){return o.translateField(t,"title")},p.translateP=o.translateP,p.translate=o.translate,p.toggle=function(t){return t.toggle()},p.stoggle=function(t,e){return p.currentNode=e,t.toggle()},p.menuClick=function(t){if(t.popup)window.open(t.popup);else switch(t.action||(t.action=t.title),typeof t.action){case"function":t.action(p.currentNode,p);break;case"string":p[t.action]();break;default:console.log(typeof t.action)}return p.showM=!1},p.getLanguage=function(t){return p.lang=t,c(),p.showM=!1},i=function(n,r){var o;return o=l.defer(),null==p.cfg[n]||p.cfg[n]!==r?a.get(""+confPrefix+r).then(function(t){var e;return t&&t.data?(p.cfg[n]=t.data,e=new Date(1e3*t.data.cfgDate),p.cfg[n].date=e.toLocaleString(),console.log("Metadatas of cfg "+r+" loaded"),o.resolve("OK")):o.reject(t)},function(t){return console.log(t),o.reject("NOK")}):o.resolve(),o.promise},c=function(){return p.message=null,p.currentNode=null,l.all([o.init(p.lang),a.get(staticPrefix+"reverseTree.json").then(function(t){return t.data,console.log("Structure loaded")})]).then(function(){return l.defer(),a.get(scriptname+"diff/"+p.cfg[0].cfgNum+"/"+p.cfg[1].cfgNum).then(function(t){var e;return[],e=s(t.data[0],t.data[1]),p.data=n(e),p.message="",p.waiting=!1},function(t){return p.message=p.translate("error")+" : "+t.statusLine})}),p.activeModule="conf",p.myStyle={color:"#ffb84d"}},s=function(t,e,n){var r,o,a,l;for(r in null==n&&(n=!0),o=[],t)l=t[r],a=n?{title:p.translate(r),id:r}:{title:r},r.match(/^cfg(?:Num|Log|Author(?:IP)?|Date)$/)||(null!=l&&"object"==typeof l?"array"===l.constructor?(a.oldvalue=l,a.newvalue=e[r]):"object"==typeof e[r]?a.nodes=s(t[r],e[r],!1):a.oldnodes=f(l,"old"):(a.oldvalue=l,a.newvalue=e[r]),o.push(a));for(r in e)l=e[r],r.match(/^cfg(?:Num|Log|Author(?:IP)?|Date)$/)||null!=t[r]||(a=n?{title:p.translate(r),id:r}:{title:r},null!=l&&"object"==typeof l?"array"===l.constructor?a.newvalue=l:(console.log("Iteration"),a.newnodes=f(l,"new")):a.newvalue=l,o.push(a));return o},f=function(t,e){var n,r,o,a;for(n in r=[],t)o={title:n},"object"==typeof(a=t[n])?"array"===a.constructor?o[e+"value"]=a:o[e+"nodes"]=f(t[n],e):o[e+"value"]=a,r.push(o);return r},h=[],n=function(t){var e,n,r,o,a,l,u,i,c,s,f,g,d;if(null==h)return t;for(d=[],o=0,l=t.length;o<l;o++){for(e=t[o],f=d,a=0,u=(g=null!=h[e.id]?h[e.id].split("/"):"").length;a<u;a++)if(0<(s=g[a]).length)if(f.length){for(n=-1,r=c=0,i=f.length;c<i;r=++c)f[r].id===s&&(n=r);f=-1!==n?f[n].nodes:(f.push({id:s,title:p.translate(s),nodes:[]}),f[f.length-1].nodes)}else f.push({id:s,title:p.translate(s),nodes:[]}),f=f[0].nodes;f.push(e)}return d},p.newDiff=function(){return u.path("/"+p.cfg[0].cfgNum+"/"+p.cfg[1].cfgNum)},t=function(t,e,n){var r;return null===(r=e.match(new RegExp("#!?/(latest|[0-9]+)(?:/(latest|[0-9]+))?$")))?u.path("/latest"):(p.waiting=!0,l.all([o.init(p.lang),a.get(staticPrefix+"reverseTree.json").then(function(t){return h=t.data,console.log("Structure loaded")}),i(0,r[1]),null!=r[2]?i(1,r[2]):void 0]).then(function(){return null!=r[2]?c():p.cfg[0].prev?(p.cfg[1]=p.cfg[0],i(0,p.cfg[1].prev).then(function(){return c()})):(p.data=[],p.waiting=!1)},function(){return p.message=p.translate("error"),p.waiting=!1})),!0},p.$on("$locationChangeSuccess",t)}])}).call(this);
\ No newline at end of file
// Generated by CoffeeScript 1.12.8
// Generated by CoffeeScript 1.12.7
(function() {
var filterFunctions;
......
// Generated by CoffeeScript 1.12.8
// Generated by CoffeeScript 1.12.7
/*
LemonLDAP::NG base app module
......
// Generated by CoffeeScript 1.12.8
// Generated by CoffeeScript 1.12.7
/*
LemonLDAP::NG Manager client
......
// Generated by CoffeeScript 1.12.8
// Generated by CoffeeScript 1.12.7
/*
* LemonLDAP::NG Notifications Explorer client
......
......@@ -7,9 +7,11 @@ diff.html script
(function() {
var llapp;
llapp = angular.module('llngConfDiff', ['ui.tree', 'ui.bootstrap', 'llApp', 'ngCookies'], function($rootScopeProvider) {
return $rootScopeProvider.digestTtl(15);
});
llapp = angular.module('llngConfDiff', ['ui.tree', 'ui.bootstrap', 'llApp', 'ngCookies'], [
'$rootScopeProvider', function($rootScopeProvider) {
return $rootScopeProvider.digestTtl(15);
}
]);
llapp.controller('DiffCtrl', [
'$scope', '$http', '$q', '$translator', '$location', function($scope, $http, $q, $translator, $location) {
......
(function(){angular.module("llngConfDiff",["ui.tree","ui.bootstrap","llApp","ngCookies"],function(t){return t.digestTtl(15)}).controller("DiffCtrl",["$scope","$http","$q","$translator","$location",function(p,o,l,a,i){var n,u,c,t,s,h,f;return p.links=links,p.menulinks=menulinks,p.staticPrefix=staticPrefix,p.scriptname=scriptname,p.availableLanguages=availableLanguages,p.waiting=!0,p.showM=!1,p.cfg=[],p.data={},p.currentNode=null,p.translateTitle=function(t){return a.translateField(t,"title")},p.translateP=a.translateP,p.translate=a.translate,p.toggle=function(t){return t.toggle()},p.stoggle=function(t,e){return p.currentNode=e,t.toggle()},p.menuClick=function(t){if(t.popup)window.open(t.popup);else switch(t.action||(t.action=t.title),typeof t.action){case"function":t.action(p.currentNode,p);break;case"string":p[t.action]();break;default:console.log(typeof t.action)}return p.showM=!1},p.getLanguage=function(t){return p.lang=t,c(),p.showM=!1},u=function(n,r){var a;return a=l.defer(),null==p.cfg[n]||p.cfg[n]!==r?o.get(""+confPrefix+r).then(function(t){var e;return t&&t.data?(p.cfg[n]=t.data,e=new Date(1e3*t.data.cfgDate),p.cfg[n].date=e.toLocaleString(),console.log("Metadatas of cfg "+r+" loaded"),a.resolve("OK")):a.reject(t)},function(t){return console.log(t),a.reject("NOK")}):a.resolve(),a.promise},c=function(){return p.message=null,p.currentNode=null,l.all([a.init(p.lang),o.get(staticPrefix+"reverseTree.json").then(function(t){return t.data,console.log("Structure loaded")})]).then(function(){return l.defer(),o.get(scriptname+"view/diff/"+p.cfg[0].cfgNum+"/"+p.cfg[1].cfgNum).then(function(t){var e;return[],e=s(t.data[0],t.data[1]),p.data=n(e),p.message="",p.waiting=!1},function(t){return p.message=p.translate("error")+" : "+t.statusLine})}),p.activeModule="viewer",p.myStyle={color:"#ffb84d"}},s=function(t,e,n){var r,a,o,l;for(r in null==n&&(n=!0),a=[],t)l=t[r],o=n?{title:p.translate(r),id:r}:{title:r},r.match(/^cfg(?:Num|Log|Author(?:IP)?|Date)$/)||(null!=l&&"object"==typeof l?"array"===l.constructor?(o.oldvalue=l,o.newvalue=e[r]):"object"==typeof e[r]?o.nodes=s(t[r],e[r],!1):o.oldnodes=f(l,"old"):(o.oldvalue=l,o.newvalue=e[r]),a.push(o));for(r in e)l=e[r],r.match(/^cfg(?:Num|Log|Author(?:IP)?|Date)$/)||null!=t[r]||(o=n?{title:p.translate(r),id:r}:{title:r},null!=l&&"object"==typeof l?"array"===l.constructor?o.newvalue=l:(console.log("Iteration"),o.newnodes=f(l,"new")):o.newvalue=l,a.push(o));return a},f=function(t,e){var n,r,a,o;for(n in r=[],t)a={title:n},"object"==typeof(o=t[n])?"array"===o.constructor?a[e+"value"]=o:a[e+"nodes"]=f(t[n],e):a[e+"value"]=o,r.push(a);return r},h=[],n=function(t){var e,n,r,a,o,l,i,u,c,s,f,g,d;if(null==h)return t;for(d=[],a=0,l=t.length;a<l;a++){for(e=t[a],f=d,o=0,i=(g=null!=h[e.id]?h[e.id].split("/"):"").length;o<i;o++)if(0<(s=g[o]).length)if(f.length){for(n=-1,r=c=0,u=f.length;c<u;r=++c)f[r].id===s&&(n=r);f=-1!==n?f[n].nodes:(f.push({id:s,title:p.translate(s),nodes:[]}),f[f.length-1].nodes)}else f.push({id:s,title:p.translate(s),nodes:[]}),f=f[0].nodes;f.push(e)}return d},p.newDiff=function(){return i.path("/"+p.cfg[0].cfgNum+"/"+p.cfg[1].cfgNum)},t=function(t,e,n){var r;return null===(r=e.match(new RegExp("#!?/(latest|[0-9]+)(?:/(latest|[0-9]+))?$")))?i.path("/latest"):(p.waiting=!0,l.all([a.init(p.lang),o.get(staticPrefix+"reverseTree.json").then(function(t){return h=t.data,console.log("Structure loaded")}),u(0,r[1]),null!=r[2]?u(1,r[2]):void 0]).then(function(){return null!=r[2]?c():p.cfg[0].prev?(p.cfg[1]=p.cfg[0],u(0,p.cfg[1].prev).then(function(){return c()})):(p.data=[],p.waiting=!1)},function(){return p.message=p.translate("error"),p.waiting=!1})),!0},p.$on("$locationChangeSuccess",t)}])}).call(this);
\ No newline at end of file
(function(){angular.module("llngConfDiff",["ui.tree","ui.bootstrap","llApp","ngCookies"],["$rootScopeProvider",function(t){return t.digestTtl(15)}]).controller("DiffCtrl",["$scope","$http","$q","$translator","$location",function(p,o,l,a,i){var n,u,c,t,s,h,f;return p.links=links,p.menulinks=menulinks,p.staticPrefix=staticPrefix,p.scriptname=scriptname,p.availableLanguages=availableLanguages,p.waiting=!0,p.showM=!1,p.cfg=[],p.data={},p.currentNode=null,p.translateTitle=function(t){return a.translateField(t,"title")},p.translateP=a.translateP,p.translate=a.translate,p.toggle=function(t){return t.toggle()},p.stoggle=function(t,e){return p.currentNode=e,t.toggle()},p.menuClick=function(t){if(t.popup)window.open(t.popup);else switch(t.action||(t.action=t.title),typeof t.action){case"function":t.action(p.currentNode,p);break;case"string":p[t.action]();break;default:console.log(typeof t.action)}return p.showM=!1},p.getLanguage=function(t){return p.lang=t,c(),p.showM=!1},u=function(n,r){var a;return a=l.defer(),null==p.cfg[n]||p.cfg[n]!==r?o.get(""+confPrefix+r).then(function(t){var e;return t&&t.data?(p.cfg[n]=t.data,e=new Date(1e3*t.data.cfgDate),p.cfg[n].date=e.toLocaleString(),console.log("Metadatas of cfg "+r+" loaded"),a.resolve("OK")):a.reject(t)},function(t){return console.log(t),a.reject("NOK")}):a.resolve(),a.promise},c=function(){return p.message=null,p.currentNode=null,l.all([a.init(p.lang),o.get(staticPrefix+"reverseTree.json").then(function(t){return t.data,console.log("Structure loaded")})]).then(function(){return l.defer(),o.get(scriptname+"view/diff/"+p.cfg[0].cfgNum+"/"+p.cfg[1].cfgNum).then(function(t){var e;return[],e=s(t.data[0],t.data[1]),p.data=n(e),p.message="",p.waiting=!1},function(t){return p.message=p.translate("error")+" : "+t.statusLine})}),p.activeModule="viewer",p.myStyle={color:"#ffb84d"}},s=function(t,e,n){var r,a,o,l;for(r in null==n&&(n=!0),a=[],t)l=t[r],o=n?{title:p.translate(r),id:r}:{title:r},r.match(/^cfg(?:Num|Log|Author(?:IP)?|Date)$/)||(null!=l&&"object"==typeof l?"array"===l.constructor?(o.oldvalue=l,o.newvalue=e[r]):"object"==typeof e[r]?o.nodes=s(t[r],e[r],!1):o.oldnodes=f(l,"old"):(o.oldvalue=l,o.newvalue=e[r]),a.push(o));for(r in e)l=e[r],r.match(/^cfg(?:Num|Log|Author(?:IP)?|Date)$/)||null!=t[r]||(o=n?{title:p.translate(r),id:r}:{title:r},null!=l&&"object"==typeof l?"array"===l.constructor?o.newvalue=l:(console.log("Iteration"),o.newnodes=f(l,"new")):o.newvalue=l,a.push(o));return a},f=function(t,e){var n,r,a,o;for(n in r=[],t)a={title:n},"object"==typeof(o=t[n])?"array"===o.constructor?a[e+"value"]=o:a[e+"nodes"]=f(t[n],e):a[e+"value"]=o,r.push(a);return r},h=[],n=function(t){var e,n,r,a,o,l,i,u,c,s,f,g,d;if(null==h)return t;for(d=[],a=0,l=t.length;a<l;a++){for(e=t[a],f=d,o=0,i=(g=null!=h[e.id]?h[e.id].split("/"):"").length;o<i;o++)if(0<(s=g[o]).length)if(f.length){for(n=-1,r=c=0,u=f.length;c<u;r=++c)f[r].id===s&&(n=r);f=-1!==n?f[n].nodes:(f.push({id:s,title:p.translate(s),nodes:[]}),f[f.length-1].nodes)}else f.push({id:s,title:p.translate(s),nodes:[]}),f=f[0].nodes;f.push(e)}return d},p.newDiff=function(){return i.path("/"+p.cfg[0].cfgNum+"/"+p.cfg[1].cfgNum)},t=function(t,e,n){var r;return null===(r=e.match(new RegExp("#!?/(latest|[0-9]+)(?:/(latest|[0-9]+))?$")))?i.path("/latest"):(p.waiting=!0,l.all([a.init(p.lang),o.get(staticPrefix+"reverseTree.json").then(function(t){return h=t.data,console.log("Structure loaded")}),u(0,r[1]),null!=r[2]?u(1,r[2]):void 0]).then(function(){return null!=r[2]?c():p.cfg[0].prev?(p.cfg[1]=p.cfg[0],u(0,p.cfg[1].prev).then(function(){return c()})):(p.data=[],p.waiting=!1)},function(){return p.message=p.translate("error"),p.waiting=!1})),!0},p.$on("$locationChangeSuccess",t)}])}).call(this);
\ No newline at end of file
// Generated by CoffeeScript 1.12.8
// Generated by CoffeeScript 1.12.7
/*
LemonLDAP::NG Viewer client
......
......@@ -5,7 +5,7 @@
<link rel="prefetch" href="<TMPL_VAR NAME="STATIC_PREFIX">struct.json" />
</head>
<body ng-app="llngConfDiff" ng-controller="DiffCtrl" ng-csp>
<body ng-app="llngConfDiff" ng-strict-di ng-controller="DiffCtrl" ng-csp>
<TMPL_INCLUDE NAME="menubar.tpl">
......
......@@ -94,7 +94,7 @@
</table>
</div>
<div ng-if="!node.nodes">
<th ng-if="node.td!='1' && node.td!='2'">{{node.title}}</th>
<th ng-if="node.td!='1' && node.td!='2'"><span title="{{node.title}}">{{translate(node.title)}}</span></th>
<td class="data-{{node.epoch}}" ng-if="node.td>='1'">{{node.title}}</td>
<th ng-if="node.title=='type' || node.title=='rp'">{{translate(node.value)}}</th>
<td id="v-{{node.title}}" class="col-md-4 data-{{node.epoch}}" ng-if="node.title!='type' && node.title!='rp'">{{node.value}}</td>
......
......@@ -5,7 +5,7 @@
<link rel="prefetch" href="<TMPL_VAR NAME="STATIC_PREFIX">struct.json" />
</head>
<body ng-app="llngConfDiff" ng-controller="DiffCtrl" ng-csp>
<body ng-app="llngConfDiff" ng-strict-di ng-controller="DiffCtrl" ng-csp>
<TMPL_INCLUDE NAME="menubar.tpl">
......
......@@ -38,8 +38,8 @@ foreach my $i ( 0 .. 1 ) {
}
ok(
@{ $resBody->{details}->{__changes__} } == 23,
'JSON response contains 22 changes'
@{ $resBody->{details}->{__changes__} } == 24,
'JSON response contains 24 changes'
) or print STDERR Dumper($resBody);
#print STDERR Dumper($resBody);
......@@ -91,8 +91,8 @@ ok( ( @c1 = sort keys %{ $res->[0] } ), 'diff() detects changes in conf 1' );
ok( ( @c2 = sort keys %{ $res->[1] } ), 'diff() detects changes in conf 2' );
ok( @c1 == 11, '11 keys changed in conf 1' )
or print STDERR "Expect: 11 keys, get: " . join( ', ', @c1 ) . "\n";
ok( @c2 == 14, '14 keys changed or created in conf 2' )
or print STDERR "Expect: 14 keys, get: " . join( ',', @c2 ) . "\n";
ok( @c2 == 15, '15 keys changed or created in conf 2' )
or print STDERR "Expect: 15 keys, get: " . join( ',', @c2 ) . "\n";
count(5);
......@@ -232,6 +232,11 @@ sub changes {
{
'confCompacted' => '1',
'removedKeys' => 'some; keys'
}
},
{
'key' => 'cookieExpiration',
'old' => undef,
'new' => '10'
},
];
}
......@@ -1209,7 +1209,9 @@
"data": 1
}, {
"id": "cookieExpiration",
"title": "cookieExpiration"
"title": "cookieExpiration",
"type": "int",
"data": "a"
}]
}, {
"id": "sessionParams",
......
......@@ -22,6 +22,9 @@ useRedirectOnError = 0
[manager]
skippedUnitTests = cookieExpiration
skippedGlobalTests = cookieTTL
protection = manager
staticPrefix = app/
languages = fr, en, vi, ar
......
......@@ -475,6 +475,7 @@ t/26-AuthRemote.t
t/27-AuthProxy.t
t/28-AuthChoice-and-password.t
t/28-AuthChoice-with-captcha.t
t/28-AuthChoice-with-over.t
t/28-AuthChoice-with-rules.t
t/28-AuthChoice-with-token.t
t/29-AuthGPG.t
......@@ -493,6 +494,7 @@ t/30-Auth-SAML-with-choice.t
t/30-CDC.t
t/30-SAML-Head-to-Tail-POST.t
t/30-SAML-POST-Logout-when-expired.t
t/30-SAML-POST-with-2F-and-Notification.t
t/30-SAML-POST-with-Notification.t
t/30-SAML-ReAuth-with-choice.t
t/30-SAML-ReAuth.t
......
......@@ -43,9 +43,6 @@ has authnLevel => (
sub authenticate {
my ( $self, $req ) = @_;
unless ( $self->ldap ) {
return PE_LDAPCONNECTFAILED;
}
# Set the dn unless done before
unless ( $req->data->{dn} ) {
......@@ -76,8 +73,15 @@ sub authenticate {
# Security: never create session here
return $res || PE_DONE;
}
$self->validateLdap;
unless ( $self->ldap ) {
return PE_LDAPCONNECTFAILED;
}
my $res =
$self->userBind( $req, $req->data->{dn},
$self->ldap->userBind( $req, $req->data->{dn},
password => $req->data->{password} );
$self->setSecurity($req) if ( $res > PE_OK );
......
......@@ -14,6 +14,7 @@ use Lemonldap::NG::Portal::Main::Constants qw(
PE_UNAUTHORIZEDPARTNER
PE_OIDC_SERVICE_NOT_ALLOWED
);
use String::Random qw/random_string/;
our $VERSION = '2.1.0';
......
......@@ -113,6 +113,7 @@ sub init {
sub getUser {
my ( $self, $req, %args ) = @_;
return PE_LDAPCONNECTFAILED unless $self->ldap and $self->bind();
my $mesg = $self->ldap->search(
base => $self->conf->{ldapBase},
......@@ -126,7 +127,8 @@ sub getUser {
attrs => $self->attrs,
);
if ( $mesg->code() != 0 ) {
$self->logger->error( 'LDAP Search error: ' . $mesg->error );
$self->logger->error(
'LDAP Search error ' . $mesg->code . ": " . $mesg->error );
return PE_LDAPERROR;
}
if ( $mesg->count() > 1 ) {
......@@ -143,15 +145,23 @@ sub getUser {
PE_OK;
}
# Test LDAP connection before trying to bind
sub bind {
my $self = shift;
# Validate LDAP connection before use
sub validateLdap {
my ($self) = @_;
unless ($self->ldap
and $self->ldap->root_dse( attrs => ['supportedLDAPVersion'] ) )
{
$self->ldap->DESTROY if ( $self->ldap );
$self->ldap( $self->newLdap );
}
}
# Bind
sub bind {
my $self = shift;
$self->validateLdap;
return undef unless ( $self->ldap );
my $msg = $self->ldap->bind(@_);
if ( $msg->code ) {
......
......@@ -183,7 +183,15 @@ sub userBind {
$self->{portal}->userLogger->warn("Bad password");
return PE_BADCREDENTIALS;
}
return ( $mesg->code == 0 ? PE_OK : PE_LDAPERROR );
elsif ( $mesg->code == 0 ) {
return PE_OK;
}
else {
$self->{portal}->logger->error( "Bind failed with error "
. $mesg->code . ": "
. $mesg->error );
return PE_LDAPERROR;
}
}
# Check for ppolicy error
......@@ -399,7 +407,13 @@ sub userModifyPassword {
# Standard errors
return PE_WRONGMANAGERACCOUNT
if ( $mesg->code == 50 || $mesg->code == 8 );
return PE_LDAPERROR unless ( $mesg->code == 0 );
unless ( $mesg->code == 0 ) {
$self->{portal}
->logger->error( "Password modification failed with LDAP error "
. $mesg->code . ": "
. $mesg->error );
return PE_LDAPERROR;
}
$self->{portal}->userLogger->notice("Password changed for $dn");
......@@ -562,6 +576,9 @@ sub userModifyPassword {
}
}
else {
$self->{portal}->logger->error(
"Missing PPolicy control from server response. Code: "
. $mesg->code );
return PE_LDAPERROR;
}
}
......
......@@ -91,6 +91,7 @@ sub _redirect {
'Add ' . $self->ipath . ', ' . $self->ipath . 'Path in keepPdata' );
push @{ $req->pdata->{keepPdata} }, $self->ipath, $self->ipath . 'Path';
$req->{urldc} = $self->conf->{portal} . '/' . $self->path;
$req->pdata->{_url} = encode_base64($req->urldc, '');
}
else {
$self->logger->debug('Not seen as Issuer request, skipping');
......
......@@ -118,7 +118,6 @@ sub _verify {
$req->id( delete $req->sessionInfo->{_2fRealSession} );
$req->urldc( delete $req->sessionInfo->{_2fUrldc} );
$req->{sessionInfo}->{_utime} = delete $req->{sessionInfo}->{_2fUtime};
$self->p->rebuildCookies($req);
$req->mustRedirect(1);
$self->userLogger->notice( $self->prefix
. '2F verification for '
......@@ -133,6 +132,7 @@ sub _verify {
[
@{ $self->p->afterData },
$self->p->validSession,
'rebuildCookies',
@{ $self->p->endAuth },
sub { PE_OK }
]
......
......@@ -2,8 +2,12 @@ package Lemonldap::NG::Portal::Password::AD;
use strict;
use Mouse;
use Lemonldap::NG::Portal::Main::Constants
qw(PE_PASSWORD_OK PE_LDAPERROR PE_ERROR);
use Lemonldap::NG::Portal::Main::Constants qw(
PE_PASSWORD_OK
PE_LDAPERROR
PE_LDAPCONNECTFAILED
PE_ERROR
);
extends 'Lemonldap::NG::Portal::Lib::LDAP',
'Lemonldap::NG::Portal::Password::Base';
......@@ -30,6 +34,10 @@ sub modifyPassword {
return PE_ERROR;
}
# Ensure connection is valid
$self->bind;
return PE_LDAPCONNECTFAILED unless $self->ldap;
# Call the modify password method
my $code =
$self->ldap->userModifyPassword( $dn, $pwd, $req->data->{oldpassword},
......@@ -49,8 +57,9 @@ sub modifyPassword {
);
unless ( $result->code == 0 ) {
$self->logger->error(
"LDAP modify pwdLastSet error: " . $result->code );
$self->logger->error( "LDAP modify pwdLastSet error "
. $result->code . ": "
. $result->error );
return PE_LDAPERROR;