pydantic validation for auth
import enum
import typing
+from abc import ABC
import pydantic
from pydantic import validator, root_validator
@@ -135,12 +136,58 @@ class Auth0Config(Base):
auth0_subdomain: str
-class Authentication(Base):
+class Authentication(Base, ABC):
+ _types: typing.Dict[str, type] = {}
+
type: AuthenticationEnum
- authentication_class: typing.Optional[str]
- config: typing.Optional[
- typing.Union[Auth0Config, GitHubConfig, typing.Dict[str, typing.Any]]
- ]
+
+ # Based on https://github.com/samuelcolvin/pydantic/issues/2177#issuecomment-739578307
+
+ # This allows type field to determine which subclass of Authentication should be used for validation.
+
+ # Used to register automatically all the submodels in `_types`.
+ def __init_subclass__(cls):
+ cls._types[cls._typ.value] = cls
+
+ @classmethod
+ def __get_validators__(cls):
+ yield cls.validate
+
+ @classmethod
+ def validate(cls, value: typing.Dict[str, typing.Any]) -> "Authentication":
+ if "type" not in value:
+ raise ValueError("type field is missing from security.authentication")
+
+ specified_type = value.get("type")
+ sub_class = cls._types.get(specified_type, None)
+
+ if not sub_class:
+ raise ValueError(
+ f"No registered Authentication type called {specified_type}"
+ )
+
+ # init with right submodel
+ return sub_class(**value)
+
+
+class PasswordAuthentication(Authentication):
+ _typ = AuthenticationEnum.password
+
+
+class Auth0Authentication(Authentication):
+ _typ = AuthenticationEnum.auth0
+ config: Auth0Config
+
+
+class GitHubAuthentication(Authentication):
+ _typ = AuthenticationEnum.github
+ config: GitHubConfig
+
+
+class CustomAuthentication(Authentication):
+ _typ = AuthenticationEnum.custom
+ authentication_class: str
+ config: typing.Dict[str, typing.Any]
# =========== Users and Groups =============
