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
@@ -4,7 +4,7 @@ RSpec.describe Scimitar::Resources::Base do
4
4
  context 'basic operation' do
5
5
  FirstCustomSchema = Class.new(Scimitar::Schema::Base) do
6
6
  def self.id
7
- 'custom-id'
7
+ 'urn:ietf:params:scim:schemas:custom-id'
8
8
  end
9
9
 
10
10
  def self.scim_attributes
@@ -14,7 +14,10 @@ RSpec.describe Scimitar::Resources::Base do
14
14
  ),
15
15
  Scimitar::Schema::Attribute.new(
16
16
  name: 'names', multiValued: true, complexType: Scimitar::ComplexTypes::Name, required: false
17
- )
17
+ ),
18
+ Scimitar::Schema::Attribute.new(
19
+ name: 'privateName', complexType: Scimitar::ComplexTypes::Name, required: false, returned: 'never'
20
+ ),
18
21
  ]
19
22
  end
20
23
  end
@@ -24,12 +27,24 @@ RSpec.describe Scimitar::Resources::Base do
24
27
  end
25
28
 
26
29
  context '#initialize' do
30
+ it 'accepts nil for non-required attributes' do
31
+ resource = CustomResourse.new(name: nil, names: nil, privateName: nil)
32
+
33
+ expect(resource.name).to be_nil
34
+ expect(resource.names).to be_nil
35
+ expect(resource.privateName).to be_nil
36
+ end
37
+
27
38
  shared_examples 'an initializer' do | force_upper_case: |
28
39
  it 'which builds the nested type' do
29
40
  attributes = {
30
41
  name: {
31
42
  givenName: 'John',
32
43
  familyName: 'Smith'
44
+ },
45
+ privateName: {
46
+ givenName: 'Alt John',
47
+ familyName: 'Alt Smith'
33
48
  }
34
49
  }
35
50
 
@@ -39,6 +54,9 @@ RSpec.describe Scimitar::Resources::Base do
39
54
  expect(resource.name.is_a?(Scimitar::ComplexTypes::Name)).to be(true)
40
55
  expect(resource.name.givenName).to eql('John')
41
56
  expect(resource.name.familyName).to eql('Smith')
57
+ expect(resource.privateName.is_a?(Scimitar::ComplexTypes::Name)).to be(true)
58
+ expect(resource.privateName.givenName).to eql('Alt John')
59
+ expect(resource.privateName.familyName).to eql('Alt Smith')
42
60
  end
43
61
 
44
62
  it 'which builds an array of nested resources' do
@@ -101,14 +119,38 @@ RSpec.describe Scimitar::Resources::Base do
101
119
  context '#as_json' do
102
120
  it 'renders the json with the resourceType' do
103
121
  resource = CustomResourse.new(name: {
104
- givenName: 'John',
122
+ givenName: 'John',
105
123
  familyName: 'Smith'
106
124
  })
107
125
 
108
126
  result = resource.as_json
109
- expect(result['schemas']).to eql(['custom-id'])
127
+
128
+ expect(result['schemas'] ).to eql(['urn:ietf:params:scim:schemas:custom-id'])
129
+ expect(result['meta']['resourceType']).to eql('CustomResourse')
130
+ expect(result['errors'] ).to be_nil
131
+ end
132
+
133
+ it 'excludes attributes that are flagged as do-not-return' do
134
+ resource = CustomResourse.new(
135
+ name: {
136
+ givenName: 'John',
137
+ familyName: 'Smith'
138
+ },
139
+ privateName: {
140
+ givenName: 'Alt John',
141
+ familyName: 'Alt Smith'
142
+ }
143
+ )
144
+
145
+ result = resource.as_json
146
+
147
+ expect(result['schemas'] ).to eql(['urn:ietf:params:scim:schemas:custom-id'])
110
148
  expect(result['meta']['resourceType']).to eql('CustomResourse')
111
- expect(result['errors']).to be_nil
149
+ expect(result['errors'] ).to be_nil
150
+ expect(result['name'] ).to be_present
151
+ expect(result['name']['givenName'] ).to eql('John')
152
+ expect(result['name']['familyName'] ).to eql('Smith')
153
+ expect(result['privateName'] ).to be_present
112
154
  end
113
155
  end # "context '#as_json' do"
114
156
 
@@ -253,7 +295,7 @@ RSpec.describe Scimitar::Resources::Base do
253
295
  context 'of custom schema' do
254
296
  ThirdCustomSchema = Class.new(Scimitar::Schema::Base) do
255
297
  def self.id
256
- 'custom-id'
298
+ 'urn:ietf:params:scim:schemas:custom-id'
257
299
  end
258
300
 
259
301
  def self.scim_attributes
