Skip to content

The library doesn't comply with RFC 7643 attribute naming definitions #166

Description

@NaqGuug

RFC 7643 §2.1 states the following ABNF rules for attribute names:

ATTRNAME = ALPHA *(nameChar)
nameChar = "$" / "-" / "_" / DIGIT / ALPHA

However, currently it is impossible to have attributes with special characters "-", "_" and "$". The reason is too aggressive normalisation removing all special characters from attributes.

def _normalize_attribute_name(attribute_name: str) -> str:
"""Remove all non-alphabetical characters and lowerise a string.
This method is used for attribute name validation.
"""
is_extension_attribute = ":" in attribute_name
if not is_extension_attribute:
attribute_name = _NON_WORD_UNDERSCORE.sub("", attribute_name)
return attribute_name.lower()

For example in the following situation the attributes gets merged together while by RFC 7643 the attributes would be considered different.

from scim2_models import Resource, AnyExtension, URN
from pydantic import Field


class CustomModel(Resource[AnyExtension]):
    __schema__ = URN("urn:ietf:param:scim:something")

    # userName
    user_name: str | None = None

    # For users this field will show as "user_name"
    # which is fine by RFC 7643 rules
    string_field: str | None = Field(None, serialization_alias="user_name")


model = CustomModel.model_validate({"userName": "string1", "user_name": "string2"})
print(model.model_dump())
# "userName" got the value from "user_name", even if they are two separate fields
# {'schemas': ['urn:ietf:param:scim:something'], 'userName': 'string2'}

There is a even simpler example where using alias breaks things. User clearly wanted to set value for "string_field" which has been defined, but the library doesn't allow that. Yes, in this situation serialization_alias works, but as above example shows, it can get merged with another field like "stringfield", "string-field" or even "s$t$r$i$n$g$f$i$e$l$d$"

class CustomModel(Resource[AnyExtension]):
    __schema__ = URN("urn:ietf:param:scim:something")

    # It's impossible to access this value because
    # during validation the incoming field "string_field"
    # gets converted to "stringfield" and raises an error.
    string_field: str | None = Field(None, alias="string_field")


model = CustomModel.model_validate({"string_field": "string"})

# Validation error
# pydantic_core._pydantic_core.ValidationError: 1 validation error for CustomModel
# stringfield
#   Extra inputs are not permitted [type=extra_forbidden, input_value='string', input_type=str]
#     For further information visit https://errors.pydantic.dev/2.13/v/extra_forbidden

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions