Merge branch '2276' into 'v2.0'
2276 See merge request lemonldap-ng/lemonldap-ng!159
This commit is contained in:
commit
5d056699c4
|
@ -20,6 +20,15 @@ Go in Manager, ``General Parameters`` » ``Advanced Parameters`` »
|
||||||
``Security`` » ``Brute-force attack protection`` » ``Activation``\ and
|
``Security`` » ``Brute-force attack protection`` » ``Activation``\ and
|
||||||
set to ``On``.
|
set to ``On``.
|
||||||
|
|
||||||
|
- **Parameters**:
|
||||||
|
|
||||||
|
- **Activation**: Enable/disable brute force attack protection
|
||||||
|
- **Lock time**: Waiting time before another login attempt
|
||||||
|
- **Allowed failed login**: Number of failed login attempts allowed before account is locked
|
||||||
|
- **Incremental lock**: Enable/disable incremental lock times
|
||||||
|
- **Incremental lock times**: List of comma separated lock time values in seconds
|
||||||
|
|
||||||
|
|
||||||
Incremental lock time enabled
|
Incremental lock time enabled
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -35,33 +44,29 @@ in ``lemonldap-ng.ini`` [portal] section:
|
||||||
[portal]
|
[portal]
|
||||||
bruteForceProtectionIncrementalTempo = 1
|
bruteForceProtectionIncrementalTempo = 1
|
||||||
|
|
||||||
Lock time increases between each failed login attempt. To modify lock
|
Lock time increases between each failed login attempt after allowed failed logins.
|
||||||
time values ('5 15 60 300 600' seconds by default) or max lock time
|
|
||||||
value (900 seconds by default) edit ``lemonldap-ng.ini`` in [portal]
|
|
||||||
section:
|
|
||||||
|
|
||||||
.. code-block:: ini
|
.. code-block:: ini
|
||||||
|
|
||||||
[portal]
|
[portal]
|
||||||
bruteForceProtectionLockTimes = '5 15 60 300 600'
|
bruteForceProtectionLockTimes = 5, 15, 60, 300, 600
|
||||||
bruteForceProtectionMaxLockTime = 900
|
bruteForceProtectionMaxLockTime = 900
|
||||||
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Max lock time value is used by this plugin if a lock time is
|
Max lock time value is used if a lock time is missing
|
||||||
missing (number of failed logins higher than listed lock time values).
|
(number of failed logins higher than listed lock time values).
|
||||||
Lock time values can not be higher than max lock time.
|
Lock time values can not be higher than max lock time.
|
||||||
|
|
||||||
|
|
||||||
Incremental lock time disabled
|
Incremental lock time disabled
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
After ``bruteForceProtectionMaxFailed`` failed login attempts, user must
|
After allowed failed login attempts, user must
|
||||||
wait ``bruteForceProtectionTempo`` seconds before trying to log in
|
wait the lock time before trying to log in again.
|
||||||
again. To modify waiting time (30 seconds by default), MaxAge between
|
To modify delta (MaxAge) between current and last stored
|
||||||
current and last stored failed login (300 seconds by default) or number
|
failed login (300 seconds by default) edit ``lemonldap-ng.ini`` in [portal] section:
|
||||||
of allowed failed login attempts (3 by default) edit
|
|
||||||
``lemonldap-ng.ini`` in [portal] section:
|
|
||||||
|
|
||||||
.. code-block:: ini
|
.. code-block:: ini
|
||||||
|
|
||||||
|
@ -72,7 +77,12 @@ of allowed failed login attempts (3 by default) edit
|
||||||
|
|
||||||
|
|
||||||
.. attention::
|
.. attention::
|
||||||
|
Number of failed login attempts history might be also higher than
|
||||||
|
number of incremental lock time value plus allowed failed login attempts.
|
||||||
|
Incremental lock time values list will be truncated if not.
|
||||||
|
|
||||||
|
|
||||||
|
.. danger::
|
||||||
Number of failed login attempts stored in history MUST
|
Number of failed login attempts stored in history MUST
|
||||||
be higher than allowed failed logins for this plugin takes effect.
|
be higher than allowed failed logins for this plugin takes effect.
|
||||||
See :doc:`History plugin<loginhistory>`
|
See :doc:`History plugin<loginhistory>`
|
|
@ -19,7 +19,7 @@ sub defaultValues {
|
||||||
'authentication' => 'Demo',
|
'authentication' => 'Demo',
|
||||||
'available2F' => 'UTOTP,TOTP,U2F,REST,Mail2F,Ext2F,Yubikey,Radius',
|
'available2F' => 'UTOTP,TOTP,U2F,REST,Mail2F,Ext2F,Yubikey,Radius',
|
||||||
'available2FSelfRegistration' => 'TOTP,U2F,Yubikey',
|
'available2FSelfRegistration' => 'TOTP,U2F,Yubikey',
|
||||||
'bruteForceProtectionLockTimes' => '5 15 60 300 600',
|
'bruteForceProtectionLockTimes' => '5, 15, 60, 300, 600',
|
||||||
'bruteForceProtectionMaxAge' => 300,
|
'bruteForceProtectionMaxAge' => 300,
|
||||||
'bruteForceProtectionMaxFailed' => 3,
|
'bruteForceProtectionMaxFailed' => 3,
|
||||||
'bruteForceProtectionMaxLockTime' => 900,
|
'bruteForceProtectionMaxLockTime' => 900,
|
||||||
|
|
|
@ -636,7 +636,7 @@ sub attributes {
|
||||||
'type' => 'bool'
|
'type' => 'bool'
|
||||||
},
|
},
|
||||||
'bruteForceProtectionLockTimes' => {
|
'bruteForceProtectionLockTimes' => {
|
||||||
'default' => '5 15 60 300 600',
|
'default' => '5, 15, 60, 300, 600',
|
||||||
'type' => 'text'
|
'type' => 'text'
|
||||||
},
|
},
|
||||||
'bruteForceProtectionMaxAge' => {
|
'bruteForceProtectionMaxAge' => {
|
||||||
|
|
|
@ -833,7 +833,7 @@ sub attributes {
|
||||||
},
|
},
|
||||||
bruteForceProtectionLockTimes => {
|
bruteForceProtectionLockTimes => {
|
||||||
type => 'text',
|
type => 'text',
|
||||||
default => '5 15 60 300 600',
|
default => '5, 15, 60, 300, 600',
|
||||||
documentation =>
|
documentation =>
|
||||||
'Incremental lock time values for brute force attack protection',
|
'Incremental lock time values for brute force attack protection',
|
||||||
},
|
},
|
||||||
|
|
|
@ -630,7 +630,8 @@ sub tree {
|
||||||
'notificationStorageOptions',
|
'notificationStorageOptions',
|
||||||
{
|
{
|
||||||
title => 'serverNotification',
|
title => 'serverNotification',
|
||||||
help => 'notifications.html#notification-server',
|
help =>
|
||||||
|
'notifications.html#notification-server',
|
||||||
nodes => [
|
nodes => [
|
||||||
'notificationServer',
|
'notificationServer',
|
||||||
'notificationDefaultCond',
|
'notificationDefaultCond',
|
||||||
|
@ -959,7 +960,10 @@ sub tree {
|
||||||
form => 'simpleInputContainer',
|
form => 'simpleInputContainer',
|
||||||
nodes => [
|
nodes => [
|
||||||
'bruteForceProtection',
|
'bruteForceProtection',
|
||||||
|
'bruteForceProtectionTempo',
|
||||||
|
'bruteForceProtectionMaxFailed',
|
||||||
'bruteForceProtectionIncrementalTempo',
|
'bruteForceProtectionIncrementalTempo',
|
||||||
|
'bruteForceProtectionLockTimes',
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
'lwpOpts',
|
'lwpOpts',
|
||||||
|
|
|
@ -254,8 +254,6 @@ sub tests {
|
||||||
return ( 1, "Cookie TTL should be higher or equal than one hour" )
|
return ( 1, "Cookie TTL should be higher or equal than one hour" )
|
||||||
unless ( $conf->{cookieExpiration} >= 3600
|
unless ( $conf->{cookieExpiration} >= 3600
|
||||||
|| $conf->{cookieExpiration} == 0 );
|
|| $conf->{cookieExpiration} == 0 );
|
||||||
|
|
||||||
# Return
|
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -265,8 +263,6 @@ sub tests {
|
||||||
return ( -1, "Session timeout should be higher than ten minutes" )
|
return ( -1, "Session timeout should be higher than ten minutes" )
|
||||||
unless ( $conf->{timeout} > 600
|
unless ( $conf->{timeout} > 600
|
||||||
|| $conf->{timeout} == 0 );
|
|| $conf->{timeout} == 0 );
|
||||||
|
|
||||||
# Return
|
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -278,8 +274,6 @@ sub tests {
|
||||||
)
|
)
|
||||||
unless ( $conf->{timeoutActivity} > 59
|
unless ( $conf->{timeoutActivity} > 59
|
||||||
|| $conf->{timeoutActivity} == 0 );
|
|| $conf->{timeoutActivity} == 0 );
|
||||||
|
|
||||||
# Return
|
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -292,8 +286,6 @@ sub tests {
|
||||||
if ( $conf->{timeoutActivity}
|
if ( $conf->{timeoutActivity}
|
||||||
and $conf->{timeoutActivity} <=
|
and $conf->{timeoutActivity} <=
|
||||||
$conf->{timeoutActivityInterval} );
|
$conf->{timeoutActivityInterval} );
|
||||||
|
|
||||||
# Return
|
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -338,8 +330,6 @@ sub tests {
|
||||||
return ( 1, "SMTP authentication failed" )
|
return ( 1, "SMTP authentication failed" )
|
||||||
unless $smtp->auth( $conf->{SMTPAuthUser},
|
unless $smtp->auth( $conf->{SMTPAuthUser},
|
||||||
$conf->{SMTPAuthPass} );
|
$conf->{SMTPAuthPass} );
|
||||||
|
|
||||||
# Return
|
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -441,8 +431,6 @@ sub tests {
|
||||||
unless ( $conf->{combination} );
|
unless ( $conf->{combination} );
|
||||||
return ( 0, 'userDB must be set to "Same" to enable Combination' )
|
return ( 0, 'userDB must be set to "Same" to enable Combination' )
|
||||||
unless ( $conf->{userDB} eq "Same" );
|
unless ( $conf->{userDB} eq "Same" );
|
||||||
|
|
||||||
# Return
|
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -482,8 +470,6 @@ sub tests {
|
||||||
"Auth::Yubikey_WebClient module is required to enable Yubikey"
|
"Auth::Yubikey_WebClient module is required to enable Yubikey"
|
||||||
) if ($@);
|
) if ($@);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Return
|
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -521,8 +507,6 @@ sub tests {
|
||||||
unless ( $conf->{totp2fRange} );
|
unless ( $conf->{totp2fRange} );
|
||||||
return ( 1, "TOTP interval should be higher than 10s" )
|
return ( 1, "TOTP interval should be higher than 10s" )
|
||||||
unless ( $conf->{totp2fInterval} > 10 );
|
unless ( $conf->{totp2fInterval} > 10 );
|
||||||
|
|
||||||
# Return
|
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -570,7 +554,6 @@ sub tests {
|
||||||
|| $conf->{'totp2fSelfRegistration'} );
|
|| $conf->{'totp2fSelfRegistration'} );
|
||||||
$msg = "A self registrable module should be enabled to require 2FA"
|
$msg = "A self registrable module should be enabled to require 2FA"
|
||||||
unless ($ok);
|
unless ($ok);
|
||||||
|
|
||||||
return ( 1, $msg );
|
return ( 1, $msg );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -583,8 +566,6 @@ sub tests {
|
||||||
return ( 0, "External 2F Validate command must be set" )
|
return ( 0, "External 2F Validate command must be set" )
|
||||||
unless ( defined $conf->{ext2FValidateCommand} );
|
unless ( defined $conf->{ext2FValidateCommand} );
|
||||||
}
|
}
|
||||||
|
|
||||||
# Return
|
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -595,8 +576,6 @@ sub tests {
|
||||||
unless ( $conf->{formTimeout} > 30 );
|
unless ( $conf->{formTimeout} > 30 );
|
||||||
return ( 1, "XSRF form token TTL should not be higher than 2mn" )
|
return ( 1, "XSRF form token TTL should not be higher than 2mn" )
|
||||||
if ( $conf->{formTimeout} > 120 );
|
if ( $conf->{formTimeout} > 120 );
|
||||||
|
|
||||||
# Return
|
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -607,8 +586,6 @@ sub tests {
|
||||||
unless ( $conf->{issuersTimeout} > 30 );
|
unless ( $conf->{issuersTimeout} > 30 );
|
||||||
return ( 1, "Issuers token TTL should not be higher than 2mn" )
|
return ( 1, "Issuers token TTL should not be higher than 2mn" )
|
||||||
if ( $conf->{issuersTimeout} > 120 );
|
if ( $conf->{issuersTimeout} > 120 );
|
||||||
|
|
||||||
# Return
|
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -617,8 +594,6 @@ sub tests {
|
||||||
return 1 unless ( $conf->{portalDisplayResetPassword} );
|
return 1 unless ( $conf->{portalDisplayResetPassword} );
|
||||||
return ( 1, "Number of reset password retries should not be null" )
|
return ( 1, "Number of reset password retries should not be null" )
|
||||||
unless ( $conf->{passwordResetAllowedRetries} );
|
unless ( $conf->{passwordResetAllowedRetries} );
|
||||||
|
|
||||||
# Return
|
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -641,8 +616,18 @@ sub tests {
|
||||||
return ( 1,
|
return ( 1,
|
||||||
'Number of failed logins must be higher than 2 to enable "BruteForceProtection" plugin'
|
'Number of failed logins must be higher than 2 to enable "BruteForceProtection" plugin'
|
||||||
) unless ( $conf->{failedLoginNumber} > 2 );
|
) unless ( $conf->{failedLoginNumber} > 2 );
|
||||||
|
return ( 1,
|
||||||
# Return
|
'Number of failed logins history must be higher than allowed failed logins plus lock time values'
|
||||||
|
)
|
||||||
|
if ( $conf->{bruteForceProtectionIncrementalTempo}
|
||||||
|
&& $conf->{failedLoginNumber} <=
|
||||||
|
$conf->{bruteForceProtectionMaxFailed} +
|
||||||
|
$conf->{bruteForceProtectionLockTimes} );
|
||||||
|
return ( 1,
|
||||||
|
'Number of failed logins history must be higher than allowed failed logins'
|
||||||
|
)
|
||||||
|
unless ( $conf->{failedLoginNumber} >
|
||||||
|
$conf->{bruteForceProtectionMaxFailed} );
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -654,8 +639,6 @@ sub tests {
|
||||||
)
|
)
|
||||||
unless ( $conf->{requireToken}
|
unless ( $conf->{requireToken}
|
||||||
or $conf->{captcha_mail_enabled} );
|
or $conf->{captcha_mail_enabled} );
|
||||||
|
|
||||||
# Return
|
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -666,8 +649,6 @@ sub tests {
|
||||||
)
|
)
|
||||||
if ( $conf->{impersonationRule}
|
if ( $conf->{impersonationRule}
|
||||||
&& $conf->{contextSwitchingRule} );
|
&& $conf->{contextSwitchingRule} );
|
||||||
|
|
||||||
# Return
|
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -691,8 +672,6 @@ sub tests {
|
||||||
return ( 1,
|
return ( 1,
|
||||||
"BruteForceProtection plugin enabled WITHOUT persistent session storage"
|
"BruteForceProtection plugin enabled WITHOUT persistent session storage"
|
||||||
) if ( $conf->{bruteForceProtection} );
|
) if ( $conf->{bruteForceProtection} );
|
||||||
|
|
||||||
# Return
|
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -707,8 +686,6 @@ sub tests {
|
||||||
return ( 1,
|
return ( 1,
|
||||||
"XML::LibXSLT module is required to enable old format notifications"
|
"XML::LibXSLT module is required to enable old format notifications"
|
||||||
) if ($@);
|
) if ($@);
|
||||||
|
|
||||||
# Return
|
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -722,8 +699,6 @@ sub tests {
|
||||||
return ( 1,
|
return ( 1,
|
||||||
"DateTime::Format::RFC3339 module is required to enable CertificateResetByMail plugin"
|
"DateTime::Format::RFC3339 module is required to enable CertificateResetByMail plugin"
|
||||||
) if ($@);
|
) if ($@);
|
||||||
|
|
||||||
# Return
|
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -867,7 +842,6 @@ sub tests {
|
||||||
and $conf->{portal} !~ /^https:/ );
|
and $conf->{portal} !~ /^https:/ );
|
||||||
return 1;
|
return 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,10 @@
|
||||||
"browseTree":"تصفح الهيكل",
|
"browseTree":"تصفح الهيكل",
|
||||||
"bruteForceProtection":"تفعيل",
|
"bruteForceProtection":"تفعيل",
|
||||||
"bruteForceAttackProtection":"Brute-force attack protection",
|
"bruteForceAttackProtection":"Brute-force attack protection",
|
||||||
"bruteForceProtectionIncrementalTempo":"Incremental lock times",
|
"bruteForceProtectionIncrementalTempo":"Incremental lock",
|
||||||
|
"bruteForceProtectionLockTimes":"Incremental lock times",
|
||||||
|
"bruteForceProtectionMaxFailed":"Allowed failed logins",
|
||||||
|
"bruteForceProtectionTempo":"Lock time",
|
||||||
"cancel":"إلغاء",
|
"cancel":"إلغاء",
|
||||||
"captcha_login_enabled":"التفعيل في استمارة تسجيل الدخول",
|
"captcha_login_enabled":"التفعيل في استمارة تسجيل الدخول",
|
||||||
"captcha_mail_enabled":"التفعيل في إعادة تعيين كلمة المرور بواسطة استمارة البريد",
|
"captcha_mail_enabled":"التفعيل في إعادة تعيين كلمة المرور بواسطة استمارة البريد",
|
||||||
|
|
|
@ -106,7 +106,10 @@
|
||||||
"browseTree":"Browse tree",
|
"browseTree":"Browse tree",
|
||||||
"bruteForceProtection":"Activation",
|
"bruteForceProtection":"Activation",
|
||||||
"bruteForceAttackProtection":"Brute-force attack protection",
|
"bruteForceAttackProtection":"Brute-force attack protection",
|
||||||
"bruteForceProtectionIncrementalTempo":"Incremental lock times",
|
"bruteForceProtectionIncrementalTempo":"Incremental lock",
|
||||||
|
"bruteForceProtectionLockTimes":"Incremental lock times",
|
||||||
|
"bruteForceProtectionMaxFailed":"Allowed failed logins",
|
||||||
|
"bruteForceProtectionTempo":"Lock time",
|
||||||
"cancel":"Abbrechen",
|
"cancel":"Abbrechen",
|
||||||
"captcha_login_enabled":"Activation in login form",
|
"captcha_login_enabled":"Activation in login form",
|
||||||
"captcha_mail_enabled":"Activation in password reset by mail form",
|
"captcha_mail_enabled":"Activation in password reset by mail form",
|
||||||
|
|
|
@ -106,7 +106,10 @@
|
||||||
"browseTree":"Browse tree",
|
"browseTree":"Browse tree",
|
||||||
"bruteForceProtection":"Activation",
|
"bruteForceProtection":"Activation",
|
||||||
"bruteForceAttackProtection":"Brute-force attack protection",
|
"bruteForceAttackProtection":"Brute-force attack protection",
|
||||||
"bruteForceProtectionIncrementalTempo":"Incremental lock times",
|
"bruteForceProtectionIncrementalTempo":"Incremental lock",
|
||||||
|
"bruteForceProtectionLockTimes":"Incremental lock times",
|
||||||
|
"bruteForceProtectionMaxFailed":"Allowed failed logins",
|
||||||
|
"bruteForceProtectionTempo":"Lock time",
|
||||||
"cancel":"Cancel",
|
"cancel":"Cancel",
|
||||||
"captcha_login_enabled":"Activation in login form",
|
"captcha_login_enabled":"Activation in login form",
|
||||||
"captcha_mail_enabled":"Activation in password reset by mail form",
|
"captcha_mail_enabled":"Activation in password reset by mail form",
|
||||||
|
|
|
@ -106,7 +106,10 @@
|
||||||
"browseTree":"Parcourir l'arbre",
|
"browseTree":"Parcourir l'arbre",
|
||||||
"bruteForceProtection":"Activation",
|
"bruteForceProtection":"Activation",
|
||||||
"bruteForceAttackProtection":"Protection contre les attaques par force brute",
|
"bruteForceAttackProtection":"Protection contre les attaques par force brute",
|
||||||
"bruteForceProtectionIncrementalTempo":"Temps de verrouillage incrémentiels",
|
"bruteForceProtectionIncrementalTempo":"Verrouillage incrémentiel",
|
||||||
|
"bruteForceProtectionLockTimes":"Temps de verrouillage incrémentiel",
|
||||||
|
"bruteForceProtectionMaxFailed":"Nombre d'échecs de connexion autorisés",
|
||||||
|
"bruteForceProtectionTempo":"Temps de verrouillage",
|
||||||
"cancel":"Annuler",
|
"cancel":"Annuler",
|
||||||
"captcha_login_enabled":"Activation dans le formulaire d'authentification",
|
"captcha_login_enabled":"Activation dans le formulaire d'authentification",
|
||||||
"captcha_mail_enabled":"Activation dans le formulaire de réinitialisation par mail",
|
"captcha_mail_enabled":"Activation dans le formulaire de réinitialisation par mail",
|
||||||
|
|
|
@ -106,7 +106,10 @@
|
||||||
"browseTree":"Naviga albero",
|
"browseTree":"Naviga albero",
|
||||||
"bruteForceProtection":"Attivazione",
|
"bruteForceProtection":"Attivazione",
|
||||||
"bruteForceAttackProtection":"Brute-force attack protection",
|
"bruteForceAttackProtection":"Brute-force attack protection",
|
||||||
"bruteForceProtectionIncrementalTempo":"Incremental lock times",
|
"bruteForceProtectionIncrementalTempo":"Incremental lock",
|
||||||
|
"bruteForceProtectionLockTimes":"Incremental lock times",
|
||||||
|
"bruteForceProtectionMaxFailed":"Allowed failed logins",
|
||||||
|
"bruteForceProtectionTempo":"Lock time",
|
||||||
"cancel":"Cancella",
|
"cancel":"Cancella",
|
||||||
"captcha_login_enabled":"Attivazione nel modulo di login",
|
"captcha_login_enabled":"Attivazione nel modulo di login",
|
||||||
"captcha_mail_enabled":"Attivazione della reimpostazione della password tramite modulo di posta",
|
"captcha_mail_enabled":"Attivazione della reimpostazione della password tramite modulo di posta",
|
||||||
|
|
|
@ -106,7 +106,10 @@
|
||||||
"browseTree":"Przeglądaj drzewo",
|
"browseTree":"Przeglądaj drzewo",
|
||||||
"bruteForceProtection":"Aktywacja",
|
"bruteForceProtection":"Aktywacja",
|
||||||
"bruteForceAttackProtection":"Ochrona przed atakiem siłowym",
|
"bruteForceAttackProtection":"Ochrona przed atakiem siłowym",
|
||||||
"bruteForceProtectionIncrementalTempo":"Przyrostowe czasy blokady",
|
"bruteForceProtectionIncrementalTempo":"Incremental lock",
|
||||||
|
"bruteForceProtectionLockTimes":"Incremental lock times",
|
||||||
|
"bruteForceProtectionMaxFailed":"Allowed failed logins",
|
||||||
|
"bruteForceProtectionTempo":"Lock time",
|
||||||
"cancel":"Anuluj",
|
"cancel":"Anuluj",
|
||||||
"captcha_login_enabled":"Aktywacja w formularzu logowania",
|
"captcha_login_enabled":"Aktywacja w formularzu logowania",
|
||||||
"captcha_mail_enabled":"Aktywacja przy resetowaniu hasła za pomocą formularza pocztowego",
|
"captcha_mail_enabled":"Aktywacja przy resetowaniu hasła za pomocą formularza pocztowego",
|
||||||
|
|
|
@ -106,7 +106,10 @@
|
||||||
"browseTree":"Ağaca göz at",
|
"browseTree":"Ağaca göz at",
|
||||||
"bruteForceProtection":"Aktivasyon",
|
"bruteForceProtection":"Aktivasyon",
|
||||||
"bruteForceAttackProtection":"Kaba kuvvet saldırı koruması",
|
"bruteForceAttackProtection":"Kaba kuvvet saldırı koruması",
|
||||||
"bruteForceProtectionIncrementalTempo":"Artan gecikme zamanı",
|
"bruteForceProtectionIncrementalTempo":"Incremental lock",
|
||||||
|
"bruteForceProtectionLockTimes":"Incremental lock times",
|
||||||
|
"bruteForceProtectionMaxFailed":"Allowed failed logins",
|
||||||
|
"bruteForceProtectionTempo":"Lock time",
|
||||||
"cancel":"İptal Et",
|
"cancel":"İptal Et",
|
||||||
"captcha_login_enabled":"Giriş formunda aktivasyon",
|
"captcha_login_enabled":"Giriş formunda aktivasyon",
|
||||||
"captcha_mail_enabled":"E-posta formu tarafından parola sıfırlamada aktivasyon",
|
"captcha_mail_enabled":"E-posta formu tarafından parola sıfırlamada aktivasyon",
|
||||||
|
|
|
@ -106,7 +106,10 @@
|
||||||
"browseTree":"Duyệt cây",
|
"browseTree":"Duyệt cây",
|
||||||
"bruteForceProtection":"Kích hoạt",
|
"bruteForceProtection":"Kích hoạt",
|
||||||
"bruteForceAttackProtection":"Brute-force attack protection",
|
"bruteForceAttackProtection":"Brute-force attack protection",
|
||||||
"bruteForceProtectionIncrementalTempo":"Incremental lock times",
|
"bruteForceProtectionIncrementalTempo":"Incremental lock",
|
||||||
|
"bruteForceProtectionLockTimes":"Incremental lock times",
|
||||||
|
"bruteForceProtectionMaxFailed":"Allowed failed logins",
|
||||||
|
"bruteForceProtectionTempo":"Lock time",
|
||||||
"cancel":"Hủy",
|
"cancel":"Hủy",
|
||||||
"captcha_login_enabled":"Kích hoạt ở dạng đăng nhập",
|
"captcha_login_enabled":"Kích hoạt ở dạng đăng nhập",
|
||||||
"captcha_mail_enabled":"Kích hoạt đặt lại mật khẩu bằng biểu mẫu thư",
|
"captcha_mail_enabled":"Kích hoạt đặt lại mật khẩu bằng biểu mẫu thư",
|
||||||
|
|
|
@ -106,7 +106,10 @@
|
||||||
"browseTree":"浏览树",
|
"browseTree":"浏览树",
|
||||||
"bruteForceProtection":"激活",
|
"bruteForceProtection":"激活",
|
||||||
"bruteForceAttackProtection":"Brute-force attack protection",
|
"bruteForceAttackProtection":"Brute-force attack protection",
|
||||||
"bruteForceProtectionIncrementalTempo":"Incremental lock times",
|
"bruteForceProtectionIncrementalTempo":"Incremental lock",
|
||||||
|
"bruteForceProtectionLockTimes":"Incremental lock times",
|
||||||
|
"bruteForceProtectionMaxFailed":"Allowed failed logins",
|
||||||
|
"bruteForceProtectionTempo":"Lock time",
|
||||||
"cancel":"取消",
|
"cancel":"取消",
|
||||||
"captcha_login_enabled":" 登录激活",
|
"captcha_login_enabled":" 登录激活",
|
||||||
"captcha_mail_enabled":"通过邮件进行密码重置 激活",
|
"captcha_mail_enabled":"通过邮件进行密码重置 激活",
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -24,10 +24,6 @@ my @notManagedAttributes = (
|
||||||
'sfEngine', 'available2FSelfRegistration', 'available2F', 'max2FDevices',
|
'sfEngine', 'available2FSelfRegistration', 'available2F', 'max2FDevices',
|
||||||
'max2FDevicesNameLength',
|
'max2FDevicesNameLength',
|
||||||
|
|
||||||
# Brute force attack protection parameters
|
|
||||||
'bruteForceProtectionMaxAge', 'bruteForceProtectionTempo',
|
|
||||||
'bruteForceProtectionMaxFailed',
|
|
||||||
|
|
||||||
# Handlers
|
# Handlers
|
||||||
'handlerInternalCache', 'handlerServiceTokenTTL',
|
'handlerInternalCache', 'handlerServiceTokenTTL',
|
||||||
|
|
||||||
|
@ -42,8 +38,8 @@ my @notManagedAttributes = (
|
||||||
'syslogFacility', 'userLogger', 'logLevel',
|
'syslogFacility', 'userLogger', 'logLevel',
|
||||||
|
|
||||||
# Plugins parameters
|
# Plugins parameters
|
||||||
'notificationsMaxRetrieve', 'persistentSessionAttributes',
|
'notificationsMaxRetrieve', 'persistentSessionAttributes',
|
||||||
'bruteForceProtectionLockTimes', 'bruteForceProtectionMaxLockTime',
|
'bruteForceProtectionMaxAge', 'bruteForceProtectionMaxLockTime',
|
||||||
|
|
||||||
# PSGI/CGI protection (must be set in lemonldap-ng.ini)
|
# PSGI/CGI protection (must be set in lemonldap-ng.ini)
|
||||||
'protection',
|
'protection',
|
||||||
|
|
|
@ -4,7 +4,7 @@ use strict;
|
||||||
use Mouse;
|
use Mouse;
|
||||||
use Lemonldap::NG::Portal::Main::Constants qw(PE_OK PE_WAIT);
|
use Lemonldap::NG::Portal::Main::Constants qw(PE_OK PE_WAIT);
|
||||||
|
|
||||||
our $VERSION = '2.0.8';
|
our $VERSION = '2.0.9';
|
||||||
|
|
||||||
extends 'Lemonldap::NG::Portal::Main::Plugin';
|
extends 'Lemonldap::NG::Portal::Main::Plugin';
|
||||||
|
|
||||||
|
@ -38,9 +38,9 @@ sub init {
|
||||||
unless ( $self->conf->{failedLoginNumber} >
|
unless ( $self->conf->{failedLoginNumber} >
|
||||||
$self->conf->{bruteForceProtectionMaxFailed} )
|
$self->conf->{bruteForceProtectionMaxFailed} )
|
||||||
{
|
{
|
||||||
$self->logger->error( 'failedLoginNumber('
|
$self->logger->error( 'Number of failed logins history ('
|
||||||
. $self->conf->{failedLoginNumber}
|
. $self->conf->{failedLoginNumber}
|
||||||
. ') must be higher than bruteForceProtectionMaxFailed('
|
. ') must be higher than allowed failed logins attempt ('
|
||||||
. $self->conf->{bruteForceProtectionMaxFailed}
|
. $self->conf->{bruteForceProtectionMaxFailed}
|
||||||
. ')' );
|
. ')' );
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -48,20 +48,33 @@ sub init {
|
||||||
if ( $self->conf->{bruteForceProtectionIncrementalTempo} ) {
|
if ( $self->conf->{bruteForceProtectionIncrementalTempo} ) {
|
||||||
my $lockTimes = @{ $self->lockTimes } =
|
my $lockTimes = @{ $self->lockTimes } =
|
||||||
sort { $a <=> $b }
|
sort { $a <=> $b }
|
||||||
map { $_ < $self->conf->{bruteForceProtectionMaxLockTime} ? $_ : () }
|
map {
|
||||||
|
$_ =~ s/\D//;
|
||||||
|
$_ < $self->conf->{bruteForceProtectionMaxLockTime} ? $_ : ()
|
||||||
|
}
|
||||||
grep { /\d+/ }
|
grep { /\d+/ }
|
||||||
split /\s+/, $self->conf->{bruteForceProtectionLockTimes};
|
split /\s*,\s*/, $self->conf->{bruteForceProtectionLockTimes};
|
||||||
|
|
||||||
unless ($lockTimes) {
|
unless ($lockTimes) {
|
||||||
@{ $self->lockTimes } = ( 5, 15, 60, 300, 600 );
|
@{ $self->lockTimes } = ( 5, 15, 60, 300, 600 );
|
||||||
$lockTimes = 5;
|
$lockTimes = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $lockTimes > $self->conf->{failedLoginNumber} ) {
|
for (
|
||||||
$self->logger->warn( 'Number of incremental lock time values ('
|
my $i = 1 ;
|
||||||
. "$lockTimes) is higher than failed logins history ("
|
$i <= $self->conf->{bruteForceProtectionMaxFailed} ;
|
||||||
|
$i++
|
||||||
|
)
|
||||||
|
{
|
||||||
|
unshift @{ $self->lockTimes }, 0;
|
||||||
|
$lockTimes++;
|
||||||
|
}
|
||||||
|
|
||||||
|
unless ( $lockTimes < $self->conf->{failedLoginNumber} ) {
|
||||||
|
$self->logger->warn( 'Number failed logins history ('
|
||||||
. $self->conf->{failedLoginNumber}
|
. $self->conf->{failedLoginNumber}
|
||||||
. ')' );
|
. ') must be higher than incremental lock time values plus allowed failed logins attempt ('
|
||||||
|
. "$lockTimes)" );
|
||||||
splice @{ $self->lockTimes }, $self->conf->{failedLoginNumber};
|
splice @{ $self->lockTimes }, $self->conf->{failedLoginNumber};
|
||||||
$lockTimes = $self->conf->{failedLoginNumber};
|
$lockTimes = $self->conf->{failedLoginNumber};
|
||||||
}
|
}
|
||||||
|
@ -96,9 +109,9 @@ sub run {
|
||||||
my $delta = $now - $lastFailedLoginEpoch;
|
my $delta = $now - $lastFailedLoginEpoch;
|
||||||
$self->logger->debug(" -> Delta = $delta");
|
$self->logger->debug(" -> Delta = $delta");
|
||||||
my $waitingTime = $self->lockTimes->[ $countFailed - 1 ]
|
my $waitingTime = $self->lockTimes->[ $countFailed - 1 ]
|
||||||
|| $self->conf->{bruteForceProtectionMaxLockTime};
|
// $self->conf->{bruteForceProtectionMaxLockTime};
|
||||||
$self->logger->debug(" -> Waiting time = $waitingTime");
|
$self->logger->debug(" -> Waiting time = $waitingTime");
|
||||||
unless ( $delta > $waitingTime ) {
|
if ( $waitingTime && $delta <= $waitingTime ) {
|
||||||
$self->logger->debug("BruteForceProtection enabled");
|
$self->logger->debug("BruteForceProtection enabled");
|
||||||
$req->lockTime($waitingTime);
|
$req->lockTime($waitingTime);
|
||||||
return PE_WAIT;
|
return PE_WAIT;
|
||||||
|
|
|
@ -26,6 +26,7 @@ SKIP: {
|
||||||
totp2fSelfRegistration => 1,
|
totp2fSelfRegistration => 1,
|
||||||
totp2fActivation => 1,
|
totp2fActivation => 1,
|
||||||
failedLoginNumber => 4,
|
failedLoginNumber => 4,
|
||||||
|
bruteForceProtectionMaxFailed => 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -16,9 +16,10 @@ my $client = LLNG::Manager::Test->new( {
|
||||||
loginHistoryEnabled => 1,
|
loginHistoryEnabled => 1,
|
||||||
bruteForceProtection => 1,
|
bruteForceProtection => 1,
|
||||||
bruteForceProtectionIncrementalTempo => 1,
|
bruteForceProtectionIncrementalTempo => 1,
|
||||||
failedLoginNumber => 4,
|
failedLoginNumber => 6,
|
||||||
bruteForceProtectionMaxLockTime => 300,
|
bruteForceProtectionMaxLockTime => 300,
|
||||||
bruteForceProtectionLockTimes => '5 500 bad 20 10 ',
|
bruteForceProtectionLockTimes => '5 , 500, bad ,20, 10 ',
|
||||||
|
bruteForceProtectionMaxFailed => 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -38,6 +39,36 @@ my $id = expectCookie($res);
|
||||||
expectRedirection( $res, 'http://auth.example.com/' );
|
expectRedirection( $res, 'http://auth.example.com/' );
|
||||||
$client->logout($id);
|
$client->logout($id);
|
||||||
|
|
||||||
|
## First allowed failed login
|
||||||
|
ok(
|
||||||
|
$res = $client->_post(
|
||||||
|
'/',
|
||||||
|
IO::String->new('user=dwho&password=ohwd'),
|
||||||
|
length => 23,
|
||||||
|
accept => 'text/html',
|
||||||
|
),
|
||||||
|
'1st allowed Bad Auth query'
|
||||||
|
);
|
||||||
|
ok( $res->[2]->[0] =~ /<span trmsg="5"><\/span>/,
|
||||||
|
'Bad credential' )
|
||||||
|
or print STDERR Dumper( $res->[2]->[0] );
|
||||||
|
count(2);
|
||||||
|
|
||||||
|
## Second allowed failed login
|
||||||
|
ok(
|
||||||
|
$res = $client->_post(
|
||||||
|
'/',
|
||||||
|
IO::String->new('user=dwho&password=ohwd'),
|
||||||
|
length => 23,
|
||||||
|
accept => 'text/html',
|
||||||
|
),
|
||||||
|
'2nd allowed Bad Auth query'
|
||||||
|
);
|
||||||
|
ok( $res->[2]->[0] =~ /<span trmsg="5"><\/span>/,
|
||||||
|
'Bad credential' )
|
||||||
|
or print STDERR Dumper( $res->[2]->[0] );
|
||||||
|
count(2);
|
||||||
|
|
||||||
## First failed connection
|
## First failed connection
|
||||||
ok(
|
ok(
|
||||||
$res = $client->_post(
|
$res = $client->_post(
|
||||||
|
|
Loading…
Reference in New Issue
Block a user