core: use custom inbuilt backend, set backend login information in flow plan for events
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
56
authentik/core/auth.py
Normal file
56
authentik/core/auth.py
Normal file
@ -0,0 +1,56 @@
|
||||
"""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.flows.planner import FlowPlan
|
||||
from authentik.flows.views 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
|
||||
# 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[SESSION_KEY_PLAN]
|
||||
flow_plan.context[PLAN_CONTEXT_METHOD] = "password"
|
||||
request.session[SESSION_KEY_PLAN] = flow_plan
|
||||
return user
|
||||
|
||||
|
||||
class TokenBackend(ModelBackend):
|
||||
"""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
|
||||
tokens = Token.filter_not_expired(
|
||||
user=user, key=password, intent=TokenIntents.INTENT_APP_PASSWORD
|
||||
)
|
||||
if not tokens.exists():
|
||||
return None
|
||||
token = tokens.first()
|
||||
# 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[SESSION_KEY_PLAN]
|
||||
flow_plan.context[PLAN_CONTEXT_METHOD] = "app_password"
|
||||
flow_plan.context[PLAN_CONTEXT_METHOD_ARGS] = {"token": token}
|
||||
request.session[SESSION_KEY_PLAN] = flow_plan
|
||||
return token.user
|
||||
@ -25,7 +25,7 @@ from authentik.flows.planner import (
|
||||
from authentik.flows.views import NEXT_ARG_NAME, SESSION_KEY_GET, SESSION_KEY_PLAN
|
||||
from authentik.lib.utils.urls import redirect_with_qs
|
||||
from authentik.policies.utils import delete_none_keys
|
||||
from authentik.stages.password import BACKEND_DJANGO
|
||||
from authentik.stages.password import BACKEND_INBUILT
|
||||
from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
|
||||
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
|
||||
|
||||
@ -189,7 +189,7 @@ class SourceFlowManager:
|
||||
kwargs.update(
|
||||
{
|
||||
# Since we authenticate the user by their token, they have no backend set
|
||||
PLAN_CONTEXT_AUTHENTICATION_BACKEND: BACKEND_DJANGO,
|
||||
PLAN_CONTEXT_AUTHENTICATION_BACKEND: BACKEND_INBUILT,
|
||||
PLAN_CONTEXT_SSO: True,
|
||||
PLAN_CONTEXT_SOURCE: self.source,
|
||||
PLAN_CONTEXT_REDIRECT: final_redirect,
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
"""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
|
||||
|
||||
|
||||
class TokenBackend(ModelBackend):
|
||||
"""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
|
||||
tokens = Token.filter_not_expired(
|
||||
user=user, key=password, intent=TokenIntents.INTENT_APP_PASSWORD
|
||||
)
|
||||
if not tokens.exists():
|
||||
return None
|
||||
return tokens.first().user
|
||||
Reference in New Issue
Block a user