e64ca4ab04
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
61 lines
2.4 KiB
Python
61 lines
2.4 KiB
Python
"""Authenticate with tokens"""
|
|
|
|
from typing import Any, Optional
|
|
|
|
from django.contrib.auth.backends import ModelBackend
|
|
from django.http.request import HttpRequest
|
|
|
|
from authentik.core.models import Token, TokenIntents, User
|
|
from authentik.events.utils import cleanse_dict, sanitize_dict
|
|
from authentik.flows.planner import FlowPlan
|
|
from authentik.flows.views.executor import SESSION_KEY_PLAN
|
|
from authentik.stages.password.stage import PLAN_CONTEXT_METHOD, PLAN_CONTEXT_METHOD_ARGS
|
|
|
|
|
|
class InbuiltBackend(ModelBackend):
|
|
"""Inbuilt backend"""
|
|
|
|
def authenticate(
|
|
self, request: HttpRequest, username: Optional[str], password: Optional[str], **kwargs: Any
|
|
) -> Optional[User]:
|
|
user = super().authenticate(request, username=username, password=password, **kwargs)
|
|
if not user:
|
|
return None
|
|
self.set_method("password", request)
|
|
return user
|
|
|
|
def set_method(self, method: str, request: Optional[HttpRequest], **kwargs):
|
|
"""Set method data on current flow, if possbiel"""
|
|
if not request:
|
|
return
|
|
# Since we can't directly pass other variables to signals, and we want to log the method
|
|
# and the token used, we assume we're running in a flow and set a variable in the context
|
|
flow_plan: FlowPlan = request.session.get(SESSION_KEY_PLAN, FlowPlan(""))
|
|
flow_plan.context[PLAN_CONTEXT_METHOD] = method
|
|
flow_plan.context[PLAN_CONTEXT_METHOD_ARGS] = cleanse_dict(sanitize_dict(kwargs))
|
|
request.session[SESSION_KEY_PLAN] = flow_plan
|
|
|
|
|
|
class TokenBackend(InbuiltBackend):
|
|
"""Authenticate with token"""
|
|
|
|
def authenticate(
|
|
self, request: HttpRequest, username: Optional[str], password: Optional[str], **kwargs: Any
|
|
) -> Optional[User]:
|
|
try:
|
|
user = User._default_manager.get_by_natural_key(username)
|
|
except User.DoesNotExist:
|
|
# Run the default password hasher once to reduce the timing
|
|
# difference between an existing and a nonexistent user (#20760).
|
|
User().set_password(password)
|
|
return None
|
|
# pylint: disable=no-member
|
|
tokens = Token.filter_not_expired(
|
|
user=user, key=password, intent=TokenIntents.INTENT_APP_PASSWORD
|
|
)
|
|
if not tokens.exists():
|
|
return None
|
|
token = tokens.first()
|
|
self.set_method("token", request, token=token)
|
|
return token.user
|