authentik.providers.scim.clients.schema

Custom SCIM schemas

  1"""Custom SCIM schemas"""
  2
  3from enum import StrEnum
  4from typing import Self
  5
  6from django.core.exceptions import ValidationError
  7from django.core.validators import validate_email
  8from pydantic import AnyUrl, BaseModel, ConfigDict, Field, model_validator
  9from pydanticscim.group import Group as BaseGroup
 10from pydanticscim.group import GroupMember as BaseGroupMember
 11from pydanticscim.responses import PatchOperation as BasePatchOperation
 12from pydanticscim.responses import PatchRequest as BasePatchRequest
 13from pydanticscim.responses import SCIMError as BaseSCIMError
 14from pydanticscim.service_provider import Bulk as BaseBulk
 15from pydanticscim.service_provider import ChangePassword, Filter, Patch, Sort
 16from pydanticscim.service_provider import (
 17    ServiceProviderConfiguration as BaseServiceProviderConfiguration,
 18)
 19from pydanticscim.user import AddressKind, EmailKind
 20from pydanticscim.user import User as BaseUser
 21
 22SCIM_USER_SCHEMA = "urn:ietf:params:scim:schemas:core:2.0:User"
 23SCIM_GROUP_SCHEMA = "urn:ietf:params:scim:schemas:core:2.0:Group"
 24
 25
 26class Address(BaseModel):
 27    formatted: str | None = Field(
 28        None,
 29        description="The full mailing address, formatted for display "
 30        "or use with a mailing label.  This attribute MAY contain newlines.",
 31    )
 32    streetAddress: str | None = Field(
 33        None,
 34        description="The full street address component, which may "
 35        "include house number, street name, P.O. box, and multi-line "
 36        "extended street address information.  This attribute MAY contain newlines.",
 37    )
 38    locality: str | None = Field(None, description="The city or locality component.")
 39    region: str | None = Field(None, description="The state or region component.")
 40    postalCode: str | None = Field(None, description="The zip code or postal code component.")
 41    country: str | None = Field(None, description="The country name component.")
 42    type: AddressKind | None = Field(
 43        None,
 44        description="A label indicating the attribute's function, e.g., 'work' or 'home'.",
 45    )
 46    primary: bool | None = None
 47
 48
 49class Manager(BaseModel):
 50    value: str | None = Field(
 51        None,
 52        description="The id of the SCIM resource representingthe User's manager.  REQUIRED.",
 53    )
 54    ref: AnyUrl | None = Field(
 55        None,
 56        alias="$ref",
 57        description="The URI of the SCIM resource representing the User's manager.  REQUIRED.",
 58    )
 59    displayName: str | None = Field(
 60        None,
 61        description="The displayName of the User's manager. OPTIONAL and READ-ONLY.",
 62    )
 63
 64
 65class EnterpriseUser(BaseModel):
 66    employeeNumber: str | None = Field(
 67        None,
 68        description="Numeric or alphanumeric identifier assigned to a person, "
 69        "typically based on order of hire or association with an organization.",
 70    )
 71    costCenter: str | None = Field(None, description="Identifies the name of a cost center.")
 72    organization: str | None = Field(None, description="Identifies the name of an organization.")
 73    division: str | None = Field(None, description="Identifies the name of a division.")
 74    department: str | None = Field(
 75        None,
 76        description="Numeric or alphanumeric identifier assigned to a person,"
 77        " typically based on order of hire or association with an organization.",
 78    )
 79    manager: Manager | None = Field(
 80        None,
 81        description="The User's manager. A complex type that optionally allows "
 82        "service providers to represent organizational hierarchy by referencing"
 83        " the 'id' attribute of another User.",
 84    )
 85
 86
 87class Email(BaseModel):
 88    value: str | None = Field(
 89        None,
 90        description=(
 91            "Email addresses for the user.  The value SHOULD be canonicalized by the "
 92            "service provider, e.g., 'bjensen@example.com' instead of 'bjensen@EXAMPLE.COM'. "
 93            "Canonical type values of 'work', 'home', and 'other'."
 94        ),
 95    )
 96    display: str | None = Field(
 97        None,
 98        description="A human-readable name, primarily used for display purposes.  READ-ONLY.",
 99    )
