python-scim / scim2-models

SCIM resources serialization and validation with Pydantic
https://scim2-models.readthedocs.io
Apache License 2.0
11 stars 2 forks source link

set_extension_schemas fails for models with multiple extensions #51

Closed ets closed 4 months ago

ets commented 4 months ago

This will demonstrate the issue which produces pydantic_core._pydantic_core.PydanticSerializationError: Error calling functionset_extension_schemas: AttributeError: model_fields

payload = User[Union[EnterpriseUser, PatchOp]](
        user_name="leroyjenkins@example.com",
        external_id=str(uuid.uuid4()),
        email="leroyjenkins@example.com",
        display_name="Leroy Johnson",
    )
payload.model_dump(scim_ctx=Context.RESOURCE_REPLACEMENT_RESPONSE)

It looks like set_extension_schemas can not handle the Union.

azmeuk commented 4 months ago

Thank you for your report.

The Model[Union[ExtensionA, ExtensionB]] syntax is intended to be used for extensions, but if EnterpriseUser is a valid extension for Users, PatchOp is not.

PatchOp is a Message defined in RFC7644 §3.5.2 and while the models are defined, its usage is not really implemented in scim2-models yet.

I will open tickets and update the documentation to indicate that the implementation of PatchOp is to be done, as the implementation of Bulk operations.

ets commented 4 months ago

Oh interesting...PatchOP seems to be working for Group with no issues, but there I'm only using it alone...there's no Union.

I'm trying to use these models for an endpoint that is called directly by Microsoft's Entra's SCIM v2 support. If I don't have the PatchOP extension applied to the model, then the Entra sync requests fail validation with "No extension model found for schema '..... PatchOP'

Entra requests also require the EnterpriseUser extension for User models .... so if they are supported combined I believe I'm stuck. Unless I misunderstand something?

I might try to monkey-patch set_extension_schemas to see if I can work around this.

azmeuk commented 4 months ago

This is strange, because RFC7644 §3.5.2 illustrates PatchOperations payloads with something like:

   { "schemas":
       ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
     "Operations":[
       {
        "op":"add",
        "path":"members",
        "value":[
         {
           "display": "Babs Jensen",
           "$ref":
   "https://example.com/v2/Users/2819c223...413861904646",
           "value": "2819c223-7f76-453a-919d-413861904646"
         }
        ]
       },
       ... + additional operations if needed ...
     ]
   }

Plus, I see in your OP that you attempt to produce a RESOURCE_REPLACEMENT_RESPONSE, but the RFC indicates that Patch responses payload should contain the patched object or nothing.

On successful completion, the server either MUST return a 200 OK
   response code and the entire resource within the response body,
   subject to the "attributes" query parameter (see [Section 3.9](https://datatracker.ietf.org/doc/html/rfc7644#section-3.9)), or MAY
   return HTTP status code 204 (No Content) and the appropriate response
   headers for a successful PATCH request.  The server MUST return a 200
   OK if the "attributes" parameter is specified in the request.

The Entra documentation on Patch seems to confirm this.

ets commented 4 months ago

Wow...really appreciate that research and insight. I'm using FastAPI so the validation and parsing happens behind the scenes, then my endpoint is handed a SCIMUser[Union[EnterpriseUser, PatchOp]] object. I was using it and then simply trying to return it on success with: my_user_object.model_dump(scim_ctx=Context.RESOURCE_REPLACEMENT_RESPONSE)

That triggers the issue. Based upon your feedback, I'm now just returning a 204 and avoiding the model_dump altogether. Thanks for getting me sorted!