Merge branch '2683' into 'v2.0'

Append rule to allow StayConnected plugin (#2683)

See merge request lemonldap-ng/lemonldap-ng!243
This commit is contained in:
Christophe Maudoux 2022-02-06 11:56:12 +00:00
commit 04c29e5c71
12 changed files with 223 additions and 116 deletions

View File

@ -39,7 +39,7 @@ You can then create rules with these fields:
.. tip::
By example, to add 3 to authentication level for users from 192.168.0.0/24 network:
By example, to add 3 to authentication level for users from 192.168.0.0/16 network:
- Rule: ``$env->{REMOTE_ADDR} =~ /^192\.168\./``
- Value: ``+3``

View File

@ -11,7 +11,13 @@ Just enable it in the manager (section “plugins”).
- **Parameters**:
- **Activation**: Enable / Disable this plugin
- **Do not check fingerprint**: Enable / Disable browser fingerprint checking
- **Activation**: Rule to enable/disable this plugin
- **Do not check fingerprint**: Enable/Disable browser fingerprint checking
- **Expiration time**: Persistent session connection and cookie timeout
- **Cookie name**: Persistent connection cookie name
- **Cookie name**: Persistent connection cookie name
.. tip::
By example, you can allow users from 192.168.0.0/16 private network to register a fingerprinting:
- Rule: ``$env->{REMOTE_ADDR} =~ /^192\.168\./``

View File

@ -31,7 +31,7 @@ use constant DEFAULTCONFBACKENDOPTIONS => (
);
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|ScopeRule|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 $arrayParameters = qr/^mySessionAuthorizedRWKeys$/;
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)|t(?:ayConnected(?:BypassFG)?|orePassword)|f(?:RemovedUseNotif|OnlyUpgrade)|kip(?:Upgrade|Renew)Confirmation|oap(?:Session|Config)Server|laveDisplayLogo|howLanguages|slByAjax)|o(?:idc(?:RPMetaDataOptions(?:A(?:llow(?:(?:ClientCredentials|Password)Grant|Offline)|ccessToken(?:Claims|JWT))|Re(?:freshToken|quirePKCE)|LogoutSessionRequired|IDTokenForceClaims|BypassConsent|Public)|ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration|OnlyDeclaredScopes)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|c(?:a(?:sS(?:rvMetaDataOptions(?:Gateway|Renew)|trictMatching)|ptcha_(?:register|login|mail)_enabled)|heck(?:DevOps(?:D(?:isplayNormalizedHeaders|ownload)|CheckSessionAttributes)?|State|User|XSS)|o(?:ntextSwitching(?:Allowed2fModifications|StopWithLogout)|mpactConf|rsEnabled)|rowdsec|da)|p(?:ortal(?:Display(?:Re(?:freshMyRights|setPassword|gister)|CertificateResetByMail|GeneratePassword|PasswordPolicy)|E(?:rrorOn(?:ExpiredSession|MailNotFound)|nablePasswordDisplay)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|ForceAuthn|AntiFrame)|roxy(?:AuthServiceImpersonation|UseSoap))|l(?:dap(?:(?:G(?:roup(?:DecodeSearchedValu|Recursiv)|etUserBeforePasswordChang)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl|ITDS)|oginHistoryEnabled)|n(?:o(?:tif(?:ication(?:Server(?:(?:POS|GE)T|DELETE)?|sExplorer)?|y(?:Deleted|Other))|AjaxHook)|ewLocationWarning)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonationSkipEmptyValues)|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)|to(?:tp2f(?:UserCanRemoveKey|EncryptSecret)|kenUseGlobalStorage)|(?: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)|t(?:ayConnectedBypassFG|orePassword)|f(?:RemovedUseNotif|OnlyUpgrade)|kip(?:Upgrade|Renew)Confirmation|oap(?:Session|Config)Server|laveDisplayLogo|howLanguages|slByAjax)|o(?:idc(?:RPMetaDataOptions(?:A(?:llow(?:(?:ClientCredentials|Password)Grant|Offline)|ccessToken(?:Claims|JWT))|Re(?:freshToken|quirePKCE)|LogoutSessionRequired|IDTokenForceClaims|BypassConsent|Public)|ServiceAllow(?:(?:AuthorizationCode|Implicit|Hybrid)Flow|DynamicRegistration|OnlyDeclaredScopes)|OPMetaDataOptions(?:(?:CheckJWTSignatur|UseNonc)e|StoreIDToken))|ldNotifFormat)|c(?:a(?:sS(?:rvMetaDataOptions(?:Gateway|Renew)|trictMatching)|ptcha_(?:register|login|mail)_enabled)|heck(?:DevOps(?:D(?:isplayNormalizedHeaders|ownload)|CheckSessionAttributes)?|State|User|XSS)|o(?:ntextSwitching(?:Allowed2fModifications|StopWithLogout)|mpactConf|rsEnabled)|rowdsec|da)|p(?:ortal(?:Display(?:Re(?:freshMyRights|setPassword|gister)|CertificateResetByMail|GeneratePassword|PasswordPolicy)|E(?:rrorOn(?:ExpiredSession|MailNotFound)|nablePasswordDisplay)|(?:CheckLogin|Statu)s|OpenLinkInNewWindow|ForceAuthn|AntiFrame)|roxy(?:AuthServiceImpersonation|UseSoap))|l(?:dap(?:(?:G(?:roup(?:DecodeSearchedValu|Recursiv)|etUserBeforePasswordChang)|UsePasswordResetAttribut)e|(?:AllowResetExpired|Set)Password|ChangePasswordAsUser|PpolicyControl|ITDS)|oginHistoryEnabled)|n(?:o(?:tif(?:ication(?:Server(?:(?:POS|GE)T|DELETE)?|sExplorer)?|y(?:Deleted|Other))|AjaxHook)|ewLocationWarning)|i(?:ssuerDB(?:OpenID(?:Connect)?|SAML|CAS|Get)Activation|mpersonationSkipEmptyValues)|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)|to(?:tp2f(?:UserCanRemoveKey|EncryptSecret)|kenUseGlobalStorage)|(?: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' );

View File

@ -361,6 +361,7 @@ sub defaultValues {
'SSLAuthnLevel' => 5,
'SSLVar' => 'SSL_CLIENT_S_DN_Email',
'SSLVarIf' => {},
'stayConnected' => 0,
'stayConnectedCookieName' => 'llngconnection',
'stayConnectedTimeout' => 2592000,
'successLoginNumber' => 5,

View File

@ -4175,7 +4175,7 @@ qr/^(?:(?:(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-
},
'stayConnected' => {
'default' => 0,
'type' => 'bool'
'type' => 'boolOrExpr'
},
'stayConnectedBypassFG' => {
'default' => 0,

View File

@ -436,9 +436,9 @@ sub attributes {
flags => 'hmp',
},
stayConnected => {
type => 'bool',
type => 'boolOrExpr',
default => 0,
documentation => 'Enable StayConnected plugin',
documentation => 'Stay connected activation rule',
},
stayConnectedBypassFG => {
type => 'bool',

File diff suppressed because one or more lines are too long

View File

@ -709,6 +709,7 @@ t/62-UpgradeSession.t
t/63-History.t
t/64-StayConnected-with-2F-and-History.t
t/64-StayConnected-with-History.t
t/64-StayConnected-with-rule.t
t/64-StayConnected-without-fingerprint-checking.t
t/65-AutoSignin.t
t/65-CheckState.t

View File

@ -13,6 +13,7 @@ use URI;
has isPP => ( is => 'rw' );
has speChars => ( is => 'rw' );
has skinRules => ( is => 'rw' );
has stayConnected => ( is => 'rw', default => sub { 0 } );
has requireOldPwd => ( is => 'rw', default => sub { 1 } );
sub displayInit {
@ -28,17 +29,24 @@ sub displayInit {
else {
$self->logger->error(
qq(Skin rule "$skinRule" returns an error: )
. HANDLER->tsv->{jail}->error );
. HANDLER->tsv->{jail}->error || 'Unable to compile rule' );
}
}
}
my $rule = HANDLER->buildSub(
HANDLER->substitute( $self->conf->{portalRequireOldPassword} ) );
unless ($rule) {
my $error = HANDLER->tsv->{jail}->error || '???';
$self->logger->error( "Bad requireOldPwd rule: " . $error );
my $error = HANDLER->tsv->{jail}->error || 'Unable to compile rule';
$self->logger->error( "Bad requireOldPwd rule: $error" );
}
$self->requireOldPwd($rule);
$rule =
HANDLER->buildSub( HANDLER->substitute( $self->conf->{stayConnected} ) );
unless ($rule) {
my $error = HANDLER->tsv->{jail}->error || 'Unable to compile rule';
$self->logger->error( "Bad stayConnected rule: $error" );
}
$self->stayConnected($rule);
my $speChars =
$self->conf->{passwordPolicySpecialChar} eq '__ALL__'
@ -247,8 +255,6 @@ sub display {
LOGOUT_URL => $self->conf->{portal} . "?logout=1",
APPSLIST_ORDER => $req->{sessionInfo}->{'_appsListOrder'},
PING => $self->conf->{portalPingInterval},
REQUIRE_OLDPASSWORD =>
$self->requireOldPwd->( $req, $req->userData ),
DONT_STORE_PASSWORD => $self->conf->{browsersDontStorePassword},
HIDE_OLDPASSWORD => 0,
PPOLICY_NOPOLICY => !$self->isPP(),
@ -258,6 +264,11 @@ sub display {
PPOLICY_MINUPPER => $self->conf->{passwordPolicyMinUpper},
PPOLICY_MINDIGIT => $self->conf->{passwordPolicyMinDigit},
PPOLICY_MINSPECHAR => $self->conf->{passwordPolicyMinSpeChar},
(
$self->requireOldPwd->( $req, $req->userData )
? ( REQUIRE_OLDPASSWORD => 1 )
: ()
),
(
$self->conf->{passwordPolicyMinSpeChar} || $self->speChars()
? ( PPOLICY_ALLOWEDSPECHAR => $self->speChars() )
@ -391,16 +402,20 @@ sub display {
MAIL_URL => $self->conf->{mailUrl},
REGISTER_URL => $self->conf->{registerUrl},
HIDDEN_INPUTS => $self->buildHiddenForm($req),
STAYCONNECTED => $self->conf->{stayConnected},
IMPERSONATION => $self->conf->{impersonationRule}
|| $self->conf->{proxyAuthServiceImpersonation},
ENABLE_PASSWORD_DISPLAY =>
$self->conf->{portalEnablePasswordDisplay},
(
$self->stayConnected->( $req, $req->sessionInfo )
? ( STAYCONNECTED => 1 )
: ()
),
(
$req->data->{customScript}
? ( CUSTOM_SCRIPT => $req->data->{customScript} )
: ()
),
ENABLE_PASSWORD_DISPLAY =>
$self->conf->{portalEnablePasswordDisplay},
);
# External links

View File

@ -20,8 +20,8 @@ use constant beforeAuth => 'check';
use constant beforeLogout => 'logout';
# INITIALIZATION
has ott => (
has rule => ( is => 'rw', default => sub { 0 } );
has ott => (
is => 'rw',
lazy => 1,
default => sub {
@ -52,6 +52,11 @@ sub init {
my ($self) = @_;
$self->addAuthRoute( registerbrowser => 'storeBrowser', ['POST'] );
# Parse activation rule
$self->rule(
$self->p->buildRule( $self->conf->{stayConnected}, 'stayConnected' ) );
return 0 unless $self->rule;
return 1;
}
@ -64,7 +69,9 @@ sub newDevice {
my $checkLogins = $req->param('checkLogins');
$self->logger->debug("StayConnected: checkLogins set") if $checkLogins;
if ( $req->param('stayconnected') ) {
if ( $req->param('stayconnected')
&& $self->rule->( $req, $req->sessionInfo ) )
{
my $token = $self->ott->createToken( {
name => $req->sessionInfo->{ $self->conf->{whatToTrace} },
(
@ -96,53 +103,59 @@ sub storeBrowser {
my ( $self, $req ) = @_;
$req->urldc( $req->param('url') );
$req->mustRedirect(1);
if ( my $token = $req->param('token') ) {
if ( my $tmp = $self->ott->getToken($token) ) {
my $uid = $req->userData->{ $self->conf->{whatToTrace} };
if ( $tmp->{name} eq $uid ) {
if ( my $fg = $req->param('fg') ) {
my $ps = Lemonldap::NG::Common::Session->new(
storageModule => $self->conf->{globalStorage},
storageModuleOptions =>
$self->conf->{globalStorageOptions},
kind => "SSO",
info => {
_utime => time + $self->timeout,
_session_uid => $uid,
_connectedSince => time,
dataKeep => $req->data->{dataToKeep},
fingerprint => $fg,
},
);
if ( $self->rule->( $req, $req->sessionInfo ) ) {
if ( my $token = $req->param('token') ) {
if ( my $tmp = $self->ott->getToken($token) ) {
my $uid = $req->userData->{ $self->conf->{whatToTrace} };
if ( $tmp->{name} eq $uid ) {
if ( my $fg = $req->param('fg') ) {
my $ps = Lemonldap::NG::Common::Session->new(
storageModule => $self->conf->{globalStorage},
storageModuleOptions =>
$self->conf->{globalStorageOptions},
kind => "SSO",
info => {
_utime => time + $self->timeout,
_session_uid => $uid,
_connectedSince => time,
dataKeep => $req->data->{dataToKeep},
fingerprint => $fg,
},
);
# Cookie available 30 days by default
$req->addCookie(
$self->p->cookie(
name => $self->cookieName,
value => $ps->id,
max_age => $self->timeout,
secure => $self->conf->{securedCookie},
)
);
$req->sessionInfo->{_loginHistory} = $tmp->{history}
if exists $tmp->{history};
# Cookie available 30 days by default
$req->addCookie(
$self->p->cookie(
name => $self->cookieName,
value => $ps->id,
max_age => $self->timeout,
secure => $self->conf->{securedCookie},
)
);
$req->sessionInfo->{_loginHistory} = $tmp->{history}
if exists $tmp->{history};
}
else {
$self->logger->warn(
"Browser did not return fingerprint");
}
}
else {
$self->logger->warn("Browser did not return fingerprint");
$self->userLogger->error(
"StayConnected: mismatch UID ($tmp->{name} / $uid)");
}
}
else {
$self->userLogger->error(
"StayConnected: mismatch UID ($tmp->{name} / $uid)");
"StayConnected called with an expired token");
}
}
else {
$self->userLogger->error(
"StayConnected called with an expired token");
$self->userLogger->error('StayConnected called without token');
}
}
else {
$self->userLogger->error('StayConnected called without token');
$self->userLogger->error('StayConnected not allowed');
}
# Return persistent connection cookie
@ -156,39 +169,26 @@ sub storeBrowser {
# Then delete authentication methods from "steps" array.
sub check {
my ( $self, $req ) = @_;
if ( my $cid = $req->cookies->{ $self->cookieName } ) {
my $ps = Lemonldap::NG::Common::Session->new(
storageModule => $self->conf->{globalStorage},
storageModuleOptions => $self->conf->{globalStorageOptions},
kind => "SSO",
id => $cid,
);
if ( $ps
and my $uid = $ps->data->{_session_uid}
and time() < $ps->data->{_utime} )
{
$self->logger->debug('Persistent connection found');
if ( my $fg = $req->param('fg')
and my $token = $req->param('token') )
if ( $self->rule->( $req, $req->sessionInfo ) ) {
if ( my $cid = $req->cookies->{ $self->cookieName } ) {
my $ps = Lemonldap::NG::Common::Session->new(
storageModule => $self->conf->{globalStorage},
storageModuleOptions => $self->conf->{globalStorageOptions},
kind => "SSO",
id => $cid,
);
if ( $ps
and my $uid = $ps->data->{_session_uid}
and time() < $ps->data->{_utime} )
{
if ( my $prm = $self->ott->getToken($token) ) {
$req->data->{dataKeep} = $ps->data->{dataKeep};
$self->logger->debug('Persistent connection found');
if ( $self->conf->{stayConnectedBypassFG} ) {
$req->user($uid);
my @steps =
grep {
!ref $_
and $_ !~ /^(?:extractFormInfo|authenticate)$/
} @{ $req->steps };
$req->steps( \@steps );
$self->userLogger->notice(
"$uid connected by StayConnected cookie without fingerprint checking"
);
return PE_OK;
}
else {
if ( $fg eq $ps->data->{fingerprint} ) {
$self->logger->debug('Persistent connection found');
if ( my $fg = $req->param('fg')
and my $token = $req->param('token') )
{
if ( my $prm = $self->ott->getToken($token) ) {
$req->data->{dataKeep} = $ps->data->{dataKeep};
$self->logger->debug('Persistent connection found');
if ( $self->conf->{stayConnectedBypassFG} ) {
$req->user($uid);
my @steps =
grep {
@ -197,48 +197,68 @@ sub check {
} @{ $req->steps };
$req->steps( \@steps );
$self->userLogger->notice(
"$uid connected by StayConnected cookie");
"$uid connected by StayConnected cookie without fingerprint checking"
);
return PE_OK;
}
else {
$self->userLogger->warn(
"Fingerprint changed for $uid");
$ps->remove;
$self->logout($req);
if ( $fg eq $ps->data->{fingerprint} ) {
$req->user($uid);
my @steps =
grep {
!ref $_
and $_ !~
/^(?:extractFormInfo|authenticate)$/
} @{ $req->steps };
$req->steps( \@steps );
$self->userLogger->notice(
"$uid connected by StayConnected cookie");
return PE_OK;
}
else {
$self->userLogger->warn(
"Fingerprint changed for $uid");
$ps->remove;
$self->logout($req);
}
}
}
else {
$self->userLogger->notice(
"StayConnected: expired token for $uid");
}
}
else {
$self->userLogger->notice(
"StayConnected: expired token for $uid");
my $token = $self->ott->createToken( $req->parameters );
$req->response(
$self->p->sendHtml(
$req,
'../common/registerBrowser',
params => {
TOKEN => $token,
ACTION => '#',
}
)
);
return PE_SENDRESPONSE;
}
}
else {
my $token = $self->ott->createToken( $req->parameters );
$req->response(
$self->p->sendHtml(
$req,
'../common/registerBrowser',
params => {
TOKEN => $token,
ACTION => '#',
}
)
);
return PE_SENDRESPONSE;
}
}
else {
$self->userLogger->notice('Persistent connection expired');
unless ( $ps->{error} ) {
$self->logger->debug(
'Persistent connection session id = ' . $ps->{id} );
$self->logger->debug( 'Persistent connection session _utime = '
. $ps->data->{_utime} );
$ps->remove;
$self->userLogger->notice('Persistent connection expired');
unless ( $ps->{error} ) {
$self->logger->debug(
'Persistent connection session id = ' . $ps->{id} );
$self->logger->debug(
'Persistent connection session _utime = '
. $ps->data->{_utime} );
$ps->remove;
}
}
}
}
else {
$self->userLogger->error('StayConnected not allowed');
}
return PE_OK;
}

View File

@ -10,7 +10,7 @@ my $client = LLNG::Manager::Test->new( {
ini => {
logLevel => 'error',
useSafeJail => 1,
stayConnected => 1,
stayConnected => '$env->{REMOTE_ADDR} eq "127.0.0.1"',
loginHistoryEnabled => 1,
securedCookie => 1,
stayConnectedTimeout => 1000,

View File

@ -0,0 +1,64 @@
use Test::More;
use strict;
use IO::String;
require 't/test-lib.pm';
my $res;
my $client = LLNG::Manager::Test->new( {
ini => {
logLevel => 'error',
useSafeJail => 1,
requireToken => 1,
stayConnected => '$env->{REMOTE_ADDR} =~ /^127\.0\.0/'
}
}
);
ok( $res = $client->_get( '/', accept => 'text/html' ), 'Firt access' );
my ( $host, $url, $query ) =
expectForm( $res, undef, undef, 'user', 'password', 'stayconnected',
'checkLogins', 'token' );
ok( $res = $client->_get( '/', ip => '10.10.10.10', accept => 'text/html' ),
'Access from external LAN' );
( $host, $url, $query ) =
expectForm( $res, undef, undef, 'user', 'password', 'checkLogins', 'token' );
count(2);
$query =~ s/user=/user=dwho/;
$query =~ s/password=/password=dwho/;
# Try to authenticate
# -------------------
ok(
$res = $client->_post(
'/',
IO::String->new($query),
ip => '10.10.10.10',
accept => 'text/html',
length => length($query)
),
'Auth query'
);
count(1);
my $id = expectCookie($res);
expectRedirection( $res, 'http://auth.example.com/' );
# Try to push fingerprint
$query =~ s/fg=/fg=aaa/;
ok(
$res = $client->_post(
'/registerbrowser',
IO::String->new($query),
length => length($query),
cookie => "lemonldap=$id",
accept => 'text/html',
),
'Post fingerprint'
);
count(1);
expectRedirection( $res, 'http://auth.example.com/' );
$client->logout($id);
clean_sessions();
done_testing( count() );