diff --git a/CHANGES.rst b/CHANGES.rst index 4ccac805..e65124e7 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,7 @@ +Changed +^^^^^^^ +- Model `identifier_attributes` are fixed. + [0.0.53] - 2024-04-22 --------------------- diff --git a/canaille/backends/ldap/ldapobject.py b/canaille/backends/ldap/ldapobject.py index c40b856c..4bbbd155 100644 --- a/canaille/backends/ldap/ldapobject.py +++ b/canaille/backends/ldap/ldapobject.py @@ -6,7 +6,6 @@ import ldap.dn import ldap.filter from ldap.controls.readentry import PostReadControl -from canaille.app import classproperty from canaille.backends.models import BackendModel from .backend import Backend @@ -136,10 +135,6 @@ class LDAPObject(BackendModel, metaclass=LDAPObjectMetaclass): else "" ) - @classproperty - def identifier_attribute(cls): - return cls.rdn_attribute - def __eq__(self, other): ldap_attributes = self.may() + self.must() diff --git a/canaille/backends/ldap/models.py b/canaille/backends/ldap/models.py index 3bd190e9..0b45bf19 100644 --- a/canaille/backends/ldap/models.py +++ b/canaille/backends/ldap/models.py @@ -43,10 +43,6 @@ class User(canaille.core.models.User, LDAPObject): return super().match_filter(filter) - @property - def identifier(self): - return self.rdn_value - def save(self, *args, **kwargs): group_attr = self.python_attribute_to_ldap("groups") if group_attr not in self.changes: @@ -92,10 +88,6 @@ class Group(canaille.core.models.Group, LDAPObject): "description": "description", } - @property - def identifier(self): - return self.rdn_value - class Client(canaille.oidc.models.Client, LDAPObject): ldap_object_class = ["oauthClient"] @@ -139,10 +131,6 @@ class Client(canaille.oidc.models.Client, LDAPObject): **client_metadata_attributes, } - @property - def identifier(self): - return self.rdn_value - class AuthorizationCode(canaille.oidc.models.AuthorizationCode, LDAPObject): ldap_object_class = ["oauthAuthorizationCode"] @@ -167,10 +155,6 @@ class AuthorizationCode(canaille.oidc.models.AuthorizationCode, LDAPObject): "revokation_date": "oauthRevokationDate", } - @property - def identifier(self): - return self.rdn_value - class Token(canaille.oidc.models.Token, LDAPObject): ldap_object_class = ["oauthToken"] @@ -193,10 +177,6 @@ class Token(canaille.oidc.models.Token, LDAPObject): "audience": "oauthAudience", } - @property - def identifier(self): - return self.rdn_value - class Consent(canaille.oidc.models.Consent, LDAPObject): ldap_object_class = ["oauthConsent"] @@ -213,7 +193,3 @@ class Consent(canaille.oidc.models.Consent, LDAPObject): "issue_date": "oauthIssueDate", "revokation_date": "oauthRevokationDate", } - - @property - def identifier(self): - return self.rdn_value diff --git a/canaille/backends/memory/models.py b/canaille/backends/memory/models.py index 219ebb77..8c9317d0 100644 --- a/canaille/backends/memory/models.py +++ b/canaille/backends/memory/models.py @@ -2,7 +2,6 @@ import copy import datetime import typing import uuid -from typing import ClassVar import canaille.core.models import canaille.oidc.models @@ -235,30 +234,26 @@ class MemoryModel(BackendModel): else: super().__setattr__(name, value) - @property - def identifier(self): - return getattr(self, self.identifier_attribute) - class User(canaille.core.models.User, MemoryModel): - identifier_attribute: ClassVar[str] = "user_name" + pass class Group(canaille.core.models.Group, MemoryModel): - identifier_attribute: ClassVar[str] = "display_name" + pass class Client(canaille.oidc.models.Client, MemoryModel): - identifier_attribute: ClassVar[str] = "client_id" + pass class AuthorizationCode(canaille.oidc.models.AuthorizationCode, MemoryModel): - identifier_attribute: ClassVar[str] = "authorization_code_id" + pass class Token(canaille.oidc.models.Token, MemoryModel): - identifier_attribute: ClassVar[str] = "token_id" + pass class Consent(canaille.oidc.models.Consent, MemoryModel): - identifier_attribute: ClassVar[str] = "consent_id" + pass diff --git a/canaille/backends/models.py b/canaille/backends/models.py index dbf7e98f..699b9f09 100644 --- a/canaille/backends/models.py +++ b/canaille/backends/models.py @@ -69,6 +69,16 @@ class Model: } return cls._attributes + @property + def identifier(self): + """Returns a unique value that will be used to identify the model + instance. + + This value will be used in URLs in canaille, so it should be + unique and short. + """ + return getattr(self, self.identifier_attribute) + class BackendModel: """The backend model abstract class. @@ -109,16 +119,6 @@ class BackendModel: return only one element or :py:data:`None` if no item is matching.""" raise NotImplementedError() - @property - def identifier(self): - """Returns a unique value that will be used to identify the model - instance. - - This value will be used in URLs in canaille, so it should be - unique and short. - """ - raise NotImplementedError() - def save(self): """Validates the current modifications in the database.""" raise NotImplementedError() diff --git a/canaille/backends/sql/models.py b/canaille/backends/sql/models.py index 3fd25295..c50a7b5d 100644 --- a/canaille/backends/sql/models.py +++ b/canaille/backends/sql/models.py @@ -95,10 +95,6 @@ class SqlAlchemyModel(BackendModel): .scalar_one_or_none() ) - @property - def identifier(self): - return getattr(self, self.identifier_attribute) - def save(self): self.last_modified = datetime.datetime.now(datetime.timezone.utc).replace( microsecond=0 @@ -127,7 +123,6 @@ membership_association_table = Table( class User(canaille.core.models.User, Base, SqlAlchemyModel): __tablename__ = "user" - identifier_attribute = "user_name" id: Mapped[str] = mapped_column( String, primary_key=True, default=lambda: str(uuid.uuid4()) @@ -171,7 +166,6 @@ class User(canaille.core.models.User, Base, SqlAlchemyModel): class Group(canaille.core.models.Group, Base, SqlAlchemyModel): __tablename__ = "group" - identifier_attribute = "display_name" id: Mapped[str] = mapped_column( String, primary_key=True, default=lambda: str(uuid.uuid4()) @@ -200,7 +194,6 @@ client_audience_association_table = Table( class Client(canaille.oidc.models.Client, Base, SqlAlchemyModel): __tablename__ = "client" - identifier_attribute = "client_id" id: Mapped[str] = mapped_column( String, primary_key=True, default=lambda: str(uuid.uuid4()) @@ -250,7 +243,6 @@ class Client(canaille.oidc.models.Client, Base, SqlAlchemyModel): class AuthorizationCode(canaille.oidc.models.AuthorizationCode, Base, SqlAlchemyModel): __tablename__ = "authorization_code" - identifier_attribute = "authorization_code_id" id: Mapped[str] = mapped_column( String, primary_key=True, default=lambda: str(uuid.uuid4()) @@ -293,7 +285,6 @@ token_audience_association_table = Table( class Token(canaille.oidc.models.Token, Base, SqlAlchemyModel): __tablename__ = "token" - identifier_attribute = "token_id" id: Mapped[str] = mapped_column( String, primary_key=True, default=lambda: str(uuid.uuid4()) @@ -331,7 +322,6 @@ class Token(canaille.oidc.models.Token, Base, SqlAlchemyModel): class Consent(canaille.oidc.models.Consent, Base, SqlAlchemyModel): __tablename__ = "consent" - identifier_attribute = "consent_id" id: Mapped[str] = mapped_column( String, primary_key=True, default=lambda: str(uuid.uuid4()) diff --git a/canaille/core/models.py b/canaille/core/models.py index 2109e413..da0b3976 100644 --- a/canaille/core/models.py +++ b/canaille/core/models.py @@ -1,5 +1,6 @@ import datetime from typing import Annotated +from typing import ClassVar from typing import List from typing import Optional @@ -23,6 +24,8 @@ class User(Model): implementation in Canaille. """ + identifier_attribute: ClassVar[str] = "user_name" + user_name: str """A service provider's unique identifier for the user, typically used by the user to directly authenticate to the service provider. @@ -325,6 +328,8 @@ class Group(Model): `_. """ + identifier_attribute: ClassVar[str] = "display_name" + display_name: str """A human-readable name for the Group. diff --git a/canaille/oidc/basemodels.py b/canaille/oidc/basemodels.py index cacb4f8c..02d25f30 100644 --- a/canaille/oidc/basemodels.py +++ b/canaille/oidc/basemodels.py @@ -1,4 +1,5 @@ import datetime +from typing import ClassVar from typing import List from typing import Optional @@ -16,6 +17,8 @@ class Client(Model): specifications. """ + identifier_attribute: ClassVar[str] = "client_id" + description: Optional[str] = None preconsent: Optional[bool] = False audience: List["Client"] = [] @@ -288,6 +291,8 @@ class Client(Model): class AuthorizationCode(Model): """OpenID Connect temporary authorization code definition.""" + identifier_attribute: ClassVar[str] = "authorization_code_id" + authorization_code_id: str code: str client: "Client" @@ -306,6 +311,8 @@ class AuthorizationCode(Model): class Token(Model): """OpenID Connect token definition.""" + identifier_attribute: ClassVar[str] = "token_id" + token_id: str access_token: str client: "Client" @@ -322,6 +329,8 @@ class Token(Model): class Consent(Model): """Long-term user consent to an application.""" + identifier_attribute: ClassVar[str] = "consent_id" + consent_id: str subject: User client: "Client"