providers/scim: default to None for fields instead of empty list (#5642)

* providers/scim: default to None for fields instead of empty list

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* make name of delete_none_keys clearer

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* fix

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L 2023-05-17 00:25:28 +02:00 committed by GitHub
parent daa3c91afc
commit f4b0d6e85c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 13 additions and 19 deletions

View file

@ -28,7 +28,7 @@ from authentik.flows.views.executor import NEXT_ARG_NAME, SESSION_KEY_GET, SESSI
from authentik.lib.utils.urls import redirect_with_qs from authentik.lib.utils.urls import redirect_with_qs
from authentik.lib.views import bad_request_message from authentik.lib.views import bad_request_message
from authentik.policies.denied import AccessDeniedResponse from authentik.policies.denied import AccessDeniedResponse
from authentik.policies.utils import delete_none_keys from authentik.policies.utils import delete_none_values
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
@ -329,7 +329,7 @@ class SourceFlowManager:
) )
], ],
**{ **{
PLAN_CONTEXT_PROMPT: delete_none_keys(self.enroll_info), PLAN_CONTEXT_PROMPT: delete_none_values(self.enroll_info),
PLAN_CONTEXT_USER_PATH: self.source.get_user_path(), PLAN_CONTEXT_USER_PATH: self.source.get_user_path(),
}, },
) )

View file

@ -2,7 +2,7 @@
from typing import Any from typing import Any
def delete_none_keys(dict_: dict[Any, Any]) -> dict[Any, Any]: def delete_none_values(dict_: dict[Any, Any]) -> dict[Any, Any]:
"""Remove any keys from `dict_` that are None.""" """Remove any keys from `dict_` that are None."""
new_dict = {} new_dict = {}
for key, value in dict_.items(): for key, value in dict_.items():

View file

@ -8,7 +8,7 @@ from authentik.core.exceptions import PropertyMappingExpressionException
from authentik.core.models import Group from authentik.core.models import Group
from authentik.events.models import Event, EventAction from authentik.events.models import Event, EventAction
from authentik.lib.utils.errors import exception_to_string from authentik.lib.utils.errors import exception_to_string
from authentik.policies.utils import delete_none_keys from authentik.policies.utils import delete_none_values
from authentik.providers.scim.clients.base import SCIMClient from authentik.providers.scim.clients.base import SCIMClient
from authentik.providers.scim.clients.exceptions import ( from authentik.providers.scim.clients.exceptions import (
ResourceMissing, ResourceMissing,
@ -74,7 +74,7 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroupSchema]):
if not raw_scim_group: if not raw_scim_group:
raise StopSync(ValueError("No group mappings configured"), obj) raise StopSync(ValueError("No group mappings configured"), obj)
try: try:
scim_group = SCIMGroupSchema.parse_obj(delete_none_keys(raw_scim_group)) scim_group = SCIMGroupSchema.parse_obj(delete_none_values(raw_scim_group))
except ValidationError as exc: except ValidationError as exc:
raise StopSync(exc, obj) from exc raise StopSync(exc, obj) from exc
if not scim_group.externalId: if not scim_group.externalId:

View file

@ -6,7 +6,7 @@ from authentik.core.exceptions import PropertyMappingExpressionException
from authentik.core.models import User from authentik.core.models import User
from authentik.events.models import Event, EventAction from authentik.events.models import Event, EventAction
from authentik.lib.utils.errors import exception_to_string from authentik.lib.utils.errors import exception_to_string
from authentik.policies.utils import delete_none_keys from authentik.policies.utils import delete_none_values
from authentik.providers.scim.clients.base import SCIMClient from authentik.providers.scim.clients.base import SCIMClient
from authentik.providers.scim.clients.exceptions import ResourceMissing, StopSync from authentik.providers.scim.clients.exceptions import ResourceMissing, StopSync
from authentik.providers.scim.clients.schema import User as SCIMUserSchema from authentik.providers.scim.clients.schema import User as SCIMUserSchema
@ -64,7 +64,7 @@ class SCIMUserClient(SCIMClient[User, SCIMUserSchema]):
if not raw_scim_user: if not raw_scim_user:
raise StopSync(ValueError("No user mappings configured"), obj) raise StopSync(ValueError("No user mappings configured"), obj)
try: try:
scim_user = SCIMUserSchema.parse_obj(delete_none_keys(raw_scim_user)) scim_user = SCIMUserSchema.parse_obj(delete_none_values(raw_scim_user))
except ValidationError as exc: except ValidationError as exc:
raise StopSync(exc, obj) from exc raise StopSync(exc, obj) from exc
if not scim_user.externalId: if not scim_user.externalId:

