scimitar 2.5.0 → 2.11.0

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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +21 -0
  3. data/README.md +721 -0
  4. data/app/controllers/scimitar/active_record_backed_resources_controller.rb +72 -18
  5. data/app/controllers/scimitar/application_controller.rb +17 -9
  6. data/app/controllers/scimitar/resource_types_controller.rb +7 -3
  7. data/app/controllers/scimitar/resources_controller.rb +0 -2
  8. data/app/controllers/scimitar/schemas_controller.rb +366 -3
  9. data/app/controllers/scimitar/service_provider_configurations_controller.rb +3 -2
  10. data/app/models/scimitar/complex_types/address.rb +0 -6
  11. data/app/models/scimitar/complex_types/base.rb +2 -2
  12. data/app/models/scimitar/engine_configuration.rb +3 -1
  13. data/app/models/scimitar/lists/query_parser.rb +97 -12
  14. data/app/models/scimitar/resource_invalid_error.rb +1 -1
  15. data/app/models/scimitar/resource_type.rb +4 -6
  16. data/app/models/scimitar/resources/base.rb +52 -8
  17. data/app/models/scimitar/resources/mixin.rb +539 -76
  18. data/app/models/scimitar/schema/attribute.rb +18 -8
  19. data/app/models/scimitar/schema/base.rb +2 -2
  20. data/app/models/scimitar/schema/name.rb +2 -2
  21. data/app/models/scimitar/schema/user.rb +10 -10
  22. data/config/initializers/scimitar.rb +49 -3
  23. data/lib/scimitar/engine.rb +57 -12
  24. data/lib/scimitar/support/hash_with_indifferent_case_insensitive_access.rb +140 -10
  25. data/lib/scimitar/support/utilities.rb +111 -0
  26. data/lib/scimitar/version.rb +2 -2
  27. data/lib/scimitar.rb +1 -0
  28. data/spec/apps/dummy/app/controllers/custom_create_mock_users_controller.rb +25 -0
  29. data/spec/apps/dummy/app/controllers/custom_replace_mock_users_controller.rb +25 -0
  30. data/spec/apps/dummy/app/controllers/custom_save_mock_users_controller.rb +24 -0
  31. data/spec/apps/dummy/app/controllers/custom_update_mock_users_controller.rb +25 -0
  32. data/spec/apps/dummy/app/models/mock_user.rb +20 -3
  33. data/spec/apps/dummy/config/application.rb +8 -0
  34. data/spec/apps/dummy/config/initializers/scimitar.rb +40 -3
  35. data/spec/apps/dummy/config/routes.rb +18 -1
  36. data/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb +2 -0
  37. data/spec/apps/dummy/db/schema.rb +3 -1
  38. data/spec/controllers/scimitar/application_controller_spec.rb +56 -2
  39. data/spec/controllers/scimitar/resource_types_controller_spec.rb +8 -4
  40. data/spec/controllers/scimitar/schemas_controller_spec.rb +344 -48
  41. data/spec/controllers/scimitar/service_provider_configurations_controller_spec.rb +1 -0
  42. data/spec/models/scimitar/complex_types/address_spec.rb +3 -4
  43. data/spec/models/scimitar/lists/query_parser_spec.rb +70 -0
  44. data/spec/models/scimitar/resources/base_spec.rb +55 -13
  45. data/spec/models/scimitar/resources/base_validation_spec.rb +16 -3
  46. data/spec/models/scimitar/resources/mixin_spec.rb +781 -124
  47. data/spec/models/scimitar/schema/attribute_spec.rb +22 -0
  48. data/spec/models/scimitar/schema/user_spec.rb +2 -2
  49. data/spec/requests/active_record_backed_resources_controller_spec.rb +723 -40
  50. data/spec/requests/engine_spec.rb +75 -0
  51. data/spec/spec_helper.rb +10 -2
  52. data/spec/support/hash_with_indifferent_case_insensitive_access_spec.rb +108 -0
  53. metadata +42 -34
@@ -42,4 +42,79 @@ RSpec.describe Scimitar::Engine do
42
42
  expect(JSON.parse(response.body)['name']['familyName']).to eql('baz')
43
43
  end
44
44
  end # "context 'parameter parser' do"
