Client deletion also delete related objects

This commit is contained in:
Éloi Rivard 2023-01-30 19:58:00 +01:00
parent baf402d5da
commit b059e6e719
5 changed files with 90 additions and 16 deletions

View file

@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file.
The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.0.0/>`_,
and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_.
Fixed
*****
- Client deletion also deletes related Consent, Token and
AuthorizationCode objects. :issue:`126` :pr:`98`
[0.0.20] - 2023-01-28
=====================

View file

@ -32,6 +32,9 @@ class LDAPObject:
return f"<{self.__class__.__name__} {self.rdn}={rdn}>"
def __eq__(self, other):
for attr in self.may + self.must:
if getattr(self, attr) != getattr(other, attr):
print(getattr(self, attr), getattr(other, attr))
return (
isinstance(other, self.__class__)
and self.may == other.may

View file

@ -95,6 +95,18 @@ class Client(LDAPObject, ClientMixin):
metadata["scope"] = " ".join(metadata["scope"])
return metadata
def delete(self):
for consent in Consent.filter(client=self.dn):
consent.delete()
for code in AuthorizationCode.filter(client=self.dn):
code.delete()
for token in Token.filter(client=self.dn):
token.delete()
super().delete()
class AuthorizationCode(LDAPObject, AuthorizationCodeMixin):
object_class = ["oauthAuthorizationCode"]

View file

@ -8,44 +8,76 @@ from werkzeug.security import gen_salt
def test_clean_command(testclient, slapd_connection, client, user):
AuthorizationCode.ldap_object_classes(slapd_connection)
code = AuthorizationCode(
valid_code = AuthorizationCode(
authorization_code_id=gen_salt(48),
code="my-code",
code="my-valid-code",
client=client.dn,
subject=user.dn,
redirect_uri="https://foo.bar/callback",
response_type="code",
scope="openid profile",
nonce="nonce",
issue_date=(datetime.datetime.now() - datetime.timedelta(days=1)),
lifetime="3600",
issue_date=datetime.datetime.now().replace(microsecond=0),
lifetime=3600,
challenge="challenge",
challenge_method="method",
revokation="",
)
code.save()
valid_code.save()
expired_code = AuthorizationCode(
authorization_code_id=gen_salt(48),
code="my-expired-code",
client=client.dn,
subject=user.dn,
redirect_uri="https://foo.bar/callback",
response_type="code",
scope="openid profile",
nonce="nonce",
issue_date=(
datetime.datetime.now().replace(microsecond=0) - datetime.timedelta(days=1)
),
lifetime=3600,
challenge="challenge",
challenge_method="method",
revokation="",
)
expired_code.save()
Token.ldap_object_classes(slapd_connection)
token = Token(
valid_token = Token(
token_id=gen_salt(48),
access_token="my-token",
access_token="my-valid-token",
client=client.dn,
subject=user.dn,
type=None,
refresh_token=gen_salt(48),
scope="openid profile",
issue_date=(datetime.datetime.now() - datetime.timedelta(days=1)),
lifetime=str(3600),
issue_date=(datetime.datetime.now().replace(microsecond=0)),
lifetime=3600,
)
token.save()
valid_token.save()
expired_token = Token(
token_id=gen_salt(48),
access_token="my-expired-token",
client=client.dn,
subject=user.dn,
type=None,
refresh_token=gen_salt(48),
scope="openid profile",
issue_date=(
datetime.datetime.now().replace(microsecond=0) - datetime.timedelta(days=1)
),
lifetime=3600,
)
expired_token.save()
assert AuthorizationCode.get(code="my-code")
assert Token.get(access_token="my-token")
assert code.is_expired()
assert token.is_expired()
assert AuthorizationCode.get(code="my-expired-code")
assert Token.get(access_token="my-expired-token")
assert expired_code.is_expired()
assert expired_token.is_expired()
runner = testclient.app.test_cli_runner()
runner.invoke(cli, ["clean"])
assert not AuthorizationCode.get(code="my-code")
assert not Token.get(access_token="my-token")
assert AuthorizationCode.all() == [valid_code]
assert Token.all() == [valid_token]

View file

@ -1,4 +1,9 @@
import datetime
from canaille.oidc.models import AuthorizationCode
from canaille.oidc.models import Client
from canaille.oidc.models import Consent
from canaille.oidc.models import Token
def test_no_logged_no_access(testclient):
@ -125,10 +130,26 @@ def test_client_edit_missing_fields(testclient, client, logged_admin, other_clie
def test_client_delete(testclient, logged_admin):
client = Client(client_id="client_id")
client.save()
token = Token(
token_id="id", client=client.dn, issue_datetime=datetime.datetime.utcnow()
)
token.save()
consent = Consent(
cn="cn", subject=logged_admin.dn, client=client.dn, scope="openid"
)
consent.save()
code = AuthorizationCode(
authorization_code_id="id", client=client.dn, subject=client.dn
)
res = testclient.get("/admin/client/edit/" + client.client_id)
res = res.forms["clientadd"].submit(name="action", value="delete").follow()
assert not Client.get()
assert not Token.get()
assert not AuthorizationCode.get()
assert not Consent.get()
def test_client_delete_invalid_client(testclient, logged_admin):
testclient.post("/admin/client/edit/invalid", {"action": "delete"}, status=404)