Merge remote-tracking branch 'origin/v2.0'

This commit is contained in:
Christophe Maudoux 2019-06-10 21:06:47 +02:00
commit aabb65629b
27 changed files with 404 additions and 270 deletions

View File

@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "llng-fastcgi-server 1"
.TH llng-fastcgi-server 1 "2019-04-23" "perl v5.28.1" "User Contributed Perl Documentation"
.TH llng-fastcgi-server 1 "2019-06-06" "perl v5.28.1" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l

View File

@ -24,7 +24,7 @@ use constant MANAGERSECTION => "manager";
use constant SESSIONSEXPLORERSECTION => "sessionsExplorer";
use constant APPLYSECTION => "apply";
our $hashParameters = qr/^(?:(?:l(?:o(?:ca(?:lSessionStorageOption|tionRule)|goutService)|dapExportedVar|wp(?:Ssl)?Opt)|(?:(?:d(?:emo|bi)|facebook|webID)ExportedVa|exported(?:Heade|Va)|issuerDBGetParamete)r|re(?:moteGlobalStorageOption|st2f(?:Verify|Init)Arg|loadUrl)|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|macro)s|o(?:idc(?:RPMetaData(?:(?:Option(?:sExtraClaim)?|ExportedVar)s|Node)|OPMetaData(?:(?:ExportedVar|Option)s|J(?:SON|WKS)|Node)|S(?:erviceMetaDataAuthnContext|torageOptions))|penIdExportedVars)|s(?:aml(?:S(?:PMetaData(?:(?:ExportedAttribute|Option)s|Node|XML)|torageOptions)|IDPMetaData(?:(?:ExportedAttribute|Option)s|Node|XML))|essionDataToRemember|laveExportedVars)|c(?:as(?:S(?:rvMetaData(?:(?:ExportedVar|Option)s|Node)|torageOptions)|A(?:ppMetaData(?:(?:ExportedVar|Option)s|Node)|ttributes))|(?:ustomAddParam|ombModule)s)|p(?:ersistentStorageOptions|o(?:rtalSkinRules|st))|a(?:ut(?:hChoiceMod|oSigninR)ules|pplicationList)|v(?:hostOptions|irtualHost)|S(?:MTPTLSOpts|SLVarIf))$/;
our $boolKeys = qr/^(?:s(?:aml(?:IDP(?:MetaDataOptions(?:(?:Check(?:S[LS]OMessageSignatur|Audienc|Tim)|IsPassiv)e|A(?:llow(?:LoginFromIDP|ProxiedAuthn)|daptSessionUtime)|Force(?:Authn|UTF8)|StoreSAMLToken|RelayStateURL)|SSODescriptorWantAuthnRequestsSigned)|S(?:P(?:MetaDataOptions(?:(?:CheckS[LS]OMessageSignatur|OneTimeUs)e|EnableIDPInitiatedURL|ForceUTF8)|SSODescriptor(?:WantAssertion|AuthnRequest)sSigned)|erviceUseCertificateInResponse)|DiscoveryProtocol(?:Activation|IsPassive)|CommonDomainCookieActivation|UseQueryStringSpecific|MetadataForceUTF8)|ingle(?:Session(?:UserByIP)?|(?:UserBy)?IP)|oap(?:Session|Config)Server|t(?:ayConnecte|orePasswor)d|kipRenewConfirmation|howLanguages|slByAjax)|o(?:idc(?:ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration)|RPMetaDataOptions(?:LogoutSessionRequired|BypassConsent|RequirePKCE|Public)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|p(?:ortal(?:ErrorOn(?:ExpiredSession|MailNotFound)|DisplayRe(?:setPassword|gister)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|RequireOldPassword|ForceAuthn|AntiFrame)|roxyUseSoap)|l(?:dap(?:(?:Group(?:DecodeSearchedValu|Recursiv)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl)|oginHistoryEnabled)|c(?:a(?:ptcha_(?:register|login|mail)_enabled|sSrvMetaDataOptions(?:Gateway|Renew))|heck(?:User(?:Display(?:PersistentInfo|EmptyValues))?|State|XSS)|orsEnabled|da)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonation(?:SkipEmptyValue|MergeSSOgroup)s)|to(?:tp2f(?:UserCan(?:Chang|Remov)eKey|DisplayExistingSecret)|kenUseGlobalStorage)|u(?:se(?:RedirectOn(?:Forbidden|Error)|SafeJail)|2fUserCanRemoveKey|pgradeSession)|no(?:tif(?:ication(?:Server)?|y(?:Deleted|Other))|AjaxHook)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|(?:(?:rest(?:Session|Config)|wsdl)Serv|activeTim)er|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|krb(?:RemoveDomain|ByJs)|dbiDynamicHashEnabled|bruteForceProtection)$/;
our $boolKeys = qr/^(?:s(?:aml(?:IDP(?:MetaDataOptions(?:(?:Check(?:S[LS]OMessageSignatur|Audienc|Tim)|IsPassiv)e|A(?:llow(?:LoginFromIDP|ProxiedAuthn)|daptSessionUtime)|Force(?:Authn|UTF8)|StoreSAMLToken|RelayStateURL)|SSODescriptorWantAuthnRequestsSigned)|S(?:P(?:MetaDataOptions(?:(?:CheckS[LS]OMessageSignatur|OneTimeUs)e|EnableIDPInitiatedURL|ForceUTF8)|SSODescriptor(?:WantAssertion|AuthnRequest)sSigned)|erviceUseCertificateInResponse)|DiscoveryProtocol(?:Activation|IsPassive)|CommonDomainCookieActivation|UseQueryStringSpecific|MetadataForceUTF8)|ingle(?:Session(?:UserByIP)?|(?:UserBy)?IP)|oap(?:Session|Config)Server|t(?:ayConnecte|orePasswor)d|kipRenewConfirmation|howLanguages|slByAjax)|o(?:idc(?:ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration)|RPMetaDataOptions(?:LogoutSessionRequired|BypassConsent|RequirePKCE|Public)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|p(?:ortal(?:ErrorOn(?:ExpiredSession|MailNotFound)|DisplayRe(?:setPassword|gister)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|RequireOldPassword|ForceAuthn|AntiFrame)|roxyUseSoap)|l(?:dap(?:(?:Group(?:DecodeSearchedValu|Recursiv)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl)|oginHistoryEnabled)|c(?:a(?:ptcha_(?:register|login|mail)_enabled|sSrvMetaDataOptions(?:Gateway|Renew))|heck(?:User(?:Display(?:PersistentInfo|EmptyValues))?|State|XSS)|orsEnabled|da)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonationSkipEmptyValues)|to(?:tp2f(?:UserCan(?:Chang|Remov)eKey|DisplayExistingSecret)|kenUseGlobalStorage)|u(?:se(?:RedirectOn(?:Forbidden|Error)|SafeJail)|2fUserCanRemoveKey|pgradeSession)|no(?:tif(?:ication(?:Server)?|y(?:Deleted|Other))|AjaxHook)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|(?:(?:rest(?:Session|Config)|wsdl)Serv|activeTim)er|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|krb(?:RemoveDomain|ByJs)|dbiDynamicHashEnabled|bruteForceProtection)$/;
our @sessionTypes = ( 'remoteGlobal', 'global', 'localSession', 'persistent', 'saml', 'oidc', 'cas' );

View File

@ -83,6 +83,7 @@ sub defaultValues {
'https' => -1,
'impersonationHiddenAttributes' => '_2fDevices _loginHistory',
'impersonationIdRule' => 1,
'impersonationMergeSSOgroups' => 0,
'impersonationPrefix' => 'real_',
'impersonationRule' => 0,
'impersonationSkipEmptyValues' => 1,

View File

@ -3,6 +3,22 @@ package Lemonldap::NG::Manager::Attributes;
our $VERSION = '2.1.0';
sub perlExpr {
my ( $val, $conf ) = @_;
my $cpt = 'Safe'->new;
$cpt->share_from( 'MIME::Base64', ['&encode_base64'] );
$cpt->share_from( 'Lemonldap::NG::Handler::Main::Jail',
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; } split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
}
sub types {
return {
'array' => {
@ -27,21 +43,7 @@ sub types {
'boolOrExpr' => {
'msgFail' => '__notAValidPerlExpression__',
'test' => sub {
my ( $val, $conf ) = @_;
my $s = '';
my $cpt = 'Safe'->new;
$cpt->share_from( 'MIME::Base64', ['&encode_base64'] );
$cpt->share_from( 'Lemonldap::NG::Handler::Main::Jail',
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
return perlExpr(@_);
}
},
'catAndAppList' => {
@ -669,21 +671,7 @@ sub attributes {
},
'casAppMetaDataOptionsRule' => {
'test' => sub {
my ( $val, $conf ) = @_;
my $s = '';
my $cpt = 'Safe'->new;
$cpt->share_from( 'MIME::Base64', ['&encode_base64'] );
$cpt->share_from( 'Lemonldap::NG::Handler::Main::Jail',
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
return perlExpr(@_);
},
'type' => 'text'
},
@ -804,21 +792,7 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
'checkUserIdRule' => {
'default' => 1,
'test' => sub {
my ( $val, $conf ) = @_;
my $s = '';
my $cpt = 'Safe'->new;
$cpt->share_from( 'MIME::Base64', ['&encode_base64'] );
$cpt->share_from( 'Lemonldap::NG::Handler::Main::Jail',
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
return perlExpr(@_);
},
'type' => 'text'
},
@ -1127,21 +1101,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
'keyMsgFail' => '__badHeaderName__',
'keyTest' => qr/^(?=[^\-])[\w\-]+(?<=[^-])$/,
'test' => sub {
my ( $val, $conf ) = @_;
my $s = $val;
my $cpt = 'Safe'->new;
$cpt->share_from( 'MIME::Base64', ['&encode_base64'] );
$cpt->share_from( 'Lemonldap::NG::Handler::Main::Jail',
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $s");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
return perlExpr(@_);
}
},
'type' => 'keyTextContainer'
@ -1233,21 +1193,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
},
'grantSessionRules' => {
'keyTest' => sub {
my ( $val, $conf ) = @_;
my $s = '';
my $cpt = 'Safe'->new;
$cpt->share_from( 'MIME::Base64', ['&encode_base64'] );
$cpt->share_from( 'Lemonldap::NG::Handler::Main::Jail',
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
return perlExpr(@_);
},
'test' => sub {
1;
@ -1257,21 +1203,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
'groups' => {
'default' => {},
'test' => sub {
my ( $val, $conf ) = @_;
my $s = '';
my $cpt = 'Safe'->new;
$cpt->share_from( 'MIME::Base64', ['&encode_base64'] );
$cpt->share_from( 'Lemonldap::NG::Handler::Main::Jail',
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
return perlExpr(@_);
},
'type' => 'keyTextContainer'
},
@ -1306,27 +1238,13 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
'impersonationIdRule' => {
'default' => 1,
'test' => sub {
my ( $val, $conf ) = @_;
my $s = '';
my $cpt = 'Safe'->new;
$cpt->share_from( 'MIME::Base64', ['&encode_base64'] );
$cpt->share_from( 'Lemonldap::NG::Handler::Main::Jail',
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
return perlExpr(@_);
},
'type' => 'text'
},
'impersonationMergeSSOgroups' => {
'default' => 0,
'type' => 'bool'
'type' => 'boolOrExpr'
},
'impersonationPrefix' => {
'default' => 'real_',
@ -1666,19 +1584,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
: ( 0, '__badUrl__' );
}
$s =~ s/\b(accept|deny|unprotect|skip)\b/1/g;
my $cpt = 'Safe'->new;
$cpt->share_from( 'MIME::Base64', ['&encode_base64'] );
$cpt->share_from( 'Lemonldap::NG::Handler::Main::Jail',
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $s");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
return &perlExpr( $s, $conf );
}
},
'type' => 'ruleContainer'
@ -1711,21 +1617,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
'keyMsgFail' => '__badMacroName__',
'keyTest' => qr/^[_a-zA-Z][a-zA-Z0-9_]*$/,
'test' => sub {
my ( $val, $conf ) = @_;
my $s = '';
my $cpt = 'Safe'->new;
$cpt->share_from( 'MIME::Base64', ['&encode_base64'] );
$cpt->share_from( 'Lemonldap::NG::Handler::Main::Jail',
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
return perlExpr(@_);
},
'type' => 'keyTextContainer'
},
@ -2107,21 +1999,7 @@ qr/^(?:\*\.)?(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][
},
'oidcRPMetaDataOptionsRule' => {
'test' => sub {
my ( $val, $conf ) = @_;
my $s = '';
my $cpt = 'Safe'->new;
$cpt->share_from( 'MIME::Base64', ['&encode_base64'] );
$cpt->share_from( 'Lemonldap::NG::Handler::Main::Jail',
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
return perlExpr(@_);
},
'type' => 'text'
},
@ -2462,21 +2340,7 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
'portalSkinRules' => {
'keyMsgFail' => '__badSkinRule__',
'keyTest' => sub {
my ( $val, $conf ) = @_;
my $s = '';
my $cpt = 'Safe'->new;
$cpt->share_from( 'MIME::Base64', ['&encode_base64'] );
$cpt->share_from( 'Lemonldap::NG::Handler::Main::Jail',
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
return perlExpr(@_);
},
'msgFail' => '__badValue__',
'test' => qr/^\w+$/,
@ -3211,21 +3075,7 @@ qr/(?:(?:https?):\/\/(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.]
},
'samlSPMetaDataOptionsRule' => {
'test' => sub {
my ( $val, $conf ) = @_;
my $s = '';
my $cpt = 'Safe'->new;
$cpt->share_from( 'MIME::Base64', ['&encode_base64'] );
$cpt->share_from( 'Lemonldap::NG::Handler::Main::Jail',
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $s $val");
my $err = join(
'',
grep( { $_ =~ /Undefined subroutine/ ? () : $_; }
split( /\n/, $@, 0 ) )
);
return $err ? ( 1, "__badExpression__: $err" ) : 1;
return perlExpr(@_);
},
'type' => 'text'
},
@ -3535,6 +3385,9 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
'default' => 0,
'type' => 'boolOrExpr'
},
'totp2fTTL' => {
'type' => 'int'
},
'totp2fUserCanChangeKey' => {
'default' => 0,
'type' => 'bool'
@ -3574,6 +3427,9 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
'default' => 0,
'type' => 'boolOrExpr'
},
'u2fTTL' => {
'type' => 'int'
},
'u2fUserCanRemoveKey' => {
'default' => 1,
'type' => 'bool'
@ -3775,6 +3631,9 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
'default' => 0,
'type' => 'boolOrExpr'
},
'yubikey2fTTL' => {
'type' => 'int'
},
'yubikey2fUrl' => {
'type' => 'text'
},

View File

@ -370,6 +370,9 @@ EOF
} keys(%$attributes)
};
$managerAttr = mydump( $managerAttr, 'attributes' );
my $managerSub = Dumper( \&Lemonldap::NG::Manager::Build::Attributes::perlExpr );
$managerSub =~ s/\$VAR1 = sub/sub perlExpr/s;
$managerSub =~ s/^\s*(?:use strict;|package .*?;|)\n//gm;
my $managerTypes =
mydump( Lemonldap::NG::Manager::Build::Attributes::types(), 'types' );
$managerAttr = "# This file is generated by $module. Don't modify it by hand
@ -377,6 +380,8 @@ package Lemonldap::NG::Manager::Attributes;
our \$VERSION = '$Lemonldap::NG::Manager::Build::Attributes::VERSION';
$managerSub
$managerTypes}
$managerAttr}

View File

@ -10,16 +10,15 @@ our $VERSION = '2.1.0';
use strict;
use Regexp::Common qw/URI/;
my $perlExpr = sub {
sub perlExpr {
my ( $val, $conf ) = @_;
my $s = '';
my $cpt = new Safe;
$cpt->share_from( 'MIME::Base64', ['&encode_base64'] );
$cpt->share_from( 'Lemonldap::NG::Handler::Main::Jail',
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $s $val");
$cpt->reval("BEGIN { warnings->unimport; } $val");
my $err = join( '',
grep { $_ =~ /Undefined subroutine/ ? () : $_ } split( /\n/, $@ ) );
return $err ? ( 1, "__badExpression__: $err" ) : (1);
@ -96,7 +95,7 @@ sub types {
msgFail => '__authorizedValues__: -1, 0, 1',
},
boolOrExpr => {
test => $perlExpr,
test => sub { return perlExpr(@_) },
msgFail => '__notAValidPerlExpression__',
},
keyTextContainer => {
@ -430,7 +429,7 @@ sub attributes {
},
checkUserIdRule => {
type => 'text',
test => $perlExpr,
test => sub { return perlExpr(@_) },
default => 1,
documentation => 'checkUser identities rule',
},
@ -466,7 +465,7 @@ sub attributes {
},
impersonationMergeSSOgroups => {
default => 0,
type => 'bool',
type => 'boolOrExpr',
documentation => 'Merge spoofed and real SSO groups',
flags => 'p',
},
@ -483,7 +482,7 @@ sub attributes {
},
impersonationIdRule => {
type => 'text',
test => $perlExpr,
test => sub { return perlExpr(@_) },
default => 1,
documentation => 'Impersonation identities rule',
},
@ -638,7 +637,7 @@ sub attributes {
portalSkinRules => {
type => 'keyTextContainer',
help => 'portalcustom.html',
keyTest => $perlExpr,
keyTest => sub { return perlExpr(@_) },
keyMsgFail => '__badSkinRule__',
test => qr/^\w+$/,
msgFail => '__badValue__',
@ -711,7 +710,7 @@ sub attributes {
},
grantSessionRules => {
type => 'grantContainer',
keyTest => $perlExpr,
keyTest => sub { return perlExpr(@_) },
test => sub { 1 },
documentation => 'Rules to grant sessions',
},
@ -1070,7 +1069,7 @@ sub attributes {
type => 'keyTextContainer',
help =>
'exportedvars.html#extend_variables_using_macros_and_groups',
test => $perlExpr,
test => sub { return perlExpr(@_) },
default => {},
documentation => 'Groups',
},
@ -1080,7 +1079,7 @@ sub attributes {
'exportedvars.html#extend_variables_using_macros_and_groups',
keyTest => qr/^[_a-zA-Z][a-zA-Z0-9_]*$/,
keyMsgFail => '__badMacroName__',
test => $perlExpr,
test => sub { return perlExpr(@_) },
default => {},
documentation => 'Macros',
},
@ -1381,6 +1380,10 @@ sub attributes {
default => 1,
documentation => 'Authorize users to remove existing U2F key',
},
u2fTTL => {
type => 'int',
documentation => 'U2F device time to live',
},
# TOTP second factor
totp2fActivation => {
@ -1433,6 +1436,10 @@ sub attributes {
default => 1,
documentation => 'Authorize users to remove existing TOTP secret',
},
totp2fTTL => {
type => 'int',
documentation => 'TOTP device time to live ',
},
# UTOTP 2F
utotp2fActivation => {
@ -1590,6 +1597,10 @@ sub attributes {
default => 1,
documentation => 'Authorize users to remove existing Yubikey',
},
yubikey2fTTL => {
type => 'int',
documentation => 'Yubikey device time to live',
},
# Single session
notifyDeleted => {
@ -1698,17 +1709,7 @@ sub attributes {
: ( 0, '__badUrl__' );
}
$s =~ s/\b(accept|deny|unprotect|skip)\b/1/g;
my $cpt = new Safe;
$cpt->share_from( 'MIME::Base64', ['&encode_base64'] );
$cpt->share_from( 'Lemonldap::NG::Handler::Main::Jail',
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $s");
my $err = join( '',
grep { $_ =~ /Undefined subroutine/ ? () : $_ }
split( /\n/, $@ ) );
return $err ? ( 1, "__badExpression__: $err" ) : (1);
return &perlExpr( $s, $conf );
},
msgFail => '__badExpression__',
},
@ -1726,21 +1727,7 @@ sub attributes {
test => {
keyTest => qr/^(?=[^\-])[\w\-]+(?<=[^-])$/,
keyMsgFail => '__badHeaderName__',
test => sub {
my ( $val, $conf ) = @_;
my $s = $val;
my $cpt = new Safe;
$cpt->share_from( 'MIME::Base64', ['&encode_base64'] );
$cpt->share_from( 'Lemonldap::NG::Handler::Main::Jail',
[ '&encrypt', '&token' ] );
$cpt->share_from( 'Lemonldap::NG::Common::Safelib',
$Lemonldap::NG::Common::Safelib::functions );
$cpt->reval("BEGIN { warnings->unimport; } $s");
my $err = join( '',
grep { $_ =~ /Undefined subroutine/ ? () : $_ }
split( /\n/, $@ ) );
return $err ? ( 1, "__badExpression__: $err" ) : (1);
}
test => sub { return perlExpr(@_) },
},
documentation => 'Virtualhost headers',
flags => 'h',
@ -1910,7 +1897,7 @@ sub attributes {
},
casAppMetaDataOptionsRule => {
type => 'text',
test => $perlExpr,
test => sub { return perlExpr(@_) },
documentation => 'CAS App rule',
},
@ -2514,7 +2501,7 @@ sub attributes {
},
samlSPMetaDataOptionsRule => {
type => 'text',
test => $perlExpr,
test => sub { return perlExpr(@_) },
documentation => 'Rule to grant access to this SP',
},
@ -3508,7 +3495,7 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
},
oidcRPMetaDataOptionsRule => {
type => 'text',
test => $perlExpr,
test => sub { return perlExpr(@_) },
documentation => 'Rule to grant access to this RP',
},
};

View File

@ -701,6 +701,7 @@ sub tree {
'totp2fDisplayExistingSecret',
'totp2fUserCanChangeKey',
'totp2fUserCanRemoveKey',
'totp2fTTL',
]
},
{
@ -710,6 +711,7 @@ sub tree {
nodes => [
'u2fActivation', 'u2fSelfRegistration',
'u2fAuthnLevel', 'u2fUserCanRemoveKey',
'u2fTTL',
]
},
{
@ -757,6 +759,7 @@ sub tree {
'yubikey2fUrl',
'yubikey2fPublicIDSize',
'yubikey2fUserCanRemoveKey',
'yubikey2fTTL',
],
},
'sfRequired',

View File

@ -787,8 +787,9 @@
"totp2fIssuer":"TOTP Issuer name",
"totp2fRange":"Range of attempts",
"totp2fSelfRegistration":"التسجيل الذاتي",
"totp2fTTL":"Lifetime",
"totp2fUserCanChangeKey":"Change existing secret",
"totp2fUserCanRemoveKey":"Authorize user to remove TOTP",
"totp2fUserCanRemoveKey":"Allow user to remove TOTP",
"trustedDomains":"النطاقات الموثوق بها",
"trustedProxies":"عناوين الآي بي البروكسي الموثوق بها",
"twitterAppName":"اسم التطبيق",
@ -801,8 +802,9 @@
"u2f":"U2F",
"u2fActivation":"تفعيل",
"u2fAuthnLevel":"U2F مستوى إثبات الهوية",
"u2fUserCanRemoveKey":"Authorize user to remove U2F key",
"u2fSelfRegistration":"التسجيل الذاتي",
"u2fTTL":"Lifetime",
"u2fUserCanRemoveKey":"Allow user to remove U2F key",
"uid":"المعرف",
"unknownAttrOrMacro":"سمة غير معروفة أو ماكرو",
"unknownError":"خطأ غير معروف",
@ -865,8 +867,9 @@
"yubikey2fPublicIDSize":"حجم الجزء العام لي OTP آي دي",
"yubikey2fSecretKey":"مفتاح سرأل API",
"yubikey2fSelfRegistration":"التسجيل الذاتي",
"yubikey2fTTL":"Lifetime",
"yubikey2fUrl":"خدمة أل يو أر ل",
"yubikey2fUserCanRemoveKey":"Authorize user to remove Yubikey",
"yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey",
"zeroConfExplanations":"لا يحتوي الخادم على إعدادات. استخدام قالب لحفظ الأول",
"saml":"SAML",

View File

@ -787,8 +787,9 @@
"totp2fIssuer":"TOTP Issuer name",
"totp2fRange":"Range of attempts",
"totp2fSelfRegistration":"Self registration",
"totp2fTTL":"Lifetime",
"totp2fUserCanChangeKey":"Change existing secret",
"totp2fUserCanRemoveKey":"Authorize user to remove TOTP",
"totp2fUserCanRemoveKey":"Allow user to remove TOTP",
"trustedDomains":"Trusted domains",
"trustedProxies":"Trusted proxies IP",
"twitterAppName":"Application name",
@ -801,8 +802,9 @@
"u2f":"U2F",
"u2fActivation":"Activation",
"u2fAuthnLevel":"U2F authentication level",
"u2fUserCanRemoveKey":"Authorize user to remove U2F key",
"u2fSelfRegistration":"Self registration",
"u2fTTL":"Lifetime",
"u2fUserCanRemoveKey":"Allow user to remove U2F key",
"uid":"Identifier",
"unknownAttrOrMacro":"Unknown attribute or macro",
"unknownError":"Unknown error",
@ -865,8 +867,9 @@
"yubikey2fPublicIDSize":"OTP public ID part size",
"yubikey2fSecretKey":"API secret key",
"yubikey2fSelfRegistration":"Self registration",
"yubikey2fTTL":"Lifetime",
"yubikey2fUrl":"Service URL",
"yubikey2fUserCanRemoveKey":"Authorize user to remove Yubikey",
"yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey",
"zeroConfExplanations":"Server has no configuration. Use template to save the first.",
"saml":"SAML",

View File

@ -787,8 +787,9 @@
"totp2fIssuer":"TOTP Issuer name",
"totp2fRange":"Range of attempts",
"totp2fSelfRegistration":"Self registration",
"totp2fTTL":"Lifetime",
"totp2fUserCanChangeKey":"Change existing secret",
"totp2fUserCanRemoveKey":"Authorize user to remove TOTP",
"totp2fUserCanRemoveKey":"Allow user to remove TOTP",
"trustedDomains":"Trusted domains",
"trustedProxies":"Trusted proxies IP",
"twitterAppName":"Application name",
@ -801,8 +802,9 @@
"u2f":"U2F",
"u2fActivation":"Activation",
"u2fAuthnLevel":"U2F authentication level",
"u2fUserCanRemoveKey":"Authorize user to remove U2F key",
"u2fSelfRegistration":"Self registration",
"u2fTTL":"Lifetime",
"u2fUserCanRemoveKey":"Allow user to remove U2F key",
"uid":"Identifier",
"unknownAttrOrMacro":"Unknown attribute or macro",
"unknownError":"Unknown error",
@ -865,8 +867,9 @@
"yubikey2fPublicIDSize":"OTP public ID part size",
"yubikey2fSecretKey":"API secret key",
"yubikey2fSelfRegistration":"Self registration",
"yubikey2fTTL":"Lifetime",
"yubikey2fUrl":"Service URL",
"yubikey2fUserCanRemoveKey":"Authorize user to remove Yubikey",
"yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey",
"zeroConfExplanations":"Server has no configuration. Use template to save the first.",
"saml":"SAML",

View File

@ -787,6 +787,7 @@
"totp2fIssuer":"Nom du fournisseur TOTP",
"totp2fRange":"Nombre d'intervalles à tester",
"totp2fSelfRegistration":"Auto-enregistrement",
"totp2fTTL":"Durée de vie",
"totp2fUserCanChangeKey":"Changer une clef existante",
"totp2fUserCanRemoveKey":"Autoriser les utilisateurs à effacer leur TOTP",
"trustedDomains":"Domaines approuvés",
@ -801,8 +802,9 @@
"u2f":"U2F",
"u2fActivation":"Activation",
"u2fAuthnLevel":"Niveau d'authentification U2F",
"u2fUserCanRemoveKey":"Autoriser les utilisateurs à effacer leur clef U2F",
"u2fSelfRegistration":"Auto-enregistrement",
"u2fTTL":"Durée de vie",
"u2fUserCanRemoveKey":"Autoriser les utilisateurs à effacer leur clef U2F",
"uid":"Identifiant",
"unknownAttrOrMacro":"Attribut ou macro inconnu",
"unknownError":"Erreur inconnue",
@ -865,6 +867,7 @@
"yubikey2fPublicIDSize":"Taille de la partie publique de l'OTP",
"yubikey2fSecretKey":"Clef secrète de l'API",
"yubikey2fSelfRegistration":"Auto-enregistrement",
"yubikey2fTTL":"Durée de vie",
"yubikey2fUrl":"URL du service",
"yubikey2fUserCanRemoveKey":"Autoriser les utilisateurs à effacer leur Yubikey",
"zeroConfExplanations":"Le serveur ne dispose pas de configuration. Cette configuration de base vous permet d'en initialiser une.",

View File

@ -787,6 +787,7 @@
"totp2fIssuer":"Nome dell'emittente TOTP",
"totp2fRange":"Gamma di tentativi",
"totp2fSelfRegistration":"Auto-registrazione",
"totp2fTTL":"Lifetime",
"totp2fUserCanChangeKey":"Cambia segreto esistente",
"totp2fUserCanRemoveKey":"Autorizza l'utente a rimuovere TOTP",
"trustedDomains":"Domini attendibili",
@ -801,8 +802,9 @@
"u2f":"U2F",
"u2fActivation":"Attivazione",
"u2fAuthnLevel":"Livello di autenticazione U2F",
"u2fUserCanRemoveKey":"Autorizza l'utente a rimuovere la chiave U2F",
"u2fSelfRegistration":"Auto-registrazione",
"u2fTTL":"Lifetime",
"u2fUserCanRemoveKey":"Autorizza l'utente a rimuovere la chiave U2F",
"uid":"Identificatore",
"unknownAttrOrMacro":"Attributo o macro sconosciuti",
"unknownError":"Errore sconosciuto",
@ -865,6 +867,7 @@
"yubikey2fPublicIDSize":"Dimensione della parte ID OTP pubblica",
"yubikey2fSecretKey":"Chiave segreta API",
"yubikey2fSelfRegistration":"Auto-registrazione",
"yubikey2fTTL":"Lifetime",
"yubikey2fUrl":"URL del servizio",
"yubikey2fUserCanRemoveKey":"Autorizza l'utente a rimuovere la Yubikey",
"zeroConfExplanations":"Il server non ha alcuna configurazione. Utilizza il modello per salvare il primo.",

View File

@ -787,8 +787,9 @@
"totp2fIssuer":"TOTP Issuer name",
"totp2fRange":"Range of attempts",
"totp2fSelfRegistration":"Tự đăng ký",
"totp2fTTL":"Lifetime",
"totp2fUserCanChangeKey":"Change existing secret",
"totp2fUserCanRemoveKey":"Authorize user to remove TOTP",
"totp2fUserCanRemoveKey":"Allow user to remove TOTP",
"trustedDomains":"Miền tin cậy",
"trustedProxies":"proxies IP tin cậy",
"twitterAppName":"Tên ứng dụng",
@ -801,8 +802,9 @@
"u2f":"U2F",
"u2fActivation":"Kích hoạt",
"u2fAuthnLevel":"Mức xác thực U2F",
"u2fUserCanRemoveKey":"Authorize user to remove U2F key",
"u2fSelfRegistration":"Tự đăng ký ",
"u2fTTL":"Lifetime",
"u2fUserCanRemoveKey":"Allow user to remove U2F key",
"uid":"Trình định danh",
"unknownAttrOrMacro":"Thuộc tính hoặc macro chưa xác định",
"unknownError":"Lỗi không xác định",
@ -865,8 +867,9 @@
"yubikey2fPublicIDSize":"Kích thước phần tử công khai OTP",
"yubikey2fSecretKey":"Khóa bí mật API",
"yubikey2fSelfRegistration":"Tự đăng ký",
"yubikey2fTTL":"Lifetime",
"yubikey2fUrl":"Dịch vụ URL",
"yubikey2fUserCanRemoveKey":"Authorize user to remove Yubikey",
"yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey",
"zeroConfExplanations":"Máy chủ không có cấu hình. Sử dụng mẫu để lưu đầu tiên. ",
"saml":"SAML",

View File

@ -787,8 +787,9 @@
"totp2fIssuer":"TOTP Issuer name",
"totp2fRange":"Range of attempts",
"totp2fSelfRegistration":"Self registration",
"totp2fTTL":"Lifetime",
"totp2fUserCanChangeKey":"Change existing secret",
"totp2fUserCanRemoveKey":"Authorize user to remove TOTP",
"totp2fUserCanRemoveKey":"Allow user to remove TOTP",
"trustedDomains":"Trusted domains",
"trustedProxies":"Trusted proxies IP",
"twitterAppName":"Application name",
@ -801,8 +802,9 @@
"u2f":"U2F",
"u2fActivation":"激活",
"u2fAuthnLevel":"U2F authentication level",
"u2fUserCanRemoveKey":"Authorize user to remove U2F key",
"u2fSelfRegistration":"Self registration",
"u2fTTL":"Lifetime",
"u2fUserCanRemoveKey":"Allow user to remove U2F key",
"uid":"Identifier",
"unknownAttrOrMacro":"Unknown attribute or macro",
"unknownError":"Unknown error",
@ -865,8 +867,9 @@
"yubikey2fPublicIDSize":"OTP public ID part size",
"yubikey2fSecretKey":"API secret key",
"yubikey2fSelfRegistration":"Self registration",
"yubikey2fTTL":"Lifetime",
"yubikey2fUrl":"Service URL",
"yubikey2fUserCanRemoveKey":"Authorize user to remove Yubikey",
"yubikey2fUserCanRemoveKey":"Allow user to remove Yubikey",
"zeroConfExplanations":"Server has no configuration. Use template to save the first.",
"saml":"SAML",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -126,7 +126,6 @@ sub init {
);
}
}
return 1;
}
@ -137,7 +136,6 @@ sub init {
# run() is called at each authentication, just after sessionInfo populated
sub run {
my ( $self, $req ) = @_;
my $checkLogins = $req->param('checkLogins');
my $spoofId = $req->param('spoofId') || '';
$self->logger->debug("2F checkLogins set") if ($checkLogins);
@ -145,6 +143,65 @@ sub run {
# Skip 2F unless a module has been registered
return PE_OK unless ( @{ $self->sfModules } );
# Remove expired 2F devices
my $session = $req->sessionInfo;
if ( $session->{_2fDevices} ) {
$self->logger->debug("Loading 2F Devices ...");
# Read existing 2FDevices
my $_2fDevices =
eval { from_json( $session->{_2fDevices}, { allow_nonref => 1 } ); };
if ($@) {
$self->logger->error("Bad encoding in _2fDevices: $@");
return PE_ERROR;
}
$self->logger->debug(" -> 2F Device(s) found");
# Initialize 2FDevices TTL
my $u2fTTL = $self->conf->{u2fTTL}
&& $self->conf->{u2fTTL} > 0 ? $self->conf->{u2fTTL} : 0;
my $totpTTL = $self->conf->{totp2fTTL}
&& $self->conf->{totp2fTTL} > 0 ? $self->conf->{totp2fTTL} : 0;
my $ubkTTL = $self->conf->{yubikey2fTTL}
&& $self->conf->{yubikey2fTTL} > 0 ? $self->conf->{yubikey2fTTL} : 0;
# Processing if at least one TTL is set
if ( $u2fTTL || $totpTTL || $ubkTTL ) {
my $now = time();
my $removed = 0;
$self->logger->debug("Looking for expired 2F device(s)...");
foreach my $device (@$_2fDevices) {
foreach my $type (qw(TOTP U2F UBK)) {
if ( $device->{type} eq $type ) {
if ( eval( '$' . lc($type) . 'TTL' )
&& $now - $device->{epoch} >
eval( '$' . lc($type) . 'TTL' ) )
{
$self->logger->debug(
"Remove $type -> $device->{name} / $device->{epoch}"
);
$self->userLogger->info("Remove expired $type");
$device->{type} = 'EXPIRED';
$removed++;
last;
}
}
}
}
if ($removed) {
$self->logger->debug(
"Found $removed EXPIRED 2F device(s) => Update persistent session"
);
$self->userLogger->notice(
" -> $removed EXPIRED 2F device(s) removed");
@$_2fDevices =
map { $_->{type} =~ /\bEXPIRED\b/ ? () : $_ } @$_2fDevices;
$self->p->updatePersistentSession( $req,
{ _2fDevices => to_json($_2fDevices) } );
}
}
}
# Search for authorized modules for this user
my @am;
foreach my $m ( @{ $self->sfModules } ) {

View File

@ -166,7 +166,7 @@ sub check {
}
else {
$msg =
$self->{conf}->{impersonationMergeSSOgroups}
$self->{conf}->{impersonationMergeSSOgroups} eq 1
? 'checkUserMerged'
: 'checkUser';
$msg = 'checkUserComputeSession' if $compute;

View File

@ -55,7 +55,9 @@ sub init {
sub run {
my ( $self, $req ) = @_;
return $req->authResult if $req->authResult > PE_OK; # Skip Impersonation if error during Auth process
return $req->authResult
if $req->authResult >
PE_OK; # Skip Impersonation if error during Auth process
my $statut = PE_OK;
my $loginHistory =
@ -124,24 +126,42 @@ sub run {
# Merging SSO Groups and hGroups & dedup
$spoofSession->{groups} ||= '';
$spoofSession->{hGroups} ||= {};
if ( $self->{conf}->{impersonationMergeSSOgroups} ) {
$self->userLogger->warn("MERGING SSO groups and hGroups...");
my $spg = "$self->{conf}->{impersonationPrefix}groups";
my $sphg = "$self->{conf}->{impersonationPrefix}hGroups";
my $separator = $self->{conf}->{multiValuesSeparator};
$realSession->{$spg} ||= '';
## GROUPS
my @spoofGrps = split /\Q$separator/, $spoofSession->{groups};
my @realGrps = split /\Q$separator/, $realSession->{$spg};
## hGROUPS
$realSession->{$sphg} ||= {};
# Merge specified groups/hGroups only
unless ( $self->{conf}->{impersonationMergeSSOgroups} eq 1 ) {
my %SSOgroups = map { $_, 1 } split /\Q$separator/,
$self->{conf}->{impersonationMergeSSOgroups};
$self->logger->debug("Filtering specified groups/hGroups...");
@realGrps = grep { exists $SSOgroups{$_} } @realGrps;
my %intersct =
map {
$realSession->{$sphg}->{$_}
? ( $_, $realSession->{$sphg}->{$_} )
: ()
} keys %SSOgroups;
$realSession->{$sphg} = \%intersct;
}
$self->logger->debug("Processing groups...");
my @spoofGrps = my @realGrps = ();
@spoofGrps = split /\Q$separator/, $spoofSession->{groups};
@realGrps = split /\Q$separator/, $realSession->{$spg};
@spoofGrps = ( @spoofGrps, @realGrps );
my %hash = map { $_, 1 } @spoofGrps;
$spoofSession->{groups} = join $separator, sort keys %hash;
$self->logger->debug("Processing hGroups...");
$spoofSession->{hGroups} ||= {};
$realSession->{$sphg} ||= {};
$spoofSession->{hGroups} =
{ %{ $spoofSession->{hGroups} }, %{ $realSession->{$sphg} } };
}

View File

@ -237,11 +237,9 @@ ok(
);
count(1);
expectOK($res);
ok(
$res->[2]->[0] =~
m%<span trspan="connectedAs">Connected as</span> dwho%,
'Connected as dwho'
) or print STDERR Dumper( $res->[2]->[0] );
ok( $res->[2]->[0] =~ m%<span trspan="connectedAs">Connected as</span> dwho%,
'Connected as dwho' )
or print STDERR Dumper( $res->[2]->[0] );
count(1);
# CheckUser form
@ -310,7 +308,8 @@ ok( $res->[2]->[0] =~ m%<td class="align-middle">_whatToTrace</td>%,
ok( $res->[2]->[0] =~ m%<td class="text-left">testPrefix_groups</td>%,
'Found testPrefix_groups' )
or explain( $res->[2]->[0], 'testPrefix_groups' );
ok( $res->[2]->[0] =~ m%<td class="text-left">su</td>%, 'Found su' )
ok( $res->[2]->[0] =~ m%<td class="text-left">su; su_test; test_su</td>%,
'Found "su; su_test; test_su"' )
or explain( $res->[2]->[0], 'su' );
ok( $res->[2]->[0] =~ m%<td class="text-left">testPrefix_uid</td>%,
'Found testPrefix_uid' )

View File

@ -0,0 +1,149 @@
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,
portalMainLogo => 'common/logos/logo_llng_old.png',
requireToken => 0,
checkUser => 1,
impersonationRule => 1,
checkUserDisplayPersistentInfo => 0,
checkUserDisplayEmptyValues => 0,
impersonationMergeSSOgroups => 'su; _test_; su_test; sutest',
}
}
);
## Try to authenticate
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', );
count(1);
my ( $host, $url, $query ) =
expectForm( $res, '#', undef, 'user', 'password', 'spoofId' );
$query =~ s/user=/user=rtyler/;
$query =~ s/password=/password=rtyler/;
$query =~ s/spoofId=/spoofId=dwho/;
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/' );
# Get Menu
# ------------------------
ok(
$res = $client->_get(
'/',
cookie => "lemonldap=$id",
accept => 'text/html'
),
'Get Menu',
);
count(1);
expectOK($res);
ok(
$res->[2]->[0] =~
m%<span trspan="connectedAs">Connected as</span> dwho%,
'Connected as dwho'
) or print STDERR Dumper( $res->[2]->[0] );
expectAuthenticatedAs( $res, 'dwho' );
count(1);
# CheckUser form
# ------------------------
ok(
$res = $client->_get(
'/checkuser',
cookie => "lemonldap=$id",
accept => 'text/html'
),
'CheckUser form',
);
count(1);
( $host, $url, $query ) =
expectForm( $res, undef, '/checkuser', 'user', 'url' );
ok( $res->[2]->[0] =~ m%<span trspan="checkUserMerged">%,
'Found trspan="checkUserMerged"' )
or explain( $res->[2]->[0], 'trspan="checkUserMerged"' );
count(1);
$query =~ s/url=/url=test1.example.com/;
ok(
$res = $client->_post(
'/checkuser',
IO::String->new($query),
cookie => "lemonldap=$id",
length => length($query),
accept => 'text/html',
),
'POST checkuser'
);
count(1);
( $host, $url, $query ) =
expectForm( $res, undef, '/checkuser', 'user', 'url' );
ok( $res->[2]->[0] =~ m%<span trspan="checkUser">%,
'Found trspan="checkUser"' )
or explain( $res->[2]->[0], 'trspan="checkUser"' );
ok(
$res->[2]->[0] =~
m%<div class="alert alert-success"><b><span trspan="allowed"></span></b></div>%,
'Found trspan="allowed"'
) or explain( $res->[2]->[0], 'trspan="allowed"' );
ok( $res->[2]->[0] =~ m%<span trspan="headers">%, 'Found trspan="headers"' )
or explain( $res->[2]->[0], 'trspan="headers"' );
ok( $res->[2]->[0] =~ m%<span trspan="groups_sso">%,
'Found trspan="groups_sso"' )
or explain( $res->[2]->[0], 'trspan="groups_sso"' );
ok( $res->[2]->[0] =~ m%<span trspan="macros">%, 'Found trspan="macros"' )
or explain( $res->[2]->[0], 'trspan="macros"' );
ok( $res->[2]->[0] =~ m%<span trspan="attributes">%,
'Found trspan="attributes"' )
or explain( $res->[2]->[0], 'trspan="attributes"' );
ok( $res->[2]->[0] =~ m%<td class="text-left">_userDB</td>%, 'Found _userDB' )
or explain( $res->[2]->[0], '_userDB' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">Auth-User</td>%,
'Found Auth-User' )
or explain( $res->[2]->[0], 'Header Key: Auth-User' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">dwho</td>%, 'Found dwho' )
or explain( $res->[2]->[0], 'Header Value: dwho' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">su</td>%, 'Found su' )
or explain( $res->[2]->[0], 'SSO Groups: su' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">su_test</td>%, 'Found su_test' )
or explain( $res->[2]->[0], 'SSO Groups: su_test' );
ok( $res->[2]->[0] !~ m%<td class="align-middle">_test_</td>%, 'NOT found _test_' )
or explain( $res->[2]->[0], 'SSO Groups: _test_' );
ok( $res->[2]->[0] !~ m%<td class="align-middle">test_su</td>%, 'NOT found test_su' )
or explain( $res->[2]->[0], 'SSO Groups: test_su' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">_whatToTrace</td>%,
'Found _whatToTrace' )
or explain( $res->[2]->[0], 'Macro Key _whatToTrace' );
ok( $res->[2]->[0] =~ m%<td class="text-left">uid</td>%, 'Found uid' )
or explain( $res->[2]->[0], 'Attribute Value uid' );
count(15);
$client->logout($id);
clean_sessions();
done_testing( count() );

View File

@ -116,6 +116,15 @@ ok( $res->[2]->[0] =~ m%<span trspan="headers">%, 'Found trspan="headers"' )
ok( $res->[2]->[0] =~ m%<span trspan="groups_sso">%,
'Found trspan="groups_sso"' )
or explain( $res->[2]->[0], 'trspan="groups_sso"' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">su</td>%,
'Found SSO group "su"' )
or explain( $res->[2]->[0], 'Found SSOO group "su"' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">su_test</td>%,
'Found SSO group "su_test"' )
or explain( $res->[2]->[0], 'Found SSO group "su_test"' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">test_su</td>%,
'Found SSO group "test_su"' )
or explain( $res->[2]->[0], 'Found SSO group "test_su"' );
ok( $res->[2]->[0] =~ m%<span trspan="macros">%, 'Found trspan="macros"' )
or explain( $res->[2]->[0], 'trspan="macros"' );
ok( $res->[2]->[0] =~ m%<span trspan="attributes">%,
@ -130,12 +139,18 @@ ok( $res->[2]->[0] =~ m%<td class="align-middle">dwho</td>%, 'Found dwho' )
or explain( $res->[2]->[0], 'Header Value: dwho' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">su</td>%, 'Found su' )
or explain( $res->[2]->[0], 'SSO Groups: su' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">su_test</td>%, 'Found su_test' )
or explain( $res->[2]->[0], 'SSO Groups: su_test' );
ok( $res->[2]->[0] !~ m%<td class="align-middle">_test_</td>%, 'NOT found _test_' )
or explain( $res->[2]->[0], 'SSO Groups: _test_' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">test_su</td>%, 'Found test_su' )
or explain( $res->[2]->[0], 'SSO Groups: test_su' );
ok( $res->[2]->[0] =~ m%<td class="align-middle">_whatToTrace</td>%,
'Found _whatToTrace' )
or explain( $res->[2]->[0], 'Macro Key _whatToTrace' );
ok( $res->[2]->[0] =~ m%<td class="text-left">uid</td>%, 'Found uid' )
or explain( $res->[2]->[0], 'Attribute Value uid' );
count(12);
count(18);
$client->logout($id);
clean_sessions();

View File

@ -154,8 +154,7 @@ ok(
count(1);
expectOK($res);
ok(
$res->[2]->[0] =~
m%<span trspan="connectedAs">Connected as</span> msmith%,
$res->[2]->[0] =~ m%<span trspan="connectedAs">Connected as</span> msmith%,
'Connected as msmith'
) or print STDERR Dumper( $res->[2]->[0] );
expectAuthenticatedAs( $res, 'msmith' );
@ -235,11 +234,9 @@ ok(
);
count(1);
expectOK($res);
ok(
$res->[2]->[0] =~
m%<span trspan="connectedAs">Connected as</span> dwho%,
'Connected as dwho'
) or print STDERR Dumper( $res->[2]->[0] );
ok( $res->[2]->[0] =~ m%<span trspan="connectedAs">Connected as</span> dwho%,
'Connected as dwho' )
or print STDERR Dumper( $res->[2]->[0] );
expectAuthenticatedAs( $res, 'dwho' );
count(1);
@ -309,7 +306,8 @@ ok( $res->[2]->[0] =~ m%<td class="align-middle">_whatToTrace</td>%,
ok( $res->[2]->[0] =~ m%<td class="text-left">testPrefix_groups</td>%,
'Found testPrefix_groups' )
or explain( $res->[2]->[0], 'testPrefix_groups' );
ok( $res->[2]->[0] =~ m%<td class="text-left">su</td>%, 'Found su' )
ok( $res->[2]->[0] =~ m%<td class="text-left">su; su_test; test_su</td>%,
'Found "su; su_test; test_su"' )
or explain( $res->[2]->[0], 'su' );
ok( $res->[2]->[0] =~ m%<td class="text-left">testPrefix_uid</td>%,
'Found testPrefix_uid' )

View File

@ -3,7 +3,7 @@ use strict;
use IO::String;
require 't/test-lib.pm';
my $maintests = 16;
my $maintests = 17;
SKIP: {
eval { require Convert::Base32 };
@ -17,6 +17,7 @@ SKIP: {
logLevel => 'error',
totp2fSelfRegistration => 1,
totp2fActivation => 1,
totp2fTTL => 2,
portalMainLogo => 'common/logos/logo_llng_old.png',
}
}
@ -82,7 +83,7 @@ SKIP: {
ok( $code = Lemonldap::NG::Common::TOTP::_code( undef, $key, 0, 30, 6 ),
'Code' );
ok( $code =~ /^\d{6}$/, 'Code contains 6 digits' );
my $s = "code=$code&token=$token";
my $s = "code=$code&token=$token&TOTPName=myTOTP";
ok(
$res = $client->_post(
'/2fregisters/totp/verify',
@ -122,6 +123,22 @@ SKIP: {
);
$id = expectCookie($res);
$client->logout($id);
diag 'Waiting';
sleep 3;
# Try to sign-in
ok(
$res = $client->_post(
'/',
IO::String->new('user=dwho&password=dwho'),
length => 23,
accept => 'text/html',
),
'Auth query'
);
$id = expectCookie($res);
expectRedirection( $res, 'http://auth.example.com/' );
}
count($maintests);

View File

@ -4,7 +4,7 @@ use IO::String;
use Data::Dumper;
require 't/test-lib.pm';
my $maintests = 51;
my $maintests = 52;
SKIP: {
eval { require Convert::Base32 };
@ -92,7 +92,7 @@ SKIP: {
ok( $code = Lemonldap::NG::Common::TOTP::_code( undef, $key, 0, 30, 6 ),
'Code' );
ok( $code =~ /^\d{6}$/, 'Code contains 6 digits' );
my $s = "code=$code&token=$token";
my $s = "code=$code&token=$token&TOTPName=myTOTP";
ok(
$res = $client->_post(
'/2fregisters/totp/verify',
@ -276,6 +276,9 @@ JjTJecOOS+88fK8qL1TrYv5rapIdqUI7aQ==
or print STDERR Dumper($res);
ok( $sf[0] eq 'TOTP', 'TOTP device found' ) or print STDERR Dumper( \@sf );
ok( $sf[1] eq 'U2F', 'U2F device found' ) or print STDERR Dumper( \@sf );
ok( $res->[2]->[0] =~ qr%<td class="align-middle">myTOTP</td>%,
'Found TOTP name' )
or print STDERR Dumper($res);
# Unregister TOTP
ok( $res->[2]->[0] =~ qr%TOTP.*epoch.*(\d{10})%m, "TOTP epoch $1 found" )

View File

@ -71,7 +71,7 @@
"LockDirectory": "t/sessions/lock",
"generateModule": "Lemonldap::NG::Common::Apache::Session::Generate::SHA256"
},
"groups": { "su":"$uid eq \"rtyler\"" },
"groups": { "su":"$uid eq \"rtyler\"", "test_su": "$uid eq \"rtyler\"", "su_test": "$uid eq \"rtyler\"" },
"key": "qwertyui",
"locationRules": {
"auth.example.com" : {