45
+
46
+ # These are unit tests rather than request tests; seems like a reasonable
47
+ # place to put them in the absence of a standardised RSpec "engine" location.
48
+ #
49
+ context 'engine unit tests' do
50
+ around :each do | example |
51
+ license_schema = Class.new(Scimitar::Schema::Base) do
52
+ def initialize(options = {})
53
+ super(name: 'License', id: self.class.id(), description: 'Represents a License')
54
+ end
55
+ def self.id; 'urn:ietf:params:scim:schemas:license'; end
56
+ def self.scim_attributes; []; end
57
+ end
58
+
59
+ @license_resource = Class.new(Scimitar::Resources::Base) do
60
+ self.set_schema(license_schema)
61
+ def self.endpoint; '/License'; end
62
+ end
63
+
64
+ example.run()
65
+ ensure
66
+ Scimitar::Engine.reset_default_resources()
67
+ Scimitar::Engine.reset_custom_resources()
68
+ end
69
+
70
+ context '::resources, :add_custom_resource, ::set_default_resources' do
71
+ it 'returns default resources' do
72
+ expect(Scimitar::Engine.resources()).to match_array([Scimitar::Resources::User, Scimitar::Resources::Group])
73
+ end
74
+
75
+ it 'includes custom resources' do
76
+ Scimitar::Engine.add_custom_resource(@license_resource)
77
+ expect(Scimitar::Engine.resources()).to match_array([Scimitar::Resources::User, Scimitar::Resources::Group, @license_resource])
78
+ end
79
+
80
+ it 'notes changes to defaults' do
81
+ Scimitar::Engine.set_default_resources([Scimitar::Resources::User])
82
+ expect(Scimitar::Engine.resources()).to match_array([Scimitar::Resources::User])
83
+ end
84
+
85
+ it 'notes changes to defaults with custom resources added' do
86
+ Scimitar::Engine.set_default_resources([Scimitar::Resources::User])
87
+ Scimitar::Engine.add_custom_resource(@license_resource)
88
+ expect(Scimitar::Engine.resources()).to match_array([Scimitar::Resources::User, @license_resource])
89
+ end
90
+
91
+ it 'rejects bad defaults' do
92
+ expect {
93
+ Scimitar::Engine.set_default_resources([@license_resource])
94
+ }.to raise_error('Scimitar::Engine.set_default_resources: Only Scimitar::Resources::User, Scimitar::Resources::Group are supported')
95
+ end
96
+
97
+ it 'rejects empty defaults' do
98
+ expect {
99
+ Scimitar::Engine.set_default_resources([])
100
+ }.to raise_error('Scimitar::Engine.set_default_resources: At least one resource must be given')
101
+ end
102
+ end # "context '::resources, :add_custom_resource, ::set_default_resources' do"
103
+
104
+ context '#schemas' do
105
+ it 'returns schema instances from ::resources' do
106
+ expect(Scimitar::Engine).to receive(:resources).and_return([Scimitar::Resources::User, @license_resource])
107
+
108
+ schema_instances = Scimitar::Engine.schemas()
109
+ schema_classes = schema_instances.map(&:class)
110
+
111
+ expect(schema_classes).to match_array([
112
+ Scimitar::Schema::User,
113
+ ScimSchemaExtensions::User::Enterprise,
114
+ ScimSchemaExtensions::User::Manager,
115
+ @license_resource.schemas.first
116
+ ])
117
+ end
118
+ end # "context '#schemas' do"
119
+ end # "context 'engine unit tests' do"
45
120
  end
data/spec/spec_helper.rb CHANGED
@@ -19,7 +19,7 @@ require File.expand_path('../apps/dummy/config/environment', __FILE__)
19
19
  abort("The Rails environment is running in production mode!") if Rails.env.production?
20
20
 
21
21
  require 'rspec/rails'
22
- require 'byebug'
22
+ require 'debug'
23
23
  require 'scimitar'
24
24
 
25
25
  # ============================================================================
@@ -30,14 +30,22 @@ RSpec.configure do | config |
30
30
  config.disable_monkey_patching!
31
31
  config.infer_spec_type_from_file_location!
32
32
  config.filter_rails_from_backtrace!
33
+ config.raise_errors_for_deprecations!
33
34
 
34
35
  config.color = true
35
36
  config.tty = true
36
37
  config.order = :random
37
- config.fixture_path = "#{::Rails.root}/spec/fixtures"
38
+ config.fixture_paths = ["#{::Rails.root}/spec/fixtures"]
38
39
  config.use_transactional_fixtures = true
39
40
 
40
41
  Kernel.srand config.seed
42
+
43
+ config.around :each do | example |
44
+ original_engine_configuration = Scimitar.instance_variable_get('@engine_configuration')
45
+ example.run()
46
+ ensure
47
+ Scimitar.instance_variable_set('@engine_configuration', original_engine_configuration)
48
+ end
41
49
  end
42
50
 
