providers/scim: correctly handle 404 by re-creating object (#5405)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
parent
967a38b7ac
commit
ecce31ee87
|
@ -14,7 +14,7 @@ from requests import RequestException, Session
|
||||||
from structlog.stdlib import get_logger
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
from authentik.lib.utils.http import get_http_session
|
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
|
from authentik.providers.scim.models import SCIMProvider
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
@ -73,6 +73,8 @@ class SCIMClient(Generic[T, SchemaType]):
|
||||||
raise SCIMRequestException(None) from exc
|
raise SCIMRequestException(None) from exc
|
||||||
self.logger.debug("scim request", path=path, method=method, **kwargs)
|
self.logger.debug("scim request", path=path, method=method, **kwargs)
|
||||||
if response.status_code >= 400:
|
if response.status_code >= 400:
|
||||||
|
if response.status_code == 404:
|
||||||
|
raise ResourceMissing(response)
|
||||||
self.logger.warning(
|
self.logger.warning(
|
||||||
"Failed to send SCIM request", path=path, method=method, response=response.text
|
"Failed to send SCIM request", path=path, method=method, response=response.text
|
||||||
)
|
)
|
||||||
|
|
|
@ -41,3 +41,8 @@ class SCIMRequestException(SentryIgnoredException):
|
||||||
except ValidationError:
|
except ValidationError:
|
||||||
pass
|
pass
|
||||||
return super().__str__()
|
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"""
|
||||||
|
|
|
@ -10,7 +10,7 @@ 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_keys
|
||||||
from authentik.providers.scim.clients.base import SCIMClient
|
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.clients.schema import Group as SCIMGroupSchema
|
||||||
from authentik.providers.scim.models import SCIMGroup, SCIMMapping, SCIMUser
|
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()
|
scim_group = SCIMGroup.objects.filter(provider=self.provider, group=obj).first()
|
||||||
if not scim_group:
|
if not scim_group:
|
||||||
return self._create(obj)
|
return self._create(obj)
|
||||||
scim_group = self.to_scim(obj)
|
try:
|
||||||
scim_group.id = scim_group.id
|
return self._update(obj, scim_group)
|
||||||
return self._request(
|
except ResourceMissing:
|
||||||
"PUT",
|
scim_group.delete()
|
||||||
f"/Groups/{scim_group.id}",
|
return self._create(obj)
|
||||||
data=scim_group.json(
|
|
||||||
exclude_unset=True,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
def delete(self, obj: Group):
|
def delete(self, obj: Group):
|
||||||
"""Delete group"""
|
"""Delete group"""
|
||||||
|
@ -104,6 +100,18 @@ class SCIMGroupClient(SCIMClient[Group, SCIMGroupSchema]):
|
||||||
)
|
)
|
||||||
SCIMGroup.objects.create(provider=self.provider, group=group, id=response["id"])
|
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(
|
def _patch(
|
||||||
self,
|
self,
|
||||||
group_id: str,
|
group_id: str,
|
||||||
|
|
|
@ -8,7 +8,7 @@ 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_keys
|
||||||
from authentik.providers.scim.clients.base import SCIMClient
|
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.clients.schema import User as SCIMUserSchema
|
||||||
from authentik.providers.scim.models import SCIMMapping, SCIMUser
|
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()
|
scim_user = SCIMUser.objects.filter(provider=self.provider, user=obj).first()
|
||||||
if not scim_user:
|
if not scim_user:
|
||||||
return self._create(obj)
|
return self._create(obj)
|
||||||
|
try:
|
||||||
return self._update(obj, scim_user)
|
return self._update(obj, scim_user)
|
||||||
|
except ResourceMissing:
|
||||||
|
scim_user.delete()
|
||||||
|
return self._create(obj)
|
||||||
|
|
||||||
def delete(self, obj: User):
|
def delete(self, obj: User):
|
||||||
"""Delete user"""
|
"""Delete user"""
|
||||||
|
|
Reference in New Issue