providers/scim: correctly handle 404 by re-creating object (#5405)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L 2023-04-28 14:36:21 +03:00 committed by GitHub
parent 967a38b7ac
commit ecce31ee87
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 13 deletions

View file

@ -14,7 +14,7 @@ from requests import RequestException, Session
from structlog.stdlib import get_logger
from authentik.lib.utils.http import get_http_session
from authentik.providers.scim.clients.exceptions import SCIMRequestException
from authentik.providers.scim.clients.exceptions import ResourceMissing, SCIMRequestException
from authentik.providers.scim.models import SCIMProvider
T = TypeVar("T")
@ -73,6 +73,8 @@ class SCIMClient(Generic[T, SchemaType]):
raise SCIMRequestException(None) from exc
self.logger.debug("scim request", path=path, method=method, **kwargs)
if response.status_code >= 400:
if response.status_code == 404:
raise ResourceMissing(response)
self.logger.warning(
"Failed to send SCIM request", path=path, method=method, response=response.text
)

View file

@ -41,3 +41,8 @@ class SCIMRequestException(SentryIgnoredException):
except ValidationError:
pass
return super().__str__()
class ResourceMissing(SCIMRequestException):
"""Error raised when the provider raises a 404, meaning that we
should delete our internal ID and re-create the object"""

View file

@ -10,7 +10,7 @@ from authentik.events.models import Event, EventAction
from authentik.lib.utils.errors import exception_to_string
from authentik.policies.utils import delete_none_keys
from authentik.providers.scim.clients.base import SCIMClient
from authentik.providers.scim.clients.exceptions import StopSync
from authentik.providers.scim.clients.exceptions import ResourceMissing, StopSync
from authentik.providers.scim.clients.schema import Group as SCIMGroupSchema
from authentik.providers.scim.models import SCIMGroup, SCIMMapping, SCIMUser
@ -23,15 +23,11 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroupSchema]):
scim_group = SCIMGroup.objects.filter(provider=self.provider, group=obj).first()
if not scim_group:
return self._create(obj)
scim_group = self.to_scim(obj)
scim_group.id = scim_group.id
return self._request(
"PUT",
f"/Groups/{scim_group.id}",
data=scim_group.json(
exclude_unset=True,
),
)
try:
return self._update(obj, scim_group)
except ResourceMissing:
scim_group.delete()
return self._create(obj)
def delete(self, obj: Group):
"""Delete group"""
@ -104,6 +100,18 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroupSchema]):
)
SCIMGroup.objects.create(provider=self.provider, group=group, id=response["id"])
def _update(self, group: Group, connection: SCIMGroup):
"""Update existing group"""
scim_group = self.to_scim(group)
scim_group.id = connection.id
return self._request(
"PUT",
f"/Groups/{scim_group.id}",
data=scim_group.json(
exclude_unset=True,
),
)
def _patch(
self,
group_id: str,

View file

@ -8,7 +8,7 @@ from authentik.events.models import Event, EventAction
from authentik.lib.utils.errors import exception_to_string
from authentik.policies.utils import delete_none_keys
from authentik.providers.scim.clients.base import SCIMClient
from authentik.providers.scim.clients.exceptions import StopSync
from authentik.providers.scim.clients.exceptions import ResourceMissing, StopSync
from authentik.providers.scim.clients.schema import User as SCIMUserSchema
from authentik.providers.scim.models import SCIMMapping, SCIMUser
@ -21,7 +21,11 @@ class SCIMUserClient(SCIMClient[User, SCIMUserSchema]):
scim_user = SCIMUser.objects.filter(provider=self.provider, user=obj).first()
if not scim_user:
return self._create(obj)
return self._update(obj, scim_user)
try:
return self._update(obj, scim_user)
except ResourceMissing:
scim_user.delete()
return self._create(obj)
def delete(self, obj: User):
"""Delete user"""