43
51
  # ============================================================================
@@ -37,6 +37,114 @@ RSpec.describe Scimitar::Support::HashWithIndifferentCaseInsensitiveAccess do
37
37
  expect(subject()).to_not have_key('bar')
38
38
  end
39
39
  end # "context 'where keys set as symbols' do"
40
+
41
+ context 'access and merging' do
42
+ before :each do
43
+ @original_subject = subject().to_h().dup()
44
+ end
45
+
46
+ it 'returns keys as Strings' do
47
+ subject()[:foo] = 1
48
+ subject()[:BAR] = 2
49
+
50
+ expect(subject().keys).to match_array(@original_subject.keys + ['foo', 'BAR'])
51
+ end
52
+
53
+ it 'retains original case of keys' do
54
+ subject()[:foo ] = 1
55
+ subject()['FoO'] = 40 # (first-time-set case preservation test in passing)
56
+ subject()[:BAR ] = 2
57
+ subject()['Baz'] = 3
58
+
59
+ expectation = @original_subject.merge({
60
+ 'foo' => 40,
61
+ 'BAR' => 2,
62
+ 'Baz' => 3
63
+ })
64
+
65
+ expect(subject()).to eql(expectation)
66
+ end
67
+
68
+ it '#merge does not mutate the receiver and retains case of first-set keys' do
69
+ subject()[:foo] = 1
70
+ subject()[:BAR] = 2
71
+
72
+ pre_merge_subject = subject().dup()
73
+
74
+ result = subject().merge({:FOO => { 'onE' => 40 }, :Baz => 3})
75
+ expectation = @original_subject.merge({
76
+ 'foo' => { 'onE' => 40 },
77
+ 'BAR' => 2,
78
+ 'Baz' => 3
79
+ })
80
+
81
+ expect(subject()).to eql(pre_merge_subject)
82
+ expect(result).to eql(expectation)
83
+ end
84
+
85
+ it '#merge! mutates the receiver retains case of first-set keys' do
86
+ subject()[:foo] = 1
87
+ subject()[:BAR] = 2
88
+
89
+ subject().merge!({:FOO => { 'onE' => 40 }, :Baz => 3})
90
+
91
+ expectation = @original_subject.merge({
92
+ 'foo' => { 'onE' => 40 },
93
+ 'BAR' => 2,
94
+ 'Baz' => 3
95
+ })
96
+
97
+ expect(subject()).to eql(expectation)
98
+ end
99
+
100
+ it '#deep_merge does not mutate the receiver and retains nested key cases' do
101
+ subject()[:foo] = { :one => 10 }
102
+ subject()[:BAR] = 2
103
+
104
+ pre_merge_subject = subject().dup()
105
+
106
+ result = subject().deep_merge({:FOO => { 'ONE' => 40, :TWO => 20 }, :Baz => 3})
107
+ expectation = @original_subject.merge({
108
+ 'foo' => { 'one' => 40, 'TWO' => 20 },
109
+ 'BAR' => 2,
110
+ 'Baz' => 3
111
+ })
112
+
113
+ expect(subject()).to eql(pre_merge_subject)
114
+ expect(result).to eql(expectation)
115
+ end
116
+
117
+ it '#deep_merge! mutates the receiver and retains nested key cases' do
118
+ subject()[:foo] = { :one => 10 }
119
+ subject()[:BAR] = 2
120
+
121
+ subject().deep_merge!({:FOO => { 'ONE' => 40, :TWO => 20 }, :Baz => 3})
122
+
123
+ expectation = @original_subject.merge({
124
+ 'foo' => { 'one' => 40, 'TWO' => 20 },
125
+ 'BAR' => 2,
126
+ 'Baz' => 3
127
+ })
128
+
129
+ expect(subject()).to eql(expectation)
130
+ end
131
+
132
+ it 'retains indifferent behaviour after duplication' do
133
+ subject()[:foo] = { 'onE' => 40 }
134
+ subject()[:BAR] = 2
135
+
136
+ duplicate = subject().dup()
137
+ duplicate.merge!({ 'FOO' => true, 'baz' => 3 })
138
+
139
+ expectation = @original_subject.merge({
140
+ 'foo' => true,
141
+ 'BAR' => 2,
142
+ 'baz' => 3
143
+ })
144
+
145
+ expect(duplicate.to_h).to eql(expectation.to_h)
146
+ end
147
+ end # "context 'access and merging' do"
40
148
  end # "shared_examples 'an indifferent access, case insensitive Hash' do"
41
149
 
42
150
  context 'when created directly' do