View file

@ -91,7 +91,6 @@ class SCIMMembershipTests(TestCase):
"active": True, "active": True,
"externalId": user.uid, "externalId": user.uid,
"name": {"familyName": "", "formatted": "", "givenName": ""}, "name": {"familyName": "", "formatted": "", "givenName": ""},
"photos": [],
"displayName": "", "displayName": "",
"userName": user.username, "userName": user.username,
}, },
@ -177,7 +176,6 @@ class SCIMMembershipTests(TestCase):
"emails": [], "emails": [],
"externalId": user.uid, "externalId": user.uid,
"name": {"familyName": "", "formatted": "", "givenName": ""}, "name": {"familyName": "", "formatted": "", "givenName": ""},
"photos": [],
"userName": user.username, "userName": user.username,
}, },
) )

View file

@ -81,7 +81,6 @@ class SCIMUserTests(TestCase):
"givenName": uid, "givenName": uid,
}, },
"displayName": uid, "displayName": uid,
"photos": [],
"userName": uid, "userName": uid,
}, },
) )
@ -137,7 +136,6 @@ class SCIMUserTests(TestCase):
"formatted": uid, "formatted": uid,
"givenName": uid, "givenName": uid,
}, },
"photos": [],
"userName": uid, "userName": uid,
}, },
) )
@ -190,7 +188,6 @@ class SCIMUserTests(TestCase):
"givenName": uid, "givenName": uid,
}, },
"displayName": uid, "displayName": uid,
"photos": [],
"userName": uid, "userName": uid,
}, },
) )
@ -258,7 +255,6 @@ class SCIMUserTests(TestCase):
"givenName": uid, "givenName": uid,
}, },
"displayName": uid, "displayName": uid,
"photos": [],
"userName": uid, "userName": uid,
}, },
) )

View file

@ -21,7 +21,7 @@ from authentik.core.models import (
from authentik.core.sources.flow_manager import SourceFlowManager from authentik.core.sources.flow_manager import SourceFlowManager
from authentik.lib.expression.evaluator import BaseEvaluator from authentik.lib.expression.evaluator import BaseEvaluator
from authentik.lib.utils.time import timedelta_from_string from authentik.lib.utils.time import timedelta_from_string
from authentik.policies.utils import delete_none_keys from authentik.policies.utils import delete_none_values
from authentik.sources.saml.exceptions import ( from authentik.sources.saml.exceptions import (
InvalidSignature, InvalidSignature,
MismatchedRequestID, MismatchedRequestID,
@ -160,7 +160,7 @@ class ResponseProcessor:
self._source, self._source,
self._http_request, self._http_request,
name_id, name_id,
delete_none_keys(self.get_attributes()), delete_none_values(self.get_attributes()),
) )
def _get_name_id(self) -> "Element": def _get_name_id(self) -> "Element":
@ -237,7 +237,7 @@ class ResponseProcessor:
self._source, self._source,
self._http_request, self._http_request,
name_id.text, name_id.text,
delete_none_keys(self.get_attributes()), delete_none_values(self.get_attributes()),
) )

View file

@ -21,7 +21,7 @@ entries:
# photos supports URLs to images, however authentik might return data URIs # photos supports URLs to images, however authentik might return data URIs
avatar = request.user.avatar avatar = request.user.avatar
photos = [] photos = None
if "://" in avatar: if "://" in avatar:
photos = [{"value": avatar, "type": "photo"}] photos = [{"value": avatar, "type": "photo"}]
@ -31,11 +31,11 @@ entries:
emails = [] emails = []
if request.user.email != "": if request.user.email != "":
emails.append({ emails = [{
"value": request.user.email, "value": request.user.email,
"type": "other", "type": "other",
"primary": True, "primary": True,
}) }]
return { return {
"userName": request.user.username, "userName": request.user.username,
"name": { "name": {