Automatic unlocking when user successfully login into LDAP/AD

Post about your customizations to share with others.

Moderators: Developer, Contributor

Post Reply
lgmatabh
Posts: 2
Joined: 12 May 2024, 18:30

Automatic unlocking when user successfully login into LDAP/AD

Post by lgmatabh »

Guys

We use MantiBT 2.26.x with an AD/LDAP directory service at a large corporation.

When the user changes the password in AD/LDAP, in the Service Center, because he has forgotten it, the account is already blocked by the limit "$g_max_failed_login_count = 3;" on MantisBT.

I understand that this limit may apply well to users on the local MantisBT base and not with a central directory service, where the account must be blocked by (n) attempts in AD/LDAP.

We do not use local users on MantisBT and this creates a huge demand for administrators to perform the unlock manually.

I carried out an assessment and implemented a solution so that access with valid authentication in the central AD/LDAP does not block the user in MantisBT.

It worked adequately for me. If you have another solution to not block valid AD/LDAP users on Mantis (keeping the parameter $g_max_failed_login_count = 3 for local users). Thanks for the tip on an alternative solution. :D

Here my implementation:

config_defaults_inc.php <-- product default with parameter included.

/**
* LDAP failed login no locked
*
* Allows access when login is successful in LDAP
* - When OFF (default), keeps users locked in MantisBT
* - When enabled, resets login failure count to zero, upon successful LDAP login, user account not locked in MantisBT
*
* @global integer $g_ldap_failed_login_no_locked
*/
$g_ldap_failed_login_no_locked = OFF;

config/config_inc.php <-- Our default with parameter included.

/**
* LDAP failed login no locked
*
* Allows access when login is successful in LDAP
* - When OFF (default), keeps users locked in MantisBT
* - When enabled, resets login failure count to zero, upon successful LDAP login, user account not locked in MantisBT

$g_ldap_failed_login_no_locked = ON;

diff /var/www/html/mantisbt/core/authentication_api.php ../mantisbt-2.26.1/core/authentication_api.php

509,512c509,510
< if (( config_get_global( 'login_method' ) != LDAP ) || ( config_get_global( 'ldap_failed_login_no_locked' ) != 1 )) {
< if( !user_is_login_request_allowed( $t_user_id ) ) {
< return false;
< }
---
> if( !user_is_login_request_allowed( $t_user_id ) ) {
> return false;


--

thanks
lgmatabh
Posts: 2
Joined: 12 May 2024, 18:30

Re: Automatic unlocking when user successfully login into LDAP/AD

Post by lgmatabh »

Guys,

In addition to having WAF - Web Application Firewall, protecting our MantisBT, I improved the implementation and coded a defense for Dynamic Blocking for brute force login, based on login failure parameters and dynamic blocking time in the same HTTP session. It works in the same way as current and static locking (with manual unlocking), but dynamic.

If log_ldap is enabled, it generates additional logs.

If anyone would like to help revalidate the tests, standardize variable names and improve the code, I would be grateful.

I don't know the standardization of MantisBT

config_defaults_inc.php

/**
* LDAP failed login no locked
*
* Allows access when login is successful in LDAP
* - When OFF (default), keeps users locked in MantisBT
* - When enabled, resets login failure count to zero, upon successful LDAP login, user account not locked in MantisBT
* @global integer $g_ldap_failed_login_no_locked
*/
$g_ldap_failed_login_no_locked = OFF;

/**
* Dynamic Locked LDAP failed login by count login failed AND interval time login for existent user
*
* g_failed_ldap_login_limit = limit number of failed tentatives of login
* g_lockout_interval_time_failed = lockout interval time in seconds
*
* @global integer $g_failed_ldap_login_limit
* @global integer $g_lockout_interval_time_failed
*/
$g_failed_ldap_login_limit = 5;
$g_lockout_interval_time_failed = 600;


/config/config_inc.php

/* No locked LDAP login failed */