100    type: EmailKind | None = Field(
101        None,
102        description="A label indicating the attribute's function, e.g., 'work' or 'home'.",
103    )
104    primary: bool | None = Field(
105        None,
106        description=(
107            "A Boolean value indicating the 'primary' or preferred attribute value for "
108            "this attribute, e.g., the preferred mailing address or primary email address. "
109            "The primary attribute value 'true' MUST appear no more than once."
110        ),
111    )
112
113    @model_validator(mode="after")
114    def validate_email_django(self) -> Self:
115        """Check that the given email address validates according to django's validation rules.
116        If we used pydantic's built in EmailStr, the rules would be slightly different."""
117        try:
118            validate_email(self.value)
119        except ValidationError as exc:
120            raise ValueError(exc) from exc
121        return self
122
123
124class User(BaseUser):
125    """Modified User schema with added externalId field"""
126
127    model_config = ConfigDict(serialize_by_alias=True, extra="allow")
128
129    id: str | int | None = None
130    schemas: list[str] = [SCIM_USER_SCHEMA]
131    externalId: str | None = None
132    meta: dict | None = None
133    addresses: list[Address] | None = Field(
134        None,
135        description=(
136            "A physical mailing address for this User. Canonical type "
137            "values of 'work', 'home', and 'other'."
138        ),
139    )
140    enterprise_user: EnterpriseUser | None = Field(
141        default=None,
142        alias="urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
143        serialization_alias="urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
144    )
145    emails: list[Email] | None = Field(
146        None,
147        description=(
148            "Email addresses for the user.  The value SHOULD be canonicalized by the "
149            "service provider, e.g., 'bjensen@example.com' instead of 'bjensen@EXAMPLE.COM'. "
150            "Canonical type values of 'work', 'home', and 'other'."
151        ),
152    )
153
154
155class Group(BaseGroup):
156    """Modified Group schema with added externalId field"""
157
158    model_config = ConfigDict(extra="allow")
159
160    id: str | int | None = None
161    schemas: list[str] = [SCIM_GROUP_SCHEMA]
162    externalId: str | None = None
163    meta: dict | None = None
164    members: list[GroupMember] | None = Field(None, description="A list of members of the Group.")
165
166
167class GroupMember(BaseGroupMember):
168    """Modified GroupMember that allows extra fields"""
169
170    model_config = ConfigDict(extra="allow")
171
172
173class Bulk(BaseBulk):
174    maxOperations: int = Field()
175
176
177class ServiceProviderConfiguration(BaseServiceProviderConfiguration):
178    """ServiceProviderConfig with fallback"""
179
180    _is_fallback: bool | None = False
181    bulk: Bulk = Field(..., description="A complex type that specifies bulk configuration options.")
182
183    @property
184    def is_fallback(self) -> bool:
185        """Check if this service provider config was retrieved from the API endpoint
186        or a fallback was used"""
187        return self._is_fallback
188
189    @staticmethod
190    def default() -> ServiceProviderConfiguration:
191        """Get default configuration, which doesn't support any optional features as fallback"""
192        return ServiceProviderConfiguration(
193            patch=Patch(supported=False),
194            bulk=Bulk(supported=False, maxOperations=0),
195            filter=Filter(supported=False),
196            changePassword=ChangePassword(supported=False),
197            sort=Sort(supported=False),
198            authenticationSchemes=[],
199            _is_fallback=True,
200        )
201
202
203class PatchOp(StrEnum):
204    replace = "replace"
205    remove = "remove"
206    add = "add"
207
208    @classmethod
209    def _missing_(cls, value):
210        value = value.lower()
211        for member in cls:
212            if member.lower() == value:
213                return member
214        return None
215
216
217class PatchRequest(BasePatchRequest):
218    """PatchRequest which correctly sets schemas"""
219
220    schemas: tuple[str] = ("urn:ietf:params:scim:api:messages:2.0:PatchOp",)
221
222
223class PatchOperation(BasePatchOperation):
224    """PatchOperation with optional path"""
225
226    op: PatchOp
227    path: str | None = None
228
229
230class SCIMError(BaseSCIMError):
231    """SCIM error with optional status code"""
232
233    status: int | None
SCIM_USER_SCHEMA = 'urn:ietf:params:scim:schemas:core:2.0:User'
SCIM_GROUP_SCHEMA = 'urn:ietf:params:scim:schemas:core:2.0:Group'
class Address(pydantic.main.BaseModel):
27class Address(BaseModel):
28    formatted: str | None = Field(
29        None,
30        description="The full mailing address, formatted for display "
31        "or use with a mailing label.  This attribute MAY contain newlines.",
32    )
33    streetAddress: str | None = Field(
34        None,
35        description="The full street address component, which may "
36        "include house number, street name, P.O. box, and multi-line "
37        "extended street address information.  This attribute MAY contain newlines.",
38    )
39    locality: str | None = Field(None, description="The city or locality component.")
40    region: str | None = Field(None, description="The state or region component.")
41    postalCode: str | None = Field(None, description="The zip code or postal code component.")
42    country: str | None = Field(None, description="The country name component.")
43    type: AddressKind | None = Field(
44        None,
45        description="A label indicating the attribute's function, e.g., 'work' or 'home'.",
46    )
47    primary: bool | None = None

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes: __class_vars__: The names of the class variables defined on the model. __private_attributes__: Metadata about the private attributes of the model. __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.

__pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
__pydantic_core_schema__: The core schema of the model.
__pydantic_custom_init__: Whether the model has a custom `__init__` function.
__pydantic_decorators__: Metadata containing the decorators defined on the model.
    This replaces `Model.__validators__` and `Model.__root_validators__` from Pydantic V1.
__pydantic_generic_metadata__: Metadata for generic models; contains data used for a similar purpose to
    __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
__pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
__pydantic_post_init__: The name of the post-init method for the model, if defined.
__pydantic_root_model__: Whether the model is a [`RootModel`][pydantic.root_model.RootModel].
__pydantic_serializer__: The `pydantic-core` `SchemaSerializer` used to dump instances of the model.
__pydantic_validator__: The `pydantic-core` `SchemaValidator` used to validate instances of the model.

__pydantic_fields__: A dictionary of field names and their corresponding [`FieldInfo`][pydantic.fields.FieldInfo] objects.
__pydantic_computed_fields__: A dictionary of computed field names and their corresponding [`ComputedFieldInfo`][pydantic.fields.ComputedFieldInfo] objects.

__pydantic_extra__: A dictionary containing extra values, if [`extra`][pydantic.config.ConfigDict.extra]
    is set to `'allow'`.
__pydantic_fields_set__: The names of fields explicitly set during instantiation.
__pydantic_private__: Values of private attributes set on the model instance.
formatted: str | None = None

The full mailing address, formatted for display or use with a mailing label. This attribute MAY contain newlines.

streetAddress: str | None = None

The full street address component, which may include house number, street name, P.O. box, and multi-line extended street address information. This attribute MAY contain newlines.

locality: str | None = None

The city or locality component.

region: str | None = None

The state or region component.

postalCode: str | None = None

The zip code or postal code component.

country: str | None = None

The country name component.

type: pydanticscim.user.AddressKind | None = None

A label indicating the attribute's function, e.g., 'work' or 'home'.

primary: bool | None = None
class Manager(pydantic.main.BaseModel):
50class Manager(BaseModel):
51    value: str | None = Field(
52        None,
53        description="The id of the SCIM resource representingthe User's manager.  REQUIRED.",
54    )
55    ref: AnyUrl | None = Field(
56        None,
57        alias="$ref",
58        description="The URI of the SCIM resource representing the User's manager.  REQUIRED.",
59    )
60    displayName: str | None = Field(
61        None,
62        description="The displayName of the User's manager. OPTIONAL and READ-ONLY.",
63    )

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes: __class_vars__: The names of the class variables defined on the model. __private_attributes__: Metadata about the private attributes of the model. __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.

__pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
__pydantic_core_schema__: The core schema of the model.
__pydantic_custom_init__: Whether the model has a custom `__init__` function.
__pydantic_decorators__: Metadata containing the decorators defined on the model.
    This replaces `Model.__validators__` and `Model.__root_validators__` from Pydantic V1.
__pydantic_generic_metadata__: Metadata for generic models; contains data used for a similar purpose to
    __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
__pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
__pydantic_post_init__: The name of the post-init method for the model, if defined.
__pydantic_root_model__: Whether the model is a [`RootModel`][pydantic.root_model.RootModel].
__pydantic_serializer__: The `pydantic-core` `SchemaSerializer` used to dump instances of the model.
__pydantic_validator__: The `pydantic-core` `SchemaValidator` used to validate instances of the model.

__pydantic_fields__: A dictionary of field names and their corresponding [`FieldInfo`][pydantic.fields.FieldInfo] objects.
__pydantic_computed_fields__: A dictionary of computed field names and their corresponding [`ComputedFieldInfo`][pydantic.fields.ComputedFieldInfo] objects.

__pydantic_extra__: A dictionary containing extra values, if [`extra`][pydantic.config.ConfigDict.extra]
    is set to `'allow'`.
__pydantic_fields_set__: The names of fields explicitly set during instantiation.
__pydantic_private__: Values of private attributes set on the model instance.
value: str | None = None

The id of the SCIM resource representingthe User's manager. REQUIRED.

ref: pydantic.networks.AnyUrl | None = None

The URI of the SCIM resource representing the User's manager. REQUIRED.

displayName: str | None = None

The displayName of the User's manager. OPTIONAL and READ-ONLY.

class EnterpriseUser(pydantic.main.BaseModel):
66class EnterpriseUser(BaseModel):
67    employeeNumber: str | None = Field(
68        None,
69        description="Numeric or alphanumeric identifier assigned to a person, "
70        "typically based on order of hire or association with an organization.",
71    )
72    costCenter: str | None = Field(None, description="Identifies the name of a cost center.")
73    organization: str | None = Field(None, description="Identifies the name of an organization.")
74    division: str | None = Field(None, description="Identifies the name of a division.")
75    department: str | None = Field(
76        None,
77        description="Numeric or alphanumeric identifier assigned to a person,"
78        " typically based on order of hire or association with an organization.",
79    )
80    manager: Manager | None = Field(
81        None,
82        description="The User's manager. A complex type that optionally allows "
83        "service providers to represent organizational hierarchy by referencing"
84        " the 'id' attribute of another User.",
85    )

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes: __class_vars__: The names of the class variables defined on the model. __private_attributes__: Metadata about the private attributes of the model. __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.

__pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
__pydantic_core_schema__: The core schema of the model.
__pydantic_custom_init__: Whether the model has a custom `__init__` function.
__pydantic_decorators__: Metadata containing the decorators defined on the model.
    This replaces `Model.__validators__` and `Model.__root_validators__` from Pydantic V1.
__pydantic_generic_metadata__: Metadata for generic models; contains data used for a similar purpose to
    __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
__pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
__pydantic_post_init__: The name of the post-init method for the model, if defined.
__pydantic_root_model__: Whether the model is a [`RootModel`][pydantic.root_model.RootModel].
__pydantic_serializer__: The `pydantic-core` `SchemaSerializer` used to dump instances of the model.
__pydantic_validator__: The `pydantic-core` `SchemaValidator` used to validate instances of the model.

__pydantic_fields__: A dictionary of field names and their corresponding [`FieldInfo`][pydantic.fields.FieldInfo] objects.
__pydantic_computed_fields__: A dictionary of computed field names and their corresponding [`ComputedFieldInfo`][pydantic.fields.ComputedFieldInfo] objects.

__pydantic_extra__: A dictionary containing extra values, if [`extra`][pydantic.config.ConfigDict.extra]
    is set to `'allow'`.
__pydantic_fields_set__: The names of fields explicitly set during instantiation.
__pydantic_private__: Values of private attributes set on the model instance.
employeeNumber: str | None = None

