authentik.policies.reputation.signals
authentik reputation request signals
1"""authentik reputation request signals""" 2 3from django.contrib.auth.signals import user_logged_in 4from django.db.models import F 5from django.db.models.functions import Greatest, Least 6from django.dispatch import receiver 7from django.http import HttpRequest 8from psqlextra.query import ConflictAction 9from psqlextra.util import postgres_manager 10from structlog.stdlib import get_logger 11 12from authentik.core.signals import login_failed 13from authentik.events.context_processors.asn import ASN_CONTEXT_PROCESSOR 14from authentik.events.context_processors.geoip import GEOIP_CONTEXT_PROCESSOR 15from authentik.policies.reputation.models import Reputation, reputation_expiry 16from authentik.root.middleware import ClientIPMiddleware 17from authentik.stages.identification.signals import identification_failed 18from authentik.tenants.utils import get_current_tenant 19 20LOGGER = get_logger() 21 22 23def update_score(request: HttpRequest, identifier: str, amount: int): 24 """Update score for IP and User""" 25 remote_ip = ClientIPMiddleware.get_client_ip(request) 26 tenant = getattr(request, "tenant", get_current_tenant()) 27 amount = max(tenant.reputation_lower_limit, min(tenant.reputation_upper_limit, amount)) 28 29 with postgres_manager(Reputation) as manager: 30 reputation = manager.on_conflict( 31 ["ip", "identifier"], 32 ConflictAction.UPDATE, 33 update_values=dict( 34 score=Greatest( 35 tenant.reputation_lower_limit, 36 Least(tenant.reputation_upper_limit, F("score") + amount), 37 ), 38 ), 39 ).insert_and_get( 40 ip=remote_ip, 41 identifier=identifier, 42 score=amount, 43 ip_geo_data=GEOIP_CONTEXT_PROCESSOR.city_dict(remote_ip) or {}, 44 ip_asn_data=ASN_CONTEXT_PROCESSOR.asn_dict(remote_ip) or {}, 45 expires=reputation_expiry(), 46 ) 47 48 LOGGER.info("Updated score", amount=reputation.score, for_user=identifier, for_ip=remote_ip) 49 50 51@receiver(login_failed) 52def handle_failed_login(sender, request, credentials, **_): 53 """Lower Score for failed login attempts""" 54 if "username" in credentials: 55 update_score(request, credentials.get("username"), -1) 56 57 58@receiver(identification_failed) 59def handle_identification_failed(sender, request, uid_field: str, **_): 60 """Lower Score for failed identification attempts""" 61 update_score(request, uid_field, -1) 62 63 64@receiver(user_logged_in) 65def handle_successful_login(sender, request, user, **_): 66 """Raise score for successful attempts""" 67 update_score(request, user.username, 1)
LOGGER =
<BoundLoggerLazyProxy(logger=None, wrapper_class=None, processors=None, context_class=None, initial_values={}, logger_factory_args=())>
def
update_score( request: django.http.request.HttpRequest, identifier: str, amount: int):
24def update_score(request: HttpRequest, identifier: str, amount: int): 25 """Update score for IP and User""" 26 remote_ip = ClientIPMiddleware.get_client_ip(request) 27 tenant = getattr(request, "tenant", get_current_tenant()) 28 amount = max(tenant.reputation_lower_limit, min(tenant.reputation_upper_limit, amount)) 29 30 with postgres_manager(Reputation) as manager: 31 reputation = manager.on_conflict( 32 ["ip", "identifier"], 33 ConflictAction.UPDATE, 34 update_values=dict( 35 score=Greatest( 36 tenant.reputation_lower_limit, 37 Least(tenant.reputation_upper_limit, F("score") + amount), 38 ), 39 ), 40 ).insert_and_get( 41 ip=remote_ip, 42 identifier=identifier, 43 score=amount, 44 ip_geo_data=GEOIP_CONTEXT_PROCESSOR.city_dict(remote_ip) or {}, 45 ip_asn_data=ASN_CONTEXT_PROCESSOR.asn_dict(remote_ip) or {}, 46 expires=reputation_expiry(), 47 ) 48 49 LOGGER.info("Updated score", amount=reputation.score, for_user=identifier, for_ip=remote_ip)
Update score for IP and User
@receiver(login_failed)
def
handle_failed_login(sender, request, credentials, **_):
52@receiver(login_failed) 53def handle_failed_login(sender, request, credentials, **_): 54 """Lower Score for failed login attempts""" 55 if "username" in credentials: 56 update_score(request, credentials.get("username"), -1)
Lower Score for failed login attempts
@receiver(identification_failed)
def
handle_identification_failed(sender, request, uid_field: str, **_):
59@receiver(identification_failed) 60def handle_identification_failed(sender, request, uid_field: str, **_): 61 """Lower Score for failed identification attempts""" 62 update_score(request, uid_field, -1)
Lower Score for failed identification attempts
@receiver(user_logged_in)
def
handle_successful_login(sender, request, user, **_):
65@receiver(user_logged_in) 66def handle_successful_login(sender, request, user, **_): 67 """Raise score for successful attempts""" 68 update_score(request, user.username, 1)
Raise score for successful attempts