This quickstart shows how to utilize the extensions feature of SCIM as defined in Core Schema Specification and the Protocol Specification
Configuration
With the default validation and store implementations, extensions are already supported. When using the in-memory store, the EnterpriseUser extension is registered when you call AddScimDefaultResourcesForInMemoryStore. To add any additional extensions you can use the ScimBuilder that is returned from AddScimDefaultResourcesForInMemoryStore.
public void ConfigureServices(IServiceCollection services)
{
services.AddScimServiceProvider("/SCIM", new ScimLicensingOptions("Demo", "eyJTb2xkRm9yIjowLjAsI .... "))
.AddScimDefaultResourcesForInMemoryStore()
.AddResourceExtension<User, MyCustomExtension>("urn:ietf:params:scim:schemas:extension:enterprise:2.0:MyCustomExtension");
}
If your extension supports dynamic attributes, you can configure the extension registration to accept PATCH paths for unknown attribute names.
This is useful when an external identity provider sends PATCH requests using the full extension schema path, but the attribute being patched is not represented by a concrete property on the extension type.
public void ConfigureServices(IServiceCollection services)
{
services.AddScimServiceProvider("/SCIM", new ScimLicensingOptions("Demo", "eyJTb2xkRm9yIjowLjAsI .... "))
.AddScimDefaultResourcesForInMemoryStore()
.AddResourceExtension<User, MyDynamicExtension>(
"urn:ietf:params:scim:schemas:extension:custom-roles:2.0:User",
options => options.EnableFallback<string>());
}
In the example above, if a PATCH request targets an unknown attribute under the registered extension schema, the SCIM component will treat the attribute as a string value when generating the PatchCommand collection for your store.
For example, the following request can be processed successfully when the extension has been registered with EnableFallback<string>():
{
"schemas": [
"urn:ietf:params:scim:api:messages:2.0:PatchOp"
],
"Operations": [
{
"op": "Replace",
"path": "urn:ietf:params:scim:schemas:extension:custom-roles:2.0:User:booking",
"value": "Self-booker"
}
]
}
Choose the fallback type to match the value type used by the dynamic attributes in your extension. For example, use EnableFallback<string>() for single-valued string attributes. A fallback type of object is not supported.
Extension Validation
The default validator will validate that any extension schemas that are present in the schemas array of a request are also present within the model. For example, given the request:
{
"schemas":["urn:ietf:params:scim:schemas:core:2.0:User", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"],
"userName":"babs"
}
The validator will catch that there is the extension schema of urn:ietf:params:scim:schemas:extension:enterprise:2.0:User in the schemas array, but no property in the body to represent the schema.
{
"status": 400,
"detail": "Extension \"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User\" is missing"
}
While a valid request will look something like this:
{
"schemas":["urn:ietf:params:scim:schemas:core:2.0:User", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"],
"userName":"babs",
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User" : {
"employeeNumber": "emp1",
"costCenter": "cc1",
"organization": "org1",
"division": "d1",
"department": "d1"
}
}
The component will also validate that any extension schemas registered for the resource are present in a SCIM request. For example, the following request will fail validation:
{
"schemas":["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName":"babs"
}
and an error response will be returned to the client:
{
"schemas": [
"urn:ietf:params:scim:api:messages:2.0:Error"
],
"status": 400,
"detail": "Missing extension schema(s) - urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
}
The component can be configured to skip the validation to check for missing extensions. To do this, set the IgnoreMissingExtensionSchemas flag to true in the ScimServiceProviderConfigOptions used when calling AddScimServiceProvider,
services.AddScimServiceProvider(
"/SCIM",
new ScimLicensingOptions("Demo", "eyJTb2xkRm9yIjowLjAsI .... "),
new ScimServiceProviderConfigOptions
{
IgnoreMissingExtensionSchemas = true
}
);
Custom Extension Validator
It is possible to use your own validator to extract and validate extensions from a request. To do so, you must have a class that implements IValidateScimExtensions. The methods in this interface are as follows:
Task<IScimResult<IEnumerable<ScimExtensionValue>>> ValidateAddingExtensions(string resourceAsString, string resourceSchema);
Task<IScimResult<IEnumerable<ScimExtensionValue>>> ValidateUpdatingExtensions(string resourceAsString, string resourceId, string resourceSchema);
Then you can register this in the ConfigureServices method in your Startup class.
public void ConfigureServices(IServiceCollection services)
{
var connectionString = configuration.GetConnectionString("ExtendedScim");
services.AddScimServiceProvider("/SCIM", new ScimLicensingOptions("Demo", "eyJTb2xkRm9yIjowLjAsI .... "))
.AddExtensionValidator<ScimExtensionValidator>();
}