$g_ldap_failed_login_no_locked = ON;

$g_failed_ldap_login_limit = 5;
$g_lockout_interval_time_failed = 60;

core/authentication_api.php


function auth_attempt_login( $p_username, $p_password, $p_perm_login = false ) {
$t_user_id = auth_get_user_id_from_login_name( $p_username );

if( $t_user_id === false ) {
$t_user_id = auth_auto_create_user( $p_username, $p_password );
if( $t_user_id === false ) {
return false;
}
}

# max. failed login attempts achieved...
if (( config_get_global( 'login_method' ) != LDAP ) || ( config_get_global( 'ldap_failed_login_no_locked' ) != 1 )) {
if( !user_is_login_request_allowed( $t_user_id ) ) {
return false;
}
}

if ( config_get_global( 'login_method' ) == LDAP ) {
# only arrives here if the user exists
$t_failed_ldap_login_limit = config_get_global( 'failed_ldap_login_limit' );
$t_lockout_interval_time_failed = config_get_global( 'lockout_interval_time_failed' );

$t_failed_login_count = user_get_field( $t_user_id, 'failed_login_count' );
$t_last_visit = user_get_field( $t_user_id, 'last_visit' );

$_SESSION['g_login_ldap_prev'] = $_SESSION['g_login_ldap_next'];

if ( !$_SESSION['g_login_ldap_prev'] == null ) {
$_SESSION['g_login_ldap_next'] = db_now();
}else {
$_SESSION['g_login_ldap_prev'] = $t_last_visit;
$_SESSION['g_login_ldap_next'] = $t_last_visit;
}

++$_SESSION['g_login_attempt_counter'];

# difference between HTTP request login
$t_time_diff = ( $_SESSION['g_login_ldap_next'] - $_SESSION['g_login_ldap_prev'] );

if ( config_get_global( 'log_level' ) == LOG_LDAP ) {
log_event( LOG_LDAP, 'brute-force - parameters -> ' . ' login counter : ' . $_SESSION['g_login_attempt_counter'] . ' | User : ' . $p_username . ' | Login time diff in seconds : ' . $t_time_diff . 's ' . ' | Config - lockout_interval_time_failed : ' . config_get_global( 'lockout_interval_time_failed' ) . ' | Number of DB failed login : ' . $t_failed_login_count . ' | Config - failed ldap login limit : ' . config_get_global( 'failed_ldap_login_limit' ) . ' ' );
}

# if number of failed login in DB($t_failed_login_count) is >= then config(failed_ldap_login_limit) AND time request HTTP login in LDAP($t_time_diff) < then config (lockout_interval_time_failed)
if ( $t_failed_login_count >= config_get_global( 'failed_ldap_login_limit' ) && ( $t_time_diff < $t_lockout_interval_time_failed ) ) {
$p_session_id = session_id();
log_event( LOG_LDAP, 'Could be brute-force - 1 in session_id : ' . $p_session_id . ' | User : ' . $p_username . ' Possible login brute-force ' . ' ' );
log_event( LOG_LDAP, 'Could be brute-force - 2 in session_id : ' . $p_session_id . ' | Login time diff in seconds : ' . $t_time_diff . 's ' . ' | Config - lockout_interval_time_failed : ' . config_get_global( 'lockout_interval_time_failed' ) . ' | Number of DB failed login : ' . $t_failed_login_count . ' | Config - failed ldap login limit : ' . config_get_global( 'failed_ldap_login_limit' ) . ' ' );
return false;
}
}

# check for anonymous login
if( !user_is_anonymous( $t_user_id ) ) {
# anonymous login didn't work, so check the password
if( !auth_does_password_match( $t_user_id, $p_password ) ) {
user_increment_failed_login_count( $t_user_id );
return false;
}
}

return auth_login_user( $t_user_id, $p_perm_login );
}

Thanks
Last edited by lgmatabh on 16 May 2024, 01:07, edited 2 times in total.
Post Reply