metadata CHANGED
@@ -1,135 +1,136 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scimitar
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.0
4
+ version: 2.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - RIPA Global
8
8
  - Andrew David Hodgkinson
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2023-09-25 00:00:00.000000000 Z
11
+ date: 2025-03-05 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rails
16
15
  requirement: !ruby/object:Gem::Requirement
17
16
  requirements:
18
- - - "~>"
17
+ - - ">="
19
18
  - !ruby/object:Gem::Version
20
19
  version: '7.0'
21
20
  type: :runtime
22
21
  prerelease: false
23
22
  version_requirements: !ruby/object:Gem::Requirement
24
23
  requirements:
25
- - - "~>"
24
+ - - ">="
26
25
  - !ruby/object:Gem::Version
27
26
  version: '7.0'
28
27
  - !ruby/object:Gem::Dependency
29
- name: rake
28
+ name: debug
30
29
  requirement: !ruby/object:Gem::Requirement
31
30
  requirements:
32
31
  - - "~>"
33
32
  - !ruby/object:Gem::Version
34
- version: '13.0'
33
+ version: '1.10'
35
34
  type: :development
36
35
  prerelease: false
37
36
  version_requirements: !ruby/object:Gem::Requirement
38
37
  requirements:
39
38
  - - "~>"
40
39
  - !ruby/object:Gem::Version
41
- version: '13.0'
40
+ version: '1.10'
42
41
  - !ruby/object:Gem::Dependency
43
- name: pg
42
+ name: rake
44
43
  requirement: !ruby/object:Gem::Requirement
45
44
  requirements:
46
45
  - - "~>"
47
46
  - !ruby/object:Gem::Version
48
- version: '1.4'
47
+ version: '13.2'
49
48
  type: :development
50
49
  prerelease: false
51
50
  version_requirements: !ruby/object:Gem::Requirement
52
51
  requirements:
53
52
  - - "~>"
54
53
  - !ruby/object:Gem::Version
55
- version: '1.4'
54
+ version: '13.2'
56
55
  - !ruby/object:Gem::Dependency
57
- name: simplecov-rcov
56
+ name: pg
58
57
  requirement: !ruby/object:Gem::Requirement
59
58
  requirements:
60
59
  - - "~>"
61
60
  - !ruby/object:Gem::Version
62
- version: '0.3'
61
+ version: '1.5'
63
62
  type: :development
64
63
  prerelease: false
65
64
  version_requirements: !ruby/object:Gem::Requirement
66
65
  requirements:
67
66
  - - "~>"
68
67
  - !ruby/object:Gem::Version
69
- version: '0.3'
68
+ version: '1.5'
70
69
  - !ruby/object:Gem::Dependency
71
- name: rdoc
70
+ name: simplecov-rcov
72
71
  requirement: !ruby/object:Gem::Requirement
73
72
  requirements:
74
73
  - - "~>"
75
74
  - !ruby/object:Gem::Version
76
- version: '6.5'
75
+ version: '0.3'
77
76
  type: :development
78
77
  prerelease: false
79
78
  version_requirements: !ruby/object:Gem::Requirement
80
79
  requirements:
81
80
  - - "~>"
82
81
  - !ruby/object:Gem::Version
83
- version: '6.5'
82
+ version: '0.3'
84
83
  - !ruby/object:Gem::Dependency
85
- name: rspec-rails
84
+ name: rdoc
86
85
  requirement: !ruby/object:Gem::Requirement
87
86
  requirements:
88
87
  - - "~>"
89
88
  - !ruby/object:Gem::Version
90
- version: '6.0'
89
+ version: '6.12'
91
90
  type: :development
92
91
  prerelease: false
93
92
  version_requirements: !ruby/object:Gem::Requirement
94
93
  requirements:
95
94
  - - "~>"
96
95
  - !ruby/object:Gem::Version
97
- version: '6.0'
96
+ version: '6.12'
98
97
  - !ruby/object:Gem::Dependency
99
- name: byebug
98
+ name: rspec-rails
100
99
  requirement: !ruby/object:Gem::Requirement
101
100
  requirements:
102
101
  - - "~>"
103
102
  - !ruby/object:Gem::Version
104
- version: '11.1'
103
+ version: '7.1'
105
104
  type: :development
106
105
  prerelease: false
107
106
  version_requirements: !ruby/object:Gem::Requirement
108
107
  requirements:
109
108
  - - "~>"
110
109
  - !ruby/object:Gem::Version
111
- version: '11.1'
110
+ version: '7.1'
112
111
  - !ruby/object:Gem::Dependency
113
112
  name: doggo
