Skip to content

Commit

Permalink
fix: validate schema ID in the provided resource
Browse files Browse the repository at this point in the history
  • Loading branch information
icamys committed Mar 20, 2024
1 parent 172bf2a commit f2efa51
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 98 deletions.
25 changes: 13 additions & 12 deletions handlers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -433,40 +433,40 @@ func TestServerResourcePostHandlerValid(t *testing.T) {
tests := []struct {
name string
target string
body io.Reader
body string
expectedUserName string
expectedExternalID interface{}
}{
{
name: "Users post request without version",
target: "/Users",
body: strings.NewReader(`{"id": "other", "userName": "test1", "externalId": "external_test1"}`),
body: `{"id": "other", "userName": "test1", "externalId": "external_test1","schemas":["urn:ietf:params:scim:schemas:core:2.0:User"]}`,
expectedUserName: "test1",
expectedExternalID: "external_test1",
}, {
name: "Users post request with version",
target: "/v2/Users",
body: strings.NewReader(`{"id": "other", "userName": "test2", "externalId": "external_test2"}`),
body: `{"id": "other", "userName": "test2", "externalId": "external_test2","schemas":["urn:ietf:params:scim:schemas:core:2.0:User"]}`,
expectedUserName: "test2",
expectedExternalID: "external_test2",
}, {
name: "Users post request without externalId",
target: "/v2/Users",
body: strings.NewReader(`{"id": "other", "userName": "test3"}`),
body: `{"id": "other", "userName": "test3","schemas":["urn:ietf:params:scim:schemas:core:2.0:User"]}`,
expectedUserName: "test3",
expectedExternalID: nil,
}, {
name: "Users post request with immutable attribute",
target: "/v2/Users",
body: strings.NewReader(`{"id": "other", "userName": "test3", "immutableThing": "test"}`),
body: `{"id": "other", "userName": "test3", "immutableThing": "test","schemas":["urn:ietf:params:scim:schemas:core:2.0:User"]}`,
expectedUserName: "test3",
expectedExternalID: nil,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, test.target, test.body)
req := httptest.NewRequest(http.MethodPost, test.target, strings.NewReader(test.body))
rr := httptest.NewRecorder()
newTestServer(t).ServeHTTP(rr, req)

Expand Down Expand Up @@ -496,7 +496,8 @@ func TestServerResourcePostHandlerValid(t *testing.T) {
}

func TestServerResourcePutHandlerNotFound(t *testing.T) {
req := httptest.NewRequest(http.MethodPut, "/Users/9999", strings.NewReader(`{"userName": "other"}`))
reqBody := `{"userName": "other","schemas":["urn:ietf:params:scim:schemas:core:2.0:User"]}`
req := httptest.NewRequest(http.MethodPut, "/Users/9999", strings.NewReader(reqBody))
rr := httptest.NewRecorder()
newTestServer(t).ServeHTTP(rr, req)

Expand All @@ -520,34 +521,34 @@ func TestServerResourcePutHandlerValid(t *testing.T) {
tests := []struct {
name string
target string
body io.Reader
body string
expectedUserName string
expectedExternalID interface{}
}{
{
name: "Users put request",
target: "/v2/Users/0002",
body: strings.NewReader(`{"id": "other", "userName": "test2", "externalId": "external_test2"}`),
body: `{"id": "other", "userName": "test2", "externalId": "external_test2","schemas":["urn:ietf:params:scim:schemas:core:2.0:User"]}`,
expectedUserName: "test2",
expectedExternalID: "external_test2",
}, {
name: "Users put request without externalId",
target: "/Users/0003",
body: strings.NewReader(`{"id": "other", "userName": "test3"}`),
body: `{"id": "other", "userName": "test3","schemas":["urn:ietf:params:scim:schemas:core:2.0:User"]}`,
expectedUserName: "test3",
expectedExternalID: nil,
}, {
name: "Users put request with immutable attribute",
target: "/Users/0003",
body: strings.NewReader(`{"id": "other", "userName": "test3", "immutableThing": "test"}`),
body: `{"id": "other", "userName": "test3", "immutableThing": "test","schemas":["urn:ietf:params:scim:schemas:core:2.0:User"]}`,
expectedUserName: "test3",
expectedExternalID: nil,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
req := httptest.NewRequest(http.MethodPut, test.target, test.body)
req := httptest.NewRequest(http.MethodPut, test.target, strings.NewReader(test.body))
rr := httptest.NewRecorder()
newTestServer(t).ServeHTTP(rr, req)

Expand Down
29 changes: 29 additions & 0 deletions schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,41 @@ func (s Schema) getRawAttributes() []map[string]interface{} {
return attributes
}

func (s Schema) validateSchemaID(resource map[string]interface{}) *errors.ScimError {
resourceSchemas, present := resource["schemas"]
if !present {
return &errors.ScimErrorInvalidSyntax
}

resourceSchemasSlice, ok := resourceSchemas.([]interface{})
if !ok {
return &errors.ScimErrorInvalidSyntax
}

var schemaFound bool
for _, v := range resourceSchemasSlice {
if v == s.ID {
schemaFound = true
break
}
}
if !schemaFound {
return &errors.ScimErrorInvalidSyntax
}

return nil
}

func (s Schema) validate(resource interface{}, checkMutability bool) (map[string]interface{}, *errors.ScimError) {
core, ok := resource.(map[string]interface{})
if !ok {
return nil, &errors.ScimErrorInvalidSyntax
}

if err := s.validateSchemaID(core); err != nil {
return nil, err
}

attributes := make(map[string]interface{})
for _, attribute := range s.Attributes {
var hit interface{}
Expand Down
Loading

0 comments on commit f2efa51

Please sign in to comment.