From f052d47b642fc6da4d0ea35af3479f9780043c8f Mon Sep 17 00:00:00 2001 From: Hugo Renard Date: Thu, 20 Jan 2022 18:33:55 +0100 Subject: [PATCH] serve all core schemas --- handlers_test.go | 9 ++- schema/schemas.go | 157 ++++++++++++++++++++++++++++++++++++++++++++++ server.go | 12 +++- 3 files changed, 174 insertions(+), 4 deletions(-) diff --git a/handlers_test.go b/handlers_test.go index 4daca06..f0a0ebc 100644 --- a/handlers_test.go +++ b/handlers_test.go @@ -762,11 +762,11 @@ func TestServerSchemasEndpoint(t *testing.T) { var response listResponse assertUnmarshalNoError(t, json.Unmarshal(rr.Body.Bytes(), &response)) - expectedLen := 3 + expectedLen := 6 assertEqual(t, expectedLen, response.TotalResults) assertLen(t, response.Resources, expectedLen) - resourceIDs := make([]string, 3) + resourceIDs := make([]string, 6) for i, resource := range response.Resources { resourceType, ok := resource.(map[string]interface{}) assertTypeOk(t, ok, "object") @@ -774,6 +774,9 @@ func TestServerSchemasEndpoint(t *testing.T) { } assertEqualStrings(t, []string{ + "urn:ietf:params:scim:schemas:core:2.0:Schema", + "urn:ietf:params:scim:schemas:core:2.0:ResourceType", + "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig", "urn:ietf:params:scim:schemas:core:2.0:User", "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User", "urn:ietf:params:scim:schemas:core:2.0:Group", @@ -798,7 +801,7 @@ func TestServerSchemasEndpointFilter(t *testing.T) { var response listResponse assertUnmarshalNoError(t, json.Unmarshal(rr.Body.Bytes(), &response)) assertLen(t, response.Resources, 1) - assertEqual(t, 3, response.TotalResults) + assertEqual(t, 6, response.TotalResults) } func TestServerServiceProviderConfigHandler(t *testing.T) { diff --git a/schema/schemas.go b/schema/schemas.go index ccef554..946f076 100644 --- a/schema/schemas.go +++ b/schema/schemas.go @@ -685,3 +685,160 @@ func ResourceTypeSchema() Schema { Name: optional.NewString("Resource Type"), } } + +// ServiceProviderConfig returns the Resource Type Schema. +// RFC: https://tools.ietf.org/html/rfc7643#section-5 +func ServiceProviderConfigSchema() Schema { + return Schema{ + Attributes: []CoreAttribute{ + SimpleCoreAttribute(SimpleStringParams(StringParams{ + Description: optional.NewString("An HTTP-addressable URL pointing to the service provider's human-consumable help documentation."), + Mutability: AttributeMutabilityReadOnly(), + Name: "documentationUri", + Required: false, + })), + ComplexCoreAttribute(ComplexParams{ + Description: optional.NewString("A complex type that specifies PATCH configuration options."), + Mutability: AttributeMutabilityReadOnly(), + Name: "patch", + Required: true, + SubAttributes: []SimpleParams{ + SimpleBooleanParams(BooleanParams{ + Description: optional.NewString("A Boolean value specifying whether or not the operation is supported."), + Mutability: AttributeMutabilityReadOnly(), + Name: "supported", + Required: true, + }), + }, + }), + ComplexCoreAttribute(ComplexParams{ + Description: optional.NewString("A complex type that specifies bulk configuration options."), + Mutability: AttributeMutabilityReadOnly(), + Name: "bulk", + Required: true, + SubAttributes: []SimpleParams{ + SimpleBooleanParams(BooleanParams{ + Description: optional.NewString("A Boolean value specifying whether or not the operation is supported."), + Mutability: AttributeMutabilityReadOnly(), + Name: "supported", + Required: true, + }), + SimpleNumberParams(NumberParams{ + Description: optional.NewString("An integer value specifying the maximum number of operations."), + Mutability: AttributeMutabilityReadOnly(), + Name: "maxOperations", + Required: true, + }), + SimpleNumberParams(NumberParams{ + Description: optional.NewString("An integer value specifying the maximum payload size in bytes."), + Mutability: AttributeMutabilityReadOnly(), + Name: "maxPayloadSize", + Required: true, + }), + }, + }), + ComplexCoreAttribute(ComplexParams{ + Description: optional.NewString("A complex type that specifies FILTER options."), + Mutability: AttributeMutabilityReadOnly(), + Name: "filter", + Required: true, + SubAttributes: []SimpleParams{ + SimpleBooleanParams(BooleanParams{ + Description: optional.NewString("A Boolean value specifying whether or not the operation is supported."), + Mutability: AttributeMutabilityReadOnly(), + Name: "supported", + Required: true, + }), + SimpleNumberParams(NumberParams{ + Description: optional.NewString("An integer value specifying the maximum number of resources returned in a response."), + Mutability: AttributeMutabilityReadOnly(), + Name: "maxResults", + Required: true, + }), + }, + }), + ComplexCoreAttribute(ComplexParams{ + Description: optional.NewString("A complex type that specifies configuration options related to changing a password."), + Mutability: AttributeMutabilityReadOnly(), + Name: "changePassword", + Required: true, + SubAttributes: []SimpleParams{ + SimpleBooleanParams(BooleanParams{ + Description: optional.NewString("A Boolean value specifying whether or not the operation is supported."), + Mutability: AttributeMutabilityReadOnly(), + Name: "supported", + Required: true, + }), + }, + }), + ComplexCoreAttribute(ComplexParams{ + Description: optional.NewString("A complex type that specifies Sort configuration options."), + Mutability: AttributeMutabilityReadOnly(), + Name: "sort", + Required: true, + SubAttributes: []SimpleParams{ + SimpleBooleanParams(BooleanParams{ + Description: optional.NewString("A Boolean value specifying whether or not the operation is supported."), + Mutability: AttributeMutabilityReadOnly(), + Name: "supported", + Required: true, + }), + }, + }), + ComplexCoreAttribute(ComplexParams{ + Description: optional.NewString("A complex type that specifies ETag configuration options."), + Mutability: AttributeMutabilityReadOnly(), + Name: "etag", + Required: true, + SubAttributes: []SimpleParams{ + SimpleBooleanParams(BooleanParams{ + Description: optional.NewString("A Boolean value specifying whether or not the operation is supported."), + Mutability: AttributeMutabilityReadOnly(), + Name: "supported", + Required: true, + }), + }, + }), + ComplexCoreAttribute(ComplexParams{ + Description: optional.NewString("A complex type that specifies ETag configuration options."), + Mutability: AttributeMutabilityReadOnly(), + Name: "authenticationSchemes", + Required: true, + MultiValued: true, + SubAttributes: []SimpleParams{ + SimpleStringParams(StringParams{ + Description: optional.NewString("The authentication scheme. This specification defines the values 'oauth', 'oauth2', 'oauthbearertoken', 'httpbasic', and 'httpdigest'."), + Mutability: AttributeMutabilityReadOnly(), + Name: "type", + Required: true, + }), + SimpleStringParams(StringParams{ + Description: optional.NewString("The common authentication scheme name, e.g., HTTP Basic."), + Mutability: AttributeMutabilityReadOnly(), + Name: "name", + Required: true, + }), + SimpleStringParams(StringParams{ + Description: optional.NewString("A description of the authentication scheme."), + Mutability: AttributeMutabilityReadOnly(), + Name: "description", + Required: true, + }), + SimpleStringParams(StringParams{ + Description: optional.NewString("An HTTP-addressable URL pointing to the authentication scheme's specification."), + Mutability: AttributeMutabilityReadOnly(), + Name: "specUri", + }), + SimpleStringParams(StringParams{ + Description: optional.NewString("An HTTP-addressable URL pointing to the authentication scheme's usage documentation."), + Mutability: AttributeMutabilityReadOnly(), + Name: "documentationUri", + }), + }, + }), + }, + Description: optional.NewString("SCIM provides a schema for representing the service provider's configuration."), + ID: "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig", + Name: optional.NewString("Service Provider Config"), + } +} diff --git a/server.go b/server.go index 8baad49..ee4f74d 100644 --- a/server.go +++ b/server.go @@ -132,6 +132,14 @@ func (s Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { // getSchema extracts the schemas from the resources types defined in the server with given id. func (s Server) getSchema(id string) schema.Schema { + switch id { + case "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig": + return schema.ServiceProviderConfigSchema() + case "urn:ietf:params:scim:schemas:core:2.0:ResourceType": + return schema.ResourceTypeSchema() + case "urn:ietf:params:scim:schemas:core:2.0:Schema": + return schema.Definition() + } for _, resourceType := range s.ResourceTypes { if resourceType.Schema.ID == id { return resourceType.Schema @@ -148,7 +156,9 @@ func (s Server) getSchema(id string) schema.Schema { // getSchemas extracts all the schemas from the resources types defined in the server. Duplicate IDs will be ignored. func (s Server) getSchemas() []schema.Schema { ids := make([]string, 0) - schemas := make([]schema.Schema, 0) + schemas := []schema.Schema{ + schema.Definition(), schema.ResourceTypeSchema(), schema.ServiceProviderConfigSchema(), + } for _, resourceType := range s.ResourceTypes { if !contains(ids, resourceType.Schema.ID) { schemas = append(schemas, resourceType.Schema)