openreplay/ee/api/routers/scim_constants.py
2025-05-30 14:18:49 +02:00

778 lines
31 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# note(jon): please see https://datatracker.ietf.org/doc/html/rfc7643 for details on these constants
from typing import Any
def _attribute_characteristics(
name: str,
description: str,
type: str = "string",
sub_attributes: dict[str, Any] | None = None,
# note(jon): no default for multiValued is defined in the docs and it is marked as optional.
# from our side, we'll default it to False.
multi_valued: bool = False,
required: bool = False,
canonical_values: list[str] | None = None,
case_exact: bool = False,
mutability: str = "readWrite",
returned: str = "default",
uniqueness: str = "none",
reference_types: list[str] | None = None,
):
characteristics = {
"name": name,
"type": type,
"subAttributes": sub_attributes,
"multiValued": multi_valued,
"description": description,
"required": required,
"canonicalValues": canonical_values,
"caseExact": case_exact,
"mutability": mutability,
"returned": returned,
"uniqueness": uniqueness,
"referenceTypes": reference_types,
}
characteristics_without_none = {
key: value for key, value in characteristics.items() if value is not None
}
return characteristics_without_none
def _multi_valued_attributes(
type_canonical_values: list[str],
type_required: bool = False,
type_mutability="readWrite",
):
return [
_attribute_characteristics(
name="type",
description="A label indicating the attribute's function.",
canonical_values=type_canonical_values,
case_exact=True,
required=type_required,
mutability=type_mutability,
),
_attribute_characteristics(
name="primary",
type="boolean",
description="A Boolean value indicating the 'primary' or preferred attribute value for this attribute.",
),
_attribute_characteristics(
name="display",
description="A human-readable name.",
mutability="immutable",
),
_attribute_characteristics(
name="value",
description="The attribute's significant value.",
),
_attribute_characteristics(
name="$ref",
type="reference",
reference_types=["uri"],
description="The reference URI of a target resource.",
),
]
# note(jon): the docs are a little confusing regarding this, but
# in section 3.1 of RFC7643, it is specified that ResourceType and
# ServiceProviderConfig are not included in the common attributes. but
# in other references, they treat them as a resource.
def _common_resource_attributes(id_required: bool = True, id_uniqueness: str = "none"):
return [
_attribute_characteristics(
name="id",
description="A unique identifier for the SCIM resource.",
case_exact=True,
mutability="readOnly",
returned="always",
required=id_required,
uniqueness=id_uniqueness,
),
_attribute_characteristics(
name="externalId",
description="A String that is an identifier for the resource as defined by the provisioning client.",
case_exact=True,
),
_attribute_characteristics(
name="schemas",
type="reference",
reference_types=["uri"],
description="An array of Strings containing URI that are used to indicate the namespaces of the SCIM schemas that define the attributes present in the current JSON structure.",
multi_valued=True,
canonical_values=[
"urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig",
"urn:ietf:params:scim:schemas:core:2.0:ResourceType",
"urn:ietf:params:scim:schemas:core:2.0:Schema",
"urn:ietf:params:scim:schemas:core:2.0:User",
],
case_exact=True,
mutability="readOnly",
required=True,
returned="always",
),
_attribute_characteristics(
name="meta",
type="complex",
description="A complex attribute containing resource metadata.",
required=True,
sub_attributes=[
_attribute_characteristics(
name="resourceType",
description="The name of the resource type of the resource.",
mutability="readOnly",
case_exact=True,
required=True,
),
_attribute_characteristics(
name="created",
type="dateTime",
description="The 'DateTime' that the resource was added to the service provider.",
mutability="readOnly",
required=True,
),
_attribute_characteristics(
name="lastModified",
type="dateTime",
description="The most recent DateTime that the details of this resource were updated at the service provider.",
mutability="readOnly",
required=True,
),
_attribute_characteristics(
name="location",
type="reference",
reference_types=["uri"],
description="The URI of the resource being returned.",
mutability="readOnly",
required=True,
),
# todo(jon): decide if we'll handle versioning. for now, we won't do it.
],
),
]
SERVICE_PROVIDER_CONFIG_SCHEMA = {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Schema"],
"id": "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig",
"name": "Service Provider Configuration",
"description": "Schema for representing the service provider's configuration.",
"meta": {
"resourceType": "Schema",
"created": "2025-04-16T14:48:00Z",
# note(jon): we might want to think about adding this resource as part of our db
# and then updating these timestamps from an api and such. for now, if we update
# the configuration, we should update the timestamp here.
"lastModified": "2025-04-16T14:48:00Z",
"location": "Schemas/urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig",
},
"attributes": [
*_common_resource_attributes(id_required=False),
_attribute_characteristics(
name="documentationUri",
type="reference",
reference_types=["external"],
description="An HTTP-addressable URL pointing to the service provider's human-consumable help documentation.",
mutability="readOnly",
),
_attribute_characteristics(
name="patch",
type="complex",
description="A complex type that specifies PATCH configuration options.",
required=True,
mutability="readOnly",
sub_attributes=[
_attribute_characteristics(
name="supported",
type="boolean",
description="A Boolean value specifying whether or not the operation is supported.",
required=True,
mutability="readOnly",
),
],
),
_attribute_characteristics(
name="bulk",
type="complex",
description="A complex type that specifies bulk configuration options.",
required=True,
mutability="readOnly",
sub_attributes=[
_attribute_characteristics(
name="supported",
type="boolean",
description="A Boolean value specifying whether or not the operation is supported.",
required=True,
mutability="readOnly",
),
_attribute_characteristics(
name="maxOperations",
type="integer",
description="An integer value specifying the maximum number of operations.",
required=True,
mutability="readOnly",
),
_attribute_characteristics(
name="maxPayloadSize",
type="integer",
description="An integer value specifying the maximum payload size in bytes.",
required=True,
mutability="readOnly",
),
],
),
_attribute_characteristics(
name="filter",
type="complex",
description="A complex type that specifies FILTER options.",
required=True,
mutability="readOnly",
sub_attributes=[
_attribute_characteristics(
name="supported",
type="boolean",
description="A Boolean value specifying whether or not the operation is supported.",
required=True,
mutability="readOnly",
),
_attribute_characteristics(
name="maxResults",
type="integer",
description="The integer value specifying the maximum number of resources returned in a response.",
required=True,
mutability="readOnly",
),
],
),
_attribute_characteristics(
name="changePassword",
type="complex",
description="A complex type that specifies configuration options related to changing a password.",
required=True,
mutability="readOnly",
sub_attributes=[
_attribute_characteristics(
name="supported",
type="boolean",
description="A Boolean value specifying whether or not the operation is supported.",
required=True,
mutability="readOnly",
),
],
),
_attribute_characteristics(
name="sort",
type="complex",
description="A complex type that specifies sort result options.",
required=True,
mutability="readOnly",
sub_attributes=[
_attribute_characteristics(
name="supported",
type="boolean",
description="A Boolean value specifying whether or not the operation is supported.",
required=True,
mutability="readOnly",
),
],
),
_attribute_characteristics(
name="etag",
type="complex",
description="A complex type that specifies ETag configuration options.",
required=True,
mutability="readOnly",
sub_attributes=[
_attribute_characteristics(
name="supported",
type="boolean",
description="A Boolean value specifying whether or not the operation is supported.",
required=True,
mutability="readOnly",
),
],
),
_attribute_characteristics(
name="authenticationSchemes",
type="complex",
multi_valued=True,
description="A complex type that specifies supported authentication scheme properties.",
required=True,
mutability="readOnly",
sub_attributes=[
*_multi_valued_attributes(
type_canonical_values=[
"oauth",
"oauth2",
"oauthbearertoken",
"httpbasic",
"httpdigest",
],
type_required=True,
type_mutability="readOnly",
),
_attribute_characteristics(
name="name",
description="The common authentication scheme name, e.g., HTTP Basic.",
required=True,
mutability="readOnly",
),
_attribute_characteristics(
name="description",
description="A description of the authentication scheme.",
required=True,
mutability="readOnly",
),
_attribute_characteristics(
name="specUri",
type="reference",
reference_types=["external"],
description="An HTTP-addressable URL pointing to the authentication scheme's specification.",
mutability="readOnly",
),
_attribute_characteristics(
name="documentationUri",
type="reference",
reference_types=["external"],
description="An HTTP-addressable URL pointing to the authentication scheme's usage documentation.",
mutability="readOnly",
),
],
),
],
}
RESOURCE_TYPE_SCHEMA = {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Schema"],
"id": "urn:ietf:params:scim:schemas:core:2.0:ResourceType",
"name": "Resource Type",
"description": "Specifies the schema that describes a SCIM resource type.",
"meta": {
"resourceType": "Schema",
"created": "2025-04-16T14:48:00Z",
# note(jon): we might want to think about adding this resource as part of our db
# and then updating these timestamps from an api and such. for now, if we update
# the configuration, we should update the timestamp here.
"lastModified": "2025-04-16T14:48:00Z",
"location": "Schemas/urn:ietf:params:scim:schemas:core:2.0:ResourceType",
},
"attributes": [
*_common_resource_attributes(id_required=False, id_uniqueness="global"),
_attribute_characteristics(
name="name",
description="The resource type name.",
required=True,
mutability="readOnly",
),
_attribute_characteristics(
name="description",
description="The resource type's human-readable description.",
mutability="readOnly",
),
# todo(jon): figure out what the correct type/reference_type is here
_attribute_characteristics(
name="endpoint",
type="reference",
reference_types=["uri"],
description="The resource type's HTTP-addressable endpoint relative to the Base URL of the service provider.",
required=True,
mutability="readOnly",
),
_attribute_characteristics(
name="schema",
type="reference",
reference_types=["uri"],
description="The resource type's primary/base schema URI.",
required=True,
mutability="readOnly",
),
_attribute_characteristics(
name="schemaExtensions",
type="complex",
multi_valued=True,
description="A list of URIs of the resource type's schema extensions.",
mutability="readOnly",
sub_attributes=[
_attribute_characteristics(
name="schema",
type="reference",
reference_types=["uri"],
description="The URI of an extended schema.",
required=True,
mutability="readOnly",
),
_attribute_characteristics(
name="required",
type="boolean",
description="A Boolean value that specifies whether or not the schema extension is required for the resource type.",
required=True,
mutability="readOnly",
),
],
),
],
}
SCHEMA_SCHEMA = {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Schema"],
"id": "urn:ietf:params:scim:schemas:core:2.0:Schema",
"name": "Schema",
"description": "Specifies the schema that describes a SCIM schema.",
"meta": {
"resourceType": "Schema",
"created": "2025-04-16T14:48:00Z",
# note(jon): we might want to think about adding this resource as part of our db
# and then updating these timestamps from an api and such. for now, if we update
# the configuration, we should update the timestamp here.
"lastModified": "2025-04-16T14:48:00Z",
"location": "Schemas/urn:ietf:params:scim:schemas:core:2.0:Schema",
},
"attributes": [
*_common_resource_attributes(id_uniqueness="global"),
_attribute_characteristics(
name="name",
description="The schema's humanreadable name.",
mutability="readOnly",
),
_attribute_characteristics(
name="description",
description="The schema's human-readable name.",
mutability="readOnly",
),
_attribute_characteristics(
name="attributes",
type="complex",
multi_valued=True,
description="A complex attribute that defines service provider attributes and their qualities.",
required=True,
mutability="readOnly",
sub_attributes=[
_attribute_characteristics(
name="name",
description="The attribute's name.",
required=True,
mutability="readOnly",
),
_attribute_characteristics(
name="type",
description="The attribute's data type.",
required=True,
canonical_values=[
"string",
"complex",
"boolean",
"decimal",
"integer",
"dateTime",
"reference",
],
case_exact=True,
mutability="readOnly",
),
_attribute_characteristics(
name="multiValued",
type="boolean",
description="A Boolean value indicating an attribute's plurality.",
required=True,
mutability="readOnly",
),
_attribute_characteristics(
name="description",
description="The attribute's human-readable description.",
required=True,
mutability="readOnly",
),
_attribute_characteristics(
name="required",
type="boolean",
description="A Boolean value indicating whether or not the attribute is required.",
required=True,
mutability="readOnly",
),
_attribute_characteristics(
name="canonicalValues",
multi_valued=True,
description="A collection of canonical values.",
mutability="readOnly",
),
_attribute_characteristics(
name="caseExact",
type="boolean",
description="A Boolean that specifies whether or not a string attribute is case sensitive.",
mutability="readOnly",
),
_attribute_characteristics(
name="mutability",
description="A single keyword indicating the circumstances under which the value of the attribute can be (re)defined.",
required=True,
mutability="readOnly",
canonical_values=[
"readOnly",
"readWrite",
"immutable",
"writeOnly",
],
case_exact=True,
),
_attribute_characteristics(
name="returned",
description="A single keyword that indicates when an attribute and associated values are returned in response to a GET request or in response to a PUT, POST, or PATCH request.",
required=True,
mutability="readOnly",
canonical_values=[
"always",
"never",
"default",
"request",
],
case_exact=True,
),
_attribute_characteristics(
name="uniqueness",
description="A single keyword value that specifies how the service provider enforces uniqueness of attribute values.",
required=True,
mutability="readOnly",
canonical_values=[
"none",
"server",
"global",
],
case_exact=True,
),
_attribute_characteristics(
name="referenceTypes",
multi_valued=True,
description="A multi-valued array of JSON strings that indicate the SCIM resource types that may be referenced.",
mutability="readOnly",
canonical_values=[
# todo(jon): add "User" and "Group" once those are done.
"external",
"uri",
],
case_exact=True,
),
_attribute_characteristics(
name="subAttributes",
type="complex",
multi_valued=True,
description="When an attribute is of type 'complex', this defines a set of sub-attributes.",
mutability="readOnly",
sub_attributes=[
_attribute_characteristics(
name="name",
description="The attribute's name.",
required=True,
mutability="readOnly",
),
_attribute_characteristics(
name="type",
description="The attribute's data type.",
required=True,
canonical_values=[
"string",
"complex",
"boolean",
"decimal",
"integer",
"dateTime",
"reference",
],
case_exact=True,
mutability="readOnly",
),
_attribute_characteristics(
name="multiValued",
type="boolean",
description="A Boolean value indicating an attribute's plurality.",
required=True,
mutability="readOnly",
),
_attribute_characteristics(
name="description",
description="The attribute's human-readable description.",
required=True,
mutability="readOnly",
),
_attribute_characteristics(
name="required",
type="boolean",
description="A Boolean value indicating whether or not the attribute is required.",
required=True,
mutability="readOnly",
),
_attribute_characteristics(
name="canonicalValues",
multi_valued=True,
description="A collection of canonical values.",
mutability="readOnly",
),
_attribute_characteristics(
name="caseExact",
type="boolean",
description="A Boolean that specifies whether or not a string attribute is case sensitive.",
mutability="readOnly",
),
_attribute_characteristics(
name="mutability",
description="A single keyword indicating the circumstances under which the value of the attribute can be (re)defined.",
required=True,
mutability="readOnly",
canonical_values=[
"readOnly",
"readWrite",
"immutable",
"writeOnly",
],
case_exact=True,
),
_attribute_characteristics(
name="returned",
description="A single keyword that indicates when an attribute and associated values are returned in response to a GET request or in response to a PUT, POST, or PATCH request.",
required=True,
mutability="readOnly",
canonical_values=[
"always",
"never",
"default",
"request",
],
case_exact=True,
),
_attribute_characteristics(
name="uniqueness",
description="A single keyword value that specifies how the service provider enforces uniqueness of attribute values.",
required=True,
mutability="readOnly",
canonical_values=[
"none",
"server",
"global",
],
case_exact=True,
),
_attribute_characteristics(
name="referenceTypes",
multi_valued=True,
description="A multi-valued array of JSON strings that indicate the SCIM resource types that may be referenced.",
mutability="readOnly",
canonical_values=[
# todo(jon): add "User" and "Group" once those are done.
"external",
"uri",
],
case_exact=True,
),
],
),
],
),
],
}
USER_SCHEMA = {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Schema"],
"id": "urn:ietf:params:scim:schemas:core:2.0:User",
"name": "User",
"description": "User account.",
"meta": {
"resourceType": "Schema",
"created": "2025-04-16T14:48:00Z",
# note(jon): we might want to think about adding this resource as part of our db
# and then updating these timestamps from an api and such. for now, if we update
# the configuration, we should update the timestamp here.
"lastModified": "2025-04-16T14:48:00Z",
"location": "Schemas/urn:ietf:params:scim:schemas:core:2.0:User",
},
"attributes": [
*_common_resource_attributes(),
_attribute_characteristics(
name="userName",
description="A service provider's unique identifier for the user.",
required=True,
),
],
}
SCHEMAS = sorted(
[
SERVICE_PROVIDER_CONFIG_SCHEMA,
RESOURCE_TYPE_SCHEMA,
SCHEMA_SCHEMA,
USER_SCHEMA,
],
key=lambda x: x["id"],
)
SERVICE_PROVIDER_CONFIG = {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig"],
"patch": {
# todo(jon): this needs to be updated to True once we properly implement patching for users and groups
"supported": False,
},
"bulk": {
"supported": False,
"maxOperations": 0,
"maxPayloadSize": 0,
},
"filter": {
# todo(jon): this needs to be updated to True once we properly implement filtering for users and groups
"supported": False,
"maxResults": 0,
},
"changePassword": {
"supported": False,
},
"sort": {
"supported": False,
},
"etag": {
"supported": False,
},
"authenticationSchemes": [
{
"type": "oauthbearertoken",
"name": "OAuth Bearer Token",
"description": "Authentication scheme using the OAuth Bearer Token Standard. The access token should be sent in the 'Authorization' header using the Bearer schema.",
"specUri": "https://tools.ietf.org/html/rfc6750",
# todo(jon): see if we have our own documentation for this
# "documentationUri": "", # optional
"primary": True,
},
],
"meta": {
"resourceType": "ServiceProviderConfig",
"created": "2025-04-15T15:45:00Z",
# note(jon): we might want to think about adding this resource as part of our db
# and then updating these timestamps from an api and such. for now, if we update
# the configuration, we should update the timestamp here.
"lastModified": "2025-04-15T15:45:00Z",
"location": "", # note(jon): this field will be computed in the /ServiceProviderConfig endpoint
},
}
RESOURCE_TYPES = sorted(
[
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:ResourceType"],
"id": "User",
"name": "User",
"endpoint": "/Users",
"description": "User account",
"schema": "urn:ietf:params:scim:schemas:core:2.0:User",
"meta": {
"resourceType": "ResourceType",
"created": "2025-04-16T08:37:00Z",
# note(jon): we might want to think about adding this resource as part of our db
# and then updating these timestamps from an api and such. for now, if we update
# the configuration, we should update the timestamp here.
"lastModified": "2025-04-16T08:37:00Z",
"location": "ResourceType/User",
},
}
],
key=lambda x: x["id"],
)