Numeric or alphanumeric identifier assigned to a person, typically based on order of hire or association with an organization.

costCenter: str | None = None

Identifies the name of a cost center.

organization: str | None = None

Identifies the name of an organization.

division: str | None = None

Identifies the name of a division.

department: str | None = None

Numeric or alphanumeric identifier assigned to a person, typically based on order of hire or association with an organization.

manager: Manager | None = None

The User's manager. A complex type that optionally allows service providers to represent organizational hierarchy by referencing the 'id' attribute of another User.

class Email(pydantic.main.BaseModel):
 88class Email(BaseModel):
 89    value: str | None = Field(
 90        None,
 91        description=(
 92            "Email addresses for the user.  The value SHOULD be canonicalized by the "
 93            "service provider, e.g., 'bjensen@example.com' instead of 'bjensen@EXAMPLE.COM'. "
 94            "Canonical type values of 'work', 'home', and 'other'."
 95        ),
 96    )
 97    display: str | None = Field(
 98        None,
 99        description="A human-readable name, primarily used for display purposes.  READ-ONLY.",
100    )
101    type: EmailKind | None = Field(
102        None,
103        description="A label indicating the attribute's function, e.g., 'work' or 'home'.",
104    )
105    primary: bool | None = Field(
106        None,
107        description=(
108            "A Boolean value indicating the 'primary' or preferred attribute value for "
109            "this attribute, e.g., the preferred mailing address or primary email address. "
110            "The primary attribute value 'true' MUST appear no more than once."
111        ),
112    )
113
114    @model_validator(mode="after")
115    def validate_email_django(self) -> Self:
116        """Check that the given email address validates according to django's validation rules.
117        If we used pydantic's built in EmailStr, the rules would be slightly different."""
118        try:
119            validate_email(self.value)
120        except ValidationError as exc:
121            raise ValueError(exc) from exc
122        return self

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes: __class_vars__: The names of the class variables defined on the model. __private_attributes__: Metadata about the private attributes of the model. __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.

__pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
__pydantic_core_schema__: The core schema of the model.
__pydantic_custom_init__: Whether the model has a custom `__init__` function.
__pydantic_decorators__: Metadata containing the decorators defined on the model.
    This replaces `Model.__validators__` and `Model.__root_validators__` from Pydantic V1.
__pydantic_generic_metadata__: Metadata for generic models; contains data used for a similar purpose to
    __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
__pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
__pydantic_post_init__: The name of the post-init method for the model, if defined.
__pydantic_root_model__: Whether the model is a [`RootModel`][pydantic.root_model.RootModel].
__pydantic_serializer__: The `pydantic-core` `SchemaSerializer` used to dump instances of the model.
__pydantic_validator__: The `pydantic-core` `SchemaValidator` used to validate instances of the model.

__pydantic_fields__: A dictionary of field names and their corresponding [`FieldInfo`][pydantic.fields.FieldInfo] objects.
__pydantic_computed_fields__: A dictionary of computed field names and their corresponding [`ComputedFieldInfo`][pydantic.fields.ComputedFieldInfo] objects.

__pydantic_extra__: A dictionary containing extra values, if [`extra`][pydantic.config.ConfigDict.extra]
    is set to `'allow'`.
__pydantic_fields_set__: The names of fields explicitly set during instantiation.
__pydantic_private__: Values of private attributes set on the model instance.
value: str | None = None

Email addresses for the user. The value SHOULD be canonicalized by the service provider, e.g., 'bjensen@example.com' instead of 'bjensen@EXAMPLE.COM'. Canonical type values of 'work', 'home', and 'other'.

display: str | None = None

A human-readable name, primarily used for display purposes. READ-ONLY.

type: pydanticscim.user.EmailKind | None = None

A label indicating the attribute's function, e.g., 'work' or 'home'.

primary: bool | None = None

A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred mailing address or primary email address. The primary attribute value 'true' MUST appear no more than once.

