Skip to content

Commit

Permalink
Merge pull request #131 from RIPAGlobal/feature/handle-schema-ids-in-…
Browse files Browse the repository at this point in the history
…get-requests

Handle URNs in filters via the same strip-out approach as for PATCH traversal
  • Loading branch information
bagp1 authored Jun 13, 2024
2 parents 454af48 + 2f7042b commit ee78b5c
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 1 deletion.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,8 @@ Whatever you provide in the `::id` method in your extension class will be used a
}
```

**IMPORTANT: Attribute names must be unique** across your entire combined schema, regardless of URNs used. This is because of a limitation in Scimitar's implementation. [This GitHub issue](https://github.com/RIPAGlobal/scimitar/issues/130) explains more. If this is a problem for you, please comment on the GitHub issue to help the maintainers understand the level of demand for remediation.

Resource extensions can provide any fields you choose, under any ID/URN you choose, to either RFC-described resources or entirely custom SCIM resources. There are no hard-coded assumptions or other "magic" that might require you to only extend RFC-described resources with RFC-described extensions. Of course, if you use custom resources or custom extensions that are not described by the SCIM RFCs, then the SCIM API you provide may only work with custom-written API callers that are aware of your bespoke resources and/or extensions.

Extensions can also contain complex attributes such as groups. For instance, if you want the ability to write to groups from the User resource perspective (since 'groups' collection in a SCIM User resource is read-only), you can add one attribute to your extension like this:
Expand Down
31 changes: 30 additions & 1 deletion app/models/scimitar/lists/query_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,36 @@ def flatten_filter(filter)
end
end

return rewritten.join(' ')
# Handle schema IDs.
#
# Scimitar currently has a limitation where it strips schema IDs in
# things like PATCH operation path traversal; see
# https://github.com/RIPAGlobal/scimitar/issues/130. At least that
# makes things easy here; use the same approach and strip them out!
#
# We don't know which resource is being queried at this layer of the
# software. If Scimitar were to bump major version, then an extension
# to QueryParser#parse to include this information would be wise. In
# the mean time, all we can do is enumerate all extension schema
# subclasses with IDs and remove those IDs if present in the filter.
#
# Inbound unrecognised schema IDs will be left behind. If the client
# Scimitar application hasn't defined requested schemas, it would
# very likely never have been able to handle the filter either way.
#
rewritten_joined = rewritten.join(' ')
if rewritten_joined.include?(':')

# README.md notes that extensions *must* be a subclass of
# Scimitar::Schema::Base and must define IDs.
#
known_schema_ids = Scimitar::Schema::Base.subclasses.map { |s| s.new.id }.compact
known_schema_ids.each do | schema_id |
rewritten_joined.gsub!(/#{schema_id}[\:\.]/, '')
end
end

return rewritten_joined
end

# Service method to DRY up #flatten_filter a little. Applies a prefix
Expand Down
29 changes: 29 additions & 0 deletions spec/models/scimitar/lists/query_parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,35 @@
expect(result).to eql('emails.type eq "work" and emails.value co "@example.com" or userType eq "Admin" or ims.type eq "xmpp" and ims.value co "@foo.com"')
end

# https://github.com/RIPAGlobal/scimitar/issues/116
#
context 'with schema IDs (GitHub issue #116)' do
it 'handles simple attributes' do
result = @instance.send(:flatten_filter, 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:employeeId eq "gsar"')
expect(result).to eql('employeeId eq "gsar"')
end

it 'handles dotted attribute paths' do
result = @instance.send(:flatten_filter, 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:imaginary.path eq "gsar"')
expect(result).to eql('imaginary.path eq "gsar"')
end

it 'replaces all examples' do
result = @instance.send(:flatten_filter, 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:employeeId eq "gsar" or urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:imaginary.path eq "gsar"')
expect(result).to eql('employeeId eq "gsar" or imaginary.path eq "gsar"')
end

it 'handles the square bracket form with schema ID at the root' do
result = @instance.send(:flatten_filter, 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User[employeeId eq "gsar"')
expect(result).to eql('employeeId eq "gsar"')
end

it 'handles the square bracket form with schema ID and attribute at the root' do
result = @instance.send(:flatten_filter, 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:imaginary[path eq "gsar"')
expect(result).to eql('imaginary.path eq "gsar"')
end
end

# https://github.com/RIPAGlobal/scimitar/issues/115
#
context 'broken filters from Microsoft (GitHub issue #115)' do
Expand Down

0 comments on commit ee78b5c

Please sign in to comment.