Merge branch 'v2.0'
This commit is contained in:
commit
3f7ae26d49
6
COPYING
6
COPYING
|
@ -115,6 +115,12 @@ License: CC-3
|
||||||
Comment: This work, "star1.png", is a derivative of
|
Comment: This work, "star1.png", is a derivative of
|
||||||
"Golden star with red border.png" by ANGELUS, under CC-BYSA-3.0.
|
"Golden star with red border.png" by ANGELUS, under CC-BYSA-3.0.
|
||||||
|
|
||||||
|
Files: lemonldap-ng-portal/site/htdocs/static/common/icons/decryptValue.png
|
||||||
|
Copyright: Christophe Maudoux <chrmdx@gmail.com>
|
||||||
|
License: CC-3
|
||||||
|
Comment: This work, "decryptValue.png", is a derivative of
|
||||||
|
"secure.png" by Austin Condiff, under CC-BY-3.0.
|
||||||
|
|
||||||
Files: lemonldap-ng-portal/site/htdocs/static/common/icons/switchcontext_OFF.png
|
Files: lemonldap-ng-portal/site/htdocs/static/common/icons/switchcontext_OFF.png
|
||||||
Copyright: Christophe Maudoux <chrmdx@gmail.com>
|
Copyright: Christophe Maudoux <chrmdx@gmail.com>
|
||||||
License: CC-4
|
License: CC-4
|
||||||
|
|
|
@ -62,12 +62,12 @@ sub retrieveSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
## @rmethod protected boolean createSession(id)
|
## @rmethod protected boolean createSession(id)
|
||||||
# Ask portal to create it through a SOAP request
|
# Send a create session request to the Portal
|
||||||
# @return true if the session is created, else false
|
# @return true if the session is created, else false
|
||||||
sub createSession {
|
sub createSession {
|
||||||
my ( $class, $req, $id ) = @_;
|
my ( $class, $req, $id ) = @_;
|
||||||
|
|
||||||
# Add client IP as X-Forwarded-For IP in SOAP request
|
# Add client IP as X-Forwarded-For IP in request
|
||||||
my $xheader = $req->env->{'HTTP_X_FORWARDED_FOR'};
|
my $xheader = $req->env->{'HTTP_X_FORWARDED_FOR'};
|
||||||
$xheader .= ", " if ($xheader);
|
$xheader .= ", " if ($xheader);
|
||||||
$xheader .= $req->{env}->{REMOTE_ADDR};
|
$xheader .= $req->{env}->{REMOTE_ADDR};
|
||||||
|
@ -149,7 +149,7 @@ sub hideCookie {
|
||||||
# else redirect him to the portal to display some message defined by $arg
|
# else redirect him to the portal to display some message defined by $arg
|
||||||
# @param $url Url requested
|
# @param $url Url requested
|
||||||
# @param $arg optionnal GET parameters
|
# @param $arg optionnal GET parameters
|
||||||
# @return Apache2::Const::REDIRECT or Apache2::Const::AUTH_REQUIRED
|
# @return AUTH_REDIRECT or AUTH_REQUIRED constant
|
||||||
sub goToPortal {
|
sub goToPortal {
|
||||||
my ( $class, $req, $url, $arg ) = @_;
|
my ( $class, $req, $url, $arg ) = @_;
|
||||||
if ($arg) {
|
if ($arg) {
|
||||||
|
@ -171,7 +171,6 @@ sub ua {
|
||||||
lwpSslOpts => $class->tsv->{lwpSslOpts}
|
lwpSslOpts => $class->tsv->{lwpSslOpts}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return $_ua;
|
return $_ua;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ sub fetchId {
|
||||||
my ( $t, $_session_id, @vhosts ) = split /:/, $s;
|
my ( $t, $_session_id, @vhosts ) = split /:/, $s;
|
||||||
|
|
||||||
# Looking for service headers
|
# Looking for service headers
|
||||||
my $vh = $class->resolveAlias($req);
|
my $vhost = $class->resolveAlias($req);
|
||||||
my %serviceHeaders;
|
my %serviceHeaders;
|
||||||
@vhosts = grep {
|
@vhosts = grep {
|
||||||
if (/^([\w\-]+)=(.+)$/) {
|
if (/^([\w\-]+)=(.+)$/) {
|
||||||
|
@ -32,27 +32,31 @@ sub fetchId {
|
||||||
# $_session_id and at least one vhost
|
# $_session_id and at least one vhost
|
||||||
unless ( @vhosts and $_session_id ) {
|
unless ( @vhosts and $_session_id ) {
|
||||||
$class->userLogger->error('Bad service token');
|
$class->userLogger->error('Bad service token');
|
||||||
|
$class->logger->debug(
|
||||||
|
@vhosts ? 'No _session_id found' : 'No VH found' );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Is vhost listed in token ?
|
# Is vhost listed in token ?
|
||||||
unless ( grep { $_ eq $vh } @vhosts ) {
|
unless ( grep { $_ eq $vhost } @vhosts ) {
|
||||||
$class->userLogger->error(
|
$class->userLogger->error(
|
||||||
"$vh not authorized in token (" . join( ', ', @vhosts ) . ')' );
|
"$vhost not authorized in token (" . join( ', ', @vhosts ) . ')' );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Is token in good interval ?
|
# Is token in good interval ?
|
||||||
my $localConfig = $class->localConfig;
|
my $ttl = $class->localConfig->{vhostOptions}->{$vhost}->{vhostServiceTokenTTL}
|
||||||
my $ttl =
|
|| $class->tsv->{serviceTokenTTL}->{$vhost};
|
||||||
$localConfig->{vhostOptions}->{$vh}->{vhostServiceTokenTTL} <= 0
|
$ttl = $class->tsv->{handlerServiceTokenTTL} unless ( $ttl and $ttl > 0 );
|
||||||
? $class->tsv->{handlerServiceTokenTTL}
|
my $now = time;
|
||||||
: $localConfig->{vhostOptions}->{$vh}->{vhostServiceTokenTTL};
|
unless ( $t <= $now and $t > $now - $ttl ) {
|
||||||
unless ( $t <= time and $t > time - $ttl ) {
|
|
||||||
$class->userLogger->warn('Expired service token');
|
$class->userLogger->warn('Expired service token');
|
||||||
|
$class->logger->debug("VH: $vhost with ServiceTokenTTL: $ttl");
|
||||||
|
$class->logger->debug("TokenTime: $t / Time: $now");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Send service headers if exist
|
||||||
if (%serviceHeaders) {
|
if (%serviceHeaders) {
|
||||||
$class->logger->debug("Append service header(s)...");
|
$class->logger->debug("Append service header(s)...");
|
||||||
$class->set_header_out( $req, %serviceHeaders );
|
$class->set_header_out( $req, %serviceHeaders );
|
||||||
|
|
|
@ -231,6 +231,8 @@ sub defaultValuesInit {
|
||||||
$conf->{vhostOptions}->{$vhost}->{vhostType};
|
$conf->{vhostOptions}->{$vhost}->{vhostType};
|
||||||
$class->tsv->{authnLevel}->{$vhost} =
|
$class->tsv->{authnLevel}->{$vhost} =
|
||||||
$conf->{vhostOptions}->{$vhost}->{vhostAuthnLevel};
|
$conf->{vhostOptions}->{$vhost}->{vhostAuthnLevel};
|
||||||
|
$class->tsv->{serviceTokenTTL}->{$vhost} =
|
||||||
|
$conf->{vhostOptions}->{$vhost}->{vhostServiceTokenTTL};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -97,10 +97,10 @@ sub checkType {
|
||||||
|
|
||||||
## @rmethod int run
|
## @rmethod int run
|
||||||
# Check configuration and launch Lemonldap::NG::Handler::Main::run().
|
# Check configuration and launch Lemonldap::NG::Handler::Main::run().
|
||||||
# Each $checkTime, the Apache child verify if its configuration is the same
|
# Each $checkTime, server child verifies if its configuration is the same
|
||||||
# as the configuration stored in the local storage.
|
# as the configuration stored in the local storage.
|
||||||
# @param $rule optional Perl expression to grant access
|
# @param $rule optional Perl expression to grant access
|
||||||
# @return Apache constant
|
# @return constant
|
||||||
|
|
||||||
sub run {
|
sub run {
|
||||||
my ( $class, $req, $rule, $protection ) = @_;
|
my ( $class, $req, $rule, $protection ) = @_;
|
||||||
|
@ -121,11 +121,10 @@ sub run {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# Cross domain authentication
|
# Authentication process
|
||||||
my $uri = $req->{env}->{REQUEST_URI};
|
my $uri = $req->{env}->{REQUEST_URI};
|
||||||
|
|
||||||
$uri = $req->{env}->{REQUEST_URI};
|
|
||||||
my ($cond);
|
my ($cond);
|
||||||
|
|
||||||
( $cond, $protection ) = $class->conditionSub($rule) if ($rule);
|
( $cond, $protection ) = $class->conditionSub($rule) if ($rule);
|
||||||
$protection = $class->isUnprotected( $req, $uri ) || 0
|
$protection = $class->isUnprotected( $req, $uri ) || 0
|
||||||
unless ( defined $protection );
|
unless ( defined $protection );
|
||||||
|
@ -273,6 +272,12 @@ sub grant {
|
||||||
$vhost ||= $class->resolveAlias($req);
|
$vhost ||= $class->resolveAlias($req);
|
||||||
if ( my $level = $class->tsv->{authnLevel}->{$vhost} ) {
|
if ( my $level = $class->tsv->{authnLevel}->{$vhost} ) {
|
||||||
if ( $session->{authenticationLevel} < $level ) {
|
if ( $session->{authenticationLevel} < $level ) {
|
||||||
|
$class->logger->debug(
|
||||||
|
"User authentication level = $session->{authenticationLevel}");
|
||||||
|
$class->logger->debug("Required authentication level = $level");
|
||||||
|
$class->logger->warn(
|
||||||
|
"User rejected due to insufficient authentication level -> Session upgrade enabled"
|
||||||
|
);
|
||||||
$session->{_upgrade} = 1;
|
$session->{_upgrade} = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -415,7 +420,7 @@ sub fetchId {
|
||||||
my $value =
|
my $value =
|
||||||
$lookForHttpCookie
|
$lookForHttpCookie
|
||||||
? ( $t =~ /${cn}http=([^,; ]+)/o ? $1 : 0 )
|
? ( $t =~ /${cn}http=([^,; ]+)/o ? $1 : 0 )
|
||||||
: ( $t =~ /$cn=([^,; ]+)/o ? $1 : 0 );
|
: ( $t =~ /$cn=([^,; ]+)/o ? $1 : 0 );
|
||||||
|
|
||||||
if ( $value && $lookForHttpCookie && $class->tsv->{securedCookie} == 3 ) {
|
if ( $value && $lookForHttpCookie && $class->tsv->{securedCookie} == 3 ) {
|
||||||
$value = $class->tsv->{cipher}->decryptHex( $value, "http" );
|
$value = $class->tsv->{cipher}->decryptHex( $value, "http" );
|
||||||
|
|
|
@ -166,7 +166,7 @@ ok( @headers == 0, 'NONE service header found' )
|
||||||
or print STDERR Data::Dumper::Dumper( $res->[1] );
|
or print STDERR Data::Dumper::Dumper( $res->[1] );
|
||||||
count(1);
|
count(1);
|
||||||
|
|
||||||
$token = $crypt->encrypt( join ':', time, $sessionId, '' );
|
$token = $crypt->encrypt( join ':', time, $sessionId );
|
||||||
ok(
|
ok(
|
||||||
$res = $client->_get(
|
$res = $client->_get(
|
||||||
'/', undef, 'test2.example.com', undef,
|
'/', undef, 'test2.example.com', undef,
|
||||||
|
|
|
@ -1139,6 +1139,11 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
|
||||||
'dbiUserUser' => {
|
'dbiUserUser' => {
|
||||||
'type' => 'text'
|
'type' => 'text'
|
||||||
},
|
},
|
||||||
|
'decryptValueFunctions' => {
|
||||||
|
'msgFail' => '__badCustomFuncName__',
|
||||||
|
'test' => qr/^(?:\w+(?:::\w+)*(?:\s+\w+(?:::\w+)*)*)?$/,
|
||||||
|
'type' => 'text'
|
||||||
|
},
|
||||||
'decryptValueRule' => {
|
'decryptValueRule' => {
|
||||||
'default' => 0,
|
'default' => 0,
|
||||||
'type' => 'boolOrExpr'
|
'type' => 'boolOrExpr'
|
||||||
|
|
|
@ -540,6 +540,13 @@ sub attributes {
|
||||||
documentation => 'Decrypt value activation rule',
|
documentation => 'Decrypt value activation rule',
|
||||||
flags => 'p',
|
flags => 'p',
|
||||||
},
|
},
|
||||||
|
decryptValueFunctions => {
|
||||||
|
type => 'text',
|
||||||
|
test => qr/^(?:\w+(?:::\w+)*(?:\s+\w+(?:::\w+)*)*)?$/,
|
||||||
|
msgFail => "__badCustomFuncName__",
|
||||||
|
documentation => 'Custom function used for decrypting values',
|
||||||
|
flags => 'p',
|
||||||
|
},
|
||||||
skipRenewConfirmation => {
|
skipRenewConfirmation => {
|
||||||
type => 'bool',
|
type => 'bool',
|
||||||
default => 0,
|
default => 0,
|
||||||
|
|
|
@ -755,10 +755,11 @@ sub tree {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title => 'decryptValue',
|
title => 'decryptValue',
|
||||||
help => 'decryptValueRule.html',
|
help => 'decryptvalue.html',
|
||||||
form => 'simpleInputContainer',
|
form => 'simpleInputContainer',
|
||||||
nodes => [
|
nodes => [
|
||||||
'decryptValueRule',
|
'decryptValueRule',
|
||||||
|
'decryptValueFunctions',
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
|
@ -246,6 +246,7 @@
|
||||||
"dbiSchema":"مخطط",
|
"dbiSchema":"مخطط",
|
||||||
"dbiUserTable":"جدول المستخدم",
|
"dbiUserTable":"جدول المستخدم",
|
||||||
"decryptValue":"Decrypt value",
|
"decryptValue":"Decrypt value",
|
||||||
|
"decryptValueFunctions":"Decrypt functions",
|
||||||
"decryptValueRule":"Use rule",
|
"decryptValueRule":"Use rule",
|
||||||
"default":"الاعْتيادي",
|
"default":"الاعْتيادي",
|
||||||
"defaultRule":"القاعدة الاعتيادية ",
|
"defaultRule":"القاعدة الاعتيادية ",
|
||||||
|
|
|
@ -245,6 +245,7 @@
|
||||||
"dbiSchema":"Schema",
|
"dbiSchema":"Schema",
|
||||||
"dbiUserTable":"User table",
|
"dbiUserTable":"User table",
|
||||||
"decryptValue":"Decrypt value",
|
"decryptValue":"Decrypt value",
|
||||||
|
"decryptValueFunctions":"Decrypt functions",
|
||||||
"decryptValueRule":"Use rule",
|
"decryptValueRule":"Use rule",
|
||||||
"default":"Default",
|
"default":"Default",
|
||||||
"defaultRule":"Default rule",
|
"defaultRule":"Default rule",
|
||||||
|
|
|
@ -245,6 +245,7 @@
|
||||||
"dbiSchema":"Schema",
|
"dbiSchema":"Schema",
|
||||||
"dbiUserTable":"User table",
|
"dbiUserTable":"User table",
|
||||||
"decryptValue":"Decrypt value",
|
"decryptValue":"Decrypt value",
|
||||||
|
"decryptValueFunctions":"Decrypt functions",
|
||||||
"decryptValueRule":"Use rule",
|
"decryptValueRule":"Use rule",
|
||||||
"default":"Default",
|
"default":"Default",
|
||||||
"defaultRule":"Default rule",
|
"defaultRule":"Default rule",
|
||||||
|
|
|
@ -245,6 +245,7 @@
|
||||||
"dbiSchema":"Schéma",
|
"dbiSchema":"Schéma",
|
||||||
"dbiUserTable":"Table des utilisateurs",
|
"dbiUserTable":"Table des utilisateurs",
|
||||||
"decryptValue":"Déchiffrement",
|
"decryptValue":"Déchiffrement",
|
||||||
|
"decryptValueFunctions":"Fonctions de déchiffrement",
|
||||||
"decryptValueRule":"Règle d'utilisation",
|
"decryptValueRule":"Règle d'utilisation",
|
||||||
"default":"Défaut",
|
"default":"Défaut",
|
||||||
"defaultRule":"Règle par défaut",
|
"defaultRule":"Règle par défaut",
|
||||||
|
|
|
@ -245,6 +245,7 @@
|
||||||
"dbiSchema":"Schema",
|
"dbiSchema":"Schema",
|
||||||
"dbiUserTable":"Tabella utente",
|
"dbiUserTable":"Tabella utente",
|
||||||
"decryptValue":"Decrypt value",
|
"decryptValue":"Decrypt value",
|
||||||
|
"decryptValueFunctions":"Decrypt functions",
|
||||||
"decryptValueRule":"Use rule",
|
"decryptValueRule":"Use rule",
|
||||||
"default":"Predefinito",
|
"default":"Predefinito",
|
||||||
"defaultRule":"Regola predefinita",
|
"defaultRule":"Regola predefinita",
|
||||||
|
|
|
@ -245,6 +245,7 @@
|
||||||
"dbiSchema":"Giản đồ",
|
"dbiSchema":"Giản đồ",
|
||||||
"dbiUserTable":"Bảng người dùng",
|
"dbiUserTable":"Bảng người dùng",
|
||||||
"decryptValue":"Decrypt value",
|
"decryptValue":"Decrypt value",
|
||||||
|
"decryptValueFunctions":"Decrypt functions",
|
||||||
"decryptValueRule":"Use rule",
|
"decryptValueRule":"Use rule",
|
||||||
"default":"Mặc định",
|
"default":"Mặc định",
|
||||||
"defaultRule":"Quy tắc mặc định",
|
"defaultRule":"Quy tắc mặc định",
|
||||||
|
|
|
@ -245,6 +245,7 @@
|
||||||
"dbiSchema":"Schema",
|
"dbiSchema":"Schema",
|
||||||
"dbiUserTable":"用户表",
|
"dbiUserTable":"用户表",
|
||||||
"decryptValue":"Decrypt value",
|
"decryptValue":"Decrypt value",
|
||||||
|
"decryptValueFunctions":"Decrypt functions",
|
||||||
"decryptValueRule":"Use rule",
|
"decryptValueRule":"Use rule",
|
||||||
"default":"默认",
|
"default":"默认",
|
||||||
"defaultRule":"默认规则",
|
"defaultRule":"默认规则",
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -266,6 +266,7 @@ site/htdocs/static/common/fr.png
|
||||||
site/htdocs/static/common/icons/application_cascade.png
|
site/htdocs/static/common/icons/application_cascade.png
|
||||||
site/htdocs/static/common/icons/arrow_refresh.png
|
site/htdocs/static/common/icons/arrow_refresh.png
|
||||||
site/htdocs/static/common/icons/calendar.png
|
site/htdocs/static/common/icons/calendar.png
|
||||||
|
site/htdocs/static/common/icons/decryptValue.png
|
||||||
site/htdocs/static/common/icons/door_out.png
|
site/htdocs/static/common/icons/door_out.png
|
||||||
site/htdocs/static/common/icons/key.png
|
site/htdocs/static/common/icons/key.png
|
||||||
site/htdocs/static/common/icons/oidc.png
|
site/htdocs/static/common/icons/oidc.png
|
||||||
|
@ -574,6 +575,8 @@ t/43-MailPasswordReset-with-token.t
|
||||||
t/43-MailPasswordReset.t
|
t/43-MailPasswordReset.t
|
||||||
t/44-CertificateResetByMail-LDAP.t
|
t/44-CertificateResetByMail-LDAP.t
|
||||||
t/50-IssuerGet.t
|
t/50-IssuerGet.t
|
||||||
|
t/58-DecryptValue-with-custom-function.t
|
||||||
|
t/58-DecryptValue-with-internal-function.t
|
||||||
t/59-Double-cookies-for-a-Single-session.t
|
t/59-Double-cookies-for-a-Single-session.t
|
||||||
t/59-Double-cookies-for-Double-sessions.t
|
t/59-Double-cookies-for-Double-sessions.t
|
||||||
t/59-Double-cookies-Refresh-and-Logout.t
|
t/59-Double-cookies-Refresh-and-Logout.t
|
||||||
|
@ -645,6 +648,7 @@ t/lib/Apache/Session/Timeout.pm
|
||||||
t/lib/Lemonldap/NG/Common/Conf/Backends/Timeout.pm
|
t/lib/Lemonldap/NG/Common/Conf/Backends/Timeout.pm
|
||||||
t/lib/Lemonldap/NG/Handler/Test.pm
|
t/lib/Lemonldap/NG/Handler/Test.pm
|
||||||
t/lib/Lemonldap/NG/Portal/Auth/LDAPPolicy.pm
|
t/lib/Lemonldap/NG/Portal/Auth/LDAPPolicy.pm
|
||||||
|
t/lib/Lemonldap/NG/Portal/Custom.pm
|
||||||
t/lmConf-1.json
|
t/lmConf-1.json
|
||||||
t/pdata.pm
|
t/pdata.pm
|
||||||
t/README.md
|
t/README.md
|
||||||
|
|
|
@ -356,7 +356,11 @@ sub reloadConf {
|
||||||
|
|
||||||
# Clean $req->pdata after authentication
|
# Clean $req->pdata after authentication
|
||||||
push @{ $self->endAuth }, sub {
|
push @{ $self->endAuth }, sub {
|
||||||
my $tmp = $_[0]->pdata->{keepPdata} //= [];
|
|
||||||
|
my $tmp =
|
||||||
|
( ref( $_[0]->pdata->{keepPdata} ) eq 'ARRAY' )
|
||||||
|
? $_[0]->pdata->{keepPdata}
|
||||||
|
: [];
|
||||||
foreach my $k ( keys %{ $_[0]->pdata } ) {
|
foreach my $k ( keys %{ $_[0]->pdata } ) {
|
||||||
unless ( grep { $_ eq $k } @$tmp ) {
|
unless ( grep { $_ eq $k } @$tmp ) {
|
||||||
$self->logger->debug("Removing $k from pdata");
|
$self->logger->debug("Removing $k from pdata");
|
||||||
|
|
|
@ -130,6 +130,15 @@ sub params {
|
||||||
$self->logger->debug("Display SwitchContext link -> $res{contextSwitching}")
|
$self->logger->debug("Display SwitchContext link -> $res{contextSwitching}")
|
||||||
if $res{contextSwitching};
|
if $res{contextSwitching};
|
||||||
|
|
||||||
|
# Display DecryptValue link if allowed
|
||||||
|
my $dvPlugin =
|
||||||
|
$self->p->loadedModules->{'Lemonldap::NG::Portal::Plugins::DecryptValue'};
|
||||||
|
$res{decryptValue} =
|
||||||
|
$dvPlugin
|
||||||
|
? $dvPlugin->displayLink( $req, $req->userData )
|
||||||
|
: '';
|
||||||
|
$self->logger->debug("Display DecryptValue link") if $res{decryptValue};
|
||||||
|
|
||||||
return %res;
|
return %res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -160,7 +160,10 @@ sub authLogout {
|
||||||
my ( $self, $req ) = @_;
|
my ( $self, $req ) = @_;
|
||||||
my $res = $self->_authentication->authLogout($req);
|
my $res = $self->_authentication->authLogout($req);
|
||||||
$self->logger->debug('Cleaning pdata');
|
$self->logger->debug('Cleaning pdata');
|
||||||
my $tmp = $req->pdata->{keepPdata} //= [];
|
my $tmp =
|
||||||
|
( ref( $req->pdata->{keepPdata} ) eq 'ARRAY' )
|
||||||
|
? $req->pdata->{keepPdata}
|
||||||
|
: [];
|
||||||
foreach my $k ( keys %{ $req->pdata } ) {
|
foreach my $k ( keys %{ $req->pdata } ) {
|
||||||
delete $req->pdata->{$k} unless ( grep { $_ eq $k } @$tmp );
|
delete $req->pdata->{$k} unless ( grep { $_ eq $k } @$tmp );
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ sub display {
|
||||||
|
|
||||||
sub run {
|
sub run {
|
||||||
my ( $self, $req ) = @_;
|
my ( $self, $req ) = @_;
|
||||||
my $msg = '';
|
my ( $msg, $decryptedValue ) = ( '', '' );
|
||||||
|
|
||||||
# Check access rules
|
# Check access rules
|
||||||
unless ( $self->rule->( $req, $req->userData ) ) {
|
unless ( $self->rule->( $req, $req->userData ) ) {
|
||||||
|
@ -121,12 +121,43 @@ sub run {
|
||||||
}
|
}
|
||||||
|
|
||||||
my $cipheredValue = $req->param('cipheredValue') || '';
|
my $cipheredValue = $req->param('cipheredValue') || '';
|
||||||
my $decryptedValue =
|
$self->logger->debug("decryptValue tried with value: $cipheredValue");
|
||||||
$self->p->HANDLER->tsv->{cipher}->decrypt($cipheredValue)
|
|
||||||
if $cipheredValue;
|
|
||||||
|
|
||||||
$self->logger->debug("decryptValue try with : $cipheredValue");
|
if ($cipheredValue) {
|
||||||
$self->logger->debug("Decrypted value = $decryptedValue") if $decryptedValue;
|
if ( $self->{conf}->{decryptValueFunctions}
|
||||||
|
and $self->{conf}->{decryptValueFunctions} =~
|
||||||
|
qr/^(?:\w+(?:::\w+)*(?:\s+\w+(?:::\w+)*)*)?$/ )
|
||||||
|
{
|
||||||
|
foreach ( split( /\s+/, $self->{conf}->{decryptValueFunctions} ) ) {
|
||||||
|
$self->userLogger->notice(
|
||||||
|
"Try to decrypt value with function: $_");
|
||||||
|
/^([\w:{2}]*?)(?:::)?(?:\w+)$/;
|
||||||
|
eval "require Lemonldap::NG::Portal::$1";
|
||||||
|
$self->logger->debug("Unable to load decrypt module: $@")
|
||||||
|
if ($@);
|
||||||
|
$decryptedValue = eval "$_" . '($cipheredValue)' unless ($@);
|
||||||
|
$self->logger->debug(
|
||||||
|
$@
|
||||||
|
? "Unable to eval decrypt function: $@"
|
||||||
|
: "Decrypted value = $decryptedValue"
|
||||||
|
);
|
||||||
|
last if $decryptedValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$self->userLogger->notice("Malformed decrypt functions")
|
||||||
|
if $self->{conf}->{decryptValueFunctions};
|
||||||
|
$self->userLogger->notice(
|
||||||
|
"Try to decrypt value with internal LL::NG decrypt function");
|
||||||
|
$decryptedValue =
|
||||||
|
$self->p->HANDLER->tsv->{cipher}->decrypt($cipheredValue);
|
||||||
|
$self->logger->debug(
|
||||||
|
$@
|
||||||
|
? "Unable to decrypt value: $@"
|
||||||
|
: "Decrypted value = $decryptedValue"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Display form
|
# Display form
|
||||||
my $params = {
|
my $params = {
|
||||||
|
@ -155,4 +186,9 @@ sub run {
|
||||||
return $self->p->sendHtml( $req, 'decryptvalue', params => $params );
|
return $self->p->sendHtml( $req, 'decryptvalue', params => $params );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub displayLink {
|
||||||
|
my ( $self, $req ) = @_;
|
||||||
|
return $self->rule->( $req, $req->userData );
|
||||||
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 693 B |
|
@ -74,10 +74,16 @@
|
||||||
</TMPL_IF>
|
</TMPL_IF>
|
||||||
<TMPL_IF NAME="contextSwitching">
|
<TMPL_IF NAME="contextSwitching">
|
||||||
<li class="dropdown-item"><a href="/switchcontext" class="nav-link">
|
<li class="dropdown-item"><a href="/switchcontext" class="nav-link">
|
||||||
<img src="<TMPL_VAR NAME="STATIC_PREFIX">common/icons/switchcontext_<TMPL_VAR NAME="contextSwitching">.png" width="20" height="20" alt="refresh" />
|
<img src="<TMPL_VAR NAME="STATIC_PREFIX">common/icons/switchcontext_<TMPL_VAR NAME="contextSwitching">.png" width="20" height="20" alt="switchContext" />
|
||||||
<span trspan="contextSwitching_<TMPL_VAR NAME="contextSwitching">">contextSwitching_<TMPL_VAR NAME="contextSwitching"></span>
|
<span trspan="contextSwitching_<TMPL_VAR NAME="contextSwitching">">contextSwitching_<TMPL_VAR NAME="contextSwitching"></span>
|
||||||
</a></li>
|
</a></li>
|
||||||
</TMPL_IF>
|
</TMPL_IF>
|
||||||
|
<TMPL_IF NAME="decryptValue">
|
||||||
|
<li class="dropdown-item"><a href="/decryptvalue" class="nav-link">
|
||||||
|
<img src="<TMPL_VAR NAME="STATIC_PREFIX">common/icons/decryptValue.png" width="20" height="20" alt="decryptValue" />
|
||||||
|
<span trspan="decryptCipheredValue">decryptCipheredValue</span>
|
||||||
|
</a></li>
|
||||||
|
</TMPL_IF>
|
||||||
<li class="dropdown-item"><a href="/refresh" class="nav-link">
|
<li class="dropdown-item"><a href="/refresh" class="nav-link">
|
||||||
<img src="<TMPL_VAR NAME="STATIC_PREFIX">common/icons/arrow_refresh.png" width="16" height="16" alt="refresh" />
|
<img src="<TMPL_VAR NAME="STATIC_PREFIX">common/icons/arrow_refresh.png" width="16" height="16" alt="refresh" />
|
||||||
<span trspan="refreshrights">Refresh</span>
|
<span trspan="refreshrights">Refresh</span>
|
||||||
|
|
97
lemonldap-ng-portal/t/58-DecryptValue-with-custom-function.t
Normal file
97
lemonldap-ng-portal/t/58-DecryptValue-with-custom-function.t
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
use Test::More;
|
||||||
|
use strict;
|
||||||
|
use IO::String;
|
||||||
|
use lib 't/lib';
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
require 't/test-lib.pm';
|
||||||
|
}
|
||||||
|
|
||||||
|
my $res;
|
||||||
|
|
||||||
|
my $client = LLNG::Manager::Test->new( {
|
||||||
|
ini => {
|
||||||
|
logLevel => 'error',
|
||||||
|
authentication => 'Demo',
|
||||||
|
userDB => 'Same',
|
||||||
|
loginHistoryEnabled => 0,
|
||||||
|
brutForceProtection => 0,
|
||||||
|
requireToken => 0,
|
||||||
|
decryptValueRule => 1,
|
||||||
|
decryptValueFunctions =>
|
||||||
|
'Custom::empty Custom::test_uc Custom::undefined',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
## Try to authenticate
|
||||||
|
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', );
|
||||||
|
count(1);
|
||||||
|
my ( $host, $url, $query ) = expectForm( $res, '#', undef, 'user', 'password' );
|
||||||
|
|
||||||
|
$query = 'user=dwho&password=dwho';
|
||||||
|
ok(
|
||||||
|
$res = $client->_post(
|
||||||
|
'/',
|
||||||
|
IO::String->new($query),
|
||||||
|
length => length($query),
|
||||||
|
accept => 'text/html',
|
||||||
|
),
|
||||||
|
'Auth query'
|
||||||
|
);
|
||||||
|
|
||||||
|
my $id = expectCookie($res);
|
||||||
|
expectRedirection( $res, 'http://auth.example.com/' );
|
||||||
|
ok(
|
||||||
|
$res = $client->_get(
|
||||||
|
'/',
|
||||||
|
cookie => "lemonldap=$id",
|
||||||
|
accept => 'text/html'
|
||||||
|
),
|
||||||
|
'CheckUser form',
|
||||||
|
);
|
||||||
|
ok( $res->[2]->[0] =~ m%<img src="/static/common/icons/decryptValue\.png"%,
|
||||||
|
'Found decryptValue.png' )
|
||||||
|
or explain( $res->[2]->[0], 'decryptValue.png' );
|
||||||
|
count(3);
|
||||||
|
|
||||||
|
# DecryptValue form
|
||||||
|
# ------------------------
|
||||||
|
ok(
|
||||||
|
$res = $client->_get(
|
||||||
|
'/decryptvalue',
|
||||||
|
cookie => "lemonldap=$id",
|
||||||
|
accept => 'text/html'
|
||||||
|
),
|
||||||
|
'DecryptValue form',
|
||||||
|
);
|
||||||
|
( $host, $url, $query ) =
|
||||||
|
expectForm( $res, undef, '/decryptvalue', 'cipheredValue' );
|
||||||
|
ok( $res->[2]->[0] =~ m%<span trspan="decryptCipheredValue">%,
|
||||||
|
'Found trspan="decryptCipheredValue"' )
|
||||||
|
or explain( $res->[2]->[0], 'trspan="decryptCipheredValue"' );
|
||||||
|
count(2);
|
||||||
|
|
||||||
|
# Decrypt ciphered value
|
||||||
|
$query =~
|
||||||
|
s%cipheredValue=%cipheredValue=lowercase%;
|
||||||
|
ok(
|
||||||
|
$res = $client->_post(
|
||||||
|
'/decryptvalue',
|
||||||
|
IO::String->new($query),
|
||||||
|
cookie => "lemonldap=$id",
|
||||||
|
length => length($query),
|
||||||
|
accept => 'text/html',
|
||||||
|
),
|
||||||
|
'POST decryptvalue with valid value'
|
||||||
|
);
|
||||||
|
ok( $res->[2]->[0] =~ m%<span trspan="LOWERCASE"></span>%, 'Found decryted value' )
|
||||||
|
or explain( $res->[2]->[0], 'Decryted value NOT found' );
|
||||||
|
count(2);
|
||||||
|
( $host, $url, $query ) =
|
||||||
|
expectForm( $res, undef, '/decryptvalue', 'cipheredValue' );
|
||||||
|
|
||||||
|
$client->logout($id);
|
||||||
|
clean_sessions();
|
||||||
|
|
||||||
|
done_testing( count() );
|
153
lemonldap-ng-portal/t/58-DecryptValue-with-internal-function.t
Normal file
153
lemonldap-ng-portal/t/58-DecryptValue-with-internal-function.t
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
use Test::More;
|
||||||
|
use strict;
|
||||||
|
use IO::String;
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
require 't/test-lib.pm';
|
||||||
|
}
|
||||||
|
|
||||||
|
my $res;
|
||||||
|
|
||||||
|
my $client = LLNG::Manager::Test->new( {
|
||||||
|
ini => {
|
||||||
|
logLevel => 'error',
|
||||||
|
authentication => 'Demo',
|
||||||
|
userDB => 'Same',
|
||||||
|
loginHistoryEnabled => 0,
|
||||||
|
brutForceProtection => 0,
|
||||||
|
decryptValueRule => '$uid eq "dwho"',
|
||||||
|
requireToken => 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
## Try to authenticate
|
||||||
|
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', );
|
||||||
|
count(1);
|
||||||
|
my ( $host, $url, $query ) =
|
||||||
|
expectForm( $res, '#', undef, 'user', 'password', 'token' );
|
||||||
|
|
||||||
|
$query =~ s/user=/user=rtyler/;
|
||||||
|
$query =~ s/password=/password=rtyler/;
|
||||||
|
ok(
|
||||||
|
$res = $client->_post(
|
||||||
|
'/',
|
||||||
|
IO::String->new($query),
|
||||||
|
length => length($query),
|
||||||
|
accept => 'text/html',
|
||||||
|
),
|
||||||
|
'Auth query'
|
||||||
|
);
|
||||||
|
count(1);
|
||||||
|
|
||||||
|
my $id = expectCookie($res);
|
||||||
|
expectRedirection( $res, 'http://auth.example.com/' );
|
||||||
|
|
||||||
|
# DecryptValue form for a foridden user
|
||||||
|
# ------------------------
|
||||||
|
ok(
|
||||||
|
$res = $client->_get(
|
||||||
|
'/decryptvalue',
|
||||||
|
cookie => "lemonldap=$id",
|
||||||
|
accept => 'text/html'
|
||||||
|
),
|
||||||
|
'Try DecryptValue form for a forbidden user',
|
||||||
|
);
|
||||||
|
count(1);
|
||||||
|
ok( $res->[2]->[0] =~ m%<span trmsg="95">%, 'Found trmsg="95"' )
|
||||||
|
or explain( $res->[2]->[0], 'trmsg="95"' );
|
||||||
|
count(1);
|
||||||
|
$client->logout($id);
|
||||||
|
|
||||||
|
## Try to authenticate
|
||||||
|
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', );
|
||||||
|
count(1);
|
||||||
|
( $host, $url, $query ) =
|
||||||
|
expectForm( $res, '#', undef, 'user', 'password', 'token' );
|
||||||
|
|
||||||
|
$query =~ s/user=/user=dwho/;
|
||||||
|
$query =~ s/password=/password=dwho/;
|
||||||
|
ok(
|
||||||
|
$res = $client->_post(
|
||||||
|
'/',
|
||||||
|
IO::String->new($query),
|
||||||
|
length => length($query),
|
||||||
|
accept => 'text/html',
|
||||||
|
),
|
||||||
|
'Auth query'
|
||||||
|
);
|
||||||
|
|
||||||
|
$id = expectCookie($res);
|
||||||
|
expectRedirection( $res, 'http://auth.example.com/' );
|
||||||
|
ok(
|
||||||
|
$res = $client->_get(
|
||||||
|
'/',
|
||||||
|
cookie => "lemonldap=$id",
|
||||||
|
accept => 'text/html'
|
||||||
|
),
|
||||||
|
'CheckUser form',
|
||||||
|
);
|
||||||
|
ok( $res->[2]->[0] =~ m%<img src="/static/common/icons/decryptValue\.png"%,
|
||||||
|
'Found decryptValue.png' )
|
||||||
|
or explain( $res->[2]->[0], 'decryptValue.png' );
|
||||||
|
count(3);
|
||||||
|
|
||||||
|
# DecryptValue form
|
||||||
|
# ------------------------
|
||||||
|
ok(
|
||||||
|
$res = $client->_get(
|
||||||
|
'/decryptvalue',
|
||||||
|
cookie => "lemonldap=$id",
|
||||||
|
accept => 'text/html'
|
||||||
|
),
|
||||||
|
'DecryptValue form',
|
||||||
|
);
|
||||||
|
( $host, $url, $query ) =
|
||||||
|
expectForm( $res, undef, '/decryptvalue', 'cipheredValue', 'token' );
|
||||||
|
ok( $res->[2]->[0] =~ m%<span trspan="decryptCipheredValue">%,
|
||||||
|
'Found trspan="decryptCipheredValue"' )
|
||||||
|
or explain( $res->[2]->[0], 'trspan="decryptCipheredValue"' );
|
||||||
|
count(2);
|
||||||
|
|
||||||
|
# Valid ciphered value
|
||||||
|
$query =~
|
||||||
|
s%cipheredValue=%cipheredValue=CNCERR4E3BPrrEY0BZGnl3ISfUZARKXNhnDj3x7/xO5kxodXbeLzTk2VSHh1rq/C4TU78wzyWiove81YseYj/g==%;
|
||||||
|
ok(
|
||||||
|
$res = $client->_post(
|
||||||
|
'/decryptvalue',
|
||||||
|
IO::String->new($query),
|
||||||
|
cookie => "lemonldap=$id",
|
||||||
|
length => length($query),
|
||||||
|
accept => 'text/html',
|
||||||
|
),
|
||||||
|
'POST decryptvalue with valid value'
|
||||||
|
);
|
||||||
|
ok( $res->[2]->[0] =~ m%<span trspan="dwho"></span>%, 'Found decryted value' )
|
||||||
|
or explain( $res->[2]->[0], 'Decryted value NOT found' );
|
||||||
|
count(2);
|
||||||
|
( $host, $url, $query ) =
|
||||||
|
expectForm( $res, undef, '/decryptvalue', 'cipheredValue', 'token' );
|
||||||
|
|
||||||
|
# Unvalid ciphered value
|
||||||
|
$query =~ s%cipheredValue=%cipheredValue=test%;
|
||||||
|
ok(
|
||||||
|
$res = $client->_post(
|
||||||
|
'/decryptvalue',
|
||||||
|
IO::String->new($query),
|
||||||
|
cookie => "lemonldap=$id",
|
||||||
|
length => length($query),
|
||||||
|
accept => 'text/html',
|
||||||
|
),
|
||||||
|
'POST decryptvalue with unvalid value'
|
||||||
|
);
|
||||||
|
ok( $res->[2]->[0] =~ m%<span trspan="notAnEncryptedValue">%,
|
||||||
|
'Found trspan="notAnEncryptedValue"' )
|
||||||
|
or explain( $res->[2]->[0], 'trspan="notAnEncryptedValue"' );
|
||||||
|
count(2);
|
||||||
|
( $host, $url, $query ) =
|
||||||
|
expectForm( $res, undef, '/decryptvalue', 'cipheredValue', 'token' );
|
||||||
|
|
||||||
|
$client->logout($id);
|
||||||
|
clean_sessions();
|
||||||
|
|
||||||
|
done_testing( count() );
|
15
lemonldap-ng-portal/t/lib/Lemonldap/NG/Portal/Custom.pm
Normal file
15
lemonldap-ng-portal/t/lib/Lemonldap/NG/Portal/Custom.pm
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package Custom;
|
||||||
|
|
||||||
|
sub empty {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub undefined {
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub test_uc {
|
||||||
|
return uc $_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
Loading…
Reference in New Issue
Block a user