IDHub Splice / Connector - Implementation Guide
IDHub Splice Implementation
Maven Parent Project
https://git.sath.com/idhub-connectors/idhub-connector-parent-project
Below is an example pom.xml inheriting from the idhub-splice-parent-project
https://www.baeldung.com/jackson, https://www.baeldung.com/jackson-object-mapper-tutorial, https://fasterxml.github.io/jackson-databind/javadoc/2.11/com/fasterxml/jackson/databind/JsonNode.html
It is intended that you use Jackson to manipulate JSON. Above are some links to help you familiarize yourself with Jackson’s use.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- We inherit from the spring-starter-parent so that
spring is configured and available to us. -->
<parent>
<groupId>com.sath.idhub</groupId>
<artifactId>idhub-splice-parent-project</artifactId>
<version>4.0.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<artifactId>project-name</artifactId>
<version>1.0.0</version>
<name>Project Name</name>
<description>A description</description>
<!-- Look in the sath maven repo for dependencies -->
<repositories>
<repository>
<id>repo.sath.com</id>
<name>Sath Nexus Repository</name>
<url>https://repo.sath.com/repository/maven-releases/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
</project>
Building the Connector Application
Inheriting from the IDHub Splice Parent Project
and enabling the build-connector
profile in Maven will cause Maven to assemble the following items into a fat jar during the package
phase:
the splice that inherits from the
IDHub Splice Parent Project
the connector application
all transitive dependencies
This jar file will be named with the following format:
${project.artifactId}-${project.version}-with-connector-application-${idhub.connection-application.version}.jar
Example Name
your-splice-1.0.0-with-connector-application-2.0.0.jar
Assembling the Connector
This POM also includes instructions to run a Maven Assembly that will assemble the files described below into a zip archive at the relative locations listed. This also happens on the Maven package
phase.
File(s) | Output Location |
---|---|
Repackaged Jar |
|
|
|
|
|
|
|
application.yml
The following properties must be configured for the connector to work
Spring:
security:
oauth2:
resourceserver:
jwt:
jwk-set-uri: https://URL
idhub:
hostname: https://URL
realm: Realm-Name
clientId: Client-Id
accessToken: Token
refreshToken: Token
Where
jwk-set-uri
is the uri of the JWK set endpointhttps://environment.iamsath.com/auth/realms/IDHub/protocol/openid-connect/certs
hostname
is the host name of the authorization serverrealm
is the name of the realm the connector belongs toclient-id
is the client-id to be used for authenticationaccessToken
is the access tokenrefreshToken
is the refresh token
Port
Additionally, the port can be specified, the default is 8080
server:
port: 8080
IDHub Connector SPI (Service Provider Interface)
The IDHub Connector SPI is a library project providing the interfaces, data classes, and exceptions necessary to implement a Splice for the IDHub Connector Application.
https://git.sath.com/idhub-connectors/connector-spi-java
Common Connector Service API
The Common Connector service interface provides a single class that returns the ApplicationInformation data type, which describes information common to all the SCIM Resource Services provided by the Splice to the IDHub Connector Application.
/**
* The interface for providing information about a common connector service
*/
public interface CommonConnectorService {
/**
* This method returns the SCIM Application Information in SCIM+JSON format
* @return The SCIM Application Information in SCIM+JSON format.
*/
ApplicationInformation getApplicationInformation();
}
SCIM Resource Service
The SCIM Resource Service interface provides methods that will be used by the IDHub Connector Application to implement each required SCIM Endpoint.
see: ScimResourceService.java for more information. The javadocs available in this file will be downloaded by maven and made available to you through your IDE.
If a name is provided fro the resource via @Service(“resource name”) it shall match the SCIM Resource Information resourceName provided by ScimResourceService.getScimResourceServiceInformation()
API
package com.sath.idhub.connector.interfaces;
import com.sath.idhub.connector.datatypes.AsynchronousSearchRequest;
import com.sath.idhub.connector.datatypes.CallbackRegistration;
import com.sath.idhub.connector.datatypes.IdhubObject;
import com.sath.idhub.connector.datatypes.ResourceServiceInformation;
import com.sath.idhub.connector.exceptions.scim.*;
import com.sath.idhub.connector.datatypes.scim.*;
import org.springframework.boot.actuate.health.Health;
import org.springframework.lang.NonNull;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Future;
/**
* This interface provides for the necessary functions of a SCIM Resource Service.
*/
@SuppressWarnings({"RedundantThrows", "unused"})
@Service
public interface ScimResourceService
{
DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXX");
Schema getSchema()
throws InternalServerErrorException, NotImplementedException;
ResourceType getResourceType()
throws InternalServerErrorException, NotImplementedException;
ResourceServiceInformation getScimResourceServiceInformation()
throws InternalServerErrorException, NotImplementedException;
Health getHealth()
throws InternalServerErrorException, NotImplementedException;
IdhubObject postResource(@NonNull String resource)
throws BadRequestException, ConflictException, InternalServerErrorException, NotImplementedException;
IdhubObject getResource(
@NonNull String id, @NonNull Set<String> attributes,
@NonNull Set<String> excludedAttributes
)
throws NotFoundException, InternalServerErrorException, NotImplementedException;
IdhubObject putResource(@NonNull String id, @NonNull String resource)
throws BadRequestException, ConflictException, NotFoundException, InternalServerErrorException,
NotImplementedException;
IdhubObject patchResource(@NonNull String id, @NonNull PatchOp patchOperations)
throws BadRequestException, ConflictException, NotFoundException, InternalServerErrorException,
NotImplementedException;
void deleteResource(@NonNull String id)
throws ConflictException, NotFoundException, InternalServerErrorException,
NotImplementedException;
ListResponse searchResource(@NonNull SearchRequest searchRequest)
throws BadRequestException, PayloadTooLargeException, InternalServerErrorException, NotImplementedException;
@Async
Future<ListResponse> asyncSearchResource(@NonNull AsynchronousSearchRequest asynchronousSearchRequest)
throws BadRequestException, PayloadTooLargeException, InternalServerErrorException, NotImplementedException;
CallbackRegistration registerCallback(@NonNull CallbackRegistration callbackRegistration)
throws BadRequestException, ConflictException, InternalServerErrorException, NotImplementedException;
void unregisterCallback(@NonNull CallbackRegistration callbackRegistration)
throws BadRequestException, ConflictException, NotFoundException, InternalServerErrorException,
NotImplementedException;
ListResponse getRegisteredCallbacks()
throws InternalServerErrorException, NotImplementedException;
}
SCIM Object
public class ScimObject
{
/**
* The SCIM schemas attribute
*/
public final List<String> schemas;
/**
* The SCIM id of the object
*/
public final String id;
/**
* The external id of the object, most commonly the id in the target system
*/
public final String externalId;
/**
* The meta data required by SCIM
*/
public final Meta meta;
}
IDHub Object
Your datatypes are required to extend IdhubObject
public class IdhubObject extends ScimObject
{
private final int hashCode;
/**
* The unique name of the object in IDHub, should be identical to the SCIM id.
*/
public final String name;
/**
* The display name to be shown in IDHub
*/
public final String displayName;
/**
* The description to be shown in IDHub
*/
public final String description;
}
Schema getSchema()
To implement fill out and return a Schema object.
Implements GET /scim/v2/Schemas/{id} where {id} is the service name
ResourceType getResourceType()
To implement fill out and return a ResourceType object.
Partially Implements /scim/v2/ResourceTypes
The connector application will aggregate the results of calls to this function on to each service.
ResourceServiceInformation getScimResourceServiceInformation()
To implement fill out and return a ResourceServiceInformation object.
Returns a SCIM Resource Service Information in SCIM+JSON format.
See: urn:sath:params:scim:api:core:1.0:ScimResourceServiceInformation
Health getHealth()
This method implements a spring actuator /health endpoint.
To implement fill out and return a Health object.
public Object postResource(String resource)
To implement follow the instructions in the javadocs.
This method shall return an Object that represents your resource that can be serialized by Jackson into SCIM+JSON that conforms to the Schema provided by the getSchema() method or a String containing SCIM+JSON conforming to the Schema.
Implements POST /scim/v2/{Resource-Name}
public Object getResource(String id, Set<String> attributes, Set<String> excludedAttributes)
To implement follow the instructions in the javadocs.
This method shall return an Object that represents the Resource identified by id that can be serialized by Jackson into SCIM+JSON that conforms to the Schema provided by the getSchema() method or a String containing SCIM+JSON conforming to the Schema.
Implements GET /scim/v2/{Resource-Name}/{id}
public Object putResource(String id, String resource)
To implement follow the instructions in the javadocs.
This method should get the resource identified by id and return an Object representing it that can be serialized by Jackson into SCIM+JSON that conforms to the Schema provided by the getSchema() method or a String containing SCIM+JSON conforming to the Schema.
Implements PUT /scim/v2/{Resource-Name}/{id}
public Object patchResource(String id, String patchOp)
To implement see the javadocs and the link below.
You may specify in the ScimResourceInformation that this operation is not supported.
Implements PATCH /scim/v2/{Resource-Name}/{id}
public Object deleteResource(String id)
To implement follow the instructions in the javadocs.
This method should delete the resource or throw an error.
Implements DELETE /scim/v2/{Resource-Name}/{id}
public Object searchResource(String searchRequest)
To implement you must follow the instructions on the javadoc and the standard referenced below.
Implement POST /scim/v2/{Resource-Name}/.search
https://tools.ietf.org/html/rfc7644#section-3.4.2.4
Sorting (optional)
Future<ListResponse> asyncSearchResource(RearchRequest searchRequest)
To implement follow the instructions in the javadocs.
See https://www.baeldung.com/spring-async for more information.
boolean registerCallback(CallbackRegistration callbackRegistration)
To implement follow the instructions in the javadocs.
The purpose of this method is to support giving event driven updates to IDHub.
boolean unregisterCallback(CallbackRegistration callbackRegistration)
To implement follow the instruction in the javadocs.
The purpose of this method is to support terminating event driven updates to IDHub.
ListResponse getRegisteredCallbacks()
To implement follow the instructions in the javadocs.
The purpose of this method is to allow the connector to query for active callbacks.
Implementing a Splice
Implementing a splice is as easy as inheriting from the idhub-splice-parent-project and providing three (3) classes. One that implements CommonConnectorService and two that implement ScimResourceService. As per the warning below, you must implement one SCIM Resource Service that exposes an Account service and one that exposes an Entitlement service
You must be connector to the lab.sath.com VPN in order to fetch the maven resources correctly. If try to download resources from sath’s Maven repo while not on the VPN, Cloudflare will inject a login or some other security measure and that will be what is stored by maven. You will then have to find and remove the corrupt files from your local maven repo (~/.m2/com/sath/idhub/
) and download them again.
External Configuration File
It is mandatory to externalize any and all properties such that any application specific configuration can be modified without needing to recompile code. All the provided data types can serialize and de-serialize to/from a file.
It is mandatory to externalize any and all properties such that any application specific configuration can be modified without needing to recompile code.
DateTime Format
Resources that use the datetime type should use this java Simple Date Format “yyyy-MM-dd'T'HH:mm:ss.SSSXXX”. This is provided as dateTimeformat in the ScimResourceService interface.
Use of the date time format above is required.
Common
This schema is a reconstruction of the common attributes used by SCIM. All the schema you define essentially inherit from this schema. Therefore every schema you define will have these attributes.
Many of these attributes are mandatory. You must return the required attributes in your data types / SCIM+JSON.
{
"schemas" : [ "urn:ietf:params:scim:schemas:core:2.0:Schema" ],
"id" : "urn:ietf:params:scim:schemas:core:2.0:Common",
"name" : "CommonAttributes",
"description" : "Common Attributes",
"attributes" : [
{
"name" : "schemas",
"multiValued" : true,
"description" : "The URIs of the supported schemas",
"required" : true,
"caseExact" : true,
"mutability" : "readOnly",
"returned" : "always"
},
{
"name" : "id",
"type" : "string",
"multiValued" : false,
"description" : "A unique identifier for a SCIM resource as defined by the service provider.",
"required" : true,
"caseExact" : true,
"mutability" : "readOnly",
"returned" : "always",
"uniqueness" : "server"
},
{
"name" : "externalId",
"multiValued" : false,
"description" : "A String that is an identifier for the resource as defined by the provisioning client.",
"caseExact" : true
},
{
"name" : "meta",
"type" : "complex",
"multiValued" : false,
"description" : "A complex attribute containing resource metadata.",
"required" : true,
"caseExact" : true,
"mutability" : "readOnly",
"subAttributes" : [
{
"name" : "resourceType",
"multiValued" : false,
"description" : "A String that is an identifier for the resource as defined by the provisioning client.",
"required" : true,
"caseExact" : true,
"mutability" : "readOnly"
},
{
"name" : "created",
"type" : "DateTime",
"multiValued" : false,
"description" : "The \"DateTime\" that the resource was added to the service provider.",
"required" : true,
"caseExact" : true,
"mutability" : "readOnly"
},
{
"name" : "lastModified",
"type" : "DateTime",
"multiValued" : false,
"description" : "The most recent DateTime that the details of this resource were updated at the service provider.",
"required" : true,
"caseExact" : true,
"mutability" : "readOnly"
},
{
"name" : "location",
"multiValued" : false,
"description" : "The URI of the resource being returned.",
"required" : true,
"caseExact" : true,
"mutability" : "readOnly"
},
{
"name" : "version",
"multiValued" : false,
"description" : "The version of the resource being returned. This value must be the same as the entity-tag (ETag) HTTP response header.",
"caseExact" : true,
"mutability" : "readOnly"
}
]
}
]
}
IDHub ConnectorApplication Implementation
IDHub Provided Schema
https://tools.ietf.org/html/rfc7643#section-2.2
Schema default values.
Application Information
{
"schemas" : [
"urn:ietf:params:scim:schemas:core:2.0:Schema"
],
"id" : "urn:sath:params:scim:api:core:1.0:ApplicationInformation",
"name" : "ApplicationInformation",
"description" : "ApplicationInformation",
"attributes" : [
{
"name" : "applicationName",
"multiValued" : false,
"description" : "The name of the application. REQUIRED.",
"caseExact" : true,
"required" : true
},
{
"name" : "attributeMappings",
"multiValued" : false,
"type" : "complex",
"description" : "The attribute mappings to be used by IDHub to create the associated account form. OPTIONAL.",
"subAttributes" : [
{
"name" : "applicationFieldName",
"multiValued" : false,
"description" : "The name of the field in the application. REQUIRED.",
"caseExact" : true,
"required" : true
},
{
"name" : "ideFieldName",
"multiValued" : false,
"description" : "The name of the field in the IDE. OPTIONAL."
},
{
"name" : "synchronization",
"multiValued" : false,
"description" : "Specifies which system(s) if any should be updated for this attribute. OPTIONAL.",
"canonicalValues" : [
"to idhub",
"to application",
"bi-directional",
"no updates"
]
},
{
"name" : "dataType",
"multiValued" : false,
"description" : "The data type of the attribute. REQUIRED.",
"required" : true,
"canonicalValues" : [
"number",
"string",
"bi-directional",
"date"
]
},
{
"name" : "required",
"multiValued" : false,
"type" : "boolean",
"description" : "Whether or not the attribute is required. OPTIONAL."
},
{
"name" : "reconciliationKey",
"multiValued" : false,
"type" : "boolean",
"description" : "Whether or not the attribute is a reconciliation key. OPTIONAL."
},
{
"name" : "uniqueField",
"multiValued" : false,
"type" : "boolean",
"description" : "Whether or not the field is required to be unique. OPTIONAL."
},
{
"name" : "multiValue",
"multiValued" : false,
"type" : "boolean",
"description" : "Whether or not the field is multi-valued. OPTIONAL."
}
]
},
{
"name" : "businessOwner",
"multiValued" : false,
"description" : "The name of the business owner for this application. OPTIONAL.",
"caseExact" : true
},
{
"name" : "description",
"multiValued" : false,
"description" : "A description of the application. OPTIONAL.",
"caseExact" : true
},
{
"name" : "externalId",
"multiValued" : false,
"description" : "A String that is an identifier for the resource as defined by the provisioning client. The \"externalId\" may simplify identification of a resource between the provisioning client and the service provider by allowing the client to use a filter to locate the resource with an identifier from the provisioning domain, obviating the need to store a local mapping between the provisioning domain's identifier of the resource and the identifier used by the service provider. Each resource MAY include a non-empty \"externalId\" value. The value of the \"externalId\" attribute is always issued by the provisioning client and MUST NOT be specified by the service provider. The service provider MUST always interpret the externalId as scoped to the provisioning domain. While the server does not enforce uniqueness, it is assumed that the value's uniqueness is controlled by the client setting the value. See Section 9 for additional considerations regarding privacy. This attribute has \"caseExact\" as \"true\" and a mutability of \"readWrite\". This attribute is OPTIONAL.\n",
"mutability" : "readOnly",
"returned" : "always",
"caseExact" : true
},
{
"name" : "id",
"multiValued" : false,
"description" : "A unique identifier for a SCIM resource as defined by the service provider. Each representation of the resource MUST include a non-empty \"id\" value. This identifier MUST be unique across the SCIM service provider's entire set of resources. It MUST be a stable, non-reassignable identifier that does not change when the same resource is returned in subsequent requests. The value of the \"id\" attribute is always issued by the service provider and MUST NOT be specified by the client. The string \"bulkId\" is a reserved keyword and MUST NOT be used within any unique identifier value. The attribute characteristics are \"caseExact\" as \"true\", a mutability of \"readOnly\", and a \"returned\" characteristic of \"always\". See Section 9 for additional considerations regarding privacy.",
"mutability" : "readOnly",
"returned" : "always",
"caseExact" : true,
"required" : true
},
{
"name" : "itOwner",
"multiValued" : false,
"description" : "The name of the IT owner for this application. OPTIONAL.",
"caseExact" : true
},
{
"name" : "maximumNumberOfOperations",
"multiValued" : false,
"type" : "integer",
"description" : "The maximum payload size in bytes. REQUIRED.",
"required" : true
},
{
"name" : "maximumPayloadSize",
"multiValued" : false,
"type" : "integer",
"description" : "The maximum payload size in bytes. REQUIRED.",
"required" : true
},
{
"name" : "meta",
"multiValued" : false,
"description" : "A complex attribute containing resource metadata.",
"mutability" : "readOnly",
"subAttributes" : [
{
"name" : "resourceType",
"multiValued" : false,
"description" : "The name of the resource type of the resource.",
"mutability" : "readOnly",
"caseExact" : true
},
{
"name" : "created",
"multiValued" : false,
"type" : "dateTime",
"description" : "The \"DateTime\" that the resource was added to the service provider."
},
{
"name" : "lastModified",
"multiValued" : false,
"type" : "dateTime",
"description" : "The most recent DateTime that the details of this resource were updated at the service provider. If this resource has never been modified since its initial creation, the value MUST be the same as the value of \"created\"."
},
{
"name" : "location",
"multiValued" : false,
"description" : "The name of the resource type of the resource.",
"mutability" : "readOnly",
"caseExact" : true
},
{
"name" : "version",
"multiValued" : false,
"description" : "The version of the resource being returned. This value must be the same as the entity-tag (ETag) HTTP response header (see Sections 2.1 and 2.3 of [RFC7232]). This attribute has \"caseExact\" as \"true\". Service provider support for this attribute is optional and subject to the service provider's support for versioning (see Section 3.14 of [RFC7644]). If a service provider provides \"version\" (entity-tag) for a representation and the generation of that entity-tag does not satisfy all of the characteristics of a strong validator (see Section 2.1 of [RFC7232]), then the origin server MUST mark the \"version\" (entity-tag) as weak by prefixing its opaque value with \"W/\" (case sensitive).",
"mutability" : "readOnly",
"caseExact" : true
}
]
},
{
"name" : "schema",
"multiValued" : true,
"description" : "The \"schemas\" attribute is a REQUIRED attribute and is an array of Strings containing URIs that are used to indicate the namespaces of the SCIM schemas that define the attributes present in the current JSON structure. This attribute may be used by parsers to define the attributes present in the JSON structure that is the body to an HTTP request or response. Each String value must be a unique URI. All representations of SCIM schemas MUST include a non-empty array with value(s) of the URIs supported by that representation. The \"schemas\" attribute for a resource MUST only contain values defined as \"schema\" and \"schemaExtensions\" for the resource's defined \"resourceType\". Duplicate values MUST NOT be included. Value order is not specified and MUST NOT impact behavior.",
"mutability" : "readOnly",
"returned" : "always",
"caseExact" : true,
"required" : true
},
{
"name" : "sortSupported",
"multiValued" : false,
"type" : "boolean",
"description" : "Whether or not this resource service supports patch operations. REQUIRED."
}
]
}
SCIM Resource Service Information
{
"schemas" : [
"urn:ietf:params:scim:schemas:core:2.0:Schema"
],
"id" : "urn:sath:params:scim:api:core:1.0:ScimResourceServiceInformation",
"name" : "ScimResourceServiceInformation",
"description" : "SCIM Resource Service Information",
"attributes" : [
{
"name" : "description",
"multiValued" : false,
"description" : "The description of the resource exposed via this service. REQUIRED.",
"caseExact" : true,
"required" : true
},
{
"name" : "externalId",
"multiValued" : false,
"description" : "A String that is an identifier for the resource as defined by the provisioning client. The \"externalId\" may simplify identification of a resource between the provisioning client and the service provider by allowing the client to use a filter to locate the resource with an identifier from the provisioning domain, obviating the need to store a local mapping between the provisioning domain's identifier of the resource and the identifier used by the service provider. Each resource MAY include a non-empty \"externalId\" value. The value of the \"externalId\" attribute is always issued by the provisioning client and MUST NOT be specified by the service provider. The service provider MUST always interpret the externalId as scoped to the provisioning domain. While the server does not enforce uniqueness, it is assumed that the value's uniqueness is controlled by the client setting the value. See Section 9 for additional considerations regarding privacy. This attribute has \"caseExact\" as \"true\" and a mutability of \"readWrite\". This attribute is OPTIONAL.\n",
"mutability" : "readOnly",
"returned" : "always",
"caseExact" : true
},
{
"name" : "id",
"multiValued" : false,
"description" : "A unique identifier for a SCIM resource as defined by the service provider. Each representation of the resource MUST include a non-empty \"id\" value. This identifier MUST be unique across the SCIM service provider's entire set of resources. It MUST be a stable, non-reassignable identifier that does not change when the same resource is returned in subsequent requests. The value of the \"id\" attribute is always issued by the service provider and MUST NOT be specified by the client. The string \"bulkId\" is a reserved keyword and MUST NOT be used within any unique identifier value. The attribute characteristics are \"caseExact\" as \"true\", a mutability of \"readOnly\", and a \"returned\" characteristic of \"always\". See Section 9 for additional considerations regarding privacy.",
"mutability" : "readOnly",
"returned" : "always",
"caseExact" : true,
"required" : true
},
{
"name" : "meta",
"multiValued" : false,
"description" : "A complex attribute containing resource metadata.",
"mutability" : "readOnly",
"subAttributes" : [
{
"name" : "resourceType",
"multiValued" : false,
"description" : "The name of the resource type of the resource.",
"mutability" : "readOnly",
"caseExact" : true
},
{
"name" : "created",
"multiValued" : false,
"type" : "dateTime",
"description" : "The \"DateTime\" that the resource was added to the service provider."
},
{
"name" : "lastModified",
"multiValued" : false,
"type" : "dateTime",
"description" : "The most recent DateTime that the details of this resource were updated at the service provider. If this resource has never been modified since its initial creation, the value MUST be the same as the value of \"created\"."
},
{
"name" : "location",
"multiValued" : false,
"description" : "The name of the resource type of the resource.",
"mutability" : "readOnly",
"caseExact" : true
},
{
"name" : "version",
"multiValued" : false,
"description" : "The version of the resource being returned. This value must be the same as the entity-tag (ETag) HTTP response header (see Sections 2.1 and 2.3 of [RFC7232]). This attribute has \"caseExact\" as \"true\". Service provider support for this attribute is optional and subject to the service provider's support for versioning (see Section 3.14 of [RFC7644]). If a service provider provides \"version\" (entity-tag) for a representation and the generation of that entity-tag does not satisfy all of the characteristics of a strong validator (see Section 2.1 of [RFC7232]), then the origin server MUST mark the \"version\" (entity-tag) as weak by prefixing its opaque value with \"W/\" (case sensitive).",
"mutability" : "readOnly",
"caseExact" : true
}
]
},
{
"name" : "patchSupported",
"multiValued" : false,
"type" : "boolean",
"description" : "The name of the service account used to connect to the application. REQUIRED.",
"required" : true
},
{
"name" : "resourceName",
"multiValued" : false,
"description" : "The name of the resource exposed via this service. REQUIRED.",
"caseExact" : true,
"required" : true
},
{
"name" : "schema",
"multiValued" : true,
"description" : "The \"schemas\" attribute is a REQUIRED attribute and is an array of Strings containing URIs that are used to indicate the namespaces of the SCIM schemas that define the attributes present in the current JSON structure. This attribute may be used by parsers to define the attributes present in the JSON structure that is the body to an HTTP request or response. Each String value must be a unique URI. All representations of SCIM schemas MUST include a non-empty array with value(s) of the URIs supported by that representation. The \"schemas\" attribute for a resource MUST only contain values defined as \"schema\" and \"schemaExtensions\" for the resource's defined \"resourceType\". Duplicate values MUST NOT be included. Value order is not specified and MUST NOT impact behavior.",
"mutability" : "readOnly",
"returned" : "always",
"caseExact" : true,
"required" : true
},
{
"name" : "serviceAccount",
"multiValued" : false,
"description" : "The name of the service account used to connect to the application. REQUIRED.",
"caseExact" : true
},
{
"name" : "sortSupported",
"multiValued" : false,
"type" : "boolean",
"description" : "The name of the service account used to connect to the application. REQUIRED.",
"required" : true
},
{
"name" : "version",
"multiValued" : false,
"description" : "The version of the service. REQUIRED.",
"caseExact" : true,
"required" : true
}
]
}
UTF-8
Everything should be encoded in UTF-8
SCIM Required Rest Endpoints
All the endpoints must return SCIM Error Messages in SCIM+JSON format.
All the SCIM endpoints needs to add meta information as appropriate. This should be done by the connector.
GET Endpoints
/scim/v2/ServiceProviderConfig
This endpoint returns a SCIM Service Provider Config
https://tools.ietf.org/html/rfc7644#section-3.7.4
maxOperations and maxPayloadSize are mandatory!
As bulk operations are not currently supported by the interface max operations should be 1.
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig"],
"documentationUri": "no documentation",
"patch": {
"supported":false
},
"bulk": {
"supported":false,
"maxOperations":0,
"maxPayloadSize":0
},
"filter": {
"supported":false,
"maxResults": 0
},
"changePassword": {
"supported":false
},
"sort": {
"supported":false
},
"etag": {
"supported":false
},
"authenticationSchemes": [
{
"name": "OAuth Bearer Token",
"description": "Authentication scheme using the OAuth Bearer Token Standard",
"specUri": "http://www.rfc-editor.org/info/rfc6750",
"documentationUri": "no documentation",
"type": "oauthbearertoken",
"primary": true
},
{
"name": "HTTP Basic",
"description": "Authentication scheme using the HTTP Basic Standard",
"specUri": "http://www.rfc-editor.org/info/rfc2617",
"documentationUri": "no documentation",
"type": "httpbasic"
}
],
"meta": {
"location": "scim/v2/ServiceProviderConfig",
"resourceType": "ServiceProviderConfig",
"created": "2019-09-03T00:00:00Z",
"lastModified": "2019-09-03T00:00:00Z",
"version": "W\/\"3694e05e9dff594\""
}
}
{
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:Schema"
],
"id": "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig",
"name": "ServiceProviderConfig",
"description": "Service Provider Config Schema",
"attributes": [
{
"name": "documentationUri",
"multivalued": false,
"description": "An HTTP-addressable URL pointing to the service provider's human-consumable help documentation. OPTIONAL."
},
{
"name": "patch",
"multivalued": false,
"type": "complex",
"description": "A complex type that specifies PATCH configuration options. REQUIRED. See Section 3.5.2 of [RFC7644].",
"subAttributes": [
{
"name": "supported",
"type": "boolean",
"description": "A Boolean value specifying whether or not the operation is supported. REQUIRED.",
"required": true
}
]
},
{
"name": "bulk",
"multivalued": false,
"type": "complex",
"description": "A complex type that specifies bulk configuration options. See Section 3.7 of [RFC7644]. REQUIRED.",
"subAttributes": [
{
"name": "supported",
"multiValued": false,
"type": "boolean",
"description": "A Boolean value specifying whether or not the operation is supported. REQUIRED.",
"required": true
},
{
"name": "maxOperations",
"multiValued": false,
"type": "integer",
"description": "An integer value specifying the maximum number of operations. REQUIRED.",
"required": true
},
{
"name": "maxPayloadSize",
"multiValued": false,
"type": "integer",
"description": "An integer value specifying the maximum payload size in bytes.",
"required": true
}
]
},
{
"name": "filter",
"multivalued": false,
"type": "complex",
"description": "A complex type that specifies FILTER options. REQUIRED. See Section 3.4.2.2 of [RFC7644].",
"subAttributes": [
{
"name": "supported",
"multivalued": false,
"type": "boolean",
"description": "A Boolean value specifying whether or not the operation is supported. REQUIRED.",
"required": true
},
{
"name": "maxResults",
"multivalued": false,
"type": "integer",
"description": "An integer value specifying the maximum number of resources returned in a response. REQUIRED.",
"required": true
}
]
},
{
"name": "changePassword",
"multivalued": false,
"type": "complex",
"description": "A complex type that specifies configuration options related to changing a password. REQUIRED.",
"subAttributes": [
{
"name": "supported",
"multivalued": false,
"type": "boolean",
"description": "A Boolean value specifying whether or not the operation is supported. REQUIRED.",
"required": true
}
]
},
{
"name": "sort",
"multivalued": false,
"type": "complex",
"description": "A complex type that specifies Sort configuration options. REQUIRED.",
"subAttributes": [
{
"name": "supported",
"multivalued": false,
"type": "boolean",
"description": "A Boolean value specifying whether or not the operation is supported. REQUIRED.",
"required": true
}
]
},
{
"name": "etag",
"multivalued": false,
"type": "complex",
"description": "A complex type that specifies ETag configuration options. REQUIRED.",
"subAttributes": [
{
"name": "supported",
"multivalued": false,
"type": "boolean",
"description": "A Boolean value specifying whether or not the operation is supported. REQUIRED.",
"required": true
}
]
},
{
"name": "authenticationSchemes",
"multivalued": false,
"type": "complex",
"description": "A multi-valued complex type that specifies supported authentication scheme properties. To enable seamless discovery of configurations, the service provider SHOULD, with the appropriate security considerations, make the authenticationSchemes attribute publicly accessible without prior authentication. REQUIRED.",
"subAttributes": [
{
"name": "type",
"multivalued": false,
"description": "The authentication scheme. This specification defines the values \"oauth\", \"oauth2\", \"oauthbearertoken\", \"httpbasic\", and \"httpdigest\". REQUIRED.\n",
"required": true
},
{
"name": "name",
"multivalued": false,
"description": "The common authentication scheme name, e.g., HTTP Basic. REQUIRED.",
"required": true
},
{
"name": "description",
"multivalued": false,
"description": "A description of the authentication scheme. REQUIRED.",
"required": true
},
{
"name": "specUri",
"multivalued": false,
"description": "An HTTP-addressable URL pointing to the authentication scheme's specification. OPTIONAL."
},
{
"name": "documentationUri",
"multivalued": false,
"description": "An HTTP-addressable URL pointing to the authentication scheme's usage documentation. OPTIONAL."
}
]
}
]
}
/scim/v2/ResourceTypes
Returns a SCIM+JSON ListResponse of the SCIM Resource Types supported.
This should be implemented in the connector.
For each SCIM Service it should
take the name provided by the SCIM Resource Service Information and map it
id
name
Take the same name with the letter s appended as the endpoint.
Take the schema and schema extention from the schema provided by the getSchema() for that SCIM Resource Service.
The meta should use scim/v2/{Resource} for location with a resourceType of ResourceType
{
"schemas": [
"urn:ietf:params:scim:api:messages:2.0:ListResponse"
],
"totalResults": 2,
"itemsPerPage": 10,
"startIndex": 1,
"Resources": [
{
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:ResourceType"
],
"id": "User",
"name": "User",
"endpoint": "/Users",
"description": "User Account",
"schema": "urn:ietf:params:scim:schemas:core:2.0:User",
"schemaExtensions": [
{
"schema": "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
"required": true
}
],
"meta": {
"location": "https://example.com/v2/ResourceTypes/User",
"resourceType": "ResourceType"
}
},
{
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:ResourceType"
],
"id": "Group",
"name": "Group",
"endpoint": "/Groups",
"description": "Group",
"schema": "urn:ietf:params:scim:schemas:core:2.0:Group",
"meta": {
"location": "https://example.com/v2/ResourceTypes/Group",
"resourceType": "ResourceType"
}
}
]
}
{
"id" : "urn:ietf:params:scim:schemas:core:2.0:ResourceType",
"name" : "ResourceType",
"description" : "Resource Type Schema",
"attributes" : [
{
"name" : "id",
"multiValued" : false,
"description" : "The resource type's server unique id. This is often the same value as the \"name\" attribute. OPTIONAL.",
"mutability" : "readOnly",
"returned" : "always"
},
{
"name" : "name",
"multiValued" : false,
"description" : "The resource type name. When applicable, service providers MUST specify the name, e.g., \"User\" or \"Group\". This name is referenced by the \"meta.resourceType\" attribute in all resources. REQUIRED.",
"required" : true,
"mutability" : "readOnly"
},
{
"name" : "description",
"multiValued" : false,
"description" : "The resource type's human-readable description. When applicable, service providers MUST specify the description. OPTIONAL.",
"mutability" : "readOnly"
},
{
"name" : "endpoint",
"multiValued" : false,
"description" : "The resource type's HTTP-addressable endpoint relative to the Base URL of the service provider, e.g., \"Users\". REQUIRED.",
"required" : true,
"mutability" : "readOnly"
},
{
"name" : "schema",
"multiValued" : false,
"description" : "The resource type's primary/base schema URI, e.g.,\n \"urn:ietf:params:scim:schemas:core:2.0:User\". This MUST be equal\n to the \"id\" attribute of the associated \"Schema\" resource.\n REQUIRED.",
"required" : true,
"mutability" : "readOnly"
},
{
"name" : "schemaExtensions",
"multiValued" : false,
"description" : "A list of URIs of the resource type's schema extensions. OPTIONAL.\n\n schema The URI of an extended schema, e.g., \"urn:edu:2.0:Staff\". This MUST be equal to the \"id\" attribute of a \"Schema\" resource. REQUIRED.\n\n required A Boolean value that specifies whether or not the schema extension is required for the resource type. If true, a resource of this type MUST include this schema extension and also include any attributes declared as required in this schema extension. If false, a resource of this type MAY omit this schema extension. REQUIRED.",
"mutability" : "readOnly"
}
]
}
/scim/v2/Schemas
This endpoint returns a JSON list of all the SCIM Schema supported by the server.
This should be implemented at the connector level using the schemas returned by ScimResourceService.getSchema() for each ScimResourceService.
/scim/v2/Schemas/{id}
Implementer returns the full schema with the ID matching {id}
This should be implemented at the connector level using the schemas returned by ScimResourceService.getSchema() for each ScimResourceService.
They should probably be cached in a map or something for easy retrieval.
/scim/v2/{Resource Name}
This endpoint returns a SCIM List Response of all the resources of type {Resource Name}
The connector should convert calls to this with parameters into a search request
/scim/v2/{Resource Name}/{id}
Get the specific resource by {id}
The connector needs to support the attribute and excludedAttribute parameters here. Attribute names should come in standard attribute notation
{urn}:{Attribute name}.{Sub-Attribute name}
see https://tools.ietf.org/html/rfc7644#section-3.10
For both attribute and excludedAttribute each, the connector should verify the urn matches the schema attribute is supported by the resource, and if so remove the urn from each attribute name and provide them as a set.
/scim/v2/{Resource Name}/Me
Required to be implemented may return a 501 (not implemented) response
Not implemented in the connector.
POST Endpoints
/scim/v2/{Resource Name}
This endpoint is creates a new resource in the connected application according to the rules outlines in the link above.
/scim/v2/{Resource Name}/.search
This endpoint is required to be queried with a SCIM Search Request and required to respond with a SCIM List Response
https://tools.ietf.org/html/rfc7644#section-3.4.2.2
Filtering (Optional)
https://tools.ietf.org/html/rfc7644#section-3.4.2.4
Pagination is required to be supported by the SCIM Specification
This is aliased by /scim/v2/{Resource Name}?
Parameters: attributes, exludedAttributes, filter, sortBy, sortOrder, startIndex, count
needs to be implemented in the connector to take the parameters and construct a search request and send it into the search method on the SCIM Resource Service
{
"id" : "urn:ietf:params:scim:api:messages:2.0:ListResponse",
"name" : "List Response",
"description" : "Search Request",
"attributes" : [
{
"name" : "totalResults",
"multiValued" : false,
"type" : "integer",
"description" : "The total number of results returned by the list or query operation. The value may be larger than the number of resources returned, such as when returning a single page (see Section 3.4.2.4) of results where multiple pages are available. REQUIRED.",
"required" : true,
"caseExact" : true
},
{
"name" : "resources",
"multiValued" : true,
"type" : "complex",
"description" : "A multi-valued list of complex objects containing the requested resources. This MAY be a subset of the full set of resources if pagination (Section 3.4.2.4) is requested. REQUIRED if "totalResults" is non-zero.",
"caseExact" : true
},
{
"name" : "startIndex",
"multiValued" : false,
"type" : "integer",
"description" : "The 1-based index of the first result in the current set of list results. REQUIRED when partial results are returned due to pagination.",
"caseExact" : true
},
{
"name" : "itemsPerPage",
"multiValued" : false,
"type" : "integer",
"description" : "An integer indicating the 1-based index of the first query result. See Section 3.4.2.4. OPTIONAL.",
"caseExact" : true
}
]
}
{
"schemas" : [
"urn:ietf:params:scim:schemas:core:2.0:Schema"
],
"id" : "urn:ietf:params:scim:api:messages:2.0:SearchRequest",
"name" : "Search Request",
"description" : "Search Request",
"attributes" : [
{
"name" : "attributes",
"multiValued" : true,
"description" : "A multi-valued list of strings indicating the names of resource attributes to return in the response, overriding the set of attributes that would be returned by default. Attribute names MUST be in standard attribute notation (Section 3.10) form. See Section 3.9 for additional retrieval query parameters. OPTIONAL."
},
{
"name" : "excludedAttributes",
"multiValued" : true,
"description" : "A multi-valued list of strings indicating the names of resource attributes to be removed from the default set of attributes to return. This parameter SHALL have no effect on attributes whose schema \"returned\" setting is \"always\" (see Sections 2.2 and 7 of [RFC7643]). Attribute names MUST be in standard attribute notation (Section 3.10) form. See Section 3.9 for additional retrieval query parameters. OPTIONAL."
},
{
"name" : "filter",
"multiValued" : false,
"description" : "The filter string used to request a subset of resources. The filter string MUST be a valid filter (Section 3.4.2.2) expression. OPTIONAL.",
"caseExact" : true
},
{
"name" : "sortBy",
"multiValued" : false,
"description" : "A string indicating the attribute whose value SHALL be used to order the returned responses. The \"sortBy\" attribute MUST be in standard attribute notation (Section 3.10) form. See Section 3.4.2.3. OPTIONAL.",
"caseExact" : true
},
{
"name" : "sortOrder",
"multiValued" : false,
"description" : "A string indicating the order in which the \"sortBy\" parameter is applied. Allowed values are \"ascending\" and \"descending\". See Section 3.4.2.3. OPTIONAL.",
"caseExact" : true
},
{
"name" : "startIndex",
"multiValued" : false,
"type" : "integer",
"description" : "An integer indicating the 1-based index of the first query result. See Section 3.4.2.4. OPTIONAL.",
"caseExact" : true
},
{
"name" : "count",
"type" : "integer",
"multiValued" : false,
"description" : "An integer indicating the desired maximum number of query results per page. See Section 3.4.2.4. OPTIONAL.",
"caseExact" : true
}
]
}
/scim/v2/Bulk
Bulk endpoint can be opted out of in service provider config
Not in the user interface provided.
The connector’s GET /scim/v2/ServiceProviderConfig endpoint should specify that bulk is not supported
/scim/v2/{Resource Name}/Me
This endpoint is required to be implemented but may return a 501 (not implemented) response.
Not implemented in the connector.
DELETE Endpoints
These endpoints are used to delete resources
/scim/v2/{Resource Name}/{id}
This endpoint deletes the resource specified by {id} from the target system
/scim/v2/{Resource Name}/Me
Required to be implemented may return a 501 (not implemented) response
Not implemented in the connector.
PUT Endpoints
Used to modify resources
/scim/v2/{Resource Name}/{id}
This endpoint modifies a specific resource by id.
/scim/v2/{Resource Name}/Me
Required to be implemented may return a 501 (not implemented) response
Not implemented in the connector.
PATCH Endpoints
Can opt out of patch endpoints in the service provider config
/scim/v2/{Resource Name}/{id}
This endpoint is used to modify a resource using the patch syntax.
/scim/v2/{Resource Name}/Me
Required to be implemented may return a 501 (not implemented) response
Not implemented in the connector.
SCIM Error Messages
{
"id": "urn:ietf:params:scim:api:messages:2.0:Error",
"name": "Error",
"description": "Error",
"attributes": [
{
"name": "status",
"type": "string",
"multiValued": false,
"description": "The HTTP status code (see Section 6 of [RFC7231]) expressed as a JSON string. REQUIRED.",
"required": true
},
{
"name": "scimType",
"type": "string",
"multiValued": false,
"description": "A SCIM detail error keyword. See Table 9. OPTIONAL.",
"required": false
},
{
"name": "detail",
"type": "string",
"multiValued": false,
"description": "A detailed human-readable message. OPTIONAL.",
"required": false
}
]
}
307 (temporary redirect)
Applies to:
GET, POST, PUT, PATCH, DELETE
Recommended Response:
the same HTTP request at the location identified. The client SHOULD NOT use the location provided in the response as a permanent reference to the resource and SHOULD continue to use the original request URI [RFC7231].
308 (permanent redirect)
Applies to:
GET, POST, PUT, PATCH, DELETE
Recommended Response:
The client is directed to repeat the same HTTP request at the location identified. The client SHOULD use the location provided in the response as the permanent reference to the resource [RFC7538].
400 (bad request)
Applies to:
GET, POST, PUT, PATCH, DELETE
Recommend Response:
Request is unparsable, syntactically incorrect, or violates schema.
401 (Unauthorized)
Applies to:
GET, POST, PUT, PATCH, DELETE
Recommended Response:
Authorization failure. The authorization header is invalid or missing.
403 (Forbidden)
Applies to:
GET, POST, PUT, PATCH, DELETE
Recommended Response:
Operation is not permitted based on the supplied authorization.
404 (Not Found)
Applies to:
GET, POST, PUT, PATCH, DELETE
Recommended Response:
Specified resource (e.g., User) or endpoint does not exist.
409 (Conflict)
Applies to:
POST, PUT, PATCH, DELETE
Recommended Response:
The specified version number does not match the resource's latest version number, or a service provider refused to create a new, duplicate resource.
412 (Precondition Failed)
Applies to:
GET, POST, PUT, PATCH, DELETE
Recommended Response:
Failed to update. Resource has changed on the server.
413 (Payload Too Large)
Applies to:
POST
Recommended Response:
{"maxOperations": 1000,"maxPayloadSize": 1048576}
500 (Internal Server Error)
Applies to:
GET, POST, PUT, PATCH, DELETE
Recommended Response:
An internal error. Implementers SHOULD provide descriptive debugging advice.
501 (Not Implemented)
Applies to:
GET, POST, PUT, PATCH, DELETE
Recommended Response:
Service provider does not support the request operation, e.g., PATCH.