scimitar 2.1.0 → 2.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/scimitar/active_record_backed_resources_controller.rb +1 -0
- data/app/controllers/scimitar/application_controller.rb +2 -2
- data/app/models/scimitar/error_response.rb +1 -1
- data/app/models/scimitar/lists/query_parser.rb +11 -1
- data/app/models/scimitar/resources/mixin.rb +5 -1
- data/lib/scimitar/version.rb +2 -2
- data/spec/apps/dummy/app/models/mock_user.rb +8 -5
- data/spec/apps/dummy/db/migrate/20230109012729_add_timestamps_to_mock_user.rb +5 -0
- data/spec/apps/dummy/db/schema.rb +3 -2
- data/spec/controllers/scimitar/application_controller_spec.rb +5 -1
- data/spec/models/scimitar/lists/query_parser_spec.rb +1 -1
- data/spec/models/scimitar/resources/mixin_spec.rb +18 -0
- data/spec/models/scimitar/schema/attribute_spec.rb +0 -3
- data/spec/requests/active_record_backed_resources_controller_spec.rb +88 -4
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68d1c5d2f9f2b72a4582a04d6430b6fd7fd62ffc3fcdfe39422f2159acdcd3e1
|
4
|
+
data.tar.gz: 23a4d69326377dc1e68d3e1ff09d17a3adbc0e922bee7be6289acec2c4d790e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 98e7ececc69633a18c3e4f1b946f586959177223317a050edf8e1e8a916727f18f01e6cfb1103ff31a65c890708e6c85c41d42478636c9a4924efa99817b4a98
|
7
|
+
data.tar.gz: 9674932b834c16f8176340bfa826ebac4d06e6aade8c561c484f1031877f6803ef732210b43ed0613972fe44aeb98707a429a1f5a87388909c1a0694cdfe9f98
|
@@ -25,8 +25,8 @@ module Scimitar
|
|
25
25
|
#
|
26
26
|
# ...to "globally" invoke this handler if you wish.
|
27
27
|
#
|
28
|
-
# +
|
29
|
-
#
|
28
|
+
# +exception+:: Exception instance, used for a configured error reporter
|
29
|
+
# via #handle_scim_error (if present).
|
30
30
|
#
|
31
31
|
def handle_resource_not_found(exception)
|
32
32
|
handle_scim_error(NotFoundError.new(params[:id]), exception)
|
@@ -17,7 +17,7 @@ module Scimitar
|
|
17
17
|
data
|
18
18
|
end
|
19
19
|
|
20
|
-
#
|
20
|
+
# Originally Scimitar used attribute "detail" for exception text; it was
|
21
21
|
# only for JSON responses at the time, but in hindsight was a bad choice.
|
22
22
|
# It should have been "message" given inheritance from StandardError, which
|
23
23
|
# then works properly with e.g. error reporting services.
|
@@ -78,7 +78,7 @@ module Scimitar
|
|
78
78
|
# method's return value here.
|
79
79
|
#
|
80
80
|
def initialize(attribute_map)
|
81
|
-
@attribute_map = attribute_map
|
81
|
+
@attribute_map = attribute_map.with_indifferent_case_insensitive_access()
|
82
82
|
end
|
83
83
|
|
84
84
|
# Parse SCIM filter query into RPN stack
|
@@ -605,6 +605,16 @@ module Scimitar
|
|
605
605
|
|
606
606
|
raise Scimitar::FilterError unless all_supported
|
607
607
|
|
608
|
+
unless case_sensitive
|
609
|
+
lc_scim_attribute = scim_attribute.downcase()
|
610
|
+
|
611
|
+
case_sensitive = (
|
612
|
+
lc_scim_attribute == 'id' ||
|
613
|
+
lc_scim_attribute == 'externalid' ||
|
614
|
+
lc_scim_attribute.start_with?('meta.')
|
615
|
+
)
|
616
|
+
end
|
617
|
+
|
608
618
|
column_names.each.with_index do | column_name, index |
|
609
619
|
arel_column = arel_table[column_name]
|
610
620
|
arel_operation = case scim_operator
|
@@ -902,7 +902,11 @@ module Scimitar
|
|
902
902
|
altering_hash[path_component] = value
|
903
903
|
end
|
904
904
|
when 'replace'
|
905
|
-
|
905
|
+
if path_component == 'root'
|
906
|
+
altering_hash[path_component].merge!(value)
|
907
|
+
else
|
908
|
+
altering_hash[path_component] = value
|
909
|
+
end
|
906
910
|
when 'remove'
|
907
911
|
altering_hash.delete(path_component)
|
908
912
|
end
|
data/lib/scimitar/version.rb
CHANGED
@@ -3,11 +3,11 @@ module Scimitar
|
|
3
3
|
# Gem version. If this changes, be sure to re-run "bundle install" or
|
4
4
|
# "bundle update".
|
5
5
|
#
|
6
|
-
VERSION = '2.1.
|
6
|
+
VERSION = '2.1.3'
|
7
7
|
|
8
8
|
# Date for VERSION. If this changes, be sure to re-run "bundle install"
|
9
9
|
# or "bundle update".
|
10
10
|
#
|
11
|
-
DATE = '
|
11
|
+
DATE = '2023-01-09'
|
12
12
|
|
13
13
|
end
|
@@ -92,11 +92,14 @@ class MockUser < ActiveRecord::Base
|
|
92
92
|
|
93
93
|
def self.scim_queryable_attributes
|
94
94
|
return {
|
95
|
-
'
|
96
|
-
'
|
97
|
-
'
|
98
|
-
'
|
99
|
-
'
|
95
|
+
'id' => { column: :id },
|
96
|
+
'externalId' => { column: :scim_uid },
|
97
|
+
'meta.lastModified' => { column: :updated_at },
|
98
|
+
'name.givenName' => { column: :first_name },
|
99
|
+
'name.familyName' => { column: :last_name },
|
100
|
+
'emails' => { columns: [ :work_email_address, :home_email_address ] },
|
101
|
+
'emails.value' => { columns: [ :work_email_address, :home_email_address ] },
|
102
|
+
'emails.type' => { ignore: true } # We can't filter on that; it'll just search all e-mails
|
100
103
|
}
|
101
104
|
end
|
102
105
|
|
@@ -10,8 +10,7 @@
|
|
10
10
|
#
|
11
11
|
# It's strongly recommended that you check this file into your version control system.
|
12
12
|
|
13
|
-
ActiveRecord::Schema.define(version:
|
14
|
-
|
13
|
+
ActiveRecord::Schema[7.0].define(version: 2023_01_09_012729) do
|
15
14
|
# These are extensions that must be enabled in order to support this database
|
16
15
|
enable_extension "plpgsql"
|
17
16
|
|
@@ -37,6 +36,8 @@ ActiveRecord::Schema.define(version: 2021_03_08_044214) do
|
|
37
36
|
t.text "work_email_address"
|
38
37
|
t.text "home_email_address"
|
39
38
|
t.text "work_phone_number"
|
39
|
+
t.datetime "created_at", null: false
|
40
|
+
t.datetime "updated_at", null: false
|
40
41
|
end
|
41
42
|
|
42
43
|
end
|
@@ -208,7 +208,11 @@ RSpec.describe Scimitar::ApplicationController do
|
|
208
208
|
context 'and bad JSON' do
|
209
209
|
controller do
|
210
210
|
def index
|
211
|
-
|
211
|
+
begin
|
212
|
+
raise 'Hello'
|
213
|
+
rescue
|
214
|
+
raise ActionDispatch::Http::Parameters::ParseError
|
215
|
+
end
|
212
216
|
end
|
213
217
|
end
|
214
218
|
|
@@ -590,7 +590,7 @@ RSpec.describe Scimitar::Lists::QueryParser do
|
|
590
590
|
end
|
591
591
|
|
592
592
|
it 'complains if there is no column mapping available' do
|
593
|
-
expect { @instance.send(:activerecord_columns, '
|
593
|
+
expect { @instance.send(:activerecord_columns, 'userName') }.to raise_error(Scimitar::FilterError)
|
594
594
|
end
|
595
595
|
|
596
596
|
it 'complains about malformed declarations' do
|
@@ -1747,6 +1747,24 @@ RSpec.describe Scimitar::Resources::Mixin do
|
|
1747
1747
|
expect(scim_hash['emails'][0]['type' ]).to eql('work')
|
1748
1748
|
expect(scim_hash['emails'][0]['value']).to eql('work@test.com')
|
1749
1749
|
end
|
1750
|
+
|
1751
|
+
context 'when prior value already exists, and no path' do
|
1752
|
+
it 'simple value: overwrites' do
|
1753
|
+
path = [ 'root' ]
|
1754
|
+
scim_hash = { 'root' => { 'userName' => 'bar', 'active' => true } }.with_indifferent_case_insensitive_access()
|
1755
|
+
|
1756
|
+
@instance.send(
|
1757
|
+
:from_patch_backend!,
|
1758
|
+
nature: 'replace',
|
1759
|
+
path: path,
|
1760
|
+
value: { 'active' => false }.with_indifferent_case_insensitive_access(),
|
1761
|
+
altering_hash: scim_hash
|
1762
|
+
)
|
1763
|
+
|
1764
|
+
expect(scim_hash['root']['userName']).to eql('bar')
|
1765
|
+
expect(scim_hash['root']['active']).to eql(false)
|
1766
|
+
end
|
1767
|
+
end
|
1750
1768
|
end # context 'when value is not present' do
|
1751
1769
|
end # "context 'replace' do"
|
1752
1770
|
|
@@ -21,10 +21,8 @@ RSpec.describe Scimitar::Schema::Attribute do
|
|
21
21
|
expect(name.type).to eql('complex')
|
22
22
|
expect(name.subAttributes).to eql(Scimitar::Schema::Name.scim_attributes)
|
23
23
|
end
|
24
|
-
|
25
24
|
end
|
26
25
|
|
27
|
-
|
28
26
|
context '#valid?' do
|
29
27
|
it 'is invalid if attribute is required but value is blank' do
|
30
28
|
attribute = described_class.new(name: 'userName', type: 'string', required: true)
|
@@ -76,5 +74,4 @@ RSpec.describe Scimitar::Schema::Attribute do
|
|
76
74
|
expect(described_class.new(name: 'startDate', type: 'dateTime').valid?('gaga')).to be(false)
|
77
75
|
end
|
78
76
|
end
|
79
|
-
|
80
77
|
end
|
@@ -1,12 +1,15 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'time'
|
2
3
|
|
3
4
|
RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
|
4
5
|
before :each do
|
5
6
|
allow_any_instance_of(Scimitar::ApplicationController).to receive(:authenticated?).and_return(true)
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
@
|
8
|
+
lmt = Time.parse("2023-01-09 14:25:00 +1300")
|
9
|
+
|
10
|
+
@u1 = MockUser.create(username: '1', first_name: 'Foo', last_name: 'Ark', home_email_address: 'home_1@test.com', scim_uid: '001', created_at: lmt, updated_at: lmt + 1)
|
11
|
+
@u2 = MockUser.create(username: '2', first_name: 'Foo', last_name: 'Bar', home_email_address: 'home_2@test.com', scim_uid: '002', created_at: lmt, updated_at: lmt + 2)
|
12
|
+
@u3 = MockUser.create(username: '3', first_name: 'Foo', home_email_address: 'home_3@test.com', scim_uid: '003', created_at: lmt, updated_at: lmt + 3)
|
10
13
|
end
|
11
14
|
|
12
15
|
# ===========================================================================
|
@@ -48,7 +51,7 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
|
|
48
51
|
it 'applies a filter, with case-insensitive value comparison' do
|
49
52
|
get '/Users', params: {
|
50
53
|
format: :scim,
|
51
|
-
filter: 'name.givenName eq "
|
54
|
+
filter: 'name.givenName eq "FOO" and name.familyName pr and emails ne "home_1@test.com"'
|
52
55
|
}
|
53
56
|
|
54
57
|
expect(response.status).to eql(200)
|
@@ -64,6 +67,87 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
|
|
64
67
|
expect(usernames).to match_array(['2'])
|
65
68
|
end
|
66
69
|
|
70
|
+
it 'applies a filter, with case-insensitive attribute matching (GitHub issue #37)' do
|
71
|
+
get '/Users', params: {
|
72
|
+
format: :scim,
|
73
|
+
filter: 'name.GIVENNAME eq "Foo" and name.Familyname pr and emails ne "home_1@test.com"'
|
74
|
+
}
|
75
|
+
|
76
|
+
expect(response.status).to eql(200)
|
77
|
+
result = JSON.parse(response.body)
|
78
|
+
|
79
|
+
expect(result['totalResults']).to eql(1)
|
80
|
+
expect(result['Resources'].size).to eql(1)
|
81
|
+
|
82
|
+
ids = result['Resources'].map { |resource| resource['id'] }
|
83
|
+
expect(ids).to match_array([@u2.id.to_s])
|
84
|
+
|
85
|
+
usernames = result['Resources'].map { |resource| resource['userName'] }
|
86
|
+
expect(usernames).to match_array(['2'])
|
87
|
+
end
|
88
|
+
|
89
|
+
# Strange attribute capitalisation in tests here builds on test coverage
|
90
|
+
# for now-fixed GitHub issue #37.
|
91
|
+
#
|
92
|
+
context '"meta" / IDs (GitHub issue #36)' do
|
93
|
+
it 'applies a filter on primary keys, using direct comparison (rather than e.g. case-insensitive operators)' do
|
94
|
+
get '/Users', params: {
|
95
|
+
format: :scim,
|
96
|
+
filter: "id eq \"#{@u3.id}\""
|
97
|
+
}
|
98
|
+
|
99
|
+
expect(response.status).to eql(200)
|
100
|
+
result = JSON.parse(response.body)
|
101
|
+
|
102
|
+
expect(result['totalResults']).to eql(1)
|
103
|
+
expect(result['Resources'].size).to eql(1)
|
104
|
+
|
105
|
+
ids = result['Resources'].map { |resource| resource['id'] }
|
106
|
+
expect(ids).to match_array([@u3.id.to_s])
|
107
|
+
|
108
|
+
usernames = result['Resources'].map { |resource| resource['userName'] }
|
109
|
+
expect(usernames).to match_array(['3'])
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'applies a filter on external IDs, using direct comparison' do
|
113
|
+
get '/Users', params: {
|
114
|
+
format: :scim,
|
115
|
+
filter: "externalID eq \"#{@u2.scim_uid}\""
|
116
|
+
}
|
117
|
+
|
118
|
+
expect(response.status).to eql(200)
|
119
|
+
result = JSON.parse(response.body)
|
120
|
+
|
121
|
+
expect(result['totalResults']).to eql(1)
|
122
|
+
expect(result['Resources'].size).to eql(1)
|
123
|
+
|
124
|
+
ids = result['Resources'].map { |resource| resource['id'] }
|
125
|
+
expect(ids).to match_array([@u2.id.to_s])
|
126
|
+
|
127
|
+
usernames = result['Resources'].map { |resource| resource['userName'] }
|
128
|
+
expect(usernames).to match_array(['2'])
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'applies a filter on "meta" entries, using direct comparison' do
|
132
|
+
get '/Users', params: {
|
133
|
+
format: :scim,
|
134
|
+
filter: "Meta.LastModified eq \"#{@u3.updated_at}\""
|
135
|
+
}
|
136
|
+
|
137
|
+
expect(response.status).to eql(200)
|
138
|
+
result = JSON.parse(response.body)
|
139
|
+
|
140
|
+
expect(result['totalResults']).to eql(1)
|
141
|
+
expect(result['Resources'].size).to eql(1)
|
142
|
+
|
143
|
+
ids = result['Resources'].map { |resource| resource['id'] }
|
144
|
+
expect(ids).to match_array([@u3.id.to_s])
|
145
|
+
|
146
|
+
usernames = result['Resources'].map { |resource| resource['userName'] }
|
147
|
+
expect(usernames).to match_array(['3'])
|
148
|
+
end
|
149
|
+
end # "context '"meta" / IDs (GitHub issue #36)' do"
|
150
|
+
|
67
151
|
it 'obeys a page size' do
|
68
152
|
get '/Users', params: {
|
69
153
|
format: :scim,
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scimitar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- RIPA Global
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2023-01-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -211,6 +211,7 @@ files:
|
|
211
211
|
- spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb
|
212
212
|
- spec/apps/dummy/db/migrate/20210308020313_create_mock_groups.rb
|
213
213
|
- spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb
|
214
|
+
- spec/apps/dummy/db/migrate/20230109012729_add_timestamps_to_mock_user.rb
|
214
215
|
- spec/apps/dummy/db/schema.rb
|
215
216
|
- spec/controllers/scimitar/application_controller_spec.rb
|
216
217
|
- spec/controllers/scimitar/resource_types_controller_spec.rb
|
@@ -260,7 +261,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
260
261
|
- !ruby/object:Gem::Version
|
261
262
|
version: '0'
|
262
263
|
requirements: []
|
263
|
-
rubygems_version: 3.3.
|
264
|
+
rubygems_version: 3.3.13
|
264
265
|
signing_key:
|
265
266
|
specification_version: 4
|
266
267
|
summary: SCIM v2 for Rails
|
@@ -282,6 +283,7 @@ test_files:
|
|
282
283
|
- spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb
|
283
284
|
- spec/apps/dummy/db/migrate/20210308020313_create_mock_groups.rb
|
284
285
|
- spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb
|
286
|
+
- spec/apps/dummy/db/migrate/20230109012729_add_timestamps_to_mock_user.rb
|
285
287
|
- spec/apps/dummy/db/schema.rb
|
286
288
|
- spec/controllers/scimitar/application_controller_spec.rb
|
287
289
|
- spec/controllers/scimitar/resource_types_controller_spec.rb
|