flows: add additional sentry spans

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-12-14 11:59:36 +01:00
parent b5685ec072
commit 54f893b84f
3 changed files with 46 additions and 13 deletions

View file

@ -6,6 +6,7 @@ from django.http.response import HttpResponse
from django.urls import reverse from django.urls import reverse
from django.views.generic.base import View from django.views.generic.base import View
from rest_framework.request import Request from rest_framework.request import Request
from sentry_sdk.hub import Hub
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.core.models import DEFAULT_AVATAR, User from authentik.core.models import DEFAULT_AVATAR, User
@ -94,7 +95,15 @@ class ChallengeStageView(StageView):
keep_context=keep_context, keep_context=keep_context,
) )
return self.executor.restart_flow(keep_context) return self.executor.restart_flow(keep_context)
with Hub.current.start_span(
op="authentik.flow.stage.challenge_invalid",
description=self.__class__.__name__,
):
return self.challenge_invalid(challenge) 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) return self.challenge_valid(challenge)
def format_title(self) -> str: def format_title(self) -> str:
@ -104,6 +113,10 @@ class ChallengeStageView(StageView):
} }
def _get_challenge(self, *args, **kwargs) -> Challenge: def _get_challenge(self, *args, **kwargs) -> Challenge:
with Hub.current.start_span(
op="authentik.flow.stage.get_challenge",
description=self.__class__.__name__,
):
challenge = self.get_challenge(*args, **kwargs) challenge = self.get_challenge(*args, **kwargs)
if "flow_info" not in challenge.initial_data: if "flow_info" not in challenge.initial_data:
flow_info = ContextualFlowInfo( flow_info = ContextualFlowInfo(

View file

@ -12,6 +12,7 @@ from django.utils.translation import gettext as _
from drf_spectacular.utils import PolymorphicProxySerializer, extend_schema_field from drf_spectacular.utils import PolymorphicProxySerializer, extend_schema_field
from rest_framework.fields import BooleanField, CharField, DictField, ListField from rest_framework.fields import BooleanField, CharField, DictField, ListField
from rest_framework.serializers import ValidationError from rest_framework.serializers import ValidationError
from sentry_sdk.hub import Hub
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.core.api.utils import PassiveSerializer from authentik.core.api.utils import PassiveSerializer
@ -90,6 +91,10 @@ class IdentificationChallengeResponse(ChallengeResponse):
pre_user = self.stage.get_user(uid_field) pre_user = self.stage.get_user(uid_field)
if not pre_user: if not pre_user:
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 a random time (between 90 and 210ms) to "prevent" user enumeration attacks
sleep(0.30 * SystemRandom().randint(3, 7)) sleep(0.30 * SystemRandom().randint(3, 7))
LOGGER.debug("invalid_login", identifier=uid_field) LOGGER.debug("invalid_login", identifier=uid_field)
@ -114,6 +119,10 @@ class IdentificationChallengeResponse(ChallengeResponse):
if not password: if not password:
LOGGER.warning("Password not set for ident+auth attempt") LOGGER.warning("Password not set for ident+auth attempt")
try: try:
with Hub.current.start_span(
op="authentik.stages.identification.authenticate",
description="User authenticate call (combo stage)",
):
user = authenticate( user = authenticate(
self.stage.request, self.stage.request,
current_stage.password_stage.backends, current_stage.password_stage.backends,

View file

@ -10,6 +10,7 @@ from django.urls import reverse
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from rest_framework.exceptions import ErrorDetail, ValidationError from rest_framework.exceptions import ErrorDetail, ValidationError
from rest_framework.fields import CharField from rest_framework.fields import CharField
from sentry_sdk.hub import Hub
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.core.models import User from authentik.core.models import User
@ -43,6 +44,10 @@ def authenticate(request: HttpRequest, backends: list[str], **credentials: Any)
LOGGER.warning("Failed to import backend", path=backend_path) LOGGER.warning("Failed to import backend", path=backend_path)
continue continue
LOGGER.debug("Attempting authentication...", backend=backend_path) LOGGER.debug("Attempting authentication...", backend=backend_path)
with Hub.current.start_span(
op="authentik.stages.password.authenticate",
description=backend_path,
):
user = backend.authenticate(request, **credentials) user = backend.authenticate(request, **credentials)
if user is None: if user is None:
LOGGER.debug("Backend returned nothing, continuing", backend=backend_path) LOGGER.debug("Backend returned nothing, continuing", backend=backend_path)
@ -120,7 +125,13 @@ class PasswordStageView(ChallengeStageView):
"username": pending_user.username, "username": pending_user.username,
} }
try: 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: except PermissionDenied:
del auth_kwargs["password"] del auth_kwargs["password"]
# User was found, but permission was denied (i.e. user is not active) # User was found, but permission was denied (i.e. user is not active)