This document details how the SCIM component processes patch requests, and the commands it generates to be passed into the PartialUpdate
method on IScimStore
.
Patching is by far the most challenging part of any SCIM store implementation. The most straightforward approach is to load the resource into memory, apply the CRUD commands, and then persist the resource. There are, however, some situations where this will not be possible. Consider a group called employees that contains 100K+ users and a patch command that removes user Fred. Loading the entire group membership into memory to remove a single item will be very inefficient. What is required here is mapping the patch command onto a specific underlying store operation, e.g. executing a SQL DELETE command, or if using an Object Relational Mapper (ORM) such as EF Core, only load the user Fred into the group membership, prior to removing Fred.
The SCIM component provides an In-Memory patching service that automates your store's patching process. See below for further details.
Patch Requests
For your store to be able to handle patch requests, you will need to process a collection of PatchCommands
. The PatchCommand
object will contain the type of operation that it represents, either Add
, Remove
or Replace
. For Add
and Replace
commands, there will be a Value
property that contains the value to be used in the operation and the Path
property, which represents the property that needs to be modified on the resource.
In-Memory Patching
The SCIM component provides an out-of-the-box solution to patching resources in-memory by implementing the IPatchCommandExecutor
interface. The implementation attempts to modify your target object using a given patch command, using the mappings created when calling MapScimAttributes
. To configure the IPatchCommandExecutor
, use the extension methods described in Mapping Attributes.
To use the implementation, inject the IPatchCommandExecutor
interface into your store and call Execute
, passing a patch command and an instance of the target object. A ScimStorePatchException
is thrown if a call to Execute
is unsuccessful.
foreach (PatchCommand command in commands)
{
try
{
patchCommandExecutor.Execute(user, command);
}
catch (ScimStorePatchException)
{
logger.LogError("Failed to patch user with id {id} with command {cmd}", resourceId, command);
}
}
If you're implementing a Microsoft Entra compatible store and have set the EnableAzureAdCompatibility
to true, the IPatchCommandExecutor
will behave differently for add operations containing a filter. See the Microsoft Entra integration documentation for more details.
Patch Operation Paths
The Path
in a PatchCommand
is a PathExpression
, containing a collection of AttributePathExpression
that makes up the path of the property the patch command is operating against. By default, the SCIM component will output patch commands that always have the Path
property set, even if the incoming request omits it. This is to avoid having implementers of PartialUpdate
implement two paths for modifying a resource.
Default Behaviour
{
"op": "replace",
"value": {
"name.givenName": "newGivenName"
}
}
{
"op": "replace",
"path": "name",
"value": {
"givenName": "newGivenName"
}
}
Will both produce a PatchCommand
that can represented like the following
{
"path": "urn:ietf:params:scim:schemas:core:2.0:User:name:givenName"
"value": "newGivenName"
}
Whole Object Replacements
To change this behaviour, set the EnableWholeObjectPatchCommands
flag to true in the ScimServiceProviderConfigOptions
object passed into AddScimServiceProvider
. When set to true, patch requests without a path
will generate a PatchCommand
who's Value
property is an instance of the Resource
with the relevant properties set. As an example, the following replace command:
{
"op": "replace",
"value": {
...
"name": {
...
"familyName": "family"
...
},
"userName": "userName"
...
}
}
Will output a PatchCommand
ressembling the following representation:
{
"op": "replace",
"value": {
...
"name": {
...
"familyName": "family"
...
},
"userName": "userName"
...
}
}
When you receive this PatchCommand
you will have to check which properties have been updated on the Value
object and modify the Resource
using these.