stages/user_write: improve error handling (#5136)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
parent
986d7bf714
commit
5947c7b97e
|
@ -12,6 +12,7 @@ from authentik.core.models import USER_ATTRIBUTE_SOURCES, User, UserSourceConnec
|
||||||
from authentik.core.sources.stage import PLAN_CONTEXT_SOURCES_CONNECTION
|
from authentik.core.sources.stage import PLAN_CONTEXT_SOURCES_CONNECTION
|
||||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
||||||
from authentik.flows.stage import StageView
|
from authentik.flows.stage import StageView
|
||||||
|
from authentik.flows.views.executor import FlowExecutorView
|
||||||
from authentik.stages.password import BACKEND_INBUILT
|
from authentik.stages.password import BACKEND_INBUILT
|
||||||
from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
|
from authentik.stages.password.stage import PLAN_CONTEXT_AUTHENTICATION_BACKEND
|
||||||
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
|
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
|
||||||
|
@ -25,6 +26,12 @@ PLAN_CONTEXT_USER_PATH = "user_path"
|
||||||
class UserWriteStageView(StageView):
|
class UserWriteStageView(StageView):
|
||||||
"""Finalise Enrollment flow by creating a user object."""
|
"""Finalise Enrollment flow by creating a user object."""
|
||||||
|
|
||||||
|
def __init__(self, executor: FlowExecutorView, **kwargs):
|
||||||
|
super().__init__(executor, **kwargs)
|
||||||
|
self.disallowed_user_attributes = [
|
||||||
|
"groups",
|
||||||
|
]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def write_attribute(user: User, key: str, value: Any):
|
def write_attribute(user: User, key: str, value: Any):
|
||||||
"""Allow use of attributes.foo.bar when writing to a user, with full
|
"""Allow use of attributes.foo.bar when writing to a user, with full
|
||||||
|
@ -90,19 +97,23 @@ class UserWriteStageView(StageView):
|
||||||
setter = getattr(user, setter_name)
|
setter = getattr(user, setter_name)
|
||||||
if callable(setter):
|
if callable(setter):
|
||||||
setter(value)
|
setter(value)
|
||||||
|
elif key in self.disallowed_user_attributes:
|
||||||
|
self.logger.info("discarding key", key=key)
|
||||||
|
continue
|
||||||
# For exact attributes match, update the dictionary in place
|
# For exact attributes match, update the dictionary in place
|
||||||
elif key == "attributes":
|
elif key == "attributes":
|
||||||
user.attributes.update(value)
|
user.attributes.update(value)
|
||||||
# User has this key already
|
# If using dot notation, use the correct helper to update the nested value
|
||||||
elif hasattr(user, key) and not key.startswith("attributes."):
|
elif key.startswith("attributes.") or key.startswith("attributes_"):
|
||||||
setattr(user, key, value)
|
|
||||||
# Otherwise we just save it as custom attribute, but only if the value is prefixed with
|
|
||||||
# `attribute_`, to prevent accidentally saving values
|
|
||||||
else:
|
|
||||||
if not key.startswith("attributes.") and not key.startswith("attributes_"):
|
|
||||||
self.logger.warning("discarding key", key=key)
|
|
||||||
continue
|
|
||||||
UserWriteStageView.write_attribute(user, key, value)
|
UserWriteStageView.write_attribute(user, key, value)
|
||||||
|
# User has this key already
|
||||||
|
elif hasattr(user, key):
|
||||||
|
setattr(user, key, value)
|
||||||
|
# If none of the cases above matched, we have an attribute that the user doesn't have,
|
||||||
|
# has no setter for, is not a nested attributes value and as such is invalid
|
||||||
|
else:
|
||||||
|
self.logger.info("discarding key", key=key)
|
||||||
|
continue
|
||||||
# Check if we're writing from a source, and save the source to the attributes
|
# Check if we're writing from a source, and save the source to the attributes
|
||||||
if PLAN_CONTEXT_SOURCES_CONNECTION in self.executor.plan.context:
|
if PLAN_CONTEXT_SOURCES_CONNECTION in self.executor.plan.context:
|
||||||
if USER_ATTRIBUTE_SOURCES not in user.attributes or not isinstance(
|
if USER_ATTRIBUTE_SOURCES not in user.attributes or not isinstance(
|
||||||
|
|
Reference in New Issue