diff --git a/internal/patch/add_test.go b/internal/patch/add_test.go index fddd1b8..dc16b5c 100644 --- a/internal/patch/add_test.go +++ b/internal/patch/add_test.go @@ -6,6 +6,25 @@ import ( "github.com/elimity-com/scim/schema" ) +// The following example shows how to add extension attributes to a User resource without using a "path" attribute, +// where the extension is provided as a nested object keyed by its schema URI. See RFC 7643 Section 3.3 +// and RFC 7644 Section 3.5.2. +func Example_addExtensionWithoutPath() { + operation, _ := json.Marshal(map[string]interface{}{ + "op": "add", + "value": map[string]interface{}{ + "userName": "test", + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": map[string]interface{}{ + "organization": "SUSE", + }, + }, + }) + validator, _ := NewValidator(operation, schema.CoreUserSchema(), schema.ExtensionEnterpriseUser()) + fmt.Println(validator.Validate()) + // Output: + // map[urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:map[organization:SUSE] userName:test] +} + // The following example shows how to add a member to a group. func Example_addMemberToGroup() { operation, _ := json.Marshal(map[string]interface{}{ diff --git a/internal/patch/patch.go b/internal/patch/patch.go index 410ae18..609b2f7 100644 --- a/internal/patch/patch.go +++ b/internal/patch/patch.go @@ -184,6 +184,28 @@ func (v OperationValidator) validateEmptyPath() (interface{}, error) { rootValue := map[string]interface{}{} for p, value := range attributes { + // A key that exactly matches a schema URI is a JSON container for that + // extension's attributes, not an attribute path (RFC 7643 Section 3.3, + // RFC 7644 Section 3.5.2). Validate its members against the extension schema. + if extSchema, ok := v.schemas[p]; ok { + extAttributes, ok := value.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("the value of %s should be a complex attribute", p) + } + extValidator := OperationValidator{ + Op: v.Op, + value: extAttributes, + schema: extSchema, + schemas: v.schemas, + } + extValue, err := extValidator.validateEmptyPath() + if err != nil { + return nil, err + } + rootValue[p] = extValue + continue + } + path, err := filter.ParsePath([]byte(p)) if err != nil { return nil, fmt.Errorf("invalid attribute path: %s", p)