@@ -263,7 +305,7 @@ RSpec.describe Scimitar::Resources::Base do
263
305
 
264
306
  ExtensionSchema = Class.new(Scimitar::Schema::Base) do
265
307
  def self.id
266
- 'extension-id'
308
+ 'urn:ietf:params:scim:schemas:extension'
267
309
  end
268
310
 
269
311
  def self.scim_attributes
@@ -291,13 +333,13 @@ RSpec.describe Scimitar::Resources::Base do
291
333
 
292
334
  context '#initialize' do
293
335
  it 'allows setting extension attributes' do
294
- resource = resource_class.new('extension-id' => {relationship: 'GAGA'})
336
+ resource = resource_class.new('urn:ietf:params:scim:schemas:extension' => {relationship: 'GAGA'})
295
337
  expect(resource.relationship).to eql('GAGA')
296
338
  end
297
339
 
298
340
  it 'allows setting complex extension attributes' do
299
341
  user_groups = [{ value: '123' }, { value: '456'}]
300
- resource = resource_class.new('extension-id' => {userGroups: user_groups})
342
+ resource = resource_class.new('urn:ietf:params:scim:schemas:extension' => {userGroups: user_groups})
301
343
  expect(resource.userGroups.map(&:value)).to eql(['123', '456'])
302
344
  end
303
345
  end # "context '#initialize' do"
@@ -306,8 +348,8 @@ RSpec.describe Scimitar::Resources::Base do
306
348
  it 'namespaces the extension attributes' do
307
349
  resource = resource_class.new(relationship: 'GAGA')
308
350
  hash = resource.as_json
309
- expect(hash["schemas"]).to eql(['custom-id', 'extension-id'])
310
- expect(hash["extension-id"]).to eql("relationship" => 'GAGA')
351
+ expect(hash["schemas"]).to eql(['urn:ietf:params:scim:schemas:custom-id', 'urn:ietf:params:scim:schemas:extension'])
352
+ expect(hash["urn:ietf:params:scim:schemas:extension"]).to eql("relationship" => 'GAGA')
311
353
  end
312
354
  end # "context '#as_json' do"
313
355
 
@@ -320,10 +362,10 @@ RSpec.describe Scimitar::Resources::Base do
320
362
 
321
363
  context 'validation' do
322
364
  it 'validates into custom schema' do
323
- resource = resource_class.new('extension-id' => {})
365
+ resource = resource_class.new('urn:ietf:params:scim:schemas:extension' => {})
324
366
  expect(resource.valid?).to eql(false)
325
367
 
326
- resource = resource_class.new('extension-id' => {relationship: 'GAGA'})
368
+ resource = resource_class.new('urn:ietf:params:scim:schemas:extension' => {relationship: 'GAGA'})
327
369
  expect(resource.relationship).to eql('GAGA')
328
370
  expect(resource.valid?).to eql(true)
329
371
  end
@@ -4,7 +4,20 @@ RSpec.describe Scimitar::Resources::Base do
4
4
  context '#valid?' do
5
5
  MyCustomSchema = Class.new(Scimitar::Schema::Base) do
6
6
  def self.id
7
- 'custom-id'
7
+ 'urn:ietf:params:scim:schemas:custom-id'
8
+ end
9
+
10
+ class NameWithRequirementsSchema < Scimitar::Schema::Base
11
+ def self.scim_attributes
12
+ @scim_attributes ||= [
13
+ Scimitar::Schema::Attribute.new(name: 'familyName', type: 'string', required: true),
14
+ Scimitar::Schema::Attribute.new(name: 'givenName', type: 'string', required: true),
15
+ ]
16
+ end
17
+ end
18
+
19
+ class NameWithRequirementsComplexType < Scimitar::ComplexTypes::Base
20
+ set_schema NameWithRequirementsSchema
8
21
  end
9
22
 
10
23
  def self.scim_attributes
@@ -16,10 +29,10 @@ RSpec.describe Scimitar::Resources::Base do
16
29
  name: 'enforce', type: 'boolean', required: true
17
30
  ),
18
31
  Scimitar::Schema::Attribute.new(
19
- name: 'complexName', complexType: Scimitar::ComplexTypes::Name, required: false
32
+ name: 'complexName', complexType: NameWithRequirementsComplexType, required: false
20
33
  ),
21
34
  Scimitar::Schema::Attribute.new(
22
- name: 'complexNames', complexType: Scimitar::ComplexTypes::Name, multiValued:true, required: false
35
+ name: 'complexNames', complexType: Scimitar::ComplexTypes::Name, multiValued: true, required: false
23
36
  ),
24
37
  Scimitar::Schema::Attribute.new(
25
38
  name: 'vdtpTestByEmail', complexType: Scimitar::ComplexTypes::Email, required: false