...
 
Commits (67)
......@@ -17,12 +17,17 @@ before_script:
- env | grep ^CI_
# Converting to native package...
- sed -i "1{s/-1) /$suffix) /}" debian/changelog
- sed -i "1{s/-2) /$suffix) /}" debian/changelog
- sed -i 's/3.0 (quilt)/3.0 (native)/' debian/source/format
build_stretch:
image: buildpkg/debian:stretch
<<: *job_build
build_buster:
image: buildpkg/debian:buster
<<: *job_build
#build_xenial:
# image: buildpkg/ubuntu:xenial
# <<: *job_build
......@@ -42,6 +47,7 @@ sign:
- ci-sign-pkg
dependencies:
- build_stretch
- build_buster
# - build_xenial
- build_bionic
artifacts:
......
......@@ -32,7 +32,12 @@
# Note that Content-Security-Policy header is generated by portal itself
<Files *.fcgi>
SetHandler fcgid-script
#CGIPassAuth on
# For Authorization header to be passed, please uncomment one of the following:
# for Apache >= 2.4.13
#CGIPassAuth On
# for Apache < 2.4.13
#RewriteCond %{HTTP:Authorization} ^(.*)
#RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
Options +ExecCGI
header unset Lm-Remote-User
</Files>
......
......@@ -38,7 +38,12 @@
# Note that Content-Security-Policy header is generated by portal itself
<Files *.fcgi>
SetHandler fcgid-script
#CGIPassAuth on
# For Authorization header to be passed, please uncomment one of the following:
# for Apache >= 2.4.13
#CGIPassAuth On
# for Apache < 2.4.13
#RewriteCond %{HTTP:Authorization} ^(.*)
#RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
Options +ExecCGI
header unset Lm-Remote-User
</Files>
......
......@@ -33,7 +33,12 @@
# Note that Content-Security-Policy header is generated by portal itself
<Files *.fcgi>
SetHandler fcgid-script
#CGIPassAuth on
# For Authorization header to be passed, please uncomment one of the following:
# for Apache >= 2.4.13
#CGIPassAuth On
# for Apache < 2.4.13
#RewriteCond %{HTTP:Authorization} ^(.*)
#RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
Options +ExecCGI
header unset Lm-Remote-User
</Files>
......
lemonldap-ng (2.0.0-2) unstable; urgency=medium
* Fix warnings in Manager
-- Clement OUDOT <clement@oodo.net> Sat, 01 Dec 2018 12:00:00 +0100
lemonldap-ng (2.0.0-1) unstable; urgency=medium
* New release. See changes on our website:
......
......@@ -100,6 +100,7 @@ Section: web
Depends: ${misc:Depends},
${perl:Depends},
lsb-base,
libfcgi-perl,
libfcgi-procmanager-perl,
liblemonldap-ng-handler-perl (= ${binary:Version}),
libplack-perl
......@@ -271,10 +272,10 @@ Recommends: libcrypt-openssl-bignum-perl,
libnet-ldap-perl,
libstring-random-perl,
libunicode-string-perl
Suggests: libauthcas-perl,
libcrypt-u2f-server-perl,
Suggests: libcrypt-u2f-server-perl,
libdbi-perl,
libglib-perl,
libgssapi-perl,
libimage-magick-perl,
liblasso-perl,
libnet-facebook-oauth2-perl (>= 0.10),
......
#!/bin/bash
set -e
. /usr/share/debconf/confmodule
if [ "$1" == "configure" ]
then
find /var/lib/lemonldap-ng/manager/{static,manager.fcgi} -type l -xtype l -delete 2>/dev/null || true
fi
#DEBHELPER#
exit 0
......@@ -21,7 +21,7 @@ dirName=__pwd__/e2e-tests/conf
checkXSS = 0
portalSkin = bootstrap
staticPrefix = /static
languages = fr, en, vi, it, ar, de, zh_CN, nl, es, pt, ro
languages = fr, en, vi, it, ar, de, zh, nl, es, pt, ro
templateDir = __pwd__/lemonldap-ng-portal/site/templates
portalStatus = 1
;totp2fActivation = 1
......@@ -38,7 +38,7 @@ useRedirectOnError = 0
enabledModules = conf, sessions, notifications, 2ndFA
protection = manager
staticPrefix = /static
languages = fr, en, vi, ar, de, it, zh_CN
languages = fr, en, vi, ar, de, it, zh
templateDir = __pwd__/lemonldap-ng-manager/site/templates
[node-handler]
......
......@@ -188,7 +188,6 @@
},
"registerDB": "Demo",
"registerUrl": "http://auth.example.com:__port__/register",
"reloadUrls": {"localhost":"http://reload.example.com:__port__/reload"},
"securedCookie": 0,
"sessionDataToRemember": {},
"timeout": 72000,
......
......@@ -9,7 +9,6 @@ lib/Lemonldap/NG/Common/Apache/Session/REST.pm
lib/Lemonldap/NG/Common/Apache/Session/Serialize/JSON.pm
lib/Lemonldap/NG/Common/Apache/Session/SOAP.pm
lib/Lemonldap/NG/Common/Apache/Session/Store.pm
lib/Lemonldap/NG/Common/Captcha.pm
lib/Lemonldap/NG/Common/Cli.pm
lib/Lemonldap/NG/Common/Combination/Parser.pm
lib/Lemonldap/NG/Common/Conf.pm
......
package Lemonldap::NG::Common;
our $VERSION = '2.0.0';
our $VERSION = '2.0.1';
1;
__END__
......
##@file
# Base package for LemonLDAP::NG Captcha
##@class
# Captcha module that uses session backend
package Lemonldap::NG::Common::Captcha;
our $VERSION = '2.0.0';
use strict;
use Lemonldap::NG::Common::Session;
use Mouse;
use Digest::MD5 qw(md5_hex);
has 'storageModule' => (
is => 'ro',
isa => 'Str',
required => 1,
);
has 'storageModuleOptions' => (
is => 'ro',
isa => 'HashRef|Undef',
);
has code => ( is => 'rw', isa => 'Str' );
has md5 => ( is => 'rw', isa => 'Str' );
has image => ( is => 'rw', isa => 'Str' );
has size => ( is => 'ro', isa => 'Int' );
sub BUILD {
my $self = shift;
unless ( $self->md5 ) {
# Create captcha object
require Authen::Captcha;
my $captcha = Authen::Captcha->new();
# Generate code and md5
my $code = $captcha->generate_random_string( $self->size );
my $md5 = md5_hex($code);
$self->code($code);
$self->md5($md5);
# Generate image data
my $data = $captcha->create_image_file( $code, $md5 );
$self->image($$data);
# Save captcha session
$self->saveSession;
}
else {
$self->getSession;
}
}
sub saveSession {
my $self = shift;
# Create new session
my $session = Lemonldap::NG::Common::Session->new(
{
storageModule => $self->storageModule,
storageModuleOptions => $self->storageModuleOptions,
id => $self->md5,
force => 1,
kind => "Captcha",
info =>
{ _utime => time, code => $self->code, image => $self->image }
}
);
}
sub getSession {
my $self = shift;
# Get session
my $session = Lemonldap::NG::Common::Session->new(
{
storageModule => $self->storageModule,
storageModuleOptions => $self->storageModuleOptions,
id => $self->md5,
}
);
if ( $session && $session->data ) {
$self->code( $session->data->{code} );
$self->image( $session->data->{image} );
}
}
sub removeSession {
my $self = shift;
# Get session
my $session = Lemonldap::NG::Common::Session->new(
{
storageModule => $self->storageModule,
storageModuleOptions => $self->storageModuleOptions,
id => $self->md5,
}
);
if ($session) {
return $session->remove;
}
return 0;
}
no Mouse;
1;
......@@ -5,7 +5,7 @@ use utf8;
use strict;
use Lemonldap::NG::Common::Conf::Serializer;
our $VERSION = '2.0.0';
our $VERSION = '2.0.1';
our $initDone;
sub prereq {
......@@ -80,7 +80,7 @@ sub store {
$Lemonldap::NG::Common::Conf::msg .= "Unable to store conf: $@\n";
return 0;
}
return $res;
return $fields->{cfgNum};
}
sub load {
......
# This file is generated by Lemonldap::NG::Manager::Build. Don't modify it by hand
package Lemonldap::NG::Common::Conf::DefaultValues;
our $VERSION = '2.0.0';
our $VERSION = '2.0.1';
sub defaultValues {
return {
......@@ -15,31 +15,32 @@ sub defaultValues {
'type' => 'category'
}
},
'authChoiceParam' => 'lmAuth',
'authentication' => 'Demo',
'available2F' => 'UTOTP,TOTP,U2F,REST,Ext2F,Yubikey',
'available2FSelfRegistration' => 'TOTP,U2F,Yubikey',
'bruteForceProtectionMaxAge' => 300,
'bruteForceProtectionTempo' => 30,
'captcha_mail_enabled' => 1,
'captcha_register_enabled' => 1,
'captcha_size' => 6,
'casAccessControlPolicy' => 'none',
'casAuthnLevel' => 1,
'checkTime' => 600,
'checkXSS' => 1,
'confirmFormMethod' => 'post',
'cookieName' => 'lemonldap',
'cspConnect' => '\'self\'',
'cspDefault' => '\'self\'',
'cspFont' => '\'self\'',
'cspFormAction' => '\'self\'',
'cspImg' => '\'self\' data:',
'cspScript' => '\'self\'',
'cspStyle' => '\'self\'',
'dbiAuthnLevel' => 2,
'dbiExportedVars' => {},
'demoExportedVars' => {
'authChoiceParam' => 'lmAuth',
'authentication' => 'Demo',
'available2F' => 'UTOTP,TOTP,U2F,REST,Ext2F,Yubikey',
'available2FSelfRegistration' => 'TOTP,U2F,Yubikey',
'bruteForceProtectionMaxAge' => 300,
'bruteForceProtectionMaxFailed' => 3,
'bruteForceProtectionTempo' => 30,
'captcha_mail_enabled' => 1,
'captcha_register_enabled' => 1,
'captcha_size' => 6,
'casAccessControlPolicy' => 'none',
'casAuthnLevel' => 1,
'checkTime' => 600,
'checkXSS' => 1,
'confirmFormMethod' => 'post',
'cookieName' => 'lemonldap',
'cspConnect' => '\'self\'',
'cspDefault' => '\'self\'',
'cspFont' => '\'self\'',
'cspFormAction' => '\'self\'',
'cspImg' => '\'self\' data:',
'cspScript' => '\'self\'',
'cspStyle' => '\'self\'',
'dbiAuthnLevel' => 2,
'dbiExportedVars' => {},
'demoExportedVars' => {
'cn' => 'cn',
'mail' => 'mail',
'uid' => 'uid'
......
......@@ -7,7 +7,7 @@ use JSON;
use Plack::Request;
use URI::Escape;
our $VERSION = '2.0.0';
our $VERSION = '2.0.1';
our @ISA = ('Plack::Request');
......@@ -45,8 +45,8 @@ sub uri { $_[0]->{uri} }
sub userData {
my ( $self, $v ) = @_;
return $_[0]->{userData} = $v if ($v);
return $_[0]->{userData} || { _whatToTrace => $_[0]->user, };
return $self->{userData} = $v if ($v);
return $self->{userData} || { _whatToTrace => $self->{user}, };
}
sub respHeaders {
......
......@@ -3,7 +3,7 @@ package Lemonldap::NG::Handler;
print STDERR
"Use the appropriate handler. For Apache, use Lemonldap::NG::Handler::ApacheMP2";
our $VERSION = '2.0.0';
our $VERSION = '2.0.1';
1;
......
package Lemonldap::NG::Handler::Main::Reload;
our $VERSION = '2.0.0';
our $VERSION = '2.0.1';
package Lemonldap::NG::Handler::Main;
......@@ -213,6 +213,7 @@ sub defaultValuesInit {
if ( $conf->{vhostOptions} ) {
my $name = 'vhost' . ucfirst($opt);
foreach my $vhost ( keys %{ $conf->{vhostOptions} } ) {
$conf->{vhostOptions}->{$vhost} ||= {};
my $val = $conf->{vhostOptions}->{$vhost}->{$name};
# Keep default value if $val is negative
......
......@@ -162,7 +162,7 @@ site/htdocs/static/languages/en.json
site/htdocs/static/languages/fr.json
site/htdocs/static/languages/it.json
site/htdocs/static/languages/vi.json
site/htdocs/static/languages/zh_CN.json
site/htdocs/static/languages/zh.json
site/htdocs/static/logos/ar.png
site/htdocs/static/logos/bootstrap.png
site/htdocs/static/logos/custom.png
......@@ -174,7 +174,7 @@ site/htdocs/static/logos/it.png
site/htdocs/static/logos/llng-icon-32.png
site/htdocs/static/logos/llng-logo-32.png
site/htdocs/static/logos/vi.png
site/htdocs/static/logos/zh_CN.png
site/htdocs/static/logos/zh.png
site/htdocs/static/reverseTree.json
site/htdocs/static/struct.json
site/templates/2ndfa.tpl
......
......@@ -17,7 +17,7 @@ use JSON;
use Lemonldap::NG::Common::Conf::Constants;
use Lemonldap::NG::Common::PSGI::Constants;
our $VERSION = '2.0.0';
our $VERSION = '2.0.1';
extends 'Lemonldap::NG::Common::Conf::AccessLib',
'Lemonldap::NG::Handler::PSGI::Router';
......
# This file is generated by Lemonldap::NG::Manager::Build. Don't modify it by hand
package Lemonldap::NG::Manager::Attributes;
our $VERSION = '2.0.0';
our $VERSION = '2.0.1';
sub types {
return {
......@@ -29,7 +29,7 @@ sub types {
'test' => sub {
my ( $val, $conf ) = @_;
my $s = '';
'Safe'->new->reval("no warning; $s $val");
'Safe'->new->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
......@@ -615,6 +615,10 @@ sub attributes {
'default' => 300,
'type' => 'int'
},
'bruteForceProtectionMaxFailed' => {
'default' => 3,
'type' => 'int'
},
'bruteForceProtectionTempo' => {
'default' => 30,
'type' => 'int'
......@@ -671,7 +675,7 @@ sub attributes {
'test' => sub {
my ( $val, $conf ) = @_;
my $s = '';
'Safe'->new->reval("no warning; $s $val");
'Safe'->new->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
......@@ -1047,7 +1051,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
'test' => sub {
my ( $val, $conf ) = @_;
my $s = $val;
'Safe'->new->reval("no warnings;$s");
'Safe'->new->reval("BEGIN { warnings->unimport; } $s");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
......@@ -1131,7 +1135,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
'keyTest' => sub {
my ( $val, $conf ) = @_;
my $s = '';
'Safe'->new->reval("no warning; $s $val");
'Safe'->new->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
......@@ -1149,7 +1153,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
'test' => sub {
my ( $val, $conf ) = @_;
my $s = '';
'Safe'->new->reval("no warning; $s $val");
'Safe'->new->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
......@@ -1503,7 +1507,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
: ( 0, '__badUrl__' );
}
$s =~ s/\b(accept|deny|unprotect|skip)\b/1/g;
'Safe'->new->reval("no warnings;$s");
'Safe'->new->reval("BEGIN { warnings->unimport; } $s");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
......@@ -1544,7 +1548,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
'test' => sub {
my ( $val, $conf ) = @_;
my $s = '';
'Safe'->new->reval("no warning; $s $val");
'Safe'->new->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
......@@ -1904,7 +1908,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
'test' => sub {
my ( $val, $conf ) = @_;
my $s = '';
'Safe'->new->reval("no warning; $s $val");
'Safe'->new->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
......@@ -2251,7 +2255,7 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
'keyTest' => sub {
my ( $val, $conf ) = @_;
my $s = '';
'Safe'->new->reval("no warning; $s $val");
'Safe'->new->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
......@@ -2987,7 +2991,7 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
'test' => sub {
my ( $val, $conf ) = @_;
my $s = '';
'Safe'->new->reval("no warning; $s $val");
'Safe'->new->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
......
......@@ -6,14 +6,15 @@
package Lemonldap::NG::Manager::Build::Attributes;
our $VERSION = '2.0.0';
our $VERSION = '2.0.1';
use strict;
use Regexp::Common qw/URI/;
my $perlExpr = sub {
my ( $val, $conf ) = @_;
my $s = '';
Safe->new->reval("no warning; $s $val");
Safe->new->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join( '',
grep { $_ =~ /Undefined subroutine/ ? () : $_ } split( /\n/, $@ ) );
return $err ? ( 1, "__badExpression__: $err" ) : (1);
......@@ -611,7 +612,13 @@ sub attributes {
default => 300,
type => 'int',
documentation =>
'Brute force attack protection -> Max age third failed login',
'Brute force attack protection -> Max age between last and first allowed failed login',
},
bruteForceProtectionMaxFailed => {
default => 3,
type => 'int',
documentation =>
'Brute force attack protection -> Max allowed failed login',
},
grantSessionRules => {
type => 'grantContainer',
......@@ -1498,7 +1505,7 @@ sub attributes {
: ( 0, '__badUrl__' );
}
$s =~ s/\b(accept|deny|unprotect|skip)\b/1/g;
Safe->new->reval("no warnings;$s");
Safe->new->reval("BEGIN { warnings->unimport; } $s");
my $err = join( '',
grep { $_ =~ /Undefined subroutine/ ? () : $_ }
split( /\n/, $@ ) );
......@@ -1523,7 +1530,7 @@ sub attributes {
test => sub {
my ( $val, $conf ) = @_;
my $s = $val;
Safe->new->reval("no warnings;$s");
Safe->new->reval("BEGIN { warnings->unimport; } $s");
my $err = join( '',
grep { $_ =~ /Undefined subroutine/ ? () : $_ }
split( /\n/, $@ ) );
......
package Lemonldap::NG::Manager::Conf::Zero;
our $VERSION = '2.0.0';
our $VERSION = '2.0.1';
sub zeroConf {
my ( $domain, $sessionDir, $persistentSessionDir, $notificationDir ) = @_;
......
......@@ -35,14 +35,19 @@ llapp.provider '$translator', ->
if navigator.languages
nlangs = navigator.languages
for nl in nlangs
console.log 'Navigator lang', nl
for al in window.availableLanguages
if al == nl
console.log ' Available lang', al
re = new RegExp('^'+al+'-?')
if nl.match re
console.log ' Matching lang =', al
langs.push al
else if al.substring(0, 1) == nl.substring(0, 1)
langs2.push al
res.lang = if langs[0] then langs[0] else if langs2[0] then langs2[0] else 'en'
else
res.lang = 'en'
console.log 'Selected lang ->', res.lang
# Internal properties
res.deferredTr = []
......
......@@ -307,7 +307,7 @@ llapp.controller 'TreeCtrl', [
type: 'cmbModule'
data:
type: 'LDAP'
for: 0
for: '0'
over: []
$scope.execFilters $scope._findScopeByKey 'authParams'
......
// Generated by CoffeeScript 1.10.0
// Generated by CoffeeScript 1.12.7
/*
LemonLDAP::NG base app module
......@@ -17,7 +17,7 @@ LemonLDAP::NG base app module
llapp = angular.module('llApp', ['ngAria']);
llapp.provider('$translator', function() {
var al, c, j, k, langs, langs2, len, len1, nl, nlangs, ref, res;
var al, c, j, k, langs, langs2, len, len1, nl, nlangs, re, ref, res;
res = {};
c = decodeURIComponent(document.cookie);
if (c.match(/llnglanguage=(\w+)/)) {
......@@ -31,10 +31,14 @@ LemonLDAP::NG base app module
}
for (j = 0, len = nlangs.length; j < len; j++) {
nl = nlangs[j];
console.log('Navigator lang', nl);
ref = window.availableLanguages;
for (k = 0, len1 = ref.length; k < len1; k++) {
al = ref[k];
if (al === nl) {
console.log(' Available lang', al);
re = new RegExp('^' + al + '-?');
if (nl.match(re)) {
console.log(' Matching lang =', al);
langs.push(al);
} else if (al.substring(0, 1) === nl.substring(0, 1)) {
langs2.push(al);
......@@ -45,6 +49,7 @@ LemonLDAP::NG base app module
} else {
res.lang = 'en';
}
console.log('Selected lang ->', res.lang);
res.deferredTr = [];
res.translationFields = {};
res.translate = function(s) {
......@@ -153,7 +158,7 @@ LemonLDAP::NG base app module
restrict: 'E',
terminal: true,
compile: function(element, attr) {
var e, error, t;
var e, t;
if (t = attr.type.match(/text\/(menu|parameters)/)) {
try {
return $htmlParams.set(t[1], JSON.parse(element[0].text));
......
(function(){var a;a=angular.module("llApp",["ngAria"]);a.provider("$translator",function(){var m,p,i,g,h,f,n,l,b,d,e,o;o={};p=decodeURIComponent(document.cookie);if(p.match(/llnglanguage=(\w+)/)){o.lang=RegExp.$1}else{if(navigator){h=[];f=[];d=[navigator.language];if(navigator.languages){d=navigator.languages}for(i=0,n=d.length;i<n;i++){b=d[i];e=window.availableLanguages;for(g=0,l=e.length;g<l;g++){m=e[g];if(m===b){h.push(m)}else{if(m.substring(0,1)===b.substring(0,1)){f.push(m)}}}}o.lang=h[0]?h[0]:f[0]?f[0]:"en"}else{o.lang="en"}}o.deferredTr=[];o.translationFields={};o.translate=function(c){if(o.translationFields[c]){c=o.translationFields[c]}return c};o.translateField=function(c,j){return o.translate(c[j])};o.translateP=function(c){if(c&&o.translationFields.portal){c=c.replace(/__(\w+)__/g,function(k,j){return o.translate(j)})}return c};this.$get=["$q","$http",function(c,j){o.last="";o.init=function(q){var k;if(!q){q=o.lang}k=new Date();k.setTime(k.getTime()+30*86400000);document.cookie="llnglanguage="+q+"; expires="+(k.toUTCString())+"; path=/";k=c.defer();if(o.last!==q){o.last=q;j.get(window.staticPrefix+"languages/"+q+".json").then(function(u){var v,r,t,s;o.translationFields=u.data;s=o.deferredTr;for(r=0,t=s.length;r<t;r++){v=s[r];v.e[v.f](o.translationFields[v.m])}o.deferredTr=[];return k.resolve("Translation files loaded")},function(r){return k.reject("")})}else{k.resolve("No change")}return k.promise};return o}];return this});a.directive("trspan",["$translator",function(b){return{restrict:"A",replace:false,transclude:true,scope:{trspan:"@"},link:function(d,e,c){if(b.translationFields.portal){c.trspan=b.translate(c.trspan)}else{b.deferredTr.push({e:e,f:"text",m:c.trspan})}return e.text(c.trspan)},template:""}}]);a.provider("$htmlParams",function(){this.$get=function(){var b;b={};return{set:function(c,d){return b[c]=d},menu:function(){return b.menu},params:function(){return b.params}}};return this});a.directive("script",["$htmlParams",function(b){return{restrict:"E",terminal:true,compile:function(g,c){var h,d,f;if(f=c.type.match(/text\/(menu|parameters)/)){try{return b.set(f[1],JSON.parse(g[0].text))}catch(d){h=d;console.log("Parsing error:",h)}}}}}]);a.controller("ModalInstanceCtrl",["$scope","$uibModalInstance","elem","set","init",function(b,f,e,i,h){var d,c,g;g=null;b.elem=e;b.set=i;b.result=h;b.staticPrefix=window.staticPrefix;d=e("currentNode");b.translateP=e("translateP");if(d){c=d.data;b.currentNode=d}b.ok=function(){i("result",b.result);return f.close(true)};b.cancel=function(){if(d){b.currentNode.data=c}return f.dismiss("cancel")};return b.inSelect=function(o){var m,l,k,n;n=b.currentNode.select;for(l=0,k=n.length;l<k;l++){m=n[l];if(m.k===o){return true}}return false}}]);a.directive("onReadFile",["$parse",function(b){return{restrict:"A",scope:false,link:function(f,d,c){var e;e=b(c.onReadFile);return d.on("change",function(h){var g;g=new FileReader();g.onload=function(i){return f.$apply(function(){return e(f,{$fileContent:i.target.result})})};return g.readAsText((h.srcElement||h.target).files[0])})}}}]);a.directive("resizer",["$document",function(d){var b,c;b=null;c=null;return function(g,f,e){var h,i;f.on("mousedown",function(j){if(e.resizer==="vertical"){c=$(e.resizerRight).width()+$(e.resizerLeft).width()}else{b=$(e.resizerTop).height()+$(e.resizerBottom).height()}j.preventDefault();d.on("mousemove",h);return d.on("mouseup",i)});h=function(k){var j,l;if(e.resizer==="vertical"){j=k.pageX;if(e.resizerMax&&j>e.resizerMax){j=parseInt(e.resizerMax)}$(e.resizerLeft).css({width:j+"px"});return $(e.resizerRight).css({width:(c-j)+"px"})}else{l=k.pageY-$("#navbar").height();$(e.resizerTop).css({height:l+"px"});return $(e.resizerBottom).css({height:(b-l)+"px"})}};return i=function(){d.unbind("mousemove",h);return d.unbind("mouseup",i)}}}]);a.factory("$lmhttp",["$q","$location",function(b,c){return{responseError:function(d){if(d.status===401&&window.portal){return window.location=(window.portal+"?url=")+window.btoa(window.location).replace(/\//,"_")}else{return b.reject(d)}}}}]);a.config(["$httpProvider",function(b){return b.interceptors.push("$lmhttp")}])}).call(this);
\ No newline at end of file
(function(){var llapp;llapp=angular.module("llApp",["ngAria"]);llapp.provider("$translator",function(){var al,c,j,k,langs,langs2,len,len1,nl,nlangs,re,ref,res;res={};c=decodeURIComponent(document.cookie);if(c.match(/llnglanguage=(\w+)/)){res.lang=RegExp.$1}else if(navigator){langs=[];langs2=[];nlangs=[navigator.language];if(navigator.languages){nlangs=navigator.languages}for(j=0,len=nlangs.length;j<len;j++){nl=nlangs[j];console.log("Navigator lang",nl);ref=window.availableLanguages;for(k=0,len1=ref.length;k<len1;k++){al=ref[k];console.log(" Available lang",al);re=new RegExp("^"+al+"-?");if(nl.match(re)){console.log(" Matching lang =",al);langs.push(al)}else if(al.substring(0,1)===nl.substring(0,1)){langs2.push(al)}}}res.lang=langs[0]?langs[0]:langs2[0]?langs2[0]:"en"}else{res.lang="en"}console.log("Selected lang ->",res.lang);res.deferredTr=[];res.translationFields={};res.translate=function(s){if(res.translationFields[s]){s=res.translationFields[s]}return s};res.translateField=function(node,field){return res.translate(node[field])};res.translateP=function(s){if(s&&res.translationFields.portal){s=s.replace(/__(\w+)__/g,function(match,w){return res.translate(w)})}return s};this.$get=["$q","$http",function($q,$http){res.last="";res.init=function(lang){var d;if(!lang){lang=res.lang}d=new Date;d.setTime(d.getTime()+30*864e5);document.cookie="llnglanguage="+lang+"; expires="+d.toUTCString()+"; path=/";d=$q.defer();if(res.last!==lang){res.last=lang;$http.get(window.staticPrefix+"languages/"+lang+".json").then(function(response){var h,l,len2,ref1;res.translationFields=response.data;ref1=res.deferredTr;for(l=0,len2=ref1.length;l<len2;l++){h=ref1[l];h.e[h.f](res.translationFields[h.m])}res.deferredTr=[];return d.resolve("Translation files loaded")},function(response){return d.reject("")})}else{d.resolve("No change")}return d.promise};return res}];return this});llapp.directive("trspan",["$translator",function($translator){return{restrict:"A",replace:false,transclude:true,scope:{trspan:"@"},link:function(scope,elem,attr){if($translator.translationFields.portal){attr.trspan=$translator.translate(attr.trspan)}else{$translator.deferredTr.push({e:elem,f:"text",m:attr.trspan})}return elem.text(attr.trspan)},template:""}}]);llapp.provider("$htmlParams",function(){this.$get=function(){var params;params={};return{set:function(key,obj){return params[key]=obj},menu:function(){return params.menu},params:function(){return params.params}}};return this});llapp.directive("script",["$htmlParams",function($htmlParams){return{restrict:"E",terminal:true,compile:function(element,attr){var e,t;if(t=attr.type.match(/text\/(menu|parameters)/)){try{return $htmlParams.set(t[1],JSON.parse(element[0].text))}catch(error){e=error;console.log("Parsing error:",e)}}}}}]);llapp.controller("ModalInstanceCtrl",["$scope","$uibModalInstance","elem","set","init",function($scope,$uibModalInstance,elem,set,init){var currentNode,oldValue,oldvalue;oldvalue=null;$scope.elem=elem;$scope.set=set;$scope.result=init;$scope.staticPrefix=window.staticPrefix;currentNode=elem("currentNode");$scope.translateP=elem("translateP");if(currentNode){oldValue=currentNode.data;$scope.currentNode=currentNode}$scope.ok=function(){set("result",$scope.result);return $uibModalInstance.close(true)};$scope.cancel=function(){if(currentNode){$scope.currentNode.data=oldValue}return $uibModalInstance.dismiss("cancel")};return $scope.inSelect=function(value){var i,j,len,ref;ref=$scope.currentNode.select;for(j=0,len=ref.length;j<len;j++){i=ref[j];if(i.k===value){return true}}return false}}]);llapp.directive("onReadFile",["$parse",function($parse){return{restrict:"A",scope:false,link:function(scope,element,attrs){var fn;fn=$parse(attrs.onReadFile);return element.on("change",function(onChangeEvent){var reader;reader=new FileReader;reader.onload=function(onLoadEvent){return scope.$apply(function(){return fn(scope,{$fileContent:onLoadEvent.target.result})})};return reader.readAsText((onChangeEvent.srcElement||onChangeEvent.target).files[0])})}}}]);llapp.directive("resizer",["$document",function($document){var hsize,rsize;hsize=null;rsize=null;return function($scope,$element,$attrs){var mousemove,mouseup;$element.on("mousedown",function(event){if($attrs.resizer==="vertical"){rsize=$($attrs.resizerRight).width()+$($attrs.resizerLeft).width()}else{hsize=$($attrs.resizerTop).height()+$($attrs.resizerBottom).height()}event.preventDefault();$document.on("mousemove",mousemove);return $document.on("mouseup",mouseup)});mousemove=function(event){var x,y;if($attrs.resizer==="vertical"){x=event.pageX;if($attrs.resizerMax&&x>$attrs.resizerMax){x=parseInt($attrs.resizerMax)}$($attrs.resizerLeft).css({width:x+"px"});return $($attrs.resizerRight).css({width:rsize-x+"px"})}else{y=event.pageY-$("#navbar").height();$($attrs.resizerTop).css({height:y+"px"});return $($attrs.resizerBottom).css({height:hsize-y+"px"})}};return mouseup=function(){$document.unbind("mousemove",mousemove);return $document.unbind("mouseup",mouseup)}}}]);llapp.factory("$lmhttp",["$q","$location",function($q,$location){return{responseError:function(rejection){if(rejection.status===401&&window.portal){return window.location=window.portal+"?url="+window.btoa(window.location).replace(/\//,"_")}else{return $q.reject(rejection)}}}}]);llapp.config(["$httpProvider",function($httpProvider){return $httpProvider.interceptors.push("$lmhttp")}])}).call(this);
// Generated by CoffeeScript 1.12.8
// Generated by CoffeeScript 1.12.7
/*
LemonLDAP::NG Manager client
......@@ -357,7 +357,7 @@ This file contains:
type: 'cmbModule',
data: {
type: 'LDAP',
"for": 0,
"for": '0',
over: []
}
});
......
......@@ -33,7 +33,7 @@
<li ng-include="'languages.html'"/>
<li role="separator" class="divider"></li>
<li class="dropdown-header"><span ng-bind="translate('version')"></span></li>
<li><a name="version"><TMPL_VAR NAME="VERSION"></a></li>
<li><a href="https://lemonldap-ng.org/team" name="version"><TMPL_VAR NAME="VERSION"></a></li>
</ul>
</li>
</ul>
......
......@@ -51,3 +51,6 @@ eval { unlink $confFiles->[1]; rmdir 't/sessions'; };
done_testing( count() );
# Remove sessions directory
`rm -rf t/sessions`;
......@@ -19,16 +19,31 @@ mkdir 't/sessions';
my ( $res, $resBody );
ok( $res = &client->_post( '/confs/', 'cfgNum=1', &body, 'application/json' ),
"Request succeed" );
"Request succeed"
);
ok( $res->[0] == 200, "Result code is 200" );
ok( $resBody = from_json( $res->[2]->[0] ), "Result body contains JSON text" );
ok( $resBody = from_json( $res->[2]->[0] ),
"Result body contains JSON text" );
ok( $resBody->{result} == 1, "JSON response contains \"result:1\"" )
or print STDERR Dumper($resBody);
or print STDERR Dumper($resBody);
ok( $resBody->{details}->{__warnings__}
and @{ $resBody->{details}->{__warnings__} } == 2,
'JSON response contains 2 warnings'
) or print STDERR Dumper($resBody);
ok( $resBody->{details}->{__warnings__}->[0]->{message}
=~ /\b(unprotected|cross-domain-authentication)\b/,
"Warning with 'unprotect' or 'CDA' found"
) or print STDERR Dumper($resBody);
ok( $resBody->{details}->{__warnings__}->[1]->{message}
=~ /\b(unprotected|cross-domain-authentication)\b/,
"Warning with 'unprotect' or 'CDA' found"
) or print STDERR Dumper($resBody);
ok( -f $confFiles->[1], 'File is created' );
count(3);
my @changes = @{&changes};
my @cmsg = @{ $resBody->{details}->{__changes__} };
my $bug;
while ( my $c = shift @{ $resBody->{details}->{__changes__} } ) {
my $cmp1 = @changes;
my $cmp2 = @cmsg;
......@@ -42,13 +57,13 @@ while ( my $c = shift @{ $resBody->{details}->{__changes__} } ) {
}
else {
ok( ( $cmp1 - @changes ) == ( $cmp2 - @cmsg ), qq("$c->{key}" found) )
or print STDERR 'Expect: '
. ( $cmp1 - @changes )
. ', got: '
. ( $cmp2 - @cmsg )
. "\nExpect: "
. Dumper( \@d1 ) . "Got: "
. Dumper( \@d2 );
or print STDERR 'Expect: '
. ( $cmp1 - @changes )
. ', got: '
. ( $cmp2 - @cmsg )
. "\nExpect: "
. Dumper( \@d1 ) . "Got: "
. Dumper( \@d2 );
}
count(1);
}
......@@ -56,9 +71,9 @@ ok( !@changes, 'All changes detected' ) or $bug = 1;
if ($bug) {
print STDERR 'Expected not found: '
. Dumper( \@changes )
. 'Changes announced and not found: '
. Dumper( \@cmsg );
. Dumper( \@changes )
. 'Changes announced and not found: '
. Dumper( \@cmsg );
}
#print STDERR Dumper(\@changes,\@cmsg);
......@@ -71,124 +86,105 @@ my ( @c1, @c2 );
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";
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";
or print STDERR "Expect: 14 keys, get: " . join( ',', @c2 ) . "\n";
count(5);
unlink $confFiles->[1];
eval { rmdir 't/sessions'; };
#eval { rmdir 't/sessions'; };
done_testing( count() );
# Remove sessions directory
`rm -rf t/sessions`;
sub changes {
return [
{
'key' => 'portal',
{ 'key' => 'portal',
'new' => 'http://auth2.example.com/',
'old' => 'http://auth.example.com/'
},
{
'new' => 0,
{ 'new' => 0,
'old' => 1,
'key' => 'portalDisplayLogout'
},
{
'key' =>
'applicationList, Sample applications, Application Test 1, uri',
{ 'key' =>
'applicationList, Sample applications, Application Test 1, uri',
'old' => 'http://test1.example.com/',
'new' => 'http://testex.example.com/'
},
{
'new' => 'Application Test 3',
{ 'new' => 'Application Test 3',
'key' => 'applicationList, Sample applications'
},
{
'new' => 'Changes in cat(s)/app(s)',
{ 'new' => 'Changes in cat(s)/app(s)',
'key' => 'applicationList',
},
{
'key' => 'applicationList',
{ 'key' => 'applicationList',
'old' => 'Documentation',
'new' => 'Administration',
},
{
'key' => 'applicationList',
{ 'key' => 'applicationList',
'old' => 'Administration',
'new' => 'Sample applications',
},
{
'key' => 'applicationList',
{ 'key' => 'applicationList',
'old' => 'Sample applications',
'new' => 'Documentation',
},
{
'key' => 'userDB',
{ 'key' => 'userDB',
'new' => 'LDAP',
'old' => 'Demo'
},
{
'key' => 'passwordDB',
{ 'key' => 'passwordDB',
'new' => 'LDAP',
'old' => 'Demo'
},
{
'key' => 'openIdSPList',
{ 'key' => 'openIdSPList',
'new' => '1;bad.com'
},
{
'new' => 'Uid',
{ 'new' => 'Uid',
'key' => 'exportedVars'
},
{
'key' =>
'locationRules, test1.example.com, (?#Logout comment)^/logout',
{ 'key' =>
'locationRules, test1.example.com, (?#Logout comment)^/logout',
'new' => 'logout_sso',
'old' => undef
},
{
'old' => '^/logout',
{ 'old' => '^/logout',
'key' => 'locationRules, test1.example.com'
},
{
'key' => 'locationRules, test3.example.com, ^/logout',
{ 'key' => 'locationRules, test3.example.com, ^/logout',
'new' => 'logout_sso',
'old' => undef
},
{
'key' => 'locationRules, test3.example.com, default',
{ 'key' => 'locationRules, test3.example.com, default',
'old' => undef,
'new' => 'accept'
},
{
'key' => 'locationRules',
{ 'key' => 'locationRules',
'new' => 'test3.example.com'
},
{
'key' => 'exportedHeaders, test3.example.com, Auth-User',
{ 'key' => 'exportedHeaders, test3.example.com, Auth-User',
'old' => undef,
'new' => '$uid'
},
{
'new' => 'test3.example.com',
{ 'new' => 'test3.example.com',
'key' => 'exportedHeaders'
},
{
'key' => 'locationRules, test.ex.com, default',
{ 'key' => 'locationRules, test.ex.com, default',
'old' => undef,
'new' => 'deny'
},
{
'key' => 'locationRules',
{ 'key' => 'locationRules',
'new' => 'test.ex.com'
},
{
'key' => 'virtualHosts',
{ 'key' => 'virtualHosts',
'new' => 'test3.example.com',
'old' => 'test2.example.com'
},
{
'key' => 'virtualHosts',
{ 'key' => 'virtualHosts',
'old' => 'test2.example.com'
}
];
......
......@@ -24,7 +24,7 @@ my @notManagedAttributes = (
'sfEngine', 'available2FSelfRegistration', 'available2F',
# Brute force attack protection parameters
'bruteForceProtectionMaxAge', 'bruteForceProtectionTempo',
'bruteForceProtectionMaxAge', 'bruteForceProtectionTempo', 'bruteForceProtectionMaxFailed',
# Metadatas (added by manager itself)
'cfgAuthor', 'cfgAuthorIP', 'cfgNum', 'cfgDate', 'cfgLog', 'cfgVersion',
......
[all]
logLevel = error
logLevel = error
localSessionStorage =
localSessionStorageOptions =
......
......@@ -299,7 +299,7 @@ site/htdocs/static/common/nl.png
site/htdocs/static/common/pt.png
site/htdocs/static/common/ro.png
site/htdocs/static/common/vi.png
site/htdocs/static/common/zh_CN.png
site/htdocs/static/common/zh.png
site/htdocs/static/languages/ar.json
site/htdocs/static/languages/de.json
site/htdocs/static/languages/en.json
......@@ -310,7 +310,7 @@ site/htdocs/static/languages/nl.json
site/htdocs/static/languages/pt.json
site/htdocs/static/languages/ro.json
site/htdocs/static/languages/vi.json
site/htdocs/static/languages/zh_CN.json
site/htdocs/static/languages/zh.json
site/templates/bootstrap/2fchoice.tpl
site/templates/bootstrap/2fregisters.tpl
site/templates/bootstrap/casBack2Url.tpl
......
# Alias for Lemonldap::NG::Portal::Main
package Lemonldap::NG::Portal;
our $VERSION = '2.0.0';
our $VERSION = '2.0.1';
use Lemonldap::NG::Portal::Main;
use base 'Lemonldap::NG::Portal::Main';
......
......@@ -20,7 +20,7 @@ use Lemonldap::NG::Portal::Main::Constants qw(
PE_TOKENEXPIRED
);
our $VERSION = '2.0.0';
our $VERSION = '2.0.1';
extends 'Lemonldap::NG::Portal::Main::Plugin';
......@@ -166,11 +166,11 @@ sub run {
$req->pdata->{sfRegToken} =
$self->ott->createToken( $req->sessionInfo );
$self->logger->debug("Just one 2F is enabled");
$self->logger->debug(" -> Redirect to /2fregisters/");
$self->logger->debug(" -> Redirect to 2fregisters/");
$req->response(
[
302,
[ Location => $self->conf->{portal} . '/2fregisters/' ], []
[ Location => $self->conf->{portal} . '2fregisters/' ], []
]
);
return PE_SENDRESPONSE;
......
......@@ -9,7 +9,7 @@ use Lemonldap::NG::Portal::Main::Constants qw(
PE_OK
);
our $VERSION = '2.0.0';
our $VERSION = '2.0.1';
extends 'Lemonldap::NG::Portal::Main::Auth';
......@@ -67,4 +67,8 @@ sub getDisplayType {
return ( $self->{conf}->{sslByAjax} ? "sslform" : "logo" );
}
sub authLogout {
PE_OK;
}
1;
......@@ -5,7 +5,7 @@ use GD::SecurityImage use_magick => 1;
use Mouse;
use MIME::Base64;
our $VERSION = '2.0.0';
our $VERSION = '2.0.1';
extends 'Lemonldap::NG::Common::Module';
......@@ -88,7 +88,7 @@ sub validateCaptcha {
$self->logger->warn("Captcha token $token isn't valid");
return 0;
}
unless ( $s->{captcha} == $value ) {
unless ( $s->{captcha} eq $value ) {
$self->logger->notice('Bad captcha response');
return 0;
}
......
......@@ -15,7 +15,7 @@ use Email::Sender::Transport::SMTP qw();
use MIME::Base64;
use Encode;
our $VERSION = '2.0.0';
our $VERSION = '2.0.1';
our $transport;
......@@ -86,17 +86,27 @@ sub translate {
my ( $self, $req ) = @_;
# Get language using llnglanguage cookie
my $lang = $req->cookies->{llnglanguage} || 'en';
my $json = $self->conf->{templateDir} . "/common/mail/$lang.json";
my $lang_code = $req->cookies->{llnglanguage} || 'en';
my $json = $self->conf->{templateDir} . "/common/mail/$lang_code.json";
$json = $self->conf->{templateDir} . '/common/mail/en.json'
unless ( -f $json );
open F, $json
or die 'Installation error: '
. $!
. " ($self->{conf}->{templateDir}/$lang.json or $self->{conf}->{templateDir}/common/mail/en.json)";
. " ($self->{conf}->{templateDir}/$lang_code.json or $self->{conf}->{templateDir}/common/mail/en.json)";
$json = join '', <F>;
close F;
$lang = from_json( $json, { allow_nonref => 1 } );
my $lang = from_json( $json, { allow_nonref => 1 } );
my $langOver = from_json( $self->p->trOver, { allow_nonref => 1 } );
if ($langOver) {
for my $k ( keys %{ $langOver->{all} || {} } ) {
$lang->{$k} = $langOver->{$lang_code}->{$k};
}
for my $k ( keys %{ $langOver->{$lang_code} || {} } ) {
$lang->{$k} = $langOver->{$lang_code}->{$k};
}
}
return sub {
($_) = @_;
$$_ =~ s/\s+trspan="(\w+?)"(.*?)>.*?</"$2>".($lang->{$1}||$1).'<'/gse;
......
......@@ -7,7 +7,7 @@ use utf8;
use Mouse;
use Clone 'clone';
our $VERSION = '2.0.0';
our $VERSION = '2.0.1';
extends 'Lemonldap::NG::Common::Module';
......@@ -60,6 +60,8 @@ sub params {
my ( $self, $req ) = @_;
$self->{conf}->{imgPath} ||= $self->{staticPrefix};
my %res;
my @defaultTabs = (qw/appslist password logout loginHistory oidcConsents/);
my @customTabs = split( /,\s*/, $self->{conf}->{customMenuTabs} || '' );
# Tab to display
# Get the tab URL parameter
......@@ -90,9 +92,18 @@ sub params {
# else calculate modules to display
else {
$res{DISPLAY_TAB} = scalar( grep /^(password|logout|loginHistory)$/,
$req->param("tab") // '' )
|| "applist";
my $tab = $req->param("tab");
if ( defined $tab
and grep ( /^$tab$/, ( @defaultTabs, @customTabs ) ) )
{
$self->logger->debug( "Select menu tab "
. $req->param("tab")
. "from GET parameter" );
$res{DISPLAY_TAB} = $req->param("tab");
}
else {
$res{DISPLAY_TAB} = "appslist";
}