@model_validator(mode='after')
def validate_email_django(self) -> Self:
114    @model_validator(mode="after")
115    def validate_email_django(self) -> Self:
116        """Check that the given email address validates according to django's validation rules.
117        If we used pydantic's built in EmailStr, the rules would be slightly different."""
118        try:
119            validate_email(self.value)
120        except ValidationError as exc:
121            raise ValueError(exc) from exc
122        return self

Check that the given email address validates according to django's validation rules. If we used pydantic's built in EmailStr, the rules would be slightly different.

class User(pydanticscim.user.User):
125class User(BaseUser):
126    """Modified User schema with added externalId field"""
127
128    model_config = ConfigDict(serialize_by_alias=True, extra="allow")
129
130    id: str | int | None = None
131    schemas: list[str] = [SCIM_USER_SCHEMA]
132    externalId: str | None = None
133    meta: dict | None = None
134    addresses: list[Address] | None = Field(
135        None,
136        description=(
137            "A physical mailing address for this User. Canonical type "
138            "values of 'work', 'home', and 'other'."
139        ),
140    )
141    enterprise_user: EnterpriseUser | None = Field(
142        default=None,
143        alias="urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
144        serialization_alias="urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
145    )
146    emails: list[Email] | None = Field(
147        None,
148        description=(
149            "Email addresses for the user.  The value SHOULD be canonicalized by the "
150            "service provider, e.g., 'bjensen@example.com' instead of 'bjensen@EXAMPLE.COM'. "
151            "Canonical type values of 'work', 'home', and 'other'."
152        ),
153    )

Modified User schema with added externalId field

id: str | int | None = None
schemas: list[str] = ['urn:ietf:params:scim:schemas:core:2.0:User']
externalId: str | None = None
meta: dict | None = None
addresses: list[Address] | None = None

A physical mailing address for this User. Canonical type values of 'work', 'home', and 'other'.

enterprise_user: EnterpriseUser | None = None
emails: list[Email] | None = None

Email addresses for the user. The value SHOULD be canonicalized by the service provider, e.g., 'bjensen@example.com' instead of 'bjensen@EXAMPLE.COM'. Canonical type values of 'work', 'home', and 'other'.

class Group(pydanticscim.group.Group):
156class Group(BaseGroup):
157    """Modified Group schema with added externalId field"""
158
159    model_config = ConfigDict(extra="allow")
160
161    id: str | int | None = None
162    schemas: list[str] = [SCIM_GROUP_SCHEMA]
163    externalId: str | None = None
164    meta: dict | None = None
165    members: list[GroupMember] | None = Field(None, description="A list of members of the Group.")

Modified Group schema with added externalId field

id: str | int | None = None
schemas: list[str] = ['urn:ietf:params:scim:schemas:core:2.0:Group']
externalId: str | None = None
meta: dict | None = None
members: list[GroupMember] | None = None

A list of members of the Group.

class GroupMember(pydanticscim.group.GroupMember):
168class GroupMember(BaseGroupMember):
169    """Modified GroupMember that allows extra fields"""
170
171    model_config = ConfigDict(extra="allow")

Modified GroupMember that allows extra fields

class Bulk(pydanticscim.service_provider.Bulk):
174class Bulk(BaseBulk):
175    maxOperations: int = Field()

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes: __class_vars__: The names of the class variables defined on the model. __private_attributes__: Metadata about the private attributes of the model. __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.

__pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
__pydantic_core_schema__: The core schema of the model.
__pydantic_custom_init__: Whether the model has a custom `__init__` function.
__pydantic_decorators__: Metadata containing the decorators defined on the model.
    This replaces `Model.__validators__` and `Model.__root_validators__` from Pydantic V1.
__pydantic_generic_metadata__: Metadata for generic models; contains data used for a similar purpose to
    __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
__pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
__pydantic_post_init__: The name of the post-init method for the model, if defined.
__pydantic_root_model__: Whether the model is a [`RootModel`][pydantic.root_model.RootModel].
__pydantic_serializer__: The `pydantic-core` `SchemaSerializer` used to dump instances of the model.
__pydantic_validator__: The `pydantic-core` `SchemaValidator` used to validate instances of the model.

