Merge branch 'master' into manager-SFA-module
This commit is contained in:
commit
e3b839ee95
2
COPYING
2
COPYING
|
@ -13,7 +13,7 @@ Copyright: 2005-2018, Xavier Guimard <x.guimard@free.fr>
|
||||||
2012-2015, David Coutadeur <david.coutadeur@gmail.com>
|
2012-2015, David Coutadeur <david.coutadeur@gmail.com>
|
||||||
2018, Christophe Maudoux <chrmdx@gmail.com>
|
2018, Christophe Maudoux <chrmdx@gmail.com>
|
||||||
2006-2015, LINAGORA <info@linagora.com>
|
2006-2015, LINAGORA <info@linagora.com>
|
||||||
2015-2017, Savoir-faire Linux <contac@savoirfairelinux.com>
|
2015-2018, Savoir-faire Linux <contac@savoirfairelinux.com>
|
||||||
License: GPL-2+
|
License: GPL-2+
|
||||||
|
|
||||||
Files: lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/PAM.pm
|
Files: lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Auth/PAM.pm
|
||||||
|
|
12
RELEASE
12
RELEASE
|
@ -21,16 +21,22 @@ Before release
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
- Update documentation:
|
- Update documentation:
|
||||||
$ make documentation
|
|
||||||
|
$ ./script/parameters-for-wiki.pl >/tmp/prmlist.txt
|
||||||
|
|
||||||
|
Replace https://lemonldap-ng.org/documentation/X.X/parameterlist by
|
||||||
|
/tmp/prmlist.txt content
|
||||||
|
|
||||||
|
$ make documentation
|
||||||
|
|
||||||
- Translate documentation
|
- Translate documentation
|
||||||
$ make fr-doc
|
$ make fr-doc
|
||||||
|
|
||||||
- Update debian/changelog
|
- Update debian/changelog
|
||||||
launch just `dch -r` and force save (":w" and ot ":x")
|
launch just `dch -r` and force save (":w" and ot ":x")
|
||||||
|
|
||||||
- Check Debian packages quality
|
- Check Debian packages quality
|
||||||
$ cme check dpkg
|
$ cme check dpkg
|
||||||
|
|
||||||
For minor release
|
For minor release
|
||||||
-----------------
|
-----------------
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
* Minimal authn level system (choice only)
|
* Minimal authn level system (choice only)
|
||||||
* (2ndF/OTP mail)
|
* (2ndF/OTP mail)
|
||||||
* Combination/Choice for password (using session data)
|
* Combination/Choice for password (using session data)
|
||||||
|
|
|
@ -46,7 +46,7 @@ Log : $conf->{cfgLog}
|
||||||
|
|
||||||
sub updateCache {
|
sub updateCache {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $conf = $self->confAccess->getConf( { noCache => 1, raw => 1 } );
|
my $conf = $self->confAccess->getConf( { noCache => 2 } );
|
||||||
die "Must not be launched as root" unless ($>);
|
die "Must not be launched as root" unless ($>);
|
||||||
print STDERR
|
print STDERR
|
||||||
qq{Cache updated to configuration $conf->{cfgNum} for user $>\n};
|
qq{Cache updated to configuration $conf->{cfgNum} for user $>\n};
|
||||||
|
|
|
@ -200,7 +200,7 @@ sub getConf {
|
||||||
# Store modified configuration in cache
|
# Store modified configuration in cache
|
||||||
$self->setLocalConf($r)
|
$self->setLocalConf($r)
|
||||||
if ( $self->{refLocalStorage}
|
if ( $self->{refLocalStorage}
|
||||||
and not( $args->{noCache} or $args->{raw} ) );
|
and not( $args->{noCache} == 1 or $args->{raw} ) );
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,7 +211,7 @@ sub virtualHosts {
|
||||||
}
|
}
|
||||||
return $self->sendJSONresponse( $req, $resp );
|
return $self->sendJSONresponse( $req, $resp );
|
||||||
}
|
}
|
||||||
elsif ( $query =~ /^vhost(?:(?:Aliase|Http)s|Maintenance|Port|Type)$/ ) {
|
elsif ( $query =~ qr/^$virtualHostKeys$/o ) {
|
||||||
$self->logger->debug("Query for $vh/$query key");
|
$self->logger->debug("Query for $vh/$query key");
|
||||||
|
|
||||||
# TODO: verify how this is done actually
|
# TODO: verify how this is done actually
|
||||||
|
|
|
@ -98,10 +98,11 @@ sub unserialize {
|
||||||
unless ( utf8::is_utf8($v) ) {
|
unless ( utf8::is_utf8($v) ) {
|
||||||
$v = encode( 'UTF-8', $v );
|
$v = encode( 'UTF-8', $v );
|
||||||
}
|
}
|
||||||
$conf->{$k} =
|
$conf->{$k} = (
|
||||||
( $v =~ /./
|
$v =~ /./
|
||||||
? eval { from_json( $v, { allow_nonref => 1 } ) }
|
? eval { from_json( $v, { allow_nonref => 1 } ) }
|
||||||
: {} );
|
: {}
|
||||||
|
);
|
||||||
if ($@) {
|
if ($@) {
|
||||||
$Lemonldap::NG::Common::Conf::msg .=
|
$Lemonldap::NG::Common::Conf::msg .=
|
||||||
"Unable to decode $k, switching to old format.\n";
|
"Unable to decode $k, switching to old format.\n";
|
||||||
|
|
|
@ -93,7 +93,7 @@ sub statusInit {
|
||||||
open STDOUT, ">&$fdout";
|
open STDOUT, ">&$fdout";
|
||||||
my $perl_exec = ( $^X =~ /perl/ ) ? $^X : 'perl';
|
my $perl_exec = ( $^X =~ /perl/ ) ? $^X : 'perl';
|
||||||
exec $perl_exec, '-MLemonldap::NG::Handler::Lib::Status',
|
exec $perl_exec, '-MLemonldap::NG::Handler::Lib::Status',
|
||||||
map( {"-I$_"} @INC ),
|
map( { "-I$_" } @INC ),
|
||||||
'-e &Lemonldap::NG::Handler::Lib::Status::run()';
|
'-e &Lemonldap::NG::Handler::Lib::Status::run()';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,14 +84,18 @@ sub init {
|
||||||
my $portal = $conf->{portal};
|
my $portal = $conf->{portal};
|
||||||
$portal =~ s#https?://([^/]*).*#$1#;
|
$portal =~ s#https?://([^/]*).*#$1#;
|
||||||
$self->csp(
|
$self->csp(
|
||||||
"default-src 'self' $portal;frame-ancestors 'none';form-action 'self';"
|
"default-src 'self' $portal;frame-ancestors 'none';form-action 'self';"
|
||||||
);
|
);
|
||||||
|
|
||||||
$self->defaultRoute( $working[0]->defaultRoute );
|
$self->defaultRoute( $working[0]->defaultRoute );
|
||||||
|
|
||||||
# Find out more glyphicones at https://www.w3schools.com/icons/bootstrap_icons_glyphicons.asp
|
# Find out more glyphicones at https://www.w3schools.com/icons/bootstrap_icons_glyphicons.asp
|
||||||
my $linksIcons =
|
my $linksIcons = {
|
||||||
{ 'conf' => 'cog', 'sessions' => 'duplicate', 'notifications' => 'bell', '2ndFA' => 'wrench' };
|
'conf' => 'cog',
|
||||||
|
'sessions' => 'duplicate',
|
||||||
|
'notifications' => 'bell',
|
||||||
|
'2ndFA' => 'wrench'
|
||||||
|
};
|
||||||
|
|
||||||
$self->links( [] );
|
$self->links( [] );
|
||||||
for ( my $i = 0 ; $i < @links ; $i++ ) {
|
for ( my $i = 0 ; $i < @links ; $i++ ) {
|
||||||
|
|
|
@ -62,7 +62,6 @@ sub addRoutes {
|
||||||
$self->{hiddenAttributes} //= "_password";
|
$self->{hiddenAttributes} //= "_password";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
###################
|
###################
|
||||||
# II. 2FA METHODS #
|
# II. 2FA METHODS #
|
||||||
###################
|
###################
|
||||||
|
@ -84,18 +83,17 @@ sub delete2FAKey {
|
||||||
return $self->deleteTOTPKey( $req, $session, $skey );
|
return $self->deleteTOTPKey( $req, $session, $skey );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return $self->sendError( $req, undef, 666 );
|
return $self->sendError( $req, undef, 400 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub add2FAKey {
|
sub add2FAKey {
|
||||||
|
|
||||||
my ( $self, $req, $session, $skey ) = @_;
|
my ( $self, $req, $session, $skey ) = @_;
|
||||||
|
|
||||||
eval 'use Crypt::U2F::Server::Simple';
|
eval 'use Crypt::U2F::Server::Simple';
|
||||||
if ($@) {
|
if ($@) {
|
||||||
$self->error("Can't load U2F library: $@");
|
$self->error("Can't load U2F library: $@");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +127,7 @@ sub sfa {
|
||||||
my $Key = $params->{sessionType};
|
my $Key = $params->{sessionType};
|
||||||
|
|
||||||
my $res;
|
my $res;
|
||||||
|
|
||||||
# Case 2: list of sessions
|
# Case 2: list of sessions
|
||||||
|
|
||||||
my $whatToTrace = Lemonldap::NG::Handler::PSGI::Main->tsv->{whatToTrace};
|
my $whatToTrace = Lemonldap::NG::Handler::PSGI::Main->tsv->{whatToTrace};
|
||||||
|
|
|
@ -227,7 +227,7 @@ sub attributes {
|
||||||
},
|
},
|
||||||
localStorageOptions => {
|
localStorageOptions => {
|
||||||
type => 'keyTextContainer',
|
type => 'keyTextContainer',
|
||||||
documentation => 'Local cache',
|
documentation => 'Local cache parameters',
|
||||||
flags => 'hmp',
|
flags => 'hmp',
|
||||||
},
|
},
|
||||||
cfgNum => {
|
cfgNum => {
|
||||||
|
@ -824,7 +824,7 @@ sub attributes {
|
||||||
localSessionStorage => {
|
localSessionStorage => {
|
||||||
type => 'PerlModule',
|
type => 'PerlModule',
|
||||||
default => 'Cache::FileCache',
|
default => 'Cache::FileCache',
|
||||||
documentation => 'Sessions cache module',
|
documentation => 'Local sessions cache module',
|
||||||
},
|
},
|
||||||
localSessionStorageOptions => {
|
localSessionStorageOptions => {
|
||||||
type => 'keyTextContainer',
|
type => 'keyTextContainer',
|
||||||
|
@ -1411,8 +1411,12 @@ sub attributes {
|
||||||
},
|
},
|
||||||
|
|
||||||
# CAS IDP
|
# CAS IDP
|
||||||
casAttr => { type => 'text', },
|
casAttr =>
|
||||||
casAttributes => { type => 'keyTextContainer', },
|
{ type => 'text', documentation => 'Pivot attribute for CAS', },
|
||||||
|
casAttributes => {
|
||||||
|
type => 'keyTextContainer',
|
||||||
|
documentation => 'CAS exported attributes',
|
||||||
|
},
|
||||||
casAccessControlPolicy => {
|
casAccessControlPolicy => {
|
||||||
type => 'select',
|
type => 'select',
|
||||||
select => [
|
select => [
|
||||||
|
@ -1423,9 +1427,13 @@ sub attributes {
|
||||||
default => 'none',
|
default => 'none',
|
||||||
documentation => 'CAS access control policy',
|
documentation => 'CAS access control policy',
|
||||||
},
|
},
|
||||||
casStorage => { type => 'PerlModule', },
|
casStorage => {
|
||||||
|
type => 'PerlModule',
|
||||||
|
documentation => 'Apache::Session module to store CAS user data',
|
||||||
|
},
|
||||||
casStorageOptions => {
|
casStorageOptions => {
|
||||||
type => 'keyTextContainer',
|
type => 'keyTextContainer',
|
||||||
|
documentation => 'Apache::Session module parameters',
|
||||||
},
|
},
|
||||||
issuerDBCASActivation => {
|
issuerDBCASActivation => {
|
||||||
default => 0,
|
default => 0,
|
||||||
|
@ -1444,7 +1452,10 @@ sub attributes {
|
||||||
},
|
},
|
||||||
|
|
||||||
# Partners
|
# Partners
|
||||||
casAppMetaDataOptions => { type => 'subContainer', },
|
casAppMetaDataOptions => {
|
||||||
|
type => 'subContainer',
|
||||||
|
documentation => 'Root of CAS app options',
|
||||||
|
},
|
||||||
casAppMetaDataExportedVars => {
|
casAppMetaDataExportedVars => {
|
||||||
type => 'keyTextContainer',
|
type => 'keyTextContainer',
|
||||||
default => { cn => 'cn', mail => 'mail', uid => 'uid', },
|
default => { cn => 'cn', mail => 'mail', uid => 'uid', },
|
||||||
|
@ -1605,8 +1616,14 @@ sub attributes {
|
||||||
type => 'bool',
|
type => 'bool',
|
||||||
documentation => 'SAML force metadata UTF8 conversion',
|
documentation => 'SAML force metadata UTF8 conversion',
|
||||||
},
|
},
|
||||||
samlStorage => { type => 'PerlModule', },
|
samlStorage => {
|
||||||
samlStorageOptions => { type => 'keyTextContainer', },
|
type => 'PerlModule',
|
||||||
|
documentation => 'Apache::Session module to store SAML user data',
|
||||||
|
},
|
||||||
|
samlStorageOptions => {
|
||||||
|
type => 'keyTextContainer',
|
||||||
|
documentation => 'Apache::Session module parameters',
|
||||||
|
},
|
||||||
samlAuthnContextMapPassword => {
|
samlAuthnContextMapPassword => {
|
||||||
type => 'int',
|
type => 'int',
|
||||||
default => 2,
|
default => 2,
|
||||||
|
@ -2231,9 +2248,12 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
|
||||||
default => 'find',
|
default => 'find',
|
||||||
documentation => '"deref" param of Net::LDAP::search()',
|
documentation => '"deref" param of Net::LDAP::search()',
|
||||||
},
|
},
|
||||||
mailLDAPFilter => { type => 'text', },
|
mailLDAPFilter =>
|
||||||
LDAPFilter => { type => 'text', },
|
{ type => 'text', documentation => 'LDAP filter for mail search' },
|
||||||
AuthLDAPFilter => { type => 'text', },
|
LDAPFilter =>
|
||||||
|
{ type => 'text', documentation => 'Default LDAP filter' },
|
||||||
|
AuthLDAPFilter =>
|
||||||
|
{ type => 'text', documentation => 'LDAP filter for auth search' },
|
||||||
ldapGroupRecursive => {
|
ldapGroupRecursive => {
|
||||||
default => 0,
|
default => 0,
|
||||||
type => 'bool',
|
type => 'bool',
|
||||||
|
@ -2312,7 +2332,10 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
|
||||||
default => { cn => 'cn', mail => 'mail', uid => 'uid', },
|
default => { cn => 'cn', mail => 'mail', uid => 'uid', },
|
||||||
documentation => 'CAS exported variables',
|
documentation => 'CAS exported variables',
|
||||||
},
|
},
|
||||||
casSrvMetaDataOptions => { type => 'subContainer', },
|
casSrvMetaDataOptions => {
|
||||||
|
type => 'subContainer',
|
||||||
|
documentation => 'Root of CAS server options',
|
||||||
|
},
|
||||||
casSrvMetaDataOptionsGateway => { type => 'bool', },
|
casSrvMetaDataOptionsGateway => { type => 'bool', },
|
||||||
casSrvMetaDataOptionsProxiedServices => {
|
casSrvMetaDataOptionsProxiedServices => {
|
||||||
type => 'keyTextContainer',
|
type => 'keyTextContainer',
|
||||||
|
@ -2385,7 +2408,7 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
|
||||||
ns =>
|
ns =>
|
||||||
'http://auth.example.com/Lemonldap/NG/Common/PSGI/SOAPService',
|
'http://auth.example.com/Lemonldap/NG/Common/PSGI/SOAPService',
|
||||||
},
|
},
|
||||||
documentation => 'Demo exported variables',
|
documentation => 'Apache::Session module parameters',
|
||||||
},
|
},
|
||||||
|
|
||||||
# Proxy
|
# Proxy
|
||||||
|
@ -2649,6 +2672,7 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
|
||||||
{ k => 'Custom', v => 'customModule' },
|
{ k => 'Custom', v => 'customModule' },
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
documentation => 'Hash list of Choice strings',
|
||||||
},
|
},
|
||||||
|
|
||||||
# Combination
|
# Combination
|
||||||
|
@ -2831,8 +2855,14 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
|
||||||
default => 0,
|
default => 0,
|
||||||
documentation => 'OpenID Connect allow hybrid flow',
|
documentation => 'OpenID Connect allow hybrid flow',
|
||||||
},
|
},
|
||||||
oidcStorage => { type => 'PerlModule', },
|
oidcStorage => {
|
||||||
oidcStorageOptions => { type => 'keyTextContainer', },
|
type => 'PerlModule',
|
||||||
|
documentation => 'Apache::Session module to store OIDC user data',
|
||||||
|
},
|
||||||
|
oidcStorageOptions => {
|
||||||
|
type => 'keyTextContainer',
|
||||||
|
documentation => 'Apache::Session module parameters',
|
||||||
|
},
|
||||||
|
|
||||||
# OpenID Connect metadata nodes
|
# OpenID Connect metadata nodes
|
||||||
oidcOPMetaDataNodes => {
|
oidcOPMetaDataNodes => {
|
||||||
|
|
|
@ -342,16 +342,7 @@ llapp.controller 'TreeCtrl', [
|
||||||
$scope.showModal('prompt.html', name).then ->
|
$scope.showModal('prompt.html', name).then ->
|
||||||
n= $scope.result
|
n= $scope.result
|
||||||
if n
|
if n
|
||||||
node = $scope.addTemplateNode n, 'virtualHost'
|
$scope.addTemplateNode n, 'virtualHost'
|
||||||
delete node.nodes[0].cnodes
|
|
||||||
node.nodes[0].nodes = [
|
|
||||||
id: "virtualHosts/new__#{n}/locationRules/default",
|
|
||||||
type: "rule",
|
|
||||||
title: "default",
|
|
||||||
comment: "",
|
|
||||||
re: "default",
|
|
||||||
data: "deny"
|
|
||||||
]
|
|
||||||
|
|
||||||
$scope.duplicateVhost = ->
|
$scope.duplicateVhost = ->
|
||||||
name = if $scope.domain then ".#{$scope.domain.data}" else '.example.com'
|
name = if $scope.domain then ".#{$scope.domain.data}" else '.example.com'
|
||||||
|
@ -398,10 +389,22 @@ llapp.controller 'TreeCtrl', [
|
||||||
title: name
|
title: name
|
||||||
type: type
|
type: type
|
||||||
nodes: templates type, "new__#{name}"
|
nodes: templates type, "new__#{name}"
|
||||||
|
setDefault t.nodes
|
||||||
cs.$modelValue.nodes.push t
|
cs.$modelValue.nodes.push t
|
||||||
cs.expand()
|
cs.expand()
|
||||||
return t
|
return t
|
||||||
|
|
||||||
|
setDefault = (node) ->
|
||||||
|
for n in node
|
||||||
|
if n.cnodes and n.default
|
||||||
|
delete n.cnodes
|
||||||
|
n._nodes = n.default
|
||||||
|
if n._nodes
|
||||||
|
setDefault n._nodes
|
||||||
|
else if n.default or n.default == 0
|
||||||
|
n.data = n.default
|
||||||
|
node
|
||||||
|
|
||||||
_getAll = (node) ->
|
_getAll = (node) ->
|
||||||
d = $q.defer()
|
d = $q.defer()
|
||||||
d2 = $q.defer()
|
d2 = $q.defer()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Generated by CoffeeScript 1.10.0
|
// Generated by CoffeeScript 1.12.7
|
||||||
|
|
||||||
/*
|
/*
|
||||||
LemonLDAP::NG Manager client
|
LemonLDAP::NG Manager client
|
||||||
|
@ -23,7 +23,7 @@ This file contains:
|
||||||
|
|
||||||
llapp.controller('TreeCtrl', [
|
llapp.controller('TreeCtrl', [
|
||||||
'$scope', '$http', '$location', '$q', '$uibModal', '$translator', '$cookies', '$htmlParams', function($scope, $http, $location, $q, $uibModal, $translator, $cookies, $htmlParams) {
|
'$scope', '$http', '$location', '$q', '$uibModal', '$translator', '$cookies', '$htmlParams', function($scope, $http, $location, $q, $uibModal, $translator, $cookies, $htmlParams) {
|
||||||
var _checkSaveResponse, _download, _getAll, _stoggle, c, id, pathEvent, readError, setHelp;
|
var _checkSaveResponse, _download, _getAll, _stoggle, c, id, pathEvent, readError, setDefault, setHelp;
|
||||||
$scope.links = window.links;
|
$scope.links = window.links;
|
||||||
$scope.menu = $htmlParams.menu;
|
$scope.menu = $htmlParams.menu;
|
||||||
$scope.menulinks = window.menulinks;
|
$scope.menulinks = window.menulinks;
|
||||||
|
@ -405,21 +405,10 @@ This file contains:
|
||||||
field: 'hostname'
|
field: 'hostname'
|
||||||
};
|
};
|
||||||
return $scope.showModal('prompt.html', name).then(function() {
|
return $scope.showModal('prompt.html', name).then(function() {
|
||||||
var n, node;
|
var n;
|
||||||
n = $scope.result;
|
n = $scope.result;
|
||||||
if (n) {
|
if (n) {
|
||||||
node = $scope.addTemplateNode(n, 'virtualHost');
|
return $scope.addTemplateNode(n, 'virtualHost');
|
||||||
delete node.nodes[0].cnodes;
|
|
||||||
return node.nodes[0].nodes = [
|
|
||||||
{
|
|
||||||
id: "virtualHosts/new__" + n + "/locationRules/default",
|
|
||||||
type: "rule",
|
|
||||||
title: "default",
|
|
||||||
comment: "",
|
|
||||||
re: "default",
|
|
||||||
data: "deny"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -479,10 +468,27 @@ This file contains:
|
||||||
type: type,
|
type: type,
|
||||||
nodes: templates(type, "new__" + name)
|
nodes: templates(type, "new__" + name)
|
||||||
};
|
};
|
||||||
|
setDefault(t.nodes);
|
||||||
cs.$modelValue.nodes.push(t);
|
cs.$modelValue.nodes.push(t);
|
||||||
cs.expand();
|
cs.expand();
|
||||||
return t;
|
return t;
|
||||||
};
|
};
|
||||||
|
setDefault = function(node) {
|
||||||
|
var len, n, o;
|
||||||
|
for (o = 0, len = node.length; o < len; o++) {
|
||||||
|
n = node[o];
|
||||||
|
if (n.cnodes && n["default"]) {
|
||||||
|
delete n.cnodes;
|
||||||
|
n._nodes = n["default"];
|
||||||
|
}
|
||||||
|
if (n._nodes) {
|
||||||
|
setDefault(n._nodes);
|
||||||
|
} else if (n["default"] || n["default"] === 0) {
|
||||||
|
n.data = n["default"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
};
|
||||||
_getAll = function(node) {
|
_getAll = function(node) {
|
||||||
var d, d2;
|
var d, d2;
|
||||||
d = $q.defer();
|
d = $q.defer();
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,4 @@
|
||||||
// Generated by CoffeeScript 1.9.3
|
// Generated by CoffeeScript 1.12.7
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Session explorer
|
* Session explorer
|
||||||
|
|
|
@ -106,10 +106,11 @@ sub verify {
|
||||||
# Prepare args
|
# Prepare args
|
||||||
my $args;
|
my $args;
|
||||||
foreach my $k ( keys %{ $self->{vrfyAttrs} } ) {
|
foreach my $k ( keys %{ $self->{vrfyAttrs} } ) {
|
||||||
$args->{$k} =
|
$args->{$k} = (
|
||||||
( $k eq 'code'
|
$k eq 'code'
|
||||||
? $code
|
? $code
|
||||||
: $req->sessionInfo->{ $self->{vrfyAttrs}->{$k} } );
|
: $req->sessionInfo->{ $self->{vrfyAttrs}->{$k} }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Launch REST request
|
# Launch REST request
|
||||||
|
|
|
@ -137,24 +137,16 @@ sub selfRegister {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get or generate master key
|
# Get or generate master key
|
||||||
elsif ( $action eq 'unregister' ) {
|
elsif ( $action eq 'unregister' ) {
|
||||||
$self->p->updatePersistentSession( $req,
|
$self->p->updatePersistentSession( $req, { _totp2fSecret => '' } );
|
||||||
{ _totp2fSecret => '' }
|
|
||||||
);
|
|
||||||
$self->userLogger->notice('TOTP unregistration succeed');
|
$self->userLogger->notice('TOTP unregistration succeed');
|
||||||
return [ 200, [ 'Content-Type' => 'application/json' ],
|
return [ 200, [ 'Content-Type' => 'application/json' ],
|
||||||
['{"result":1}'] ];
|
['{"result":1}'] ];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -74,18 +74,16 @@ sub run {
|
||||||
return [ 200, [ 'Content-Type' => 'application/json' ], [$challenge] ];
|
return [ 200, [ 'Content-Type' => 'application/json' ], [$challenge] ];
|
||||||
}
|
}
|
||||||
if ( $action eq 'unregistration' ) {
|
if ( $action eq 'unregistration' ) {
|
||||||
$self->p->updatePersistentSession(
|
$self->p->updatePersistentSession(
|
||||||
$req,
|
$req,
|
||||||
{
|
{
|
||||||
_u2fKeyHandle => '',
|
_u2fKeyHandle => '',
|
||||||
_u2fUserKey => ''
|
_u2fUserKey => ''
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
$self->userLogger->notice('U2F key unregistration succeed');
|
$self->userLogger->notice('U2F key unregistration succeed');
|
||||||
return [
|
return [ 200, [ 'Content-Type' => 'application/json' ],
|
||||||
200, [ 'Content-Type' => 'application/json' ],
|
['{"result":1}'] ];
|
||||||
['{"result":1}']
|
|
||||||
];
|
|
||||||
my $err = Crypt::U2F::Server::Simple::lastError();
|
my $err = Crypt::U2F::Server::Simple::lastError();
|
||||||
$self->userLogger->warn("U2F Unregistration failed: $err");
|
$self->userLogger->warn("U2F Unregistration failed: $err");
|
||||||
return $self->p->sendError( $req, $err, 200 );
|
return $self->p->sendError( $req, $err, 200 );
|
||||||
|
@ -117,6 +115,7 @@ sub run {
|
||||||
}
|
}
|
||||||
my $res =
|
my $res =
|
||||||
( $req->datas->{crypter}->authenticationVerify($resp) ? 1 : 0 );
|
( $req->datas->{crypter}->authenticationVerify($resp) ? 1 : 0 );
|
||||||
|
|
||||||
#$self->userLogger->notice("res=$res");
|
#$self->userLogger->notice("res=$res");
|
||||||
return [
|
return [
|
||||||
200, [ 'Content-Type' => 'application/json' ],
|
200, [ 'Content-Type' => 'application/json' ],
|
||||||
|
|
|
@ -85,6 +85,7 @@ sub verify {
|
||||||
return $self->fail($req);
|
return $self->fail($req);
|
||||||
}
|
}
|
||||||
$self->logger->debug("Get challenge: $challenge");
|
$self->logger->debug("Get challenge: $challenge");
|
||||||
|
|
||||||
#eval { $challenge = JSON::from_json($challenge)->{challenge} };
|
#eval { $challenge = JSON::from_json($challenge)->{challenge} };
|
||||||
if ( not $req->datas->{crypter}->setChallenge($challenge) ) {
|
if ( not $req->datas->{crypter}->setChallenge($challenge) ) {
|
||||||
$self->logger->error(
|
$self->logger->error(
|
||||||
|
|
|
@ -177,8 +177,7 @@ sub try {
|
||||||
|
|
||||||
# On error, restart authentication with next scheme
|
# On error, restart authentication with next scheme
|
||||||
if ( $res > PE_OK ) {
|
if ( $res > PE_OK ) {
|
||||||
$self->logger->info(
|
$self->logger->info(qq'Scheme "$name" returned $res, trying next');
|
||||||
qq'Scheme "$name" returned $res, trying next');
|
|
||||||
$req->datas->{dataKeep}->{combinationTry}++;
|
$req->datas->{dataKeep}->{combinationTry}++;
|
||||||
$req->steps( [ @{ $req->datas->{combinationSteps} } ] );
|
$req->steps( [ @{ $req->datas->{combinationSteps} } ] );
|
||||||
$req->continue(1);
|
$req->continue(1);
|
||||||
|
|
|
@ -33,6 +33,13 @@ sub init {
|
||||||
|
|
||||||
sub extractFormInfo {
|
sub extractFormInfo {
|
||||||
my ( $self, $req ) = @_;
|
my ( $self, $req ) = @_;
|
||||||
|
|
||||||
|
if ( $req->datas->{_krbUser} ) {
|
||||||
|
$self->logger->debug( 'Kerberos ticket already validated for '
|
||||||
|
. $req->datas->{_krbUser} );
|
||||||
|
return PE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
my $auth = $req->env->{HTTP_AUTHORIZATION};
|
my $auth = $req->env->{HTTP_AUTHORIZATION};
|
||||||
unless ($auth) {
|
unless ($auth) {
|
||||||
|
|
||||||
|
@ -138,7 +145,7 @@ sub extractFormInfo {
|
||||||
return PE_ERROR;
|
return PE_ERROR;
|
||||||
}
|
}
|
||||||
$self->userLogger->notice("$client_name authentified by Kerberos");
|
$self->userLogger->notice("$client_name authentified by Kerberos");
|
||||||
$req->{_krbUser} = $client_name;
|
$req->datas->{_krbUser} = $client_name;
|
||||||
if ( $self->conf->{krbRemoveDomain} ) {
|
if ( $self->conf->{krbRemoveDomain} ) {
|
||||||
$client_name =~ s/^(.*)@.*$/$1/;
|
$client_name =~ s/^(.*)@.*$/$1/;
|
||||||
}
|
}
|
||||||
|
@ -157,7 +164,7 @@ sub authLogout {
|
||||||
sub setAuthSessionInfo {
|
sub setAuthSessionInfo {
|
||||||
my ( $self, $req ) = @_;
|
my ( $self, $req ) = @_;
|
||||||
$req->{sessionInfo}->{authenticationLevel} = $self->conf->{krbAuthnLevel};
|
$req->{sessionInfo}->{authenticationLevel} = $self->conf->{krbAuthnLevel};
|
||||||
$req->{sessionInfo}->{_krbUser} = $req->{_krbUser};
|
$req->{sessionInfo}->{_krbUser} = $req->datas->{_krbUser};
|
||||||
PE_OK;
|
PE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -733,7 +733,7 @@ sub extractFormInfo {
|
||||||
my $res = $self->p->deleteSession($req);
|
my $res = $self->p->deleteSession($req);
|
||||||
return (
|
return (
|
||||||
$res eq PE_LOGOUT_OK ? PE_SENDRESPONSE : $res );
|
$res eq PE_LOGOUT_OK ? PE_SENDRESPONSE : $res );
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -901,7 +901,7 @@ sub token {
|
||||||
|
|
||||||
unless ($codeSession) {
|
unless ($codeSession) {
|
||||||
$self->logger->error("Unable to find OIDC session $code");
|
$self->logger->error("Unable to find OIDC session $code");
|
||||||
$self->p->sendError( $req, 'invalid_request', 400 );
|
return $self->p->sendError( $req, 'invalid_request', 400 );
|
||||||
}
|
}
|
||||||
|
|
||||||
# Check we have the same redirect_uri value
|
# Check we have the same redirect_uri value
|
||||||
|
@ -909,7 +909,7 @@ sub token {
|
||||||
{
|
{
|
||||||
$self->userLogger->error( "Provided redirect_uri is different from "
|
$self->userLogger->error( "Provided redirect_uri is different from "
|
||||||
. $codeSession->{redirect_uri} );
|
. $codeSession->{redirect_uri} );
|
||||||
$self->p->sendError( $req, 'invalid_request', 400 );
|
return $self->p->sendError( $req, 'invalid_request', 400 );
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get user identifier
|
# Get user identifier
|
||||||
|
@ -921,7 +921,7 @@ sub token {
|
||||||
$self->userLogger->error(
|
$self->userLogger->error(
|
||||||
"Unable to find user session linked to OIDC session $code");
|
"Unable to find user session linked to OIDC session $code");
|
||||||
$codeSession->remove();
|
$codeSession->remove();
|
||||||
$self->p->sendError( $req, 'invalid_request', 400 );
|
return $self->p->sendError( $req, 'invalid_request', 400 );
|
||||||
}
|
}
|
||||||
|
|
||||||
my $user_id_attribute =
|
my $user_id_attribute =
|
||||||
|
@ -947,7 +947,7 @@ sub token {
|
||||||
$self->userLogger->error(
|
$self->userLogger->error(
|
||||||
"Unable to create OIDC session for access_token");
|
"Unable to create OIDC session for access_token");
|
||||||
$codeSession->remove();
|
$codeSession->remove();
|
||||||
$self->p->sendError( $req, 'invalid_request', 400 );
|
return $self->p->sendError( $req, 'invalid_request', 400 );
|
||||||
}
|
}
|
||||||
|
|
||||||
my $access_token = $accessTokenSession->id;
|
my $access_token = $accessTokenSession->id;
|
||||||
|
@ -1102,7 +1102,7 @@ sub registration {
|
||||||
# Check dynamic registration is allowed
|
# Check dynamic registration is allowed
|
||||||
unless ( $self->conf->{oidcServiceAllowDynamicRegistration} ) {
|
unless ( $self->conf->{oidcServiceAllowDynamicRegistration} ) {
|
||||||
$self->logger->error("Dynamic registration is not allowed");
|
$self->logger->error("Dynamic registration is not allowed");
|
||||||
$self->p->sendError( $req, 'server_error' );
|
return $self->p->sendError( $req, 'server_error' );
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get client metadata
|
# Get client metadata
|
||||||
|
|
|
@ -97,6 +97,7 @@ sub bind {
|
||||||
unless ($self->ldap
|
unless ($self->ldap
|
||||||
and $self->ldap->root_dse( attrs => ['supportedLDAPVersion'] ) )
|
and $self->ldap->root_dse( attrs => ['supportedLDAPVersion'] ) )
|
||||||
{
|
{
|
||||||
|
$self->ldap->DESTROY if ( $self->ldap );
|
||||||
$self->ldap( $self->newLdap );
|
$self->ldap( $self->newLdap );
|
||||||
}
|
}
|
||||||
return undef unless ( $self->ldap );
|
return undef unless ( $self->ldap );
|
||||||
|
|
|
@ -95,7 +95,7 @@ sub getToken {
|
||||||
$self->logger->notice("Bad (or expired) token $id");
|
$self->logger->notice("Bad (or expired) token $id");
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
$self->cache->remove($id) unless($keep);
|
$self->cache->remove($id) unless ($keep);
|
||||||
return from_json( $data, { allow_nonref => 1 } );
|
return from_json( $data, { allow_nonref => 1 } );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -178,24 +178,32 @@ sub sregHook {
|
||||||
|
|
||||||
# else build message and return 0
|
# else build message and return 0
|
||||||
else {
|
else {
|
||||||
my (@mopt,@mreq);
|
my ( @mopt, @mreq );
|
||||||
|
|
||||||
# No choice for requested parameters: just an information
|
# No choice for requested parameters: just an information
|
||||||
foreach my $k (@req) {
|
foreach my $k (@req) {
|
||||||
utf8::decode( $msg{req}->{$k} );
|
utf8::decode( $msg{req}->{$k} );
|
||||||
push @mreq, {k=>$k,m=>$msg{req}->{$k}};
|
push @mreq, { k => $k, m => $msg{req}->{$k} };
|
||||||
}
|
}
|
||||||
|
|
||||||
# For optional parameters: checkboxes are displayed
|
# For optional parameters: checkboxes are displayed
|
||||||
foreach my $k (@opt) {
|
foreach my $k (@opt) {
|
||||||
utf8::decode( $msg{opt}->{$k} );
|
utf8::decode( $msg{opt}->{$k} );
|
||||||
push @mopt,{k=>$k,m=>$msg{opt}->{$k},c=>( $ag{$k} ? 'checked' : '' )};
|
push @mopt,
|
||||||
|
{
|
||||||
|
k => $k,
|
||||||
|
m => $msg{opt}->{$k},
|
||||||
|
c => ( $ag{$k} ? 'checked' : '' )
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
$req->datas->{_openIdTrustExtMsg} .= $self->loadTemplate('openIdTrust',params => {
|
$req->datas->{_openIdTrustExtMsg} .= $self->loadTemplate(
|
||||||
required => \@mreq,
|
'openIdTrust',
|
||||||
optional => \@mopt,
|
params => {
|
||||||
});
|
required => \@mreq,
|
||||||
|
optional => \@mopt,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
$self->logger->debug('Building validation form');
|
$self->logger->debug('Building validation form');
|
||||||
return ( 0, $prm );
|
return ( 0, $prm );
|
||||||
|
|
|
@ -101,7 +101,7 @@ sub _redirect {
|
||||||
# Restore urldc if auth doesn't need to dial with browser
|
# Restore urldc if auth doesn't need to dial with browser
|
||||||
$self->restoreRequest( $req, $ir );
|
$self->restoreRequest( $req, $ir );
|
||||||
return $self->run( @_, @path );
|
return $self->run( @_, @path );
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,10 @@ sub init {
|
||||||
if ( my $rules = $self->conf->{autoSigninRules} ) {
|
if ( my $rules = $self->conf->{autoSigninRules} ) {
|
||||||
my $safe = Safe->new;
|
my $safe = Safe->new;
|
||||||
foreach my $id ( sort keys %$rules ) {
|
foreach my $id ( sort keys %$rules ) {
|
||||||
my $sub = $safe->reval('sub{my($env)=@_;return ('.$rules->{$id}.')}');
|
my $sub =
|
||||||
|
$safe->reval( 'sub{my($env)=@_;return (' . $rules->{$id} . ')}' );
|
||||||
if ($@) {
|
if ($@) {
|
||||||
$self->error('Bad Autologin rule "'.$rules->{$id}.': $@');
|
$self->error( 'Bad Autologin rule "' . $rules->{$id} . ': $@' );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
$id =~ s/^\s*([\w\-\@]+)\s*/$1/;
|
$id =~ s/^\s*([\w\-\@]+)\s*/$1/;
|
||||||
|
|
|
@ -24,8 +24,12 @@ SKIP: {
|
||||||
skip 'DBD::SQLite not found', $maintests;
|
skip 'DBD::SQLite not found', $maintests;
|
||||||
}
|
}
|
||||||
my $dbh = DBI->connect("dbi:SQLite:dbname=t/userdb.db");
|
my $dbh = DBI->connect("dbi:SQLite:dbname=t/userdb.db");
|
||||||
$dbh->do('CREATE TABLE users (user text,password text,name text,uid text,cn text,mail text)');
|
$dbh->do(
|
||||||
$dbh->do("INSERT INTO users VALUES ('dwho','dwho','Doctor who','dwho','Doctor who','dwho\@badwolf.org')");
|
'CREATE TABLE users (user text,password text,name text,uid text,cn text,mail text)'
|
||||||
|
);
|
||||||
|
$dbh->do(
|
||||||
|
"INSERT INTO users VALUES ('dwho','dwho','Doctor who','dwho','Doctor who','dwho\@badwolf.org')"
|
||||||
|
);
|
||||||
|
|
||||||
# Initialization
|
# Initialization
|
||||||
ok( $issuer = issuer(), 'Issuer portal' );
|
ok( $issuer = issuer(), 'Issuer portal' );
|
||||||
|
|
|
@ -37,11 +37,12 @@ SKIP: {
|
||||||
krbByJs => 1,
|
krbByJs => 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Simple access' );
|
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Simple access' );
|
||||||
ok( $res->[2]->[0] =~ /script.*kerberos\.js/s, 'Found Kerberos JS' );
|
ok( $res->[2]->[0] =~ /script.*kerberos\.js/s, 'Found Kerberos JS' );
|
||||||
my ( $host, $url, $query ) = expectForm( $res, '#');
|
my ( $host, $url, $query ) = expectForm( $res, '#' );
|
||||||
# TODO
|
|
||||||
|
# TODO
|
||||||
}
|
}
|
||||||
count($maintests);
|
count($maintests);
|
||||||
clean_sessions();
|
clean_sessions();
|
||||||
|
|
|
@ -83,7 +83,7 @@ SKIP: {
|
||||||
$pwd = $2;
|
$pwd = $2;
|
||||||
ok( $user eq 'fbar', 'Get good login' );
|
ok( $user eq 'fbar', 'Get good login' );
|
||||||
|
|
||||||
my $postString = 'user='.$user.'&password='.$pwd;
|
my $postString = 'user=' . $user . '&password=' . $pwd;
|
||||||
ok(
|
ok(
|
||||||
$res = $client->_post(
|
$res = $client->_post(
|
||||||
'/', IO::String->new($postString),
|
'/', IO::String->new($postString),
|
||||||
|
|
|
@ -34,10 +34,10 @@ SKIP: {
|
||||||
authentication => 'LDAP',
|
authentication => 'LDAP',
|
||||||
userDB => 'Same',
|
userDB => 'Same',
|
||||||
passwordDB => 'LDAP',
|
passwordDB => 'LDAP',
|
||||||
ldapServer => 'ldap://127.0.0.1:19389/',
|
ldapServer => 'ldap://127.0.0.1:19389/',
|
||||||
ldapBase => 'ou=users,dc=example,dc=com',
|
ldapBase => 'ou=users,dc=example,dc=com',
|
||||||
managerDn => 'cn=admin,dc=example,dc=com',
|
managerDn => 'cn=admin,dc=example,dc=com',
|
||||||
managerPassword => 'admin',
|
managerPassword => 'admin',
|
||||||
captcha_mail_enabled => 0,
|
captcha_mail_enabled => 0,
|
||||||
portalDisplayResetPassword => 1,
|
portalDisplayResetPassword => 1,
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ require './lemonldap-ng-manager/lib/Lemonldap/NG/Manager/Build/Attributes.pm';
|
||||||
require './lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/ReConstants.pm';
|
require './lemonldap-ng-common/lib/Lemonldap/NG/Common/Conf/ReConstants.pm';
|
||||||
|
|
||||||
my $rmg =
|
my $rmg =
|
||||||
"^(?:(?:$Lemonldap::NG::Common::Conf::ReConstants::virtualHostKeys)|(?:$Lemonldap::NG::Common::Conf::ReConstants::casAppMetaDataNodeKeys)|(?:$Lemonldap::NG::Common::Conf::ReConstants::casSrvMetaDataNodeKeys)|(?:$Lemonldap::NG::Common::Conf::ReConstants::oidcOPMetaDataNodeKeys)|(?:$Lemonldap::NG::Common::Conf::ReConstants::oidcRPMetaDataNodeKeys)|(?:$Lemonldap::NG::Common::Conf::ReConstants::samlIDPMetaDataNodeKeys)|(?:$Lemonldap::NG::Common::Conf::ReConstants::samlSPMetaDataNodeKeys)|(?:$Lemonldap::NG::Common::Conf::ReConstants::specialNodeKeys)|(.*Options))\$";
|
"^(?:(?:$Lemonldap::NG::Common::Conf::ReConstants::virtualHostKeys)|(?:$Lemonldap::NG::Common::Conf::ReConstants::casAppMetaDataNodeKeys)|(?:$Lemonldap::NG::Common::Conf::ReConstants::casSrvMetaDataNodeKeys)|(?:$Lemonldap::NG::Common::Conf::ReConstants::oidcOPMetaDataNodeKeys)|(?:$Lemonldap::NG::Common::Conf::ReConstants::oidcRPMetaDataNodeKeys)|(?:$Lemonldap::NG::Common::Conf::ReConstants::samlIDPMetaDataNodeKeys)|(?:$Lemonldap::NG::Common::Conf::ReConstants::samlSPMetaDataNodeKeys)|(?:$Lemonldap::NG::Common::Conf::ReConstants::specialNodeKeys))\$";
|
||||||
$rmg = qr/$rmg/;
|
$rmg = qr/$rmg/;
|
||||||
|
|
||||||
my $ignore = qr/^(?:virtualHosts)$/;
|
my $ignore = qr/^(?:virtualHosts)$/;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user