import logging from django.utils.translation import gettext_lazy from core.models import ConsoleAuthSettings from core.utils import dtnow _log = logging.getLogger(__name__) def create_authentication_log_message(action, message, ip_addr=None): log_string = f'Authentication {action}' if ip_addr: log_string += f' from ip: {ip_addr}' log_string += f': {message}' return log_string def handle_login_attempt(attempt_username_data, login_successful, ip_address): if attempt_username_data.is_username_auth_blocked: _log.info(create_authentication_log_message( 'attempt', f'[{attempt_username_data.user.username}] account is blocked until ' f'{attempt_username_data.username_unlock_time}', ip_address)) attempt_username_data.save() return False, gettext_lazy('Authentication for this user is blocked. Please contact administrator') if login_successful: if attempt_username_data.failed_login_attempts == 0: _log.info(create_authentication_log_message( 'attempt', f'[{attempt_username_data.user.username}] has been successfully authenticated', ip_address)) attempt_username_data.save() return True, None else: _log.info(create_authentication_log_message( 'attempt', f'[{attempt_username_data.user.username}] has been successfully authenticated after ' f'{attempt_username_data.failed_login_attempts} ' f'tries. Failed login attempts counter has been reset', ip_address)) attempt_username_data.failed_login_attempts = 0 attempt_username_data.save() return True, None else: # Get authentication settings auth_settings = ConsoleAuthSettings.get_solo() _log.info(create_authentication_log_message( 'attempt', f'[{attempt_username_data.user.username}] failed to authenticate. Amount of failed attempts: ' f'{attempt_username_data.failed_login_attempts + 1}/{auth_settings.login_attempts_limit}', ip_address)) amount_of_failed_attempts = attempt_username_data.failed_login_attempts + 1 attempt_username_data.failed_login_attempts += 1 if (auth_settings.login_attempts_limit > 0 and amount_of_failed_attempts == auth_settings.login_attempts_limit and attempt_username_data.is_username_auth_blocked == False): attempt_username_data.is_username_auth_blocked = True user_unlock_time = dtnow() + auth_settings.login_block_timeout _log.info(create_authentication_log_message( 'settings', f'[{attempt_username_data.user.username}] Blocked authentication for ' f'{attempt_username_data.user.username} until {user_unlock_time} ' f'due to the exceeding the limit of login attempts', ip_address)) attempt_username_data.username_unlock_time = user_unlock_time attempt_username_data.save() return False, gettext_lazy('Authentication for this user is blocked for {time}').format( time=auth_settings.login_block_timeout) elif attempt_username_data.is_username_auth_blocked: _log.info(create_authentication_log_message( 'attempt', f'[{attempt_username_data.user.username}] failed to authenticate due to timeout. ' f'Amount of failed attempts: ' f'{attempt_username_data.failed_login_attempts + 1}/{auth_settings.login_attempts_limit}', ip_address)) return False, gettext_lazy( "Authentication for this user is blocked, please contact system administrator"), attempt_username_data.save() return False, gettext_lazy('Please enter a correct username and password. ' 'Note that both fields may be case-sensitive.') def get_timeout_formatted(console_auth_settings): """ Method for formatting DurationField into dict with corresponding time values :return: dictionary with the following content: { 'days': , 'hours': , 'minutes': , 'seconds': } """ formatted_timeout = {'days': console_auth_settings.login_block_timeout.days} formatted_timeout['hours'], rem = divmod(console_auth_settings.login_block_timeout.seconds, 3600) formatted_timeout["minutes"], formatted_timeout["seconds"] = divmod(rem, 60) return formatted_timeout def set_account_block(auth_data): # todo not used. remove? """ Method for forbieden access to authentication for user account """ auth_data.is_username_auth_blocked = True _log.info(create_authentication_log_message( 'settings', f'user [{auth_data.user.username}] has been blocked by Administrator')) auth_data.save()