Merge branch 'v2.0' into findUser
This commit is contained in:
commit
cd37ccc35c
|
@ -28,6 +28,21 @@
|
|||
auth_request_set $headervalue14 $upstream_http_headervalue14;
|
||||
auth_request_set $headername15 $upstream_http_headername15;
|
||||
auth_request_set $headervalue15 $upstream_http_headervalue15;
|
||||
auth_request_set $deleteheader1 $upstream_http_deleteheader1;
|
||||
auth_request_set $deleteheader2 $upstream_http_deleteheader2;
|
||||
auth_request_set $deleteheader3 $upstream_http_deleteheader3;
|
||||
auth_request_set $deleteheader4 $upstream_http_deleteheader4;
|
||||
auth_request_set $deleteheader5 $upstream_http_deleteheader5;
|
||||
auth_request_set $deleteheader6 $upstream_http_deleteheader6;
|
||||
auth_request_set $deleteheader7 $upstream_http_deleteheader7;
|
||||
auth_request_set $deleteheader8 $upstream_http_deleteheader8;
|
||||
auth_request_set $deleteheader9 $upstream_http_deleteheader9;
|
||||
auth_request_set $deleteheader10 $upstream_http_deleteheader10;
|
||||
auth_request_set $deleteheader11 $upstream_http_deleteheader11;
|
||||
auth_request_set $deleteheader12 $upstream_http_deleteheader12;
|
||||
auth_request_set $deleteheader13 $upstream_http_deleteheader13;
|
||||
auth_request_set $deleteheader14 $upstream_http_deleteheader14;
|
||||
auth_request_set $deleteheader15 $upstream_http_deleteheader15;
|
||||
auth_request_set $lmcookie $upstream_http_cookie;
|
||||
access_by_lua '
|
||||
local i = 1
|
||||
|
@ -38,7 +53,16 @@
|
|||
else
|
||||
break
|
||||
end
|
||||
i = i +1
|
||||
i = i + 1
|
||||
end
|
||||
i = 1
|
||||
while true do
|
||||
if ngx.var["deleteheader"..i] ~= nil then
|
||||
ngx.req.clear_header(ngx.var["deleteheader"..i])
|
||||
else
|
||||
break
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
';
|
||||
|
||||
|
|
|
@ -207,7 +207,11 @@ Password
|
|||
reset (default: TRUE).
|
||||
- **Allow a user to reset his expired password**: if activated, the
|
||||
user will be prompted to change password if his password is expired
|
||||
(default: 0)
|
||||
(default: disabled)
|
||||
- **Search for user before password change**: this option forces the password
|
||||
change module to search for the user again, refreshing its DN. This feature
|
||||
is only useful in rare cases when you use LDAP as the password module, but
|
||||
not as the UserDB module. (default: enabled)
|
||||
- **IBM Tivoli DS support**: enable this option if you use ITDS. LL::NG
|
||||
will then scan error message to return a more precise error to the
|
||||
user.
|
||||
|
|
|
@ -192,6 +192,33 @@ In this example we have:
|
|||
'exportedHeaders/test.example.com' 'Auth-User' '$uid' \
|
||||
'exportedHeaders/test.example.com' 'Auth-Mail' '$mail'
|
||||
|
||||
Configure form replay
|
||||
---------------------
|
||||
|
||||
To add form replay on a host, you need to set the catched URI and
|
||||
the variables to post.
|
||||
|
||||
In this example we have:
|
||||
|
||||
- Host: test.example.com
|
||||
- Catched URI: /login.php
|
||||
- jQuery URL: default
|
||||
|
||||
- Variables:
|
||||
- login: $uid
|
||||
- password: $_password
|
||||
|
||||
::
|
||||
|
||||
/usr/share/lemonldap-ng/bin/lemonldap-ng-cli -yes 1 -sep , \
|
||||
addKey \
|
||||
post,test.example.com,'/login.php' jqueryUrl default
|
||||
|
||||
/usr/share/lemonldap-ng/bin/lemonldap-ng-cli -yes 1 -sep , \
|
||||
addPostVars \
|
||||
post,test.example.com,'/login.php' login '$uid' \
|
||||
post,test.example.com,'/login.php' password '$_password'
|
||||
|
||||
Configure LDAP authentication backend
|
||||
-------------------------------------
|
||||
|
||||
|
|
|
@ -20,6 +20,13 @@ backups and a rollback plan ready!
|
|||
2.0.10
|
||||
------
|
||||
|
||||
A vulnerability affecting LemonLDAP::NG installations has been found out when ALL following criteria apply:
|
||||
|
||||
* Your handler server uses Nginx
|
||||
* Your virtual host configuration contains per-URL 'skip' or 'unprotect' access rule
|
||||
|
||||
In this situation, you have to update your LUA configuration file like ``/etc/nginx/nginx-lua-headers.conf``
|
||||
|
||||
- New dependency: IO::Socket::Timeout
|
||||
- TOTP check tolerates forward AND backward clock drift (totp2fRange)
|
||||
- Avoid assignment in expressions option is disabled by default
|
||||
|
|
|
@ -30,7 +30,7 @@ use constant DEFAULTCONFBACKENDOPTIONS => (
|
|||
dirName => '/usr/local/lemonldap-ng/data/conf',
|
||||
);
|
||||
our $hashParameters = qr/^(?:(?:l(?:o(?:ca(?:lSessionStorageOption|tionRule)|goutService)|dapExportedVar|wp(?:Ssl)?Opt)|(?:(?:d(?:emo|bi)|webID)ExportedVa|exported(?:Heade|Va)|issuerDBGetParamete)r|f(?:indUser(?:Exclud|Search)ingAttribute|acebookExportedVar)|re(?:moteGlobalStorageOption|st2f(?:Verify|Init)Arg|loadUrl)|g(?:r(?:antSessionRule|oup)|lobalStorageOption)|n(?:otificationStorageOption|ginxCustomHandler)|macro)s|o(?:idc(?:S(?:ervice(?:DynamicRegistrationEx(?:portedVar|traClaim)s|MetaDataAuthnContext)|torageOptions)|RPMetaData(?:(?:Option(?:sExtraClaim)?|ExportedVar|Macro)s|Node)|OPMetaData(?:(?:ExportedVar|Option)s|J(?:SON|WKS)|Node))|penIdExportedVars)|c(?:as(?:A(?:ppMetaData(?:(?:ExportedVar|Option|Macro)s|Node)|ttributes)|S(?:rvMetaData(?:(?:ExportedVar|Option)s|Node)|torageOptions))|(?:ustom(?:Plugins|Add)Param|heckUserHiddenHeader|ombModule)s)|s(?:aml(?:S(?:PMetaData(?:(?:ExportedAttribute|Option|Macro)s|Node|XML)|torageOptions)|IDPMetaData(?:(?:ExportedAttribute|Option)s|Node|XML))|essionDataToRemember|laveExportedVars|fExtra)|a(?:(?:daptativeAuthenticationLevelR|ut(?:hChoiceMod|oSigninR))ules|pplicationList)|p(?:ersistentStorageOptions|o(?:rtalSkinRules|st))|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)|f(?:RemovedUseNotif|OnlyUpgrade)|kip(?:Upgrade|Renew)Confirmation|oap(?:Session|Config)Server|t(?:ayConnecte|orePasswor)d|laveDisplayLogo|howLanguages|slByAjax)|o(?:idc(?:RPMetaDataOptions(?:Allow(?:PasswordGrant|Offline)|Re(?:freshToken|quirePKCE)|LogoutSessionRequired|IDTokenForceClaims|BypassConsent|Public)|ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|p(?:ortal(?:Display(?:Re(?:freshMyRights|setPassword|gister)|CertificateResetByMail|GeneratePassword|PasswordPolicy)|ErrorOn(?:ExpiredSession|MailNotFound)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|ForceAuthn|AntiFrame)|roxyUseSoap)|c(?:o(?:ntextSwitching(?:Allowed2fModifications|StopWithLogout)|mpactConf|rsEnabled)|a(?:ptcha_(?:register|login|mail)_enabled|sSrvMetaDataOptions(?:Gateway|Renew))|heck(?:State|User|XSS)|da)|l(?:dap(?:(?:Group(?:DecodeSearchedValu|Recursiv)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl|ITDS)|oginHistoryEnabled)|no(?:tif(?:ication(?:Server(?:(?:POS|GE)T|DELETE)?|sExplorer)?|y(?:Deleted|Other))|AjaxHook)|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)|re(?:st(?:(?:Password|Session|Config|Auth)Server|ExportSecretKeys)|freshSessions)|br(?:uteForceProtection(?:IncrementalTempo)?|owsersDontStorePassword)|d(?:is(?:ablePersistentStorage|playSessionId)|biDynamicHashEnabled)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|g(?:roupsBeforeMacros|lobalLogoutTimer)|a(?:voidAssignment|ctiveTimer)|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|krb(?:RemoveDomain|ByJs)|(?:wsdlServ|findUs)er)$/;
|
||||
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)|f(?:RemovedUseNotif|OnlyUpgrade)|kip(?:Upgrade|Renew)Confirmation|oap(?:Session|Config)Server|t(?:ayConnecte|orePasswor)d|laveDisplayLogo|howLanguages|slByAjax)|o(?:idc(?:RPMetaDataOptions(?:Allow(?:PasswordGrant|Offline)|Re(?:freshToken|quirePKCE)|LogoutSessionRequired|IDTokenForceClaims|BypassConsent|Public)|ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|p(?:ortal(?:Display(?:Re(?:freshMyRights|setPassword|gister)|CertificateResetByMail|GeneratePassword|PasswordPolicy)|ErrorOn(?:ExpiredSession|MailNotFound)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|ForceAuthn|AntiFrame)|roxyUseSoap)|l(?:dap(?:(?:G(?:roup(?:DecodeSearchedValu|Recursiv)|etUserBeforePasswordChang)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl|ITDS)|oginHistoryEnabled)|c(?:o(?:ntextSwitching(?:Allowed2fModifications|StopWithLogout)|mpactConf|rsEnabled)|a(?:ptcha_(?:register|login|mail)_enabled|sSrvMetaDataOptions(?:Gateway|Renew))|heck(?:State|User|XSS)|da)|no(?:tif(?:ication(?:Server(?:(?:POS|GE)T|DELETE)?|sExplorer)?|y(?:Deleted|Other))|AjaxHook)|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)|re(?:st(?:(?:Password|Session|Config|Auth)Server|ExportSecretKeys)|freshSessions)|br(?:uteForceProtection(?:IncrementalTempo)?|owsersDontStorePassword)|d(?:is(?:ablePersistentStorage|playSessionId)|biDynamicHashEnabled)|(?:mai(?:lOnPasswordChang|ntenanc)|vhostMaintenanc)e|g(?:roupsBeforeMacros|lobalLogoutTimer)|a(?:voidAssignment|ctiveTimer)|h(?:ideOldPassword|ttpOnly)|yubikey2fUserCanRemoveKey|krb(?:RemoveDomain|ByJs)|(?:wsdlServ|findUs)er)$/;
|
||||
|
||||
our @sessionTypes = ( 'remoteGlobal', 'global', 'localSession', 'persistent', 'saml', 'oidc', 'cas' );
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ our $authParameters = {
|
|||
githubParams => [qw(githubAuthnLevel githubClientID githubClientSecret githubUserField githubScope)],
|
||||
gpgParams => [qw(gpgAuthnLevel gpgDb)],
|
||||
kerberosParams => [qw(krbAuthnLevel krbKeytab krbByJs krbRemoveDomain krbAllowedDomains)],
|
||||
ldapParams => [qw(ldapAuthnLevel ldapExportedVars ldapServer ldapPort ldapVerify ldapBase managerDn managerPassword ldapTimeout ldapIOTimeout ldapVersion ldapRaw ldapCAFile ldapCAPath LDAPFilter AuthLDAPFilter mailLDAPFilter ldapSearchDeref ldapGroupBase ldapGroupObjectClass ldapGroupAttributeName ldapGroupAttributeNameUser ldapGroupAttributeNameSearch ldapGroupDecodeSearchedValue ldapGroupRecursive ldapGroupAttributeNameGroup ldapPpolicyControl ldapSetPassword ldapChangePasswordAsUser ldapPwdEnc ldapUsePasswordResetAttribute ldapPasswordResetAttribute ldapPasswordResetAttributeValue ldapAllowResetExpiredPassword ldapITDS)],
|
||||
ldapParams => [qw(ldapAuthnLevel ldapExportedVars ldapServer ldapPort ldapVerify ldapBase managerDn managerPassword ldapTimeout ldapIOTimeout ldapVersion ldapRaw ldapCAFile ldapCAPath LDAPFilter AuthLDAPFilter mailLDAPFilter ldapSearchDeref ldapGroupBase ldapGroupObjectClass ldapGroupAttributeName ldapGroupAttributeNameUser ldapGroupAttributeNameSearch ldapGroupDecodeSearchedValue ldapGroupRecursive ldapGroupAttributeNameGroup ldapPpolicyControl ldapSetPassword ldapChangePasswordAsUser ldapPwdEnc ldapUsePasswordResetAttribute ldapPasswordResetAttribute ldapPasswordResetAttributeValue ldapAllowResetExpiredPassword ldapGetUserBeforePasswordChange ldapITDS)],
|
||||
linkedinParams => [qw(linkedInAuthnLevel linkedInClientID linkedInClientSecret linkedInFields linkedInUserField linkedInScope)],
|
||||
nullParams => [qw(nullAuthnLevel)],
|
||||
oidcParams => [qw(oidcAuthnLevel oidcRPCallbackGetParam oidcRPStateTimeout)],
|
||||
|
|
|
@ -22,7 +22,10 @@ for ( my $i = 0 ; $i < @ARGV ; $i++ ) {
|
|||
|
||||
$action ||= "help";
|
||||
|
||||
if ( $action =~ /^(?:[gs]et|del|(?:add|del)Key|save|restore|rollback)$/ ) {
|
||||
if ( $action =~
|
||||
/^(?:[gs]et|del|(?:add|del)Key|(?:add|del)PostVars|save|restore|rollback)$/
|
||||
)
|
||||
{
|
||||
eval { require Lemonldap::NG::Manager::Cli; };
|
||||
die "Manager libraries not available, aborting ($@)" if ($@);
|
||||
Lemonldap::NG::Manager::Cli->run(@ARGV);
|
||||
|
@ -40,19 +43,21 @@ sub help {
|
|||
print STDERR qq{Usage: $0 <options> action <parameters>
|
||||
|
||||
Available actions:
|
||||
- help : print this
|
||||
- info : get currentconfiguration info
|
||||
- update-cache : force configuration cache to be updated
|
||||
- test-email <destination> : send a test email
|
||||
- get <keys> : get values of parameters
|
||||
- set <key> <value> : set parameter(s) value(s)
|
||||
- del <keys> : delete parameters
|
||||
- addKey <key> <subkey> <value> : add or set a subkey in a parameter
|
||||
- delKey <key> <subkey> : delete subkey of a parameter
|
||||
- save : export configuration to STDOUT
|
||||
- restore - : import configuration from STDIN
|
||||
- restore <file> : import configuration from file
|
||||
- rollback : restore previous configuration
|
||||
- help : print this
|
||||
- info : get currentconfiguration info
|
||||
- update-cache : force configuration cache to be updated
|
||||
- test-email <destination> : send a test email
|
||||
- get <key> : get values of parameters
|
||||
- set <key> <value> : set parameter(s) value(s)
|
||||
- del <key> : delete parameters
|
||||
- addKey <key> <subkey> <value> : add or set a subkey in a parameter
|
||||
- delKey <key> <subkey> : delete subkey of a parameter
|
||||
- addPostVars <host> <uri> <key> <value> : add post vars for form replay
|
||||
- delPostVars <host> <uri> <key> : delete post vars for form replay
|
||||
- save : export configuration to STDOUT
|
||||
- restore - : import configuration from STDIN
|
||||
- restore <file> : import configuration from file
|
||||
- rollback : restore previous configuration
|
||||
|
||||
Options:
|
||||
- yes <0|1> : accept confirmation prompt automatically
|
||||
|
|
|
@ -228,6 +228,10 @@ sub run {
|
|||
elsif ( $protection == $class->MAYSKIP
|
||||
and $class->grant( $req, $session, $uri, $cond ) eq '999_SKIP' )
|
||||
{
|
||||
$class->logger->debug("Access control skipped");
|
||||
$class->updateStatus( $req, 'SKIP' );
|
||||
$class->hideCookie($req);
|
||||
$class->cleanHeaders($req);
|
||||
return $class->OK;
|
||||
}
|
||||
|
||||
|
@ -764,6 +768,7 @@ sub cleanHeaders {
|
|||
my ( $class, $req ) = @_;
|
||||
my $vhost = $class->resolveAlias($req);
|
||||
if ( defined( $class->tsv->{headerList}->{$vhost} ) ) {
|
||||
$class->logger->debug("Remove headers relative to $vhost");
|
||||
$class->unset_header_in( $req,
|
||||
@{ $class->tsv->{headerList}->{$vhost} } );
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ package Lemonldap::NG::Handler::Server::Main;
|
|||
|
||||
use strict;
|
||||
|
||||
our $VERSION = '2.0.6';
|
||||
our $VERSION = '2.0.10';
|
||||
|
||||
use base 'Lemonldap::NG::Handler::PSGI::Main';
|
||||
|
||||
|
@ -25,13 +25,27 @@ sub set_header_in {
|
|||
push @{ $req->{respHeaders} }, %headers;
|
||||
}
|
||||
|
||||
## @method void unset_header_in(array headers)
|
||||
# deletes request headers and push headers that will be removed by LUA
|
||||
# @param headers array containing header names
|
||||
sub unset_header_in {
|
||||
my ( $class, $req, $header ) = @_;
|
||||
$req->{respHeaders} = [ grep { $_ ne $header and $_ ne cgiName($header) }
|
||||
@{ $req->{respHeaders} } ];
|
||||
delete $req->{env}->{ cgiName($header) };
|
||||
$header =~ s/-/_/g;
|
||||
delete $req->{env}->{$header};
|
||||
my ( $class, $req, @headers ) = @_;
|
||||
$req->data->{deleteIndex} //= 1;
|
||||
my $i = $req->data->{deleteIndex};
|
||||
foreach my $header (@headers) {
|
||||
$class->logger->debug("Delete header $header");
|
||||
$req->{respHeaders} =
|
||||
[ grep { $_ ne $header and $_ ne cgiName($header) }
|
||||
@{ $req->{respHeaders} } ];
|
||||
delete $req->{env}->{ cgiName($header) };
|
||||
push @{ $req->{respHeaders} }, "Deleteheader$i", $header;
|
||||
$i++;
|
||||
push @{ $req->{respHeaders} }, "Deleteheader$i", cgiName($header);
|
||||
$header =~ s/-/_/g;
|
||||
delete $req->{env}->{$header};
|
||||
$i++;
|
||||
}
|
||||
$req->data->{deleteIndex} = $i;
|
||||
}
|
||||
|
||||
# Inheritence is broken in this case with Debian >= jessie
|
||||
|
|
|
@ -70,7 +70,7 @@ sub handler {
|
|||
( 'Content-Length' => 0, Cookie => ( $req->env->{HTTP_COOKIE} // '' ) );
|
||||
my $i = 0;
|
||||
while ( my ( $k, $v ) = splice( @{ $req->{respHeaders} }, 0, 2 ) ) {
|
||||
if ( $k =~ /^(?:Lm-Remote-(?:User|Custom)|Cookie)$/ ) {
|
||||
if ( $k =~ /^(?:Deleteheader\d+|Lm-Remote-(?:User|Custom)|Cookie)$/ ) {
|
||||
push @convertedHdrs, $k, $v;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -204,11 +204,7 @@ count(3);
|
|||
ok( $res = $client->_get( '/skipif/za', undef, 'test1.example.com' ),
|
||||
'Test skip() rule 1' );
|
||||
ok( $res->[0] == 302, ' Code is 302' ) or explain( $res, 302 );
|
||||
$SKIPUSER = 1;
|
||||
ok( $res = $client->_get( '/skipif/zz', undef, 'test1.example.com' ),
|
||||
'Test skip() rule 2' );
|
||||
ok( $res->[0] == 200, ' Code is 200' ) or explain( $res, 200 );
|
||||
count(4);
|
||||
count(2);
|
||||
|
||||
# Wildcards
|
||||
ok(
|
||||
|
@ -219,6 +215,20 @@ ok(
|
|||
ok( $res->[0] == 200, ' Code is 200' ) or explain( $res, 200 );
|
||||
count(2);
|
||||
|
||||
# SKIP TESTS
|
||||
$SKIPUSER = 1;
|
||||
|
||||
ok( $res = $client->_get( '/skipif/zz', undef, 'test1.example.com' ),
|
||||
'Test skip() rule 2' );
|
||||
ok( $res->[0] == 200, ' Code is 200' ) or explain( $res, 200 );
|
||||
count(2);
|
||||
|
||||
# Forged headers
|
||||
ok( $res = $client->_get( '/skipif/zz', undef, 'test1.example.com', undef, HTTP_AUTH_USER => 'rtyler' ),
|
||||
'Test skip() with forged header' );
|
||||
ok( $res->[0] == 200, ' Code is 200' ) or explain( $res, 200 );
|
||||
count(2);
|
||||
|
||||
ok(
|
||||
$res =
|
||||
$client->_get( '/', undef, 'foo.example.fr', "lemonldap=$sessionId" ),
|
||||
|
@ -295,10 +305,14 @@ clean();
|
|||
|
||||
sub Lemonldap::NG::Handler::PSGI::handler {
|
||||
my ( $self, $req ) = @_;
|
||||
unless ($SKIPUSER) {
|
||||
if ($SKIPUSER) {
|
||||
ok( !$req->env->{HTTP_AUTH_USER}, 'No HTTP_AUTH_USER' )
|
||||
or explain( $req->env->{HTTP_AUTH_USER}, '<empty>' );
|
||||
}
|
||||
else {
|
||||
ok( $req->env->{HTTP_AUTH_USER} eq 'dwho', 'Header is given to app' )
|
||||
or explain( $req->env->{HTTP_AUTH_USER}, 'dwho' );
|
||||
count(1);
|
||||
}
|
||||
count(1);
|
||||
return [ 200, [ 'Content-Type', 'text/plain' ], ['Hello'] ];
|
||||
}
|
||||
|
|
|
@ -191,6 +191,28 @@ ok(
|
|||
);
|
||||
count(3);
|
||||
|
||||
# Clean headers
|
||||
ok(
|
||||
$res = $client->_get(
|
||||
'/skipif/zz', undef, 'test1.example.com', undef,
|
||||
HTTP_AUTH_USER => 'rtyler'
|
||||
),
|
||||
'Test skip() with forged header'
|
||||
);
|
||||
ok( $res->[0] == 200, 'Code is 200' ) or explain( $res, 200 );
|
||||
count(2);
|
||||
%h = @{ $res->[1] };
|
||||
my %delete;
|
||||
foreach ( keys %h ) {
|
||||
/^Deleteheader\d$/ and $delete{ $h{$_} }++;
|
||||
}
|
||||
foreach (qw(Cookie HTTP_COOKIE Auth-User HTTP_AUTH_USER)) {
|
||||
ok( $delete{$_}, "Delete command for $_" )
|
||||
or explain( \%h, 'Delete* headers' );
|
||||
ok( !$h{$_}, "$_ is deleted" ) or explain( \%h, 'Delete* headers' );
|
||||
count(2);
|
||||
}
|
||||
|
||||
done_testing( count() );
|
||||
|
||||
clean();
|
||||
|
|
|
@ -5,7 +5,6 @@ sub accessToTrace {
|
|||
my $custom = $hash->{custom};
|
||||
my $req = $hash->{req};
|
||||
my $vhost = $hash->{vhost};
|
||||
my $custom = $hash->{custom};
|
||||
my $params = $hash->{params};
|
||||
my $session = $hash->{session};
|
||||
|
||||
|
|
|
@ -166,6 +166,16 @@ sub updateOidcRp {
|
|||
return $self->sendError( $req, "Invalid input: " . $req->error, 400 )
|
||||
unless ($update);
|
||||
|
||||
if ( $update->{redirectUris} ) {
|
||||
if ( ref( $update->{redirectUris} ) eq "ARRAY" ) {
|
||||
$update->{options}->{redirectUris} = $update->{redirectUris};
|
||||
}
|
||||
else {
|
||||
return $self->sendError( $req,
|
||||
'Invalid input: redirectUris must be an array', 400 );
|
||||
}
|
||||
}
|
||||
|
||||
$self->logger->debug(
|
||||
"[API] OIDC RP $confKey configuration update requested");
|
||||
|
||||
|
@ -294,7 +304,11 @@ sub _getOidcRpByConfKey {
|
|||
my $macros = $conf->{oidcRPMetaDataMacros}->{$confKey} || {};
|
||||
|
||||
# Redirect URIs, filled later
|
||||
my $redirectUris;
|
||||
my $redirectUris = $self->_translateValueConfToApi(
|
||||
'oidcRPMetaDataOptionsRedirectUris',
|
||||
$conf->{oidcRPMetaDataOptions}->{$confKey}
|
||||
->{oidcRPMetaDataOptionsRedirectUris}
|
||||
);
|
||||
|
||||
# Get options
|
||||
my $options = {};
|
||||
|
|
|
@ -1685,6 +1685,10 @@ qr/^(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-
|
|||
'LDAPFilter' => {
|
||||
'type' => 'text'
|
||||
},
|
||||
'ldapGetUserBeforePasswordChange' => {
|
||||
'default' => 0,
|
||||
'type' => 'bool'
|
||||
},
|
||||
'ldapGroupAttributeName' => {
|
||||
'default' => 'member',
|
||||
'type' => 'text'
|
||||
|
|
|
@ -3324,6 +3324,10 @@ m{^(?:ldapi://[^/]*/?|\w[\w\-\.]*(?::\d{1,5})?|ldap(?:s|\+tls)?://\w[\w\-\.]*(?:
|
|||
default => 0,
|
||||
type => 'bool',
|
||||
},
|
||||
ldapGetUserBeforePasswordChange => {
|
||||
default => 0,
|
||||
type => 'bool',
|
||||
},
|
||||
ldapSearchDeref => {
|
||||
type => 'select',
|
||||
select => [
|
||||
|
|
|
@ -302,6 +302,7 @@ sub tree {
|
|||
'ldapPasswordResetAttribute',
|
||||
'ldapPasswordResetAttributeValue',
|
||||
'ldapAllowResetExpiredPassword',
|
||||
'ldapGetUserBeforePasswordChange',
|
||||
'ldapITDS'
|
||||
]
|
||||
},
|
||||
|
|
|
@ -7,7 +7,7 @@ use Data::Dumper;
|
|||
use JSON;
|
||||
use Lemonldap::NG::Common::Conf::ReConstants;
|
||||
|
||||
our $VERSION = '2.0.9';
|
||||
our $VERSION = '2.0.10';
|
||||
$Data::Dumper::Useperl = 1;
|
||||
|
||||
extends('Lemonldap::NG::Manager::Cli::Lib');
|
||||
|
@ -43,6 +43,23 @@ sub get {
|
|||
print "$key has the following keys:\n";
|
||||
print " $_\n" foreach ( sort keys %$value );
|
||||
}
|
||||
elsif ( ref $value eq 'ARRAY' ) {
|
||||
print "$key is an array with values:\n";
|
||||
foreach my $avalue (@$value) {
|
||||
if ( ref $avalue eq 'HASH' ) {
|
||||
print "\tHash with following keys:\n";
|
||||
print "\t\t$_\n" foreach ( sort keys %$avalue );
|
||||
}
|
||||
elsif ( ref $value eq 'ARRAY' ) {
|
||||
print "\tArray with following keys:\n";
|
||||
print "\t\t$_\n" foreach (@$avalue);
|
||||
}
|
||||
else {
|
||||
$avalue //= '';
|
||||
print "\tValue = $avalue\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$value //= '';
|
||||
print "$key = $value\n";
|
||||
|
@ -230,6 +247,68 @@ sub delKey {
|
|||
return $self->_save($new);
|
||||
}
|
||||
|
||||
sub addPostVars {
|
||||
my $self = shift;
|
||||
unless ( @_ % 4 == 0 ) {
|
||||
die 'usage: "addPostVars (?:vhost uri key value)+';
|
||||
}
|
||||
my @list;
|
||||
while (@_) {
|
||||
my $vhost = shift;
|
||||
my $uri = shift;
|
||||
my $key = shift;
|
||||
my $value = shift;
|
||||
$self->logger->info(
|
||||
"CLI: Append post vars $key $value to URI $uri for vhost $vhost");
|
||||
push @list, [ $vhost, $uri, $key, $value ];
|
||||
}
|
||||
require Clone;
|
||||
my $new = Clone::clone( $self->mgr->hLoadedPlugins->{conf}->currentConf );
|
||||
foreach my $el (@list) {
|
||||
$new->{post}->{ $el->[0] }->{ $el->[1] }->{vars} = []
|
||||
unless ( defined $new->{post}->{ $el->[0] }->{ $el->[1] }->{vars} );
|
||||
push(
|
||||
@{ $new->{post}->{ $el->[0] }->{ $el->[1] }->{vars} },
|
||||
[ $el->[2], $el->[3] ]
|
||||
);
|
||||
}
|
||||
return $self->_save($new);
|
||||
}
|
||||
|
||||
sub delPostVars {
|
||||
my $self = shift;
|
||||
unless ( @_ % 3 == 0 ) {
|
||||
die 'usage: "delPostVars (?:vhost uri key)+';
|
||||
}
|
||||
my @list;
|
||||
while (@_) {
|
||||
my $vhost = shift;
|
||||
my $uri = shift;
|
||||
my $key = shift;
|
||||
$self->logger->info(
|
||||
"CLI: Delete post vars $key from URI $uri for vhost $vhost");
|
||||
push @list, [ $vhost, $uri, $key ];
|
||||
}
|
||||
require Clone;
|
||||
my $new = Clone::clone( $self->mgr->hLoadedPlugins->{conf}->currentConf );
|
||||
foreach my $el (@list) {
|
||||
$new->{post}->{ $el->[0] }->{ $el->[1] }->{vars} = []
|
||||
unless ( defined $new->{post}->{ $el->[0] }->{ $el->[1] }->{vars} );
|
||||
for (
|
||||
my $i = 0 ;
|
||||
$i <= $#{ $new->{post}->{ $el->[0] }->{ $el->[1] }->{vars} } ;
|
||||
$i++
|
||||
)
|
||||
{
|
||||
delete( $new->{post}->{ $el->[0] }->{ $el->[1] }->{vars}->[$i] )
|
||||
if (
|
||||
$new->{post}->{ $el->[0] }->{ $el->[1] }->{vars}->[$i]->[0] eq
|
||||
$el->[2] );
|
||||
}
|
||||
}
|
||||
return $self->_save($new);
|
||||
}
|
||||
|
||||
sub lastCfg {
|
||||
my ($self) = @_;
|
||||
$self->logger->info("CLI: Retrieve last conf.");
|
||||
|
@ -337,7 +416,8 @@ sub _setKey {
|
|||
sub _save {
|
||||
my ( $self, $new ) = @_;
|
||||
require Lemonldap::NG::Manager::Conf::Parser;
|
||||
my $parser = Lemonldap::NG::Manager::Conf::Parser->new( {
|
||||
my $parser = Lemonldap::NG::Manager::Conf::Parser->new(
|
||||
{
|
||||
newConf => $new,
|
||||
refConf => $self->mgr->hLoadedPlugins->{conf}->currentConf,
|
||||
req => $self->req
|
||||
|
@ -432,11 +512,12 @@ sub run {
|
|||
die 'nothing to do, aborting';
|
||||
}
|
||||
my $action = shift;
|
||||
unless (
|
||||
$action =~ /^(?:get|set|del|addKey|delKey|save|restore|rollback)$/ )
|
||||
unless ( $action =~
|
||||
/^(?:get|set|del|addKey|delKey|addPostVars|delPostVars|save|restore|rollback)$/
|
||||
)
|
||||
{
|
||||
die
|
||||
"Unknown action $action. Only get, set, del, addKey, delKey, save, restore, rollback allowed";
|
||||
"Unknown action $action. Only get, set, del, addKey, delKey, addPostVars, delPostVars, save, restore, rollback allowed";
|
||||
}
|
||||
|
||||
unless ( $action eq "restore" ) {
|
||||
|
|
|
@ -443,6 +443,7 @@
|
|||
"ldapFilters":"فلتر",
|
||||
"LDAPFilter":"فلتر الاعْتيادي",
|
||||
"ldapGroupAttributeName":"السمات المستهدف",
|
||||
"ldapGetUserBeforePasswordChange":"Search for user before password change",
|
||||
"ldapGroupAttributeNameGroup":"سمات مصدر المجموعة",
|
||||
"ldapGroupAttributeNameSearch":"السمات التي تم البحث عنها",
|
||||
"ldapGroupAttributeNameUser":"سمة مصدر المستخدم",
|
||||
|
|
|
@ -442,6 +442,7 @@
|
|||
"ldapExportedVars":"Exported variables",
|
||||
"ldapFilters":"Filters",
|
||||
"LDAPFilter":"Default filter",
|
||||
"ldapGetUserBeforePasswordChange":"Search for user before password change",
|
||||
"ldapGroupAttributeName":"Target attribute",
|
||||
"ldapGroupAttributeNameGroup":"Group source attribute",
|
||||
"ldapGroupAttributeNameSearch":"Searched attributes",
|
||||
|
|
|
@ -442,6 +442,7 @@
|
|||
"ldapExportedVars":"Exported variables",
|
||||
"ldapFilters":"Filters",
|
||||
"LDAPFilter":"Default filter",
|
||||
"ldapGetUserBeforePasswordChange":"Search for user before password change",
|
||||
"ldapGroupAttributeName":"Target attribute",
|
||||
"ldapGroupAttributeNameGroup":"Group source attribute",
|
||||
"ldapGroupAttributeNameSearch":"Searched attributes",
|
||||
|
|
|
@ -442,6 +442,7 @@
|
|||
"ldapExportedVars":"Variables exportadas",
|
||||
"ldapFilters":"Filtros",
|
||||
"LDAPFilter":"Filtro por defecto",
|
||||
"ldapGetUserBeforePasswordChange":"Search for user before password change",
|
||||
"ldapGroupAttributeName":"Atributo objetivo",
|
||||
"ldapGroupAttributeNameGroup":"Group source attribute",
|
||||
"ldapGroupAttributeNameSearch":"Atributos buscados",
|
||||
|
|
|
@ -442,6 +442,7 @@
|
|||
"ldapExportedVars":"Variables exportées",
|
||||
"ldapFilters":"Filtres",
|
||||
"LDAPFilter":"Filtre par défaut",
|
||||
"ldapGetUserBeforePasswordChange":"Rechercher l'utilisateur avant le changement de mot de passe",
|
||||
"ldapGroupAttributeName":"Attribut cible",
|
||||
"ldapGroupAttributeNameGroup":"Attribut source groupe",
|
||||
"ldapGroupAttributeNameSearch":"Attributs recherchés",
|
||||
|
|
|
@ -442,6 +442,7 @@
|
|||
"ldapExportedVars":"Variabili esportate",
|
||||
"ldapFilters":"Filtri",
|
||||
"LDAPFilter":"Filtro predefinito",
|
||||
"ldapGetUserBeforePasswordChange":"Search for user before password change",
|
||||
"ldapGroupAttributeName":"Attributo target",
|
||||
"ldapGroupAttributeNameGroup":"Attributo del gruppo sorgente",
|
||||
"ldapGroupAttributeNameSearch":"Attributi ricercati",
|
||||
|
|
|
@ -442,6 +442,7 @@
|
|||
"ldapExportedVars":"Wyeksportowane zmienne",
|
||||
"ldapFilters":"Filtry",
|
||||
"LDAPFilter":"Domyślny filtr",
|
||||
"ldapGetUserBeforePasswordChange":"Search for user before password change",
|
||||
"ldapGroupAttributeName":"Atrybut docelowy",
|
||||
"ldapGroupAttributeNameGroup":"Atrybut źródła grupy",
|
||||
"ldapGroupAttributeNameSearch":"Szukane atrybuty",
|
||||
|
|
|
@ -442,6 +442,7 @@
|
|||
"ldapExportedVars":"Dışa aktarılan değişkenler",
|
||||
"ldapFilters":"Filtreler",
|
||||
"LDAPFilter":"Varsayılan filtre",
|
||||
"ldapGetUserBeforePasswordChange":"Search for user before password change",
|
||||
"ldapGroupAttributeName":"Hedef nitelik",
|
||||
"ldapGroupAttributeNameGroup":"Grup kaynağı niteliği",
|
||||
"ldapGroupAttributeNameSearch":"Aranan nitelikler",
|
||||
|
|
|
@ -442,6 +442,7 @@
|
|||
"ldapExportedVars":"Biến đã được xuất",
|
||||
"ldapFilters":"Bộ lọc",
|
||||
"LDAPFilter":"Bộ lọc mặc định",
|
||||
"ldapGetUserBeforePasswordChange":"Search for user before password change",
|
||||
"ldapGroupAttributeName":"Thuộc tính đích",
|
||||
"ldapGroupAttributeNameGroup":"Thuộc tính nguồn nhóm",
|
||||
"ldapGroupAttributeNameSearch":"Thuộc tính đã tìm kiếm",
|
||||
|
|
|
@ -442,6 +442,7 @@
|
|||
"ldapExportedVars":"Exported variables",
|
||||
"ldapFilters":"Filters",
|
||||
"LDAPFilter":"Default filter",
|
||||
"ldapGetUserBeforePasswordChange":"Search for user before password change",
|
||||
"ldapGroupAttributeName":"Target attribute",
|
||||
"ldapGroupAttributeNameGroup":"Group source attribute",
|
||||
"ldapGroupAttributeNameSearch":"Searched attributes",
|
||||
|
|
|
@ -442,6 +442,7 @@
|
|||
"ldapExportedVars":"已匯出的變數",
|
||||
"ldapFilters":"過濾器",
|
||||
"LDAPFilter":"預設過濾器",
|
||||
"ldapGetUserBeforePasswordChange":"Search for user before password change",
|
||||
"ldapGroupAttributeName":"目標屬性",
|
||||
"ldapGroupAttributeNameGroup":"群組來源屬性",
|
||||
"ldapGroupAttributeNameSearch":"已搜尋的屬性",
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -21,7 +21,7 @@ use Lemonldap::NG::Portal::Main::Constants qw(
|
|||
PE_UNAUTHORIZEDPARTNER
|
||||
);
|
||||
|
||||
our $VERSION = '2.0.9';
|
||||
our $VERSION = '2.0.10';
|
||||
|
||||
extends 'Lemonldap::NG::Portal::Main::Issuer',
|
||||
'Lemonldap::NG::Portal::Lib::SAML';
|
||||
|
@ -680,20 +680,20 @@ sub run {
|
|||
unless ( defined $value ) {
|
||||
if ($mandatory) {
|
||||
$self->logger->error(
|
||||
"Session key $_ is required to set SAML $name attribute"
|
||||
"Session key $_ is required to set SAML $name attribute ($sp)"
|
||||
);
|
||||
return PE_ISSUERMISSINGREQATTR;
|
||||
}
|
||||
else {
|
||||
$self->logger->debug(
|
||||
"SAML2 attribute $name has no value but is not mandatory, skip it"
|
||||
"SAML2 attribute $name has no value but is not mandatory ($sp), skip it"
|
||||
);
|
||||
next;
|
||||
}
|
||||
}
|
||||
|
||||
$self->logger->debug(
|
||||
"SAML2 attribute $name will be set with $_ session key");
|
||||
"SAML2 attribute $name will be set with $_ session key ($sp)");
|
||||
|
||||
# SAML2 attribute
|
||||
my $attribute =
|
||||
|
|
|
@ -30,6 +30,12 @@ sub confirm {
|
|||
|
||||
sub modifyPassword {
|
||||
my ( $self, $req, $pwd, $useMail ) = @_;
|
||||
|
||||
# If the password change is done in a different backend,
|
||||
# we need to reload the correct DN
|
||||
$self->getUser( $req, useMail => $useMail )
|
||||
if $self->conf->{ldapGetUserBeforePasswordChange};
|
||||
|
||||
my $dn = $req->data->{dn} || $req->sessionInfo->{_dn};
|
||||
unless ($dn) {
|
||||
$self->logger->error('"dn" is not set, abort password modification');
|
||||
|
|
|
@ -37,7 +37,7 @@ sub init {
|
|||
$tmp =
|
||||
$self->loadModule( "::Password::$mod->{type}", $mod->{over} );
|
||||
unless ($tmp) {
|
||||
$self->notice("Unable to load Password::$mod->{type}");
|
||||
$self->logger->notice("Unable to load Password::$mod->{type}");
|
||||
next;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,11 @@ sub modifyPassword {
|
|||
my $dn;
|
||||
my $requireOldPassword;
|
||||
|
||||
# If the password change is done in a different backend,
|
||||
# we need to reload the correct DN
|
||||
$self->getUser( $req, useMail => $useMail )
|
||||
if $self->conf->{ldapGetUserBeforePasswordChange};
|
||||
|
||||
if ( $req->data->{dn} ) {
|
||||
$dn = $req->data->{dn};
|
||||
$requireOldPassword = $self->requireOldPwdRule->( $req, $req->userData );
|
||||
|
|
Loading…
Reference in New Issue
Block a user