__pydantic_fields__: A dictionary of field names and their corresponding [`FieldInfo`][pydantic.fields.FieldInfo] objects.
__pydantic_computed_fields__: A dictionary of computed field names and their corresponding [`ComputedFieldInfo`][pydantic.fields.ComputedFieldInfo] objects.

__pydantic_extra__: A dictionary containing extra values, if [`extra`][pydantic.config.ConfigDict.extra]
    is set to `'allow'`.
__pydantic_fields_set__: The names of fields explicitly set during instantiation.
__pydantic_private__: Values of private attributes set on the model instance.
maxOperations: int = PydanticUndefined
class ServiceProviderConfiguration(pydanticscim.service_provider.ServiceProviderConfiguration):
178class ServiceProviderConfiguration(BaseServiceProviderConfiguration):
179    """ServiceProviderConfig with fallback"""
180
181    _is_fallback: bool | None = False
182    bulk: Bulk = Field(..., description="A complex type that specifies bulk configuration options.")
183
184    @property
185    def is_fallback(self) -> bool:
186        """Check if this service provider config was retrieved from the API endpoint
187        or a fallback was used"""
188        return self._is_fallback
189
190    @staticmethod
191    def default() -> ServiceProviderConfiguration:
192        """Get default configuration, which doesn't support any optional features as fallback"""
193        return ServiceProviderConfiguration(
194            patch=Patch(supported=False),
195            bulk=Bulk(supported=False, maxOperations=0),
196            filter=Filter(supported=False),
197            changePassword=ChangePassword(supported=False),
198            sort=Sort(supported=False),
199            authenticationSchemes=[],
200            _is_fallback=True,
201        )

ServiceProviderConfig with fallback

bulk: Bulk = PydanticUndefined

A complex type that specifies bulk configuration options.

is_fallback: bool
184    @property
185    def is_fallback(self) -> bool:
186        """Check if this service provider config was retrieved from the API endpoint
187        or a fallback was used"""
188        return self._is_fallback

Check if this service provider config was retrieved from the API endpoint or a fallback was used

@staticmethod
def default() -> ServiceProviderConfiguration:
190    @staticmethod
191    def default() -> ServiceProviderConfiguration:
192        """Get default configuration, which doesn't support any optional features as fallback"""
193        return ServiceProviderConfiguration(
194            patch=Patch(supported=False),
195            bulk=Bulk(supported=False, maxOperations=0),
196            filter=Filter(supported=False),
197            changePassword=ChangePassword(supported=False),
198            sort=Sort(supported=False),
199            authenticationSchemes=[],
200            _is_fallback=True,
201        )

Get default configuration, which doesn't support any optional features as fallback

class PatchOp(enum.StrEnum):
204class PatchOp(StrEnum):
205    replace = "replace"
206    remove = "remove"
207    add = "add"
208
209    @classmethod
210    def _missing_(cls, value):
211        value = value.lower()
212        for member in cls:
213            if member.lower() == value:
214                return member
215        return None
replace

The type of the None singleton.

remove = <PatchOp.remove: 'remove'>
add = <PatchOp.add: 'add'>
class PatchRequest(pydanticscim.responses.PatchRequest):
218class PatchRequest(BasePatchRequest):
219    """PatchRequest which correctly sets schemas"""
220
221    schemas: tuple[str] = ("urn:ietf:params:scim:api:messages:2.0:PatchOp",)

PatchRequest which correctly sets schemas

schemas: tuple[str] = ('urn:ietf:params:scim:api:messages:2.0:PatchOp',)
class PatchOperation(pydanticscim.responses.PatchOperation):
224class PatchOperation(BasePatchOperation):
225    """PatchOperation with optional path"""
226
227    op: PatchOp
228    path: str | None = None

PatchOperation with optional path

op: PatchOp = PydanticUndefined
path: str | None = None
class SCIMError(pydanticscim.responses.SCIMError):
231class SCIMError(BaseSCIMError):
232    """SCIM error with optional status code"""
233
234    status: int | None

SCIM error with optional status code

status: int | None = PydanticUndefined