...
 
Commits (50)
## map directive must be in http context
# Uncomment this if you use Auth SSL:
#map $ssl_client_s_dn $ssl_client_s_dn_cn {
# default "";
# ~/CN=(?<CN>[^/]+) $CN;
#}
server {
listen __PORT__;
server_name auth.__DNSDOMAIN__;
......@@ -29,11 +36,7 @@ server {
fastcgi_split_path_info ^(.*\.psgi)(/.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
# Uncomment this if you use Auth SSL:
#map $ssl_client_s_dn $ssl_client_s_dn_cn {
# default "";
# ~/CN=(?<CN>[^/]+) $CN;
#}
#fastcgi_param SSL_CLIENT_S_DN_CN $ssl_client_s_dn_cn
#fastcgi_param SSL_CLIENT_S_DN_CN $ssl_client_s_dn_cn;
# OR TO USE uWSGI
#include /etc/nginx/uwsgi_params;
......@@ -41,6 +44,8 @@ server {
#uwsgi_param LLTYPE psgi;
#uwsgi_param SCRIPT_FILENAME $document_root$sc;
#uwsgi_param SCRIPT_NAME $sc;
# Uncomment this if you use Auth SSL:
#uwsgi_param SSL_CLIENT_S_DN_CN $ssl_client_s_dn_cn;
}
......@@ -49,7 +54,7 @@ server {
try_files $uri $uri/ =404;
# Uncomment this if you use https only
#add_header Strict-Transport-Security "15768000";
#add_header Strict-Transport-Security max-age=15768000;
}
location /static/ {
......
......@@ -28,6 +28,7 @@ sub defaultValues {
'casAccessControlPolicy' => 'none',
'casAuthnLevel' => 1,
'checkTime' => 600,
'checkUserHiddenAttributes' => 'UA _2fDevices _loginHistory',
'checkXSS' => 1,
'confirmFormMethod' => 'post',
'cookieName' => 'lemonldap',
......@@ -240,6 +241,7 @@ sub defaultValues {
'samlOrganizationDisplayName' => 'Example',
'samlOrganizationName' => 'Example',
'samlOrganizationURL' => 'http://www.example.com',
'samlOverrideIDPEntityID' => '',
'samlRelayStateTimeout' => 600,
'samlServiceSignatureMethod' => 'RSA_SHA1',
'samlSPSSODescriptorArtifactResolutionServiceArtifact' =>
......
......@@ -66,7 +66,7 @@ our $issuerParameters = {
issuerDBOpenIDConnect => [qw(issuerDBOpenIDConnectActivation issuerDBOpenIDConnectPath issuerDBOpenIDConnectRule)],
issuerDBSAML => [qw(issuerDBSAMLActivation issuerDBSAMLPath issuerDBSAMLRule)],
};
our $samlServiceParameters = [qw(samlEntityID samlServicePrivateKeySig samlServicePrivateKeySigPwd samlServicePublicKeySig samlServicePrivateKeyEnc samlServicePrivateKeyEncPwd samlServicePublicKeyEnc samlServiceUseCertificateInResponse samlServiceSignatureMethod samlNameIDFormatMapEmail samlNameIDFormatMapX509 samlNameIDFormatMapWindows samlNameIDFormatMapKerberos samlAuthnContextMapPassword samlAuthnContextMapPasswordProtectedTransport samlAuthnContextMapTLSClient samlAuthnContextMapKerberos samlOrganizationDisplayName samlOrganizationName samlOrganizationURL samlSPSSODescriptorAuthnRequestsSigned samlSPSSODescriptorWantAssertionsSigned samlSPSSODescriptorSingleLogoutServiceHTTPRedirect samlSPSSODescriptorSingleLogoutServiceHTTPPost samlSPSSODescriptorSingleLogoutServiceSOAP samlSPSSODescriptorAssertionConsumerServiceHTTPArtifact samlSPSSODescriptorAssertionConsumerServiceHTTPPost samlSPSSODescriptorArtifactResolutionServiceArtifact samlIDPSSODescriptorWantAuthnRequestsSigned samlIDPSSODescriptorSingleSignOnServiceHTTPRedirect samlIDPSSODescriptorSingleSignOnServiceHTTPPost samlIDPSSODescriptorSingleSignOnServiceHTTPArtifact samlIDPSSODescriptorSingleLogoutServiceHTTPRedirect samlIDPSSODescriptorSingleLogoutServiceHTTPPost samlIDPSSODescriptorSingleLogoutServiceSOAP samlIDPSSODescriptorArtifactResolutionServiceArtifact samlAttributeAuthorityDescriptorAttributeServiceSOAP samlIdPResolveCookie samlMetadataForceUTF8 samlStorage samlStorageOptions samlRelayStateTimeout samlUseQueryStringSpecific samlCommonDomainCookieActivation samlCommonDomainCookieDomain samlCommonDomainCookieReader samlCommonDomainCookieWriter samlDiscoveryProtocolActivation samlDiscoveryProtocolURL samlDiscoveryProtocolPolicy samlDiscoveryProtocolIsPassive)];
our $samlServiceParameters = [qw(samlEntityID samlServicePrivateKeySig samlServicePrivateKeySigPwd samlServicePublicKeySig samlServicePrivateKeyEnc samlServicePrivateKeyEncPwd samlServicePublicKeyEnc samlServiceUseCertificateInResponse samlServiceSignatureMethod samlNameIDFormatMapEmail samlNameIDFormatMapX509 samlNameIDFormatMapWindows samlNameIDFormatMapKerberos samlAuthnContextMapPassword samlAuthnContextMapPasswordProtectedTransport samlAuthnContextMapTLSClient samlAuthnContextMapKerberos samlOrganizationDisplayName samlOrganizationName samlOrganizationURL samlSPSSODescriptorAuthnRequestsSigned samlSPSSODescriptorWantAssertionsSigned samlSPSSODescriptorSingleLogoutServiceHTTPRedirect samlSPSSODescriptorSingleLogoutServiceHTTPPost samlSPSSODescriptorSingleLogoutServiceSOAP samlSPSSODescriptorAssertionConsumerServiceHTTPArtifact samlSPSSODescriptorAssertionConsumerServiceHTTPPost samlSPSSODescriptorArtifactResolutionServiceArtifact samlIDPSSODescriptorWantAuthnRequestsSigned samlIDPSSODescriptorSingleSignOnServiceHTTPRedirect samlIDPSSODescriptorSingleSignOnServiceHTTPPost samlIDPSSODescriptorSingleSignOnServiceHTTPArtifact samlIDPSSODescriptorSingleLogoutServiceHTTPRedirect samlIDPSSODescriptorSingleLogoutServiceHTTPPost samlIDPSSODescriptorSingleLogoutServiceSOAP samlIDPSSODescriptorArtifactResolutionServiceArtifact samlAttributeAuthorityDescriptorAttributeServiceSOAP samlIdPResolveCookie samlMetadataForceUTF8 samlStorage samlStorageOptions samlRelayStateTimeout samlUseQueryStringSpecific samlCommonDomainCookieActivation samlCommonDomainCookieDomain samlCommonDomainCookieReader samlCommonDomainCookieWriter samlDiscoveryProtocolActivation samlDiscoveryProtocolURL samlDiscoveryProtocolPolicy samlDiscoveryProtocolIsPassive samlOverrideIDPEntityID)];
our $oidcServiceParameters = [qw(oidcServiceMetaDataIssuer oidcServiceMetaDataAuthorizeURI oidcServiceMetaDataTokenURI oidcServiceMetaDataUserInfoURI oidcServiceMetaDataJWKSURI oidcServiceMetaDataRegistrationURI oidcServiceMetaDataEndSessionURI oidcServiceMetaDataCheckSessionURI oidcServiceMetaDataFrontChannelURI oidcServiceMetaDataBackChannelURI oidcServiceMetaDataAuthnContext oidcServicePrivateKeySig oidcServicePublicKeySig oidcServiceKeyIdSig oidcServiceAllowDynamicRegistration oidcServiceAllowAuthorizationCodeFlow oidcServiceAllowImplicitFlow oidcServiceAllowHybridFlow oidcStorage oidcStorageOptions)];
1;
# Main running methods file
package Lemonldap::NG::Handler::Main::Run;
our $VERSION = '2.0.2';
our $VERSION = '2.0.3';
package Lemonldap::NG::Handler::Main;
......@@ -44,20 +44,20 @@ sub getStatus {
if ( $ENV{LLNGSTATUSHOST} ) {
require IO::Socket::INET;
foreach ( 64322 .. 64331 ) {
if ( $statusOut =
IO::Socket::INET->new( Proto => 'udp', LocalPort => $_ ) )
if ( $statusOut
= IO::Socket::INET->new( Proto => 'udp', LocalPort => $_ ) )
{
$args =
' host=' . ( $ENV{LLNGSTATUSCLIENT} || 'localhost' ) . ":$_";
$args = ' host='
. ( $ENV{LLNGSTATUSCLIENT} || 'localhost' ) . ":$_";
last;
}
}
return $class->abort( $req,
"$class: status page can not be displayed, unable to open socket" )
unless ($statusOut);
"$class: status page can not be displayed, unable to open socket"
) unless ($statusOut);
}
return $class->abort( $req, "$class: status page can not be displayed" )
unless ( $statusPipe and $statusOut );
unless ( $statusPipe and $statusOut );
my $q = $req->{env}->{QUERY_STRING} || '';
if ( $q =~ /\s/ ) {
$class->logger->error("Bad characters in query");
......@@ -84,12 +84,12 @@ sub checkType {
if ( time() - $class->lastCheck > $class->checkTime ) {
die("$class: No configuration found")
unless ( $class->checkConf );
unless ( $class->checkConf );
}
my $vhost = $class->resolveAlias($req);
return ( defined $class->tsv->{type}->{$vhost} )
? $class->tsv->{type}->{$vhost}
: 'Main';
? $class->tsv->{type}->{$vhost}
: 'Main';
}
## @rmethod int run
......@@ -125,7 +125,7 @@ sub run {
my ($cond);
( $cond, $protection ) = $class->conditionSub($rule) if ($rule);
$protection = $class->isUnprotected( $req, $uri ) || 0
unless ( defined $protection );
unless ( defined $protection );
if ( $protection == $class->SKIP ) {
$class->logger->debug("Access control skipped");
......@@ -150,7 +150,7 @@ sub run {
# AUTHORIZATION
return ( $class->forbidden( $req, $session ), $session )
unless ( $class->grant( $req, $session, $uri, $cond ) );
unless ( $class->grant( $req, $session, $uri, $cond ) );
$class->updateStatus( $req, 'OK',
$session->{ $class->tsv->{whatToTrace} } );
......@@ -168,8 +168,8 @@ sub run {
# Log access granted
$class->logger->debug( "User "
. $session->{ $class->tsv->{whatToTrace} }
. " was granted to access to $uri" );
. $session->{ $class->tsv->{whatToTrace} }
. " was granted to access to $uri" );
# Catch POST rules
$class->postOutputFilter( $req, $session, $uri );
......@@ -192,7 +192,7 @@ sub run {
# Redirect user to the portal
$class->logger->info("No cookie found")
unless ($id);
unless ($id);
# if the cookie was fetched, a log is sent by retrieveSession()
$class->updateStatus( $req, $id ? 'EXPIRED' : 'REDIRECT' );
......@@ -243,10 +243,10 @@ sub lmLog {
sub checkMaintenanceMode {
my ( $class, $req ) = @_;
my $vhost = $class->resolveAlias($req);
my $_maintenance =
( defined $class->tsv->{maintenance}->{$vhost} )
? $class->tsv->{maintenance}->{$vhost}
: $class->tsv->{maintenance}->{_};
my $_maintenance
= ( defined $class->tsv->{maintenance}->{$vhost} )
? $class->tsv->{maintenance}->{$vhost}
: $class->tsv->{maintenance}->{_};
if ($_maintenance) {
$class->logger->debug("Maintenance mode enabled");
......@@ -272,17 +272,17 @@ sub grant {
}
}
for (
my $i = 0 ;
$i < ( $class->tsv->{locationCount}->{$vhost} || 0 ) ;
my $i = 0;
$i < ( $class->tsv->{locationCount}->{$vhost} || 0 );
$i++
)
)
{
if ( $uri =~ $class->tsv->{locationRegexp}->{$vhost}->[$i] ) {
$class->logger->debug( 'Regexp "'
. $class->tsv->{locationConditionText}->{$vhost}->[$i]
. '" match' );
. $class->tsv->{locationConditionText}->{$vhost}->[$i]
. '" match' );
return $class->tsv->{locationCondition}->{$vhost}->[$i]
->( $req, $session );
->( $req, $session );
}
}
unless ( $class->tsv->{defaultCondition}->{$vhost} ) {
......@@ -319,8 +319,8 @@ sub forbidden {
# Log forbidding
$class->userLogger->notice( "User "
. $session->{ $class->tsv->{whatToTrace} }
. " was forbidden to access to $vhost$uri" );
. $session->{ $class->tsv->{whatToTrace} }
. " was forbidden to access to $vhost$uri" );
$class->updateStatus( $req, 'REJECT',
$session->{ $class->tsv->{whatToTrace} } );
......@@ -377,9 +377,9 @@ sub goToPortal {
$class->logger->debug(
"Redirect $req->{env}->{REMOTE_ADDR} to portal (url was $url)");
$class->set_header_out( $req,
'Location' => $class->tsv->{portal}->()
. "$path?url=$urlc_init"
. ( $arg ? "&$arg" : "" ) );
'Location' => $class->tsv->{portal}->()
. "$path?url=$urlc_init"
. ( $arg ? "&$arg" : "" ) );
return $class->REDIRECT;
}
......@@ -389,9 +389,9 @@ sub goToError {
$class->logger->debug(
"Redirect $req->{env}->{REMOTE_ADDR} to lmError (url was $url)");
$class->set_header_out( $req,
'Location' => $class->tsv->{portal}->()
. "/lmerror/$code"
. "?url=$urlc_init" );
'Location' => $class->tsv->{portal}->()
. "/lmerror/$code"
. "?url=$urlc_init" );
return $class->REDIRECT;
}
......@@ -403,12 +403,12 @@ sub fetchId {
my $t = $req->{env}->{HTTP_COOKIE} or return 0;
my $vhost = $class->resolveAlias($req);
my $lookForHttpCookie = ( $class->tsv->{securedCookie} =~ /^(2|3)$/
and not $class->_isHttps( $req, $vhost ) );
and not $class->_isHttps( $req, $vhost ) );
my $cn = $class->tsv->{cookieName};
my $value =
$lookForHttpCookie
? ( $t =~ /${cn}http=([^,; ]+)/o ? $1 : 0 )
: ( $t =~ /$cn=([^,; ]+)/o ? $1 : 0 );
my $value
= $lookForHttpCookie
? ( $t =~ /${cn}http=([^,; ]+)/o ? $1 : 0 )
: ( $t =~ /$cn=([^,; ]+)/o ? $1 : 0 );
if ( $value && $lookForHttpCookie && $class->tsv->{securedCookie} == 3 ) {
$value = $class->tsv->{cipher}->decryptHex( $value, "http" );
......@@ -446,8 +446,8 @@ sub retrieveSession {
# 2. Get the session from cache or backend
my $session = $req->data->{session} = (
Lemonldap::NG::Common::Session->new( {
storageModule => $class->tsv->{sessionStorageModule},
Lemonldap::NG::Common::Session->new(
{ storageModule => $class->tsv->{sessionStorageModule},
storageModuleOptions => $class->tsv->{sessionStorageOptions},
cacheModule => $class->tsv->{sessionCacheModule},
cacheModuleOptions => $class->tsv->{sessionCacheOptions},
......@@ -464,36 +464,36 @@ sub retrieveSession {
# Verify that session is valid
$class->logger->error(
"_utime is not defined. This should not happen. Check if it is well transmitted to handler"
"_utime is not defined. This should not happen. Check if it is well transmitted to handler"
) unless $session->data->{_utime};
$class->logger->debug("Check session validity from Handler");
$class->logger->debug( "Session timeout -> " . $class->tsv->{timeout} );
$class->logger->debug(
"Session timeout -> " . $class->tsv->{timeout} );
$class->logger->debug( "Session timeoutActivity -> "
. $class->tsv->{timeoutActivity}
. "s" )
if ( $class->tsv->{timeoutActivity} );
. $class->tsv->{timeoutActivity}
. "s" )
if ( $class->tsv->{timeoutActivity} );
$class->logger->debug(
"Session _utime -> " . $session->data->{_utime} );
$class->logger->debug( "now -> " . $now );
$class->logger->debug( "_lastSeen -> " . $session->data->{_lastSeen} )
if ( $session->data->{_lastSeen} );
if ( $session->data->{_lastSeen} );
my $delta = $now - $session->data->{_lastSeen}
if ( $session->data->{_lastSeen} );
if ( $session->data->{_lastSeen} );
$class->logger->debug( "now - _lastSeen = " . $delta )
if ( $session->data->{_lastSeen} );
if ( $session->data->{_lastSeen} );
$class->logger->debug( "Session timeoutActivityInterval -> "
. $class->tsv->{timeoutActivityInterval} )
if ( $class->tsv->{timeoutActivityInterval} );
. $class->tsv->{timeoutActivityInterval} )
if ( $class->tsv->{timeoutActivityInterval} );
my $ttl = $class->tsv->{timeout} - $now + $session->data->{_utime};
$class->logger->debug( "Session TTL = " . $ttl );
if (
$now - $session->data->{_utime} > $class->tsv->{timeout}
if ($now - $session->data->{_utime} > $class->tsv->{timeout}
or ( $class->tsv->{timeoutActivity}
and $session->data->{_lastSeen}
and $delta > $class->tsv->{timeoutActivity} )
)
)
{
$class->logger->info("Session $id expired");
......@@ -503,11 +503,10 @@ sub retrieveSession {
}
# Update the session to notify activity, if necessary
if (
$class->tsv->{timeoutActivity}
and ( $now - $session->data->{_lastSeen} >
$class->tsv->{timeoutActivityInterval} )
)
if ($class->tsv->{timeoutActivity}
and ( $now - $session->data->{_lastSeen}
> $class->tsv->{timeoutActivityInterval} )
)
{
$req->data->{session}->update( { '_lastSeen' => $now } );
$class->data( $session->data );
......@@ -594,9 +593,9 @@ sub _buildUrl {
my $_https = $class->_isHttps( $req, $vhost );
my $portString = $class->_getPort( $req, $vhost );
$portString = (
( $realvhost =~ /:\d+/ )
or ( $_https && $portString == 443 )
or ( !$_https && $portString == 80 )
( $realvhost =~ /:\d+/ )
or ( $_https && $portString == 443 )
or ( !$_https && $portString == 80 )
) ? '' : ":$portString";
my $url = "http" . ( $_https ? "s" : "" ) . "://$realvhost$portString$s";
$class->logger->debug("Build URL $url");
......@@ -612,10 +611,10 @@ sub isUnprotected {
my ( $class, $req, $uri ) = @_;
my $vhost = $class->resolveAlias($req);
for (
my $i = 0 ;
$i < ( $class->tsv->{locationCount}->{$vhost} || 0 ) ;
my $i = 0;
$i < ( $class->tsv->{locationCount}->{$vhost} || 0 );
$i++
)
)
{
if ( $uri =~ $class->tsv->{locationRegexp}->{$vhost}->[$i] ) {
return $class->tsv->{locationProtection}->{$vhost}->[$i];
......@@ -632,8 +631,8 @@ sub sendHeaders {
if ( defined $class->tsv->{forgeHeaders}->{$vhost} ) {
# Log headers in debug mode
my %headers =
$class->tsv->{forgeHeaders}->{$vhost}->( $req, $session );
my %headers
= $class->tsv->{forgeHeaders}->{$vhost}->( $req, $session );
foreach my $h ( sort keys %headers ) {
if ( defined( my $v = $headers{$h} ) ) {
$class->logger->debug("Send header $h with value $v");
......@@ -646,6 +645,27 @@ sub sendHeaders {
}
}
## @rfunction array ref checkHeaders()
# Return computed headers by forgeHeadersInit() for the current virtual host
# [ { key => 'header1', value => 'value1' }, { key => 'header2', value => 'value2' }, ...]
sub checkHeaders {
my ( $class, $req, $session ) = @_;
my $vhost = $class->resolveAlias($req);
my $array_headers = [];
if ( defined $class->tsv->{forgeHeaders}->{$vhost} ) {
# Create array of hashes with headers
my %headers
= $class->tsv->{forgeHeaders}->{$vhost}->( $req, $session );
foreach my $h ( sort keys %headers ) {
defined $headers{$h}
? push @$array_headers, { key => $h, value => $headers{$h} }
: push @$array_headers, { key => $h, value => '' };
}
}
return $array_headers;
}
## @rmethod void cleanHeaders()
# Unset HTTP headers, when sendHeaders is skipped
sub cleanHeaders {
......@@ -665,7 +685,7 @@ sub resolveAlias {
$vhost =~ s/:\d+//;
return $class->tsv->{vhostAlias}->{$vhost}
if ( $class->tsv->{vhostAlias}->{$vhost} );
if ( $class->tsv->{vhostAlias}->{$vhost} );
return $vhost if ( $class->tsv->{defaultCondition}->{$vhost} );
my $v = $vhost;
while ( $v =~ s/[\w\-]+/\*/ ) {
......@@ -738,8 +758,8 @@ sub postOutputFilter {
$class->logger->debug("Filling a html form with fake data");
$class->unset_header_in( $req, "Accept-Encoding" );
my %postdata =
$class->tsv->{outputPostData}->{$vhost}->{$uri}->( $req, $session );
my %postdata = $class->tsv->{outputPostData}->{$vhost}->{$uri}
->( $req, $session );
my $formParams = $class->tsv->{postFormParams}->{$vhost}->{$uri};
my $js = $class->postJavascript( $req, \%postdata, $formParams );
$class->addToHtmlHead( $req, $js );
......@@ -756,8 +776,8 @@ sub postInputFilter {
if ( defined( $class->tsv->{inputPostData}->{$vhost}->{$uri} ) ) {
$class->logger->debug("Replacing fake data with real form data");
my %data =
$class->tsv->{inputPostData}->{$vhost}->{$uri}->( $req, $session );
my %data = $class->tsv->{inputPostData}->{$vhost}->{$uri}
->( $req, $session );
foreach ( keys %data ) {
$data{$_} = uri_escape( $data{$_} );
}
......@@ -777,32 +797,33 @@ sub postJavascript {
foreach my $name ( keys %$data ) {
use bytes;
my $value = "x" x bytes::length( $data->{$name} );
$filler .=
"form.find('input[name=\"$name\"], select[name=\"$name\"], textarea[name=\"$name\"]').val('$value')\n";
$filler
.= "form.find('input[name=\"$name\"], select[name=\"$name\"], textarea[name=\"$name\"]').val('$value')\n";
}
my $submitter =
$formParams->{buttonSelector} eq "none" ? ""
: $formParams->{buttonSelector}
? "form.find('$formParams->{buttonSelector}').click();\n"
: "form.submit();\n";
my $submitter
= $formParams->{buttonSelector} eq "none" ? ""
: $formParams->{buttonSelector}
? "form.find('$formParams->{buttonSelector}').click();\n"
: "form.submit();\n";
my $jqueryUrl = $formParams->{jqueryUrl} || "";
$jqueryUrl = &{ $class->tsv->{portal} } . "skins/common/js/jquery-1.10.2.js"
if ( $jqueryUrl eq "default" );
$jqueryUrl
= &{ $class->tsv->{portal} } . "skins/common/js/jquery-1.10.2.js"
if ( $jqueryUrl eq "default" );
$jqueryUrl = "<script type='text/javascript' src='$jqueryUrl'></script>\n"
if ($jqueryUrl);
if ($jqueryUrl);
return
$jqueryUrl
. "<script type='text/javascript'>\n"
. "/* script added by Lemonldap::NG */\n"
. "jQuery(window).on('load', function() {\n"
. "var form = jQuery('$form');\n"
. "form.attr('autocomplete', 'off');\n"
. $filler
. $submitter . "})\n"
. "</script>\n";
$jqueryUrl
. "<script type='text/javascript'>\n"
. "/* script added by Lemonldap::NG */\n"
. "jQuery(window).on('load', function() {\n"
. "var form = jQuery('$form');\n"
. "form.attr('autocomplete', 'off');\n"
. $filler
. $submitter . "})\n"
. "</script>\n";
}
1;
......@@ -60,7 +60,7 @@ sub _run {
$self->routes( $self->authRoutes );
$req->userData( $self->api->data );
}
else {
elsif ( $res->[0] != 403 ) {
# Unset headers (handler adds a Location header)
$self->logger->debug(
"User not authenticated, Try in use, cancel redirection");
......@@ -68,6 +68,9 @@ sub _run {
$req->respHeaders( [] );
$self->routes( $self->unAuthRoutes );
}
else {
return $res;
}
$res = $self->handler($req);
# Insert respHeaders in response only if not already set
......
......@@ -767,6 +767,22 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
'default' => 600,
'type' => 'int'
},
'checkUser' => {
'default' => 0,
'type' => 'bool'
},
'checkUserDisplayEmptyValues' => {
'default' => 0,
'type' => 'bool'
},
'checkUserDisplayPersistentInfo' => {
'default' => 0,
'type' => 'bool'
},
'checkUserHiddenAttributes' => {
'default' => 'UA _2fDevices _loginHistory',
'type' => 'text'
},
'checkXSS' => {
'default' => 1,
'type' => 'bool'
......@@ -2849,6 +2865,10 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
'default' => 'http://www.example.com',
'type' => 'text'
},
'samlOverrideIDPEntityID' => {
'default' => '',
'type' => 'text'
},
'samlRelayStateTimeout' => {
'default' => 600,
'type' => 'int'
......
......@@ -578,6 +578,30 @@ sub attributes {
documentation => 'Enable Cross Domain Authentication',
flags => 'hp',
},
checkUser => {
default => 0,
type => 'bool',
documentation => 'Enable check user',
flags => 'p',
},
checkUserHiddenAttributes => {
type => 'text',
default => 'UA _2fDevices _loginHistory',
documentation => 'Attributes to hide in CheckUser plugin',
flags => 'p',
},
checkUserDisplayPersistentInfo => {
default => 0,
type => 'bool',
documentation => 'Display persistent session info',
flags => 'p',
},
checkUserDisplayEmptyValues => {
default => 0,
type => 'bool',
documentation => 'Display session empty values',
flags => 'p',
},
checkXSS => {
default => 1,
type => 'bool',
......@@ -1968,6 +1992,11 @@ sub attributes {
default => 600,
documentation => 'SAML timeout of relay state',
},
samlOverrideIDPEntityID => {
type => 'text',
documentation => 'Override SAML EntityID when acting as an IDP',
default => '',
},
samlUseQueryStringSpecific => {
default => 0,
type => 'bool',
......
......@@ -637,6 +637,17 @@ sub tree {
form => 'simpleInputContainer',
nodes => [ 'checkState', 'checkStateSecret', ],
},
{
title => 'checkUsers',
help => 'checkuser.html',
form => 'simpleInputContainer',
nodes => [
'checkUser',
'checkUserHiddenAttributes',
'checkUserDisplayPersistentInfo',
'checkUserDisplayEmptyValues',
]
},
]
},
{
......@@ -986,7 +997,8 @@ sub tree {
'samlDiscoveryProtocolPolicy',
'samlDiscoveryProtocolIsPassive'
]
}
},
'samlOverrideIDPEntityID',
]
}
]
......
......@@ -31,8 +31,7 @@ sub tests {
portalIsInDomain => sub {
return (
1,
(
index( $conf->{portal}, $conf->{domain} ) > 0
( index( $conf->{portal}, $conf->{domain} ) > 0
? ''
: "Portal seems not to be in the domain $conf->{domain}"
)
......@@ -44,7 +43,7 @@ sub tests {
# Checking for ending slash
$conf->{portal} .= '/'
unless ( $conf->{portal} =~ qr#/$# );
unless ( $conf->{portal} =~ qr#/$# );
# Deleting trailing ending slash
my $regex = qr#/+$#;
......@@ -62,11 +61,10 @@ sub tests {
}
return (
1,
(
@pb
( @pb
? 'Virtual hosts '
. join( ', ', @pb )
. " are not in $conf->{domain} and cross-domain-authentication is not set"
. join( ', ', @pb )
. " are not in $conf->{domain} and cross-domain-authentication is not set"
: undef
)
);
......@@ -80,9 +78,9 @@ sub tests {
}
if (@pb) {
return ( 0,
'Virtual hosts '
. join( ', ', @pb )
. " contain a port, this is not allowed" );
'Virtual hosts '
. join( ', ', @pb )
. " contain a port, this is not allowed" );
}
else { return 1; }
},
......@@ -95,9 +93,9 @@ sub tests {
}
if (@pb) {
return ( 0,
'Virtual hosts '
. join( ', ', @pb )
. " must be in lower case" );
'Virtual hosts '
. join( ', ', @pb )
. " must be in lower case" );
}
else { return 1; }
},
......@@ -105,12 +103,12 @@ sub tests {
# Check if "userDB" and "authentication" are consistent
authAndUserDBConsistency => sub {
foreach
my $type (qw(Facebook Google OpenID OpenIDConnect SAML WebID))
my $type (qw(Facebook Google OpenID OpenIDConnect SAML WebID))
{
return ( 0,
"\"$type\" can not be used as user database without using \"$type\" for authentication"
)
if ( $conf->{userDB} =~ /$type/
"\"$type\" can not be used as user database without using \"$type\" for authentication"
)
if ($conf->{userDB} =~ /$type/
and $conf->{authentication} !~ /$type/ );
}
return 1;
......@@ -120,30 +118,29 @@ sub tests {
checkAttrAndMacros => sub {
my @tmp;
foreach my $k ( keys %$conf ) {
if ( $k =~
/^(?:openIdSreg_(?:(?:(?:full|nick)nam|languag|postcod|timezon)e|country|gender|email|dob)|whatToTrace)$/
)
if ( $k
=~ /^(?:openIdSreg_(?:(?:(?:full|nick)nam|languag|postcod|timezon)e|country|gender|email|dob)|whatToTrace)$/
)
{
my $v = $conf->{$k};
$v =~ s/^$//;
next if ( $v =~ /^_/ );
push @tmp,
$k
unless (
$k
unless (
defined(
$conf->{exportedVars}->{$v}
or defined( $conf->{macros}->{$v} )
or defined( $conf->{macros}->{$v} )
)
);
);
}
}
return (
1,
(
@tmp
( @tmp
? 'Values of parameter(s) "'
. join( ', ', @tmp )
. '" are not defined in exported attributes or macros'
. join( ', ', @tmp )
. '" are not defined in exported attributes or macros'
: ''
)
);
......@@ -155,18 +152,18 @@ sub tests {
if ( $conf->{userDB} =~ /^Google$/ ) {
foreach my $k ( keys %{ $conf->{exportedVars} } ) {
my $v = $conf->{exportedVars}->{$k};
if ( $v !~ Lemonldap::NG::Common::Regexp::GOOGLEAXATTR() ) {
if ( $v !~ Lemonldap::NG::Common::Regexp::GOOGLEAXATTR() )
{
push @tmp, $v;
}
}
}
return (
1,
(
@tmp
( @tmp
? 'Values of parameter(s) "'
. join( ', ', @tmp )
. '" are not exported by Google'
. join( ', ', @tmp )
. '" are not exported by Google'
: ''
)
);
......@@ -178,7 +175,8 @@ sub tests {
if ( $conf->{userDB} =~ /^OpenID$/ ) {
foreach my $k ( keys %{ $conf->{exportedVars} } ) {
my $v = $conf->{exportedVars}->{$k};
if ( $v !~ Lemonldap::NG::Common::Regexp::OPENIDSREGATTR() )
if ( $v
!~ Lemonldap::NG::Common::Regexp::OPENIDSREGATTR() )
{
push @tmp, $v;
}
......@@ -186,11 +184,10 @@ sub tests {
}
return (
1,
(
@tmp
( @tmp
? 'Values of parameter(s) "'
. join( ', ', @tmp )
. '" are not exported by OpenID SREG'
. join( ', ', @tmp )
. '" are not exported by OpenID SREG'
: ''
)
);
......@@ -199,39 +196,40 @@ sub tests {
# Try to use Apache::Session module
testApacheSession => sub {
my ( $id, %h );
my $gc = Lemonldap::NG::Handler::Main->tsv->{sessionStorageModule};
my $gc
= Lemonldap::NG::Handler::Main->tsv->{sessionStorageModule};
return 1
if ( ( $gc and $gc eq $conf->{globalStorage} )
or $conf->{globalStorage} =~
/^Lemonldap::NG::Common::Apache::Session::/ );
if ( ( $gc and $gc eq $conf->{globalStorage} )
or $conf->{globalStorage}
=~ /^Lemonldap::NG::Common::Apache::Session::/ );
eval "use $conf->{globalStorage}";
return ( -1, "Unknown package $conf->{globalStorage}" ) if ($@);
eval {
tie %h, 'Lemonldap::NG::Common::Apache::Session', undef,
{
{
%{ $conf->{globalStorageOptions} },
backend => $conf->{globalStorage}
};
};
};
return ( -1, "Unable to create a session ($@)" )
if ( $@ or not tied(%h) );
if ( $@ or not tied(%h) );
eval {
$h{a} = 1;
$id = $h{_session_id} or return ( -1, 'No _session_id' );
untie(%h);
tie %h, 'Lemonldap::NG::Common::Apache::Session', $id,
{
{
%{ $conf->{globalStorageOptions} },
backend => $conf->{globalStorage}
};
};
};
return ( -1, "Unable to insert data ($@)" ) if ($@);
return ( -1, "Unable to recover data stored" )
unless ( $h{a} == 1 );
unless ( $h{a} == 1 );
eval { tied(%h)->delete; };
return ( -1, "Unable to delete session ($@)" ) if ($@);
return ( -1,
'All sessions may be lost and you must restart all your Apache servers'
'All sessions may be lost and you must restart all your Apache servers'
) if ( $gc and $conf->{globalStorage} ne $gc );
return 1;
},
......@@ -241,9 +239,8 @@ sub tests {
my $cn = Lemonldap::NG::Handler::Main->tsv->{cookieName};
return (
1,
(
$cn
and $cn ne $conf->{cookieName}
( $cn
and $cn ne $conf->{cookieName}
? 'Cookie name has changed, you must restart all your web servers'
: ()
)
......@@ -254,10 +251,10 @@ sub tests {
cookieTTL => sub {
return 1 unless ( defined $conf->{cookieExpiration} );
return ( 0, "Cookie TTL must be higher than one minute" )
unless ( $conf->{cookieExpiration} == 0
unless ( $conf->{cookieExpiration} == 0
|| $conf->{cookieExpiration} > 60 );
return ( 1, "Cookie TTL should be higher or equal than one hour" )
unless ( $conf->{cookieExpiration} >= 3600
unless ( $conf->{cookieExpiration} >= 3600
|| $conf->{cookieExpiration} == 0 );
# Return
......@@ -268,7 +265,7 @@ sub tests {
sessionTimeout => sub {
return 1 unless ( defined $conf->{timeout} );
return ( -1, "Session timeout should be higher than ten minutes" )
unless ( $conf->{timeout} > 600
unless ( $conf->{timeout} > 600
|| $conf->{timeout} == 0 );
# Return
......@@ -279,9 +276,9 @@ sub tests {
sessionTimeoutActivity => sub {
return 1 unless ( defined $conf->{timeoutActivity} );
return ( 0,
"Session activity timeout must be higher or equal than one minute"
)
unless ( $conf->{timeoutActivity} > 59
"Session activity timeout must be higher or equal than one minute"
)
unless ( $conf->{timeoutActivity} > 59
|| $conf->{timeoutActivity} == 0 );
# Return
......@@ -292,11 +289,11 @@ sub tests {
timeoutActivityInterval => sub {
return 1 unless ( defined $conf->{timeoutActivityInterval} );
return ( 0,
"Activity timeout interval must be lower than session activity timeout"
)
if ( $conf->{timeoutActivity}
and $conf->{timeoutActivity} <=
$conf->{timeoutActivityInterval} );
"Activity timeout interval must be lower than session activity timeout"
)
if ($conf->{timeoutActivity}
and $conf->{timeoutActivity}
<= $conf->{timeoutActivityInterval} );
# Return
return 1;
......@@ -306,8 +303,7 @@ sub tests {
managerProtection => sub {
return (
1,
(
$conf->{cfgAuthor} eq 'anonymous'
( $conf->{cfgAuthor} eq 'anonymous'
? 'Your manager seems to be unprotected'
: ''
)
......@@ -323,7 +319,7 @@ sub tests {
# Use SMTP
eval "use Net::SMTP";
return ( 1, "Net::SMTP module is required to use SMTP server" )
if ($@);
if ($@);
# Create SMTP object
my $smtp = Net::SMTP->new(
......@@ -333,15 +329,15 @@ sub tests {
);
return ( 1,
"SMTP connection to " . $conf->{SMTPServer} . " failed" )
unless ($smtp);
unless ($smtp);
# Skip other tests if no authentication
return 1
unless ( $conf->{SMTPAuthUser} and $conf->{SMTPAuthPass} );
unless ( $conf->{SMTPAuthUser} and $conf->{SMTPAuthPass} );
# Try authentication
return ( 1, "SMTP authentication failed" )
unless $smtp->auth( $conf->{SMTPAuthUser},
unless $smtp->auth( $conf->{SMTPAuthUser},
$conf->{SMTPAuthPass} );
# Return
......@@ -351,15 +347,14 @@ sub tests {
# SAML entity ID must be uniq
samlIDPEntityIdUniqueness => sub {
return 1
unless ( $conf->{samlIDPMetaDataXML}
unless ( $conf->{samlIDPMetaDataXML}
and %{ $conf->{samlIDPMetaDataXML} } );
my @msg;
my $res = 1;
my %entityIds;
foreach my $idpId ( keys %{ $conf->{samlIDPMetaDataXML} } ) {
unless (
$conf->{samlIDPMetaDataXML}->{$idpId}->{samlIDPMetaDataXML}
=~ /entityID=(['"])(.+?)\1/si )
unless ( $conf->{samlIDPMetaDataXML}->{$idpId}
->{samlIDPMetaDataXML} =~ /entityID=(['"])(.+?)\1/si )
{
push @msg, "$idpId SAML metadata has no EntityID";
$res = 0;
......@@ -368,7 +363,7 @@ sub tests {
my $eid = $2;
if ( defined $entityIds{$eid} ) {
push @msg,
"$idpId and $entityIds{$eid} have the same SAML EntityID";
"$idpId and $entityIds{$eid} have the same SAML EntityID";
$res = 0;
next;
}
......@@ -378,15 +373,15 @@ sub tests {
},
samlSPEntityIdUniqueness => sub {
return 1
unless ( $conf->{samlSPMetaDataXML}
unless ( $conf->{samlSPMetaDataXML}
and %{ $conf->{samlSPMetaDataXML} } );
my @msg;
my $res = 1;
my %entityIds;
foreach my $spId ( keys %{ $conf->{samlSPMetaDataXML} } ) {
unless (
$conf->{samlSPMetaDataXML}->{$spId}->{samlSPMetaDataXML} =~
/entityID=(['"])(.+?)\1/si )
$conf->{samlSPMetaDataXML}->{$spId}->{samlSPMetaDataXML}
=~ /entityID=(['"])(.+?)\1/si )
{
push @msg, "$spId SAML metadata has no EntityID";
$res = 0;
......@@ -395,7 +390,7 @@ sub tests {
my $eid = $2;
if ( defined $entityIds{$eid} ) {
push @msg,
"$spId and $entityIds{$eid} have the same SAML EntityID";
"$spId and $entityIds{$eid} have the same SAML EntityID";
$res = 0;
next;
}
......@@ -409,7 +404,7 @@ sub tests {
return 1 unless ( $conf->{authentication} eq 'Combination' );
require Lemonldap::NG::Common::Combination::Parser;
return ( 0, 'No module declared for combination' )
unless ( $conf->{combModules} and %{ $conf->{combModules} } );
unless ( $conf->{combModules} and %{ $conf->{combModules} } );
my $moduleList;
foreach my $md ( keys %{ $conf->{combModules} } ) {
my $entry = $conf->{combModules}->{$md};
......@@ -420,8 +415,8 @@ sub tests {
);
}
eval {
Lemonldap::NG::Common::Combination::Parser->parse( $moduleList,
$conf->{combination} );
Lemonldap::NG::Common::Combination::Parser->parse(
$moduleList, $conf->{combination} );
};
return ( 0, $@ ) if ($@);
......@@ -433,9 +428,9 @@ sub tests {
combinationParameters => sub {
return 1 unless ( $conf->{authentication} eq "Combination" );
return ( 0, "Combination rule must be defined" )
unless ( $conf->{combination} );
unless ( $conf->{combination} );
return ( 0, 'userDB must be set to "Same" to enable Combination' )
unless ( $conf->{userDB} eq "Same" );
unless ( $conf->{userDB} eq "Same" );
# Return
return 1;
......@@ -458,7 +453,7 @@ sub tests {
eval "use Convert::Base32";
return ( 1,
"Convert::Base32 module is required to enable TOTP" )
if ($@);
if ($@);
}
# Use U2F
......@@ -467,7 +462,7 @@ sub tests {
{
eval "use Crypt::U2F::Server::Simple";
return ( 1,
"Crypt::U2F::Server::Simple module is required to enable U2F"
"Crypt::U2F::Server::Simple module is required to enable U2F"
) if ($@);
}
......@@ -475,7 +470,7 @@ sub tests {
if ( $conf->{yubikey2fActivation} ) {
eval "use Auth::Yubikey_WebClient";
return ( 1,
"Auth::Yubikey_WebClient module is required to enable Yubikey"
"Auth::Yubikey_WebClient module is required to enable Yubikey"
) if ($@);
}
......@@ -489,7 +484,7 @@ sub tests {
my $w = "";
foreach ( 'totp', 'u' ) {
$w .= uc($_) . "2F is activated twice \n"
if ( $conf->{ $_ . '2fActivation' } eq '1' );
if ( $conf->{ $_ . '2fActivation' } eq '1' );
}
return ( 1, ( $w ? $w : () ) );
},
......@@ -500,9 +495,9 @@ sub tests {
return 1 unless ( defined $conf->{totp2fDigits} );
return (
1,
( (
$conf->{totp2fDigits} == 6
or $conf->{totp2fDigits} == 8
(
( $conf->{totp2fDigits} == 6
or $conf->{totp2fDigits} == 8
)
? ''
: 'TOTP should be 6 or 8 digits long'
......@@ -514,9 +509,9 @@ sub tests {
totp2fParams => sub {
return 1 unless ( $conf->{totp2fActivation} );
return ( 0, 'TOTP range must be defined' )
unless ( $conf->{totp2fRange} );
unless ( $conf->{totp2fRange} );
return ( 1, "TOTP interval should be higher than 10s" )
unless ( $conf->{totp2fInterval} > 10 );
unless ( $conf->{totp2fInterval} > 10 );
# Return
return 1;
......@@ -527,12 +522,11 @@ sub tests {
yubikey2fParams => sub {
return 1 unless ( $conf->{yubikey2fActivation} );
return ( 0, "Yubikey client ID and secret key must be set" )
unless ( defined $conf->{yubikey2fSecretKey}
unless ( defined $conf->{yubikey2fSecretKey}
&& defined $conf->{yubikey2fClientID} );
return (
1,
(
( $conf->{yubikey2fPublicIDSize} == 12 )
( ( $conf->{yubikey2fPublicIDSize} == 12 )
? ''
: 'Yubikey public ID size should be 12 digits long'
)
......@@ -543,7 +537,7 @@ sub tests {
rest2fVerifyUrl => sub {
return 1 unless ( $conf->{rest2fActivation} );
return ( 0, "REST 2F Verify URL must be set" )
unless ( defined $conf->{rest2fVerifyUrl} );
unless ( defined $conf->{rest2fVerifyUrl} );
# Return
return 1;
......@@ -557,15 +551,16 @@ sub tests {
my $ok = 0;
foreach (qw(u totp yubikey)) {
$ok ||= $conf->{ $_ . '2fActivation' }
&& $conf->{ $_ . '2fSelfRegistration' };
&& $conf->{ $_ . '2fSelfRegistration' };
last if ($ok);
}
$ok ||= $conf->{'utotp2fActivation'}
&& ( $conf->{'u2fSelfRegistration'}
&& ( $conf->{'u2fSelfRegistration'}
|| $conf->{'totp2fSelfRegistration'} );
$msg = "A self registrable module should be enabled to require 2FA"
unless ($ok);
$msg
= "A self registrable module should be enabled to require 2FA"
unless ($ok);
return ( 1, $msg );
},
......@@ -573,9 +568,12 @@ sub tests {
# Error if external 2F Send or Validate command is missing
ext2fCommands => sub {
return 1 unless ( $conf->{ext2fActivation} );
return ( 0, "External 2F Send or Validate command must be set" )
unless ( defined $conf->{ext2FSendCommand}
&& defined $conf->{ext2FValidateCommand} );
return ( 0, "External 2F Send command must be set" )
unless ( defined $conf->{ext2FSendCommand} );
unless ( defined $conf->{ext2fCodeActivation} ) {
return ( 0, "External 2F Validate command must be set" )
unless ( defined $conf->{ext2FValidateCommand} );
}
# Return
return 1;
......@@ -585,9 +583,9 @@ sub tests {
formTimeout => sub {
return 1 unless ( defined $conf->{formTimeout} );
return ( 0, "XSRF form token TTL must be higher than 30s" )
unless ( $conf->{formTimeout} > 30 );
unless ( $conf->{formTimeout} > 30 );
return ( 1, "XSRF form token TTL should not be higher than 2mn" )
if ( $conf->{formTimeout} > 120 );
if ( $conf->{formTimeout} > 120 );
# Return
return 1;
......@@ -596,8 +594,9 @@ sub tests {
# Warn if number of password reset retries is null
passwordResetRetries => sub {
return 1 unless ( $conf->{portalDisplayResetPassword} );
return ( 1, "Number of reset password retries should not be null" )
unless ( $conf->{passwordResetAllowedRetries} );
return ( 1,
"Number of reset password retries should not be null" )
unless ( $conf->{passwordResetAllowedRetries} );
# Return
return 1;
......@@ -607,10 +606,10 @@ sub tests {
bruteForceProtection => sub {
return 1 unless ( $conf->{bruteForceProtection} );
return ( 1,
'"History" plugin is required to enable "BruteForceProtection" plugin'
'"History" plugin is required to enable "BruteForceProtection" plugin'
) unless ( $conf->{loginHistoryEnabled} );
return ( 1,
'Number of failed logins must be higher than 2 to enable "BruteForceProtection" plugin'
'Number of failed logins must be higher than 2 to enable "BruteForceProtection" plugin'
) unless ( $conf->{failedLoginNumber} > 2 );
# Return
......@@ -621,9 +620,9 @@ sub tests {
checkMailResetSecurity => sub {
return 1 unless ( $conf->{portalDisplayResetPassword} );
return ( -1,
'"passwordMailReset" plugin is enabled without CSRF Token neither Captcha required !!!'
)
unless ( $conf->{requireToken}
'"passwordMailReset" plugin is enabled without CSRF Token neither Captcha required !!!'
)
unless ( $conf->{requireToken}
or $conf->{captcha_mail_enabled} );
# Return
......
......@@ -151,6 +151,11 @@
"clickHereToForce":"انقر هنا لإجبار",
"checkState":"Activation",
"checkStateSecret":"Shared secret",
"checkUsers":"Session check",
"checkUser":"Activation",
"checkUserHiddenAttributes":"Hidden attributes",
"checkUserDisplayPersistentInfo":"Display persistent session",
"checkUserDisplayEmptyValues":"Display empty values",
"choiceParams":"اختيارالإعدادات",
"chooseLogo":"اختيار الشعار",
"chooseSkin":"اختيار الغلاف",
......@@ -243,7 +248,7 @@
"exportedVars":"المتغيرات المصدرة",
"external2f":"External second factor",
"ext2fActivation":"تفعيل",
"ext2fCodeActivation":"2F code generated by Portal",
"ext2fCodeActivation":"Code regex",
"ext2fAuthnLevel":"مستوى إثبات الهوية",
"ext2fLogo":"Logo",
"ext2FSendCommand":"إرسال الأمر",
......@@ -964,5 +969,6 @@
"samlCommonDomainCookieReader":"يو آر إل القارئ",
"samlCommonDomainCookieWriter":"يو آر إل الكاتب",
"samlRelayStateTimeout":"تناوب حالة مهلة الجلسة ",
"samlUseQueryStringSpecific":"استخدام أسلوب query_string المعين"
}
\ No newline at end of file
"samlUseQueryStringSpecific":"استخدام أسلوب query_string المعين",
"samlOverrideIDPEntityID": "Override Entity ID when acting as IDP"
}
......@@ -152,6 +152,11 @@
"checkState":"Activation",
"checkStateSecret":"Shared secret",
"choiceParams":"Choice parameters",
"checkUsers":"Session check",
"checkUser":"Activation",
"checkUserHiddenAttributes":"Hidden attributes",
"checkUserDisplayPersistentInfo":"Display persistent session",
"checkUserDisplayEmptyValues":"Display empty values",
"chooseLogo":"Choose logo",
"chooseSkin":"Choose skin",
"combination":"Combination",
......@@ -243,7 +248,7 @@
"exportedVars":"Exported Variables",
"external2f":"External second factor",
"ext2fActivation":"Activation",
"ext2fCodeActivation":"2F code generated by Portal",
"ext2fCodeActivation":"Code regex",
"ext2fAuthnLevel":"Authentication level",
"ext2fLogo":"Logo",
"ext2FSendCommand":"Send comand",
......@@ -964,5 +969,6 @@
"samlCommonDomainCookieReader":"Reader URL",
"samlCommonDomainCookieWriter":"Writer URL",
"samlRelayStateTimeout":"RelayState session timeout",
"samlUseQueryStringSpecific":"Use specific query_string method"
}
\ No newline at end of file
"samlUseQueryStringSpecific":"Use specific query_string method",
"samlOverrideIDPEntityID": "Override Entity ID when acting as IDP"
}
......@@ -151,6 +151,11 @@
"clickHereToForce":"Click here to force",
"checkState":"Activation",
"checkStateSecret":"Shared secret",
"checkUsers":"Session check",
"checkUser":"Activation",
"checkUserHiddenAttributes":"Hidden attributes",
"checkUserDisplayPersistentInfo":"Display persistent session",
"checkUserDisplayEmptyValues":"Display empty values",
"choiceParams":"Choice parameters",
"chooseLogo":"Choose logo",
"chooseSkin":"Choose skin",
......@@ -243,7 +248,7 @@
"exportedVars":"Exported Variables",
"external2f":"External second factor",
"ext2fActivation":"Activation",
"ext2fCodeActivation":"2F code generated by Portal",
"ext2fCodeActivation":"Code regex",
"ext2fAuthnLevel":"Authentication level",
"ext2fLogo":"Logo",
"ext2FSendCommand":"Send comand",
......@@ -964,5 +969,6 @@
"samlCommonDomainCookieReader":"Reader URL",
"samlCommonDomainCookieWriter":"Writer URL",
"samlRelayStateTimeout":"RelayState session timeout",
"samlUseQueryStringSpecific":"Use specific query_string method"
"samlUseQueryStringSpecific":"Use specific query_string method",
"samlOverrideIDPEntityID": "Override Entity ID when acting as IDP"
}
......@@ -152,6 +152,11 @@
"checkState":"Activation",
"checkStateSecret":"Secret partagé",
"choiceParams":"Paramètres des choix",
"checkUsers":"Vérification de session",
"checkUser":"Activation",
"checkUserHiddenAttributes":"Attributs masqués",
"checkUserDisplayPersistentInfo":"Afficher les données de session persistante",
"checkUserDisplayEmptyValues":"Afficher les valeurs nulles",
"chooseLogo":"Choisir le logo",
"chooseSkin":"Choisir le thème",
"combination":"Combinaison",
......@@ -243,7 +248,7 @@
"exportedVars":"Attributs à exporter",
"external2f":"Second facteur externe",
"ext2fActivation":"Activation",
"ext2fCodeActivation":"2F code généré par le Portail",
"ext2fCodeActivation":"Expression régulière pour la génération du code",
"ext2fAuthnLevel":"Niveau de l'authentification",
"ext2fLogo":"Logo",
"ext2FSendCommand":"Commande pour l'envoi",
......@@ -964,5 +969,6 @@
"samlCommonDomainCookieReader":"URL de lecture",
"samlCommonDomainCookieWriter":"URL d'écriture",
"samlRelayStateTimeout":"Durée de vie d'une session RelayState",
"samlUseQueryStringSpecific":"Utilisation d'une fonction spécifique pour query_string"
"samlUseQueryStringSpecific":"Utilisation d'une fonction spécifique pour query_string",
"samlOverrideIDPEntityID": "Valeur de l'Entity ID en mode IDP"
}
......@@ -151,6 +151,11 @@
"clickHereToForce":"Clicca qui per forzare",
"checkState":"Attivazione",
"checkStateSecret":"Segreto condiviso",
"checkUsers":"Session check",
"checkUser":"Activation",
"checkUserHiddenAttributes":"Hidden attributes",
"checkUserDisplayPersistentInfo":"Display persistent session",
"checkUserDisplayEmptyValues":"Display empty values",
"choiceParams":"Scelta parametri",
"chooseLogo":"Scegli logo",
"chooseSkin":"Scegli interfaccia",
......@@ -243,7 +248,7 @@
"exportedVars":"Variabili esportate",
"external2f":"2° fattore esterno",
"ext2fActivation":"Attivazione",
"ext2fCodeActivation":"2F code generated by Portal",
"ext2fCodeActivation":"Code regex",
"ext2fAuthnLevel":"Livello di autenticazione",
"ext2fLogo":"Logo",
"ext2FSendCommand":"Invia comando",
......@@ -964,5 +969,6 @@
"samlCommonDomainCookieReader":"URL del lettore",
"samlCommonDomainCookieWriter":"URL dell'autore",
"samlRelayStateTimeout":"Timeout di sessione di RelayState",
"samlUseQueryStringSpecific":"Utilizza il metodo specifico query_string"
}
\ No newline at end of file
"samlUseQueryStringSpecific":"Utilizza il metodo specifico query_string",
"samlOverrideIDPEntityID": "Override Entity ID when acting as IDP"
}