Skip to content

04. Adding & Modifying Resource Types

Alejandro Mora edited this page May 18, 2018 · 6 revisions

SCIM Type Definitions

All core SCIM resource types are added by default. Each resource has an associated ScimTypeDefinition which defines the qualities associated with each attribute. *Even if you introduce a custom resource type or resource type extension, Owin.Scim will automatically create a type definition for all attributes on your type. There are many valid use cases to modify the core Owin.Scim resource type definitions: e.g.

  • service provider may require certain fields
  • service provider has specific canonicalization rules
  • service provider has specific canonical values
  • service provider has specific validation logic
  • etc ...

The majority of SCIM's resource type attributes and sub-attributes have qualities which default to:

  • caseExact: false
  • mutability: readWrite (readOnly, writeOnly, immutable)
  • required: false
  • returned: default (always, never)
  • uniqueness: none (server, global)

By default, Owin.Scim assigns all attribute qualities as per https://tools.ietf.org/html/rfc7643#section-7. Depending on your requirements as a SCIM service provider, you may need to modify these qualities as you see fit. It is up to you to ensure any modifications remain in compliance of the SCIM standard.

Owin.Scim uses these rules for processing and enforcing mutability rules during deserialization for POST/PUT/PATCH request operations. It is also used to enforce SCIM Returned values upon outbound serialization. More on this in a later chapter.

Resource Type Definitions vs Type Definitions

In order to process rules concerning mutability and attribute serialization, Owin.Scim requires all types to define their metadata schema. If you do not create your own type definition, Owin.Scim will create it for you - interpreting each attribute with the default SCIM attribute behaviors: (Mutability.ReadWrite, Returned.Default, etc.)

A type definition must implement Owin.Scim.Model.IScimTypeDefinition and furthermore, inherit from either ScimResourceTypeDefinitionBuilder<T> or ScimTypeDefinitionBuilder<T>. Inherit from the former when you are defining resource types and the latter when defining any other object.

public class User : Resource
{
  // ...
}

public class UserDefinition : ScimResourceTypeDefinitionBuilder<User>
{
    public UserDefinition()
        : base(
            ScimConstants.ResourceTypes.User,
            ScimConstants.Schemas.User,
            ScimConstants.Endpoints.Users,
            typeof(UserValidator),
            schemaIdentifiers => schemaIdentifiers.Contains(ScimConstants.Schemas.User))
    {
        AddSchemaExtension<EnterpriseUserExtension, EnterpriseUserExtensionValidator>(ScimConstants.Schemas.UserEnterprise, false); // add optional or required schema extensions
        
        For(u => u.Schemas)
            .SetReturned(Returned.Always);

        For(u => u.Id)
            .SetMutability(Mutability.ReadOnly)
            .SetReturned(Returned.Always)
            .SetUniqueness(Uniqueness.Server)
            .SetCaseExact(true);

        For(u => u.UserName)
            .SetRequired(true)
            .SetUniqueness(Uniqueness.Server);

        // ...
    }
}

Schema Binding Rules

For all POST, PUT, and PATCH operations Owin.Scim must interpret the request content and decide which concrete type to instantiate and deserialize to. In the above resource type definition constructor, if the predicate schemaIdentifiers => schemaIdentifiers.Contains(ScimConstants.Schemas.User) is satisfied by the schemas collection obtained from the request's json schemas collection, Owin.Scim will instantiate (deserialize) an instance of the associated type argument User.

Canonical Values

Owin.Scim defines all canonical values as per SCIM specification. The SCIM specification frequently references "canonical values" for multi-valued attribute's type attribute. Values like: work, home, other, etc. Owin.Scim does not currently provide any automated validation around these type definition canonical values. In this light, canonicalization should be viewed strictly in terms of normalization of data. There is a GitHub issue that exists for automating validation rules based upon type definitions which may be built in the future.

Modifying Resource Types

You have complete control over schema definitions for built-in core SCIM resource types and their attributes. (e.g. User, Group). To customize these schema definitions you may do one of the following:

  1. Create a class which inherits from a built-in schema definition (e.g. UserDefinition)
    Use this when you want to keep the majority of Owin.Scim's default attribute definitions for the resource.
  2. Create a class which inherits from ScimResourceTypeDefinitionBuilder<T> (where T is the Resource)
    Use this when you want to define all attribute definitions yourself. (Owin.Scim will still initialize all attribute definitions to the default SCIM qualities, but will not use any customizations found in built-in definitions.)
  3. Specify a ModifyResourceType<T>(Action<ScimResourceTypeDefinitionBuilder<T>> builder) configuration action
    Use this when you only need to minimally customize the resource. (e.g. changing the validator) You cannot modify complex attribute's schema definitions from this function.

1. Inheriting Owin.Scim Built-In Definitions

public class CustomUserDefinition : UserDefinition
{
    public CustomUserDefinition(ScimServerConfiguration serverConfiguration) : base(serverConfiguration)
    {
        For(u => u.Name)
            .SetRequired(true);
    }
}

2. Inheriting from ScimResourceTypeDefinitionBuilder

3. Specifying a ModifyResourceType Action

app.UseScimServer(
    configuration => {
        configuration.ModifyResourceType<User>(ModifyUserResourceType));
    });

// ...

private void ModifyUserResourceType(ScimResourceTypeDefinitionBuilder<User> builder)
{
  builder
    .SetValidator<UserValidator>(); // allows you to change the validator for the resource
}

Adding Custom Resources & Endpoints

To add new resource types, all you have to do is:

  1. Create a new class which inherits from Resource
  2. Create a custom validator for this resource which inherits from ResourceValidatorBase<TResource>
  3. Create a new ApiController for this resource endpoint which inherits from ScimControllerBase
  4. Create an associated resource type definition which inherits from ScimResourceTypeDefinitionBuilder<TResource>

An example of this process can be seen at: CustomResourceTypes

Clone this wiki locally