114
113
  requirement: !ruby/object:Gem::Requirement
115
114
  requirements:
116
115
  - - "~>"
117
116
  - !ruby/object:Gem::Version
118
- version: '1.3'
117
+ version: '1.4'
119
118
  type: :development
120
119
  prerelease: false
121
120
  version_requirements: !ruby/object:Gem::Requirement
122
121
  requirements:
123
122
  - - "~>"
124
123
  - !ruby/object:Gem::Version
125
- version: '1.3'
124
+ version: '1.4'
126
125
  description: SCIM v2 support for Users and Groups in Ruby On Rails
127
126
  email:
128
- - dev@ripaglobal.com
127
+ - ahodgkin@rowing.org.uk
129
128
  executables: []
130
129
  extensions: []
131
130
  extra_rdoc_files: []
132
131
  files:
132
+ - LICENSE.txt
133
+ - README.md
133
134
  - Rakefile
134
135
  - app/controllers/scimitar/active_record_backed_resources_controller.rb
135
136
  - app/controllers/scimitar/application_controller.rb
@@ -193,9 +194,14 @@ files:
193
194
  - lib/scimitar.rb
194
195
  - lib/scimitar/engine.rb
195
196
  - lib/scimitar/support/hash_with_indifferent_case_insensitive_access.rb
197
+ - lib/scimitar/support/utilities.rb
196
198
  - lib/scimitar/version.rb
199
+ - spec/apps/dummy/app/controllers/custom_create_mock_users_controller.rb
197
200
  - spec/apps/dummy/app/controllers/custom_destroy_mock_users_controller.rb
201
+ - spec/apps/dummy/app/controllers/custom_replace_mock_users_controller.rb
198
202
  - spec/apps/dummy/app/controllers/custom_request_verifiers_controller.rb
203
+ - spec/apps/dummy/app/controllers/custom_save_mock_users_controller.rb
204
+ - spec/apps/dummy/app/controllers/custom_update_mock_users_controller.rb
199
205
  - spec/apps/dummy/app/controllers/mock_groups_controller.rb
200
206
  - spec/apps/dummy/app/controllers/mock_users_controller.rb
201
207
  - spec/apps/dummy/app/models/mock_group.rb
@@ -237,15 +243,14 @@ files:
237
243
  - spec/spec_helper.rb
238
244
  - spec/spec_helper_spec.rb
239
245
  - spec/support/hash_with_indifferent_case_insensitive_access_spec.rb
240
- homepage: https://www.ripaglobal.com/
246
+ homepage: https://github.com/pond/scimitar/
241
247
  licenses:
242
248
  - MIT
243
249
  metadata:
244
- homepage_uri: https://www.ripaglobal.com/
245
- source_code_uri: https://github.com/RIPAGlobal/scimitar/
246
- bug_tracker_uri: https://github.com/RIPAGlobal/scimitar/issues/
247
- changelog_uri: https://github.com/RIPAGlobal/scimitar/blob/master/CHANGELOG.md
248
- post_install_message:
250
+ homepage_uri: https://github.com/pond/scimitar/
251
+ source_code_uri: https://github.com/pond/scimitar/
252
+ bug_tracker_uri: https://github.com/pond/scimitar/issues/
253
+ changelog_uri: https://github.com/pond/scimitar/blob/main/CHANGELOG.md
249
254
  rdoc_options: []
250
255
  require_paths:
251
256
  - lib
@@ -260,13 +265,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
260
265
  - !ruby/object:Gem::Version
261
266
  version: '0'
262
267
  requirements: []
263
- rubygems_version: 3.4.4
264
- signing_key:
268
+ rubygems_version: 3.6.2
265
269
  specification_version: 4
266
270
  summary: SCIM v2 for Rails
267
271
  test_files:
272
+ - spec/apps/dummy/app/controllers/custom_create_mock_users_controller.rb
268
273
  - spec/apps/dummy/app/controllers/custom_destroy_mock_users_controller.rb
274
+ - spec/apps/dummy/app/controllers/custom_replace_mock_users_controller.rb
269
275
  - spec/apps/dummy/app/controllers/custom_request_verifiers_controller.rb
276
+ - spec/apps/dummy/app/controllers/custom_save_mock_users_controller.rb
277
+ - spec/apps/dummy/app/controllers/custom_update_mock_users_controller.rb
270
278
  - spec/apps/dummy/app/controllers/mock_groups_controller.rb
271
279
  - spec/apps/dummy/app/controllers/mock_users_controller.rb
272
280
  - spec/apps/dummy/app/models/mock_group.rb