scimitar 1.3.0 → 1.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 742d9f1195cc1ec3c86c17e2ca731119413925f3b5e0a3bd67fc90bf7183c2dd
4
- data.tar.gz: c4e90cbd8d59eb564deebfd0278e96f2f1896b9fa6c0eb8697f1975115e2cf47
3
+ metadata.gz: 382f2feb979c655de91c1d30bf1fa8bb5347059abe376839758a9b34992f8616
4
+ data.tar.gz: d1d8f8c32a92f4b879699a995b4e1746b7b778d782ab3101695e59891a107606
5
5
  SHA512:
6
- metadata.gz: b1df7b83b8adaf904891983a1059a690ed7435917c8ae409a81254a2b13314e35ce45d630aecc917165c527314cd140913ce4d31494da4a8ca54c65f8b7f6d6f
7
- data.tar.gz: 2855fcbe539ae73ff31fbae32a7e4841a31be1c48c39eae94ae34b9ab96341fdb17e53ee82d42c318a5bf928143d39181461a9bbb86d435ecb37e4fdda6876da
6
+ metadata.gz: 87373dddf17fe6791e7464c228e688338267bf1a230cd2ab1d69372185ea3adcf165b969872e0e05556ba28b1e9e1581ddaac5639f89235bd7f19da081ff3e7f
7
+ data.tar.gz: ae79056e07500c1b195807a9a3f12755895f47a4383c7451208a2956b79ec02e600a8c915fa8a600cccce559c16b5c62f73e081ced2e09e8bee5da63910a2a1e
@@ -37,6 +37,7 @@ module Scimitar
37
37
  pagination_info = scim_pagination_info(query.count())
38
38
 
39
39
  page_of_results = query
40
+ .order(id: :asc)
40
41
  .offset(pagination_info.offset)
41
42
  .limit(pagination_info.limit)
42
43
  .to_a()
@@ -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
- altering_hash[path_component] = value
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
@@ -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 = '1.3.0'
6
+ VERSION = '1.3.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 = '2022-07-14'
11
+ DATE = '2023-01-10'
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
- 'name.givenName' => { column: :first_name },
96
- 'name.familyName' => { column: :last_name },
97
- 'emails' => { columns: [ :work_email_address, :home_email_address ] },
98
- 'emails.value' => { columns: [ :work_email_address, :home_email_address ] },
99
- 'emails.type' => { ignore: true } # We can't filter on that; it'll just search all e-mails
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
 
@@ -0,0 +1,5 @@
1
+ class AddTimestampsToMockUser < ActiveRecord::Migration[6.1]
2
+ def change
3
+ add_timestamps :mock_users
4
+ end
5
+ end
@@ -10,7 +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: 2021_03_08_044214) do
13
+ ActiveRecord::Schema.define(version: 2023_01_09_012729) do
14
14
 
15
15
  # These are extensions that must be enabled in order to support this database
16
16
  enable_extension "plpgsql"
@@ -37,6 +37,8 @@ ActiveRecord::Schema.define(version: 2021_03_08_044214) do
37
37
  t.text "work_email_address"
38
38
  t.text "home_email_address"
39
39
  t.text "work_phone_number"
40
+ t.datetime "created_at", precision: 6, null: false
41
+ t.datetime "updated_at", precision: 6, null: false
40
42
  end
41
43
 
42
44
  end
@@ -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, 'externalId') }.to raise_error(Scimitar::FilterError)
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
- @u1 = MockUser.create(username: '1', first_name: 'Foo', last_name: 'Ark', home_email_address: 'home_1@test.com')
8
- @u2 = MockUser.create(username: '2', first_name: 'Foo', last_name: 'Bar', home_email_address: 'home_2@test.com')
9
- @u3 = MockUser.create(username: '3', first_name: 'Foo', home_email_address: 'home_3@test.com')
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 "Foo" and name.familyName pr and emails ne "home_1@TEST.COM"'
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,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scimitar
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - RIPA Global
8
8
  - Andrew David Hodgkinson
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-07-14 00:00:00.000000000 Z
12
+ date: 2023-01-10 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
@@ -245,7 +246,7 @@ metadata:
245
246
  source_code_uri: https://github.com/RIPAGlobal/scimitar/
246
247
  bug_tracker_uri: https://github.com/RIPAGlobal/scimitar/issues/
247
248
  changelog_uri: https://github.com/RIPAGlobal/scimitar/blob/master/CHANGELOG.md
248
- post_install_message:
249
+ post_install_message:
249
250
  rdoc_options: []
250
251
  require_paths:
251
252
  - lib
@@ -261,7 +262,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
261
262
  version: '0'
262
263
  requirements: []
263
264
  rubygems_version: 3.1.6
264
- signing_key:
265
+ signing_key:
265
266
  specification_version: 4
266
267
  summary: SCIM v2 for Rails
267
268
  test_files:
@@ -307,4 +308,5 @@ test_files:
307
308
  - spec/apps/dummy/db/schema.rb
308
309
  - spec/apps/dummy/db/migrate/20210308020313_create_mock_groups.rb
309
310
  - spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb
311
+ - spec/apps/dummy/db/migrate/20230109012729_add_timestamps_to_mock_user.rb
310
312
  - spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb