Append bruteForce Protection number of allowed failed Login parameter (#1506)
This commit is contained in:
parent
caa408b424
commit
aa45cf148a
|
@ -15,31 +15,32 @@ sub defaultValues {
|
|||
'type' => 'category'
|
||||
}
|
||||
},
|
||||
'authChoiceParam' => 'lmAuth',
|
||||
'authentication' => 'Demo',
|
||||
'available2F' => 'UTOTP,TOTP,U2F,REST,Ext2F,Yubikey',
|
||||
'available2FSelfRegistration' => 'TOTP,U2F,Yubikey',
|
||||
'bruteForceProtectionMaxAge' => 300,
|
||||
'bruteForceProtectionTempo' => 30,
|
||||
'captcha_mail_enabled' => 1,
|
||||
'captcha_register_enabled' => 1,
|
||||
'captcha_size' => 6,
|
||||
'casAccessControlPolicy' => 'none',
|
||||
'casAuthnLevel' => 1,
|
||||
'checkTime' => 600,
|
||||
'checkXSS' => 1,
|
||||
'confirmFormMethod' => 'post',
|
||||
'cookieName' => 'lemonldap',
|
||||
'cspConnect' => '\'self\'',
|
||||
'cspDefault' => '\'self\'',
|
||||
'cspFont' => '\'self\'',
|
||||
'cspFormAction' => '\'self\'',
|
||||
'cspImg' => '\'self\' data:',
|
||||
'cspScript' => '\'self\'',
|
||||
'cspStyle' => '\'self\'',
|
||||
'dbiAuthnLevel' => 2,
|
||||
'dbiExportedVars' => {},
|
||||
'demoExportedVars' => {
|
||||
'authChoiceParam' => 'lmAuth',
|
||||
'authentication' => 'Demo',
|
||||
'available2F' => 'UTOTP,TOTP,U2F,REST,Ext2F,Yubikey',
|
||||
'available2FSelfRegistration' => 'TOTP,U2F,Yubikey',
|
||||
'bruteForceProtectionMaxAge' => 300,
|
||||
'bruteForceProtectionMaxFailed' => 3,
|
||||
'bruteForceProtectionTempo' => 30,
|
||||
'captcha_mail_enabled' => 1,
|
||||
'captcha_register_enabled' => 1,
|
||||
'captcha_size' => 6,
|
||||
'casAccessControlPolicy' => 'none',
|
||||
'casAuthnLevel' => 1,
|
||||
'checkTime' => 600,
|
||||
'checkXSS' => 1,
|
||||
'confirmFormMethod' => 'post',
|
||||
'cookieName' => 'lemonldap',
|
||||
'cspConnect' => '\'self\'',
|
||||
'cspDefault' => '\'self\'',
|
||||
'cspFont' => '\'self\'',
|
||||
'cspFormAction' => '\'self\'',
|
||||
'cspImg' => '\'self\' data:',
|
||||
'cspScript' => '\'self\'',
|
||||
'cspStyle' => '\'self\'',
|
||||
'dbiAuthnLevel' => 2,
|
||||
'dbiExportedVars' => {},
|
||||
'demoExportedVars' => {
|
||||
'cn' => 'cn',
|
||||
'mail' => 'mail',
|
||||
'uid' => 'uid'
|
||||
|
|
|
@ -615,6 +615,10 @@ sub attributes {
|
|||
'default' => 300,
|
||||
'type' => 'int'
|
||||
},
|
||||
'bruteForceProtectionMaxFailed' => {
|
||||
'default' => 3,
|
||||
'type' => 'int'
|
||||
},
|
||||
'bruteForceProtectionTempo' => {
|
||||
'default' => 30,
|
||||
'type' => 'int'
|
||||
|
|
|
@ -612,7 +612,13 @@ sub attributes {
|
|||
default => 300,
|
||||
type => 'int',
|
||||
documentation =>
|
||||
'Brute force attack protection -> Max age third failed login',
|
||||
'Brute force attack protection -> Max age between last and first allowed failed login',
|
||||
},
|
||||
bruteForceProtectionMaxFailed => {
|
||||
default => 3,
|
||||
type => 'int',
|
||||
documentation =>
|
||||
'Brute force attack protection -> Max allowed failed login',
|
||||
},
|
||||
grantSessionRules => {
|
||||
type => 'grantContainer',
|
||||
|
|
|
@ -27,7 +27,7 @@ sub init {
|
|||
sub run {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
my $MaxAge = 0;
|
||||
my $MaxAge = $self->conf->{bruteForceProtectionMaxAge} + 1;
|
||||
my $countFailed = 0;
|
||||
my @lastFailedLoginEpoch = ();
|
||||
|
||||
|
@ -37,32 +37,39 @@ sub run {
|
|||
}
|
||||
|
||||
$self->logger->debug(" Number of failedLogin = $countFailed");
|
||||
return PE_OK if ( $countFailed < 3 );
|
||||
return PE_OK
|
||||
if ( $countFailed <= $self->conf->{bruteForceProtectionMaxFailed} );
|
||||
|
||||
foreach ( 0 .. 2 ) {
|
||||
if ( defined $req->sessionInfo->{_loginHistory}->{failedLogin}->[$_] ) {
|
||||
foreach ( 0 .. $self->conf->{bruteForceProtectionMaxFailed} - 1 ) {
|
||||
if ( defined $req->sessionInfo->{_loginHistory}->{failedLogin}->[$_] )
|
||||
{
|
||||
push @lastFailedLoginEpoch,
|
||||
$req->sessionInfo->{_loginHistory}->{failedLogin}->[$_]->{_utime};
|
||||
$req->sessionInfo->{_loginHistory}->{failedLogin}->[$_]
|
||||
->{_utime};
|
||||
}
|
||||
}
|
||||
$self->logger->debug("BruteForceProtection enabled");
|
||||
|
||||
# If Auth_N-2 older than MaxAge -> another try allowed
|
||||
$MaxAge = $lastFailedLoginEpoch[0] - $lastFailedLoginEpoch[2];
|
||||
# If Auth_N-MaxFailed older than MaxAge -> another try allowed
|
||||
$MaxAge
|
||||
= $lastFailedLoginEpoch[0]
|
||||
- $lastFailedLoginEpoch[ $self->conf->{bruteForceProtectionMaxFailed} - 1 ]
|
||||
if $self->conf->{bruteForceProtectionMaxFailed};
|
||||
$self->logger->debug(" -> MaxAge = $MaxAge");
|
||||
return PE_OK
|
||||
if ( $MaxAge > $self->conf->{bruteForceProtectionMaxAge} );
|
||||
if ( $MaxAge > $self->conf->{bruteForceProtectionMaxAge} );
|
||||
|
||||
# Delta between the two last failed logins -> Auth_N - Auth_N-1
|
||||
my $delta = time - $lastFailedLoginEpoch[1];
|
||||
my $delta = 0;
|
||||
$delta = time - $lastFailedLoginEpoch[1]
|
||||
if defined $lastFailedLoginEpoch[1];
|
||||
$self->logger->debug(" -> Delta = $delta");
|
||||
|
||||
# Delta between the two last failed logins < 30s => wait
|
||||
# Delta between the two last failed logins < Tempo => wait
|
||||
return PE_OK
|
||||
unless ( $delta <= $self->conf->{bruteForceProtectionTempo} );
|
||||
unless ( $delta <= $self->conf->{bruteForceProtectionTempo} );
|
||||
|
||||
# Account locked
|
||||
#shift @{ $req->sessionInfo->{_loginHistory}->{failedLogin} };
|
||||
return PE_WAIT;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,9 @@ my $client = LLNG::Manager::Test->new(
|
|||
loginHistoryEnabled => 1,
|
||||
bruteForceProtection => 1,
|
||||
bruteForceProtectionTempo => 5,
|
||||
bruteForceProtectionMaxFailed => 4,
|
||||
failedLoginNumber => 6,
|
||||
successLoginNumber => 4,
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -30,7 +33,7 @@ ok(
|
|||
length => 23,
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Auth query'
|
||||
'1st Auth query'
|
||||
);
|
||||
count(1);
|
||||
my $id1 = expectCookie($res);
|
||||
|
@ -46,7 +49,55 @@ ok(
|
|||
length => 23,
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Auth query'
|
||||
'2nd Auth query'
|
||||
);
|
||||
count(1);
|
||||
$id1 = expectCookie($res);
|
||||
expectRedirection( $res, 'http://auth.example.com/' );
|
||||
|
||||
$client->logout($id1);
|
||||
|
||||
## Third successful connection
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new('user=dwho&password=dwho'),
|
||||
length => 23,
|
||||
accept => 'text/html',
|
||||
),
|
||||
'3rd Auth query'
|
||||
);
|
||||
count(1);
|
||||
$id1 = expectCookie($res);
|
||||
expectRedirection( $res, 'http://auth.example.com/' );
|
||||
|
||||
$client->logout($id1);
|
||||
|
||||
## Forth successful connection
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new('user=dwho&password=dwho'),
|
||||
length => 23,
|
||||
accept => 'text/html',
|
||||
),
|
||||
'4th Auth query'
|
||||
);
|
||||
count(1);
|
||||
$id1 = expectCookie($res);
|
||||
expectRedirection( $res, 'http://auth.example.com/' );
|
||||
|
||||
$client->logout($id1);
|
||||
|
||||
## Fifth successful connection
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new('user=dwho&password=dwho'),
|
||||
length => 23,
|
||||
accept => 'text/html',
|
||||
),
|
||||
'5th Auth query'
|
||||
);
|
||||
count(1);
|
||||
$id1 = expectCookie($res);
|
||||
|
@ -61,7 +112,7 @@ ok(
|
|||
IO::String->new('user=dwho&password=ohwd'),
|
||||
length => 23
|
||||
),
|
||||
'Auth query'
|
||||
'1st Bad Auth query'
|
||||
);
|
||||
count(1);
|
||||
expectReject($res);
|
||||
|
@ -73,12 +124,36 @@ ok(
|
|||
IO::String->new('user=dwho&password=ohwd'),
|
||||
length => 23
|
||||
),
|
||||
'Auth query'
|
||||
'2nd Bad Auth query'
|
||||
);
|
||||
count(1);
|
||||
expectReject($res);
|
||||
|
||||
## Third failed connection -> rejected
|
||||
## Third failed connection
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new('user=dwho&password=ohwd'),
|
||||
length => 23
|
||||
),
|
||||
'3rd Bad Auth query'
|
||||
);
|
||||
count(1);
|
||||
expectReject($res);
|
||||
|
||||
## Forth failed connection
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
IO::String->new('user=dwho&password=ohwd'),
|
||||
length => 23
|
||||
),
|
||||
'4th Bad Auth query'
|
||||
);
|
||||
count(1);
|
||||
expectReject($res);
|
||||
|
||||
## Fifth failed connection -> rejected
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
|
@ -86,15 +161,15 @@ ok(
|
|||
length => 23,
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Auth query'
|
||||
'5th Bad Auth query'
|
||||
);
|
||||
count(1);
|
||||
|
||||
ok( $res->[2]->[0] =~ /<span trmsg="86"><\/span>/, 'Protection enabled' );
|
||||
ok( $res->[2]->[0] =~ /<span trmsg="86"><\/span>/, 'Rejected -> Protection enabled' );
|
||||
count(1);
|
||||
sleep 1;
|
||||
|
||||
## Fourth failed connection -> Rejected
|
||||
## Sixth failed connection -> Rejected
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
|
@ -102,15 +177,15 @@ ok(
|
|||
length => 23,
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Auth query'
|
||||
'6th Bad Auth query'
|
||||
);
|
||||
count(1);
|
||||
|
||||
ok( $res->[2]->[0] =~ /<span trmsg="86"><\/span>/, 'Protection enabled' );
|
||||
ok( $res->[2]->[0] =~ /<span trmsg="86"><\/span>/, 'Rejected -> Protection enabled' );
|
||||
count(1);
|
||||
sleep 2;
|
||||
|
||||
## Third successful connection -> Rejected
|
||||
## Sixth successful connection -> Rejected
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
|
@ -118,15 +193,15 @@ ok(
|
|||
length => 23,
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Auth query'
|
||||
'6th Auth query'
|
||||
);
|
||||
count(1);
|
||||
|
||||
ok( $res->[2]->[0] =~ /<span trmsg="86"><\/span>/, 'Protection enabled' );
|
||||
ok( $res->[2]->[0] =~ /<span trmsg="86"><\/span>/, 'Rejected -> Protection enabled' );
|
||||
count(1);
|
||||
sleep 3;
|
||||
|
||||
## Fourth successful connection -> Accepted
|
||||
## Seventh successful connection -> Accepted
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/',
|
||||
|
@ -134,7 +209,7 @@ ok(
|
|||
length => 37,
|
||||
accept => 'text/html',
|
||||
),
|
||||
'Auth query'
|
||||
'7th Auth query'
|
||||
);
|
||||
count(1);
|
||||
$id1 = expectCookie($res);
|
||||
|
@ -145,9 +220,9 @@ ok( $res->[2]->[0] =~ /trspan="lastLogins"/, 'History found' )
|
|||
my @c = ( $res->[2]->[0] =~ /<td>127.0.0.1/gs );
|
||||
my @cf = ( $res->[2]->[0] =~ /PE5<\/td>/gs );
|
||||
|
||||
# History with 5 entries
|
||||
ok( @c == 7, ' -> Seven entries found' );
|
||||
ok( @cf == 4, " -> Four 'failedLogin' entries found" );
|
||||
# History with 10 entries
|
||||
ok( @c == 10, ' -> Ten entries found' );
|
||||
ok( @cf == 6, " -> Six 'failedLogin' entries found" );
|
||||
count(3);
|
||||
|
||||
$client->logout($id1);
|
||||
|
|
Loading…
Reference in New Issue
Block a user