flows: add additional sentry spans
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
b5685ec072
commit
54f893b84f
|
@ -6,6 +6,7 @@ from django.http.response import HttpResponse
|
|||
from django.urls import reverse
|
||||
from django.views.generic.base import View
|
||||
from rest_framework.request import Request
|
||||
from sentry_sdk.hub import Hub
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.core.models import DEFAULT_AVATAR, User
|
||||
|
@ -94,8 +95,16 @@ class ChallengeStageView(StageView):
|
|||
keep_context=keep_context,
|
||||
)
|
||||
return self.executor.restart_flow(keep_context)
|
||||
return self.challenge_invalid(challenge)
|
||||
return self.challenge_valid(challenge)
|
||||
with Hub.current.start_span(
|
||||
op="authentik.flow.stage.challenge_invalid",
|
||||
description=self.__class__.__name__,
|
||||
):
|
||||
return self.challenge_invalid(challenge)
|
||||
with Hub.current.start_span(
|
||||
op="authentik.flow.stage.challenge_valid",
|
||||
description=self.__class__.__name__,
|
||||
):
|
||||
return self.challenge_valid(challenge)
|
||||
|
||||
def format_title(self) -> str:
|
||||
"""Allow usage of placeholder in flow title."""
|
||||
|
@ -104,7 +113,11 @@ class ChallengeStageView(StageView):
|
|||
}
|
||||
|
||||
def _get_challenge(self, *args, **kwargs) -> Challenge:
|
||||
challenge = self.get_challenge(*args, **kwargs)
|
||||
with Hub.current.start_span(
|
||||
op="authentik.flow.stage.get_challenge",
|
||||
description=self.__class__.__name__,
|
||||
):
|
||||
challenge = self.get_challenge(*args, **kwargs)
|
||||
if "flow_info" not in challenge.initial_data:
|
||||
flow_info = ContextualFlowInfo(
|
||||
data={
|
||||
|
|
|
@ -12,6 +12,7 @@ from django.utils.translation import gettext as _
|
|||
from drf_spectacular.utils import PolymorphicProxySerializer, extend_schema_field
|
||||
from rest_framework.fields import BooleanField, CharField, DictField, ListField
|
||||
from rest_framework.serializers import ValidationError
|
||||
from sentry_sdk.hub import Hub
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.core.api.utils import PassiveSerializer
|
||||
|
@ -90,8 +91,12 @@ class IdentificationChallengeResponse(ChallengeResponse):
|
|||
|
||||
pre_user = self.stage.get_user(uid_field)
|
||||
if not pre_user:
|
||||
# Sleep a random time (between 90 and 210ms) to "prevent" user enumeration attacks
|
||||
sleep(0.30 * SystemRandom().randint(3, 7))
|
||||
with Hub.current.start_span(
|
||||
op="authentik.stages.identification.validate_invalid_wait",
|
||||
description="Sleep random time on invalid user identifier",
|
||||
):
|
||||
# Sleep a random time (between 90 and 210ms) to "prevent" user enumeration attacks
|
||||
sleep(0.30 * SystemRandom().randint(3, 7))
|
||||
LOGGER.debug("invalid_login", identifier=uid_field)
|
||||
identification_failed.send(sender=self, request=self.stage.request, uid_field=uid_field)
|
||||
# We set the pending_user even on failure so it's part of the context, even
|
||||
|
@ -114,12 +119,16 @@ class IdentificationChallengeResponse(ChallengeResponse):
|
|||
if not password:
|
||||
LOGGER.warning("Password not set for ident+auth attempt")
|
||||
try:
|
||||
user = authenticate(
|
||||
self.stage.request,
|
||||
current_stage.password_stage.backends,
|
||||
username=self.pre_user.username,
|
||||
password=password,
|
||||
)
|
||||
with Hub.current.start_span(
|
||||
op="authentik.stages.identification.authenticate",
|
||||
description="User authenticate call (combo stage)",
|
||||
):
|
||||
user = authenticate(
|
||||
self.stage.request,
|
||||
current_stage.password_stage.backends,
|
||||
username=self.pre_user.username,
|
||||
password=password,
|
||||
)
|
||||
if not user:
|
||||
raise ValidationError("Failed to authenticate.")
|
||||
self.pre_user = user
|
||||
|
|
|
@ -10,6 +10,7 @@ from django.urls import reverse
|
|||
from django.utils.translation import gettext as _
|
||||
from rest_framework.exceptions import ErrorDetail, ValidationError
|
||||
from rest_framework.fields import CharField
|
||||
from sentry_sdk.hub import Hub
|
||||
from structlog.stdlib import get_logger
|
||||
|
||||
from authentik.core.models import User
|
||||
|
@ -43,7 +44,11 @@ def authenticate(request: HttpRequest, backends: list[str], **credentials: Any)
|
|||
LOGGER.warning("Failed to import backend", path=backend_path)
|
||||
continue
|
||||
LOGGER.debug("Attempting authentication...", backend=backend_path)
|
||||
user = backend.authenticate(request, **credentials)
|
||||
with Hub.current.start_span(
|
||||
op="authentik.stages.password.authenticate",
|
||||
description=backend_path,
|
||||
):
|
||||
user = backend.authenticate(request, **credentials)
|
||||
if user is None:
|
||||
LOGGER.debug("Backend returned nothing, continuing", backend=backend_path)
|
||||
continue
|
||||
|
@ -120,7 +125,13 @@ class PasswordStageView(ChallengeStageView):
|
|||
"username": pending_user.username,
|
||||
}
|
||||
try:
|
||||
user = authenticate(self.request, self.executor.current_stage.backends, **auth_kwargs)
|
||||
with Hub.current.start_span(
|
||||
op="authentik.stages.password.authenticate",
|
||||
description="User authenticate call",
|
||||
):
|
||||
user = authenticate(
|
||||
self.request, self.executor.current_stage.backends, **auth_kwargs
|
||||
)
|
||||
except PermissionDenied:
|
||||
del auth_kwargs["password"]
|
||||
# User was found, but permission was denied (i.e. user is not active)
|
||||
|
|
Reference in New Issue