scimitar 1.8.2 → 2.0.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.
- checksums.yaml +4 -4
- data/app/controllers/scimitar/active_record_backed_resources_controller.rb +20 -94
- data/app/controllers/scimitar/application_controller.rb +13 -41
- data/app/controllers/scimitar/schemas_controller.rb +0 -5
- data/app/models/scimitar/complex_types/address.rb +6 -0
- data/app/models/scimitar/engine_configuration.rb +5 -13
- data/app/models/scimitar/error_response.rb +0 -12
- data/app/models/scimitar/lists/query_parser.rb +10 -25
- data/app/models/scimitar/resource_invalid_error.rb +1 -1
- data/app/models/scimitar/resources/base.rb +4 -17
- data/app/models/scimitar/resources/mixin.rb +42 -539
- data/app/models/scimitar/schema/address.rb +0 -1
- data/app/models/scimitar/schema/attribute.rb +5 -14
- data/app/models/scimitar/schema/base.rb +1 -1
- data/app/models/scimitar/schema/vdtp.rb +1 -1
- data/app/models/scimitar/service_provider_configuration.rb +3 -14
- data/config/initializers/scimitar.rb +3 -28
- data/lib/scimitar/support/hash_with_indifferent_case_insensitive_access.rb +10 -140
- data/lib/scimitar/version.rb +2 -2
- data/lib/scimitar.rb +2 -7
- data/spec/apps/dummy/app/controllers/mock_groups_controller.rb +1 -1
- data/spec/apps/dummy/app/models/mock_group.rb +1 -1
- data/spec/apps/dummy/app/models/mock_user.rb +8 -36
- data/spec/apps/dummy/config/application.rb +1 -0
- data/spec/apps/dummy/config/environments/test.rb +28 -5
- data/spec/apps/dummy/config/initializers/scimitar.rb +10 -61
- data/spec/apps/dummy/config/routes.rb +7 -28
- data/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb +1 -10
- data/spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb +3 -8
- data/spec/apps/dummy/db/schema.rb +4 -11
- data/spec/controllers/scimitar/application_controller_spec.rb +3 -126
- data/spec/controllers/scimitar/resource_types_controller_spec.rb +2 -2
- data/spec/controllers/scimitar/schemas_controller_spec.rb +2 -10
- data/spec/models/scimitar/complex_types/address_spec.rb +4 -3
- data/spec/models/scimitar/complex_types/email_spec.rb +2 -0
- data/spec/models/scimitar/lists/query_parser_spec.rb +9 -76
- data/spec/models/scimitar/resources/base_spec.rb +70 -216
- data/spec/models/scimitar/resources/base_validation_spec.rb +2 -27
- data/spec/models/scimitar/resources/mixin_spec.rb +129 -1447
- data/spec/models/scimitar/schema/attribute_spec.rb +3 -22
- data/spec/models/scimitar/schema/base_spec.rb +1 -1
- data/spec/models/scimitar/schema/user_spec.rb +0 -10
- data/spec/requests/active_record_backed_resources_controller_spec.rb +68 -787
- data/spec/requests/application_controller_spec.rb +3 -16
- data/spec/spec_helper.rb +0 -8
- data/spec/support/hash_with_indifferent_case_insensitive_access_spec.rb +0 -108
- metadata +14 -25
- data/LICENSE.txt +0 -21
- data/README.md +0 -710
- data/lib/scimitar/support/utilities.rb +0 -51
- data/spec/apps/dummy/app/controllers/custom_create_mock_users_controller.rb +0 -25
- data/spec/apps/dummy/app/controllers/custom_replace_mock_users_controller.rb +0 -25
- data/spec/apps/dummy/app/controllers/custom_save_mock_users_controller.rb +0 -24
- data/spec/apps/dummy/app/controllers/custom_update_mock_users_controller.rb +0 -25
@@ -14,10 +14,7 @@ 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
|
-
)
|
18
|
-
Scimitar::Schema::Attribute.new(
|
19
|
-
name: 'privateName', complexType: Scimitar::ComplexTypes::Name, required: false, returned: 'never'
|
20
|
-
),
|
17
|
+
)
|
21
18
|
]
|
22
19
|
end
|
23
20
|
end
|
@@ -27,24 +24,12 @@ RSpec.describe Scimitar::Resources::Base do
|
|
27
24
|
end
|
28
25
|
|
29
26
|
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
|
-
|
38
27
|
shared_examples 'an initializer' do | force_upper_case: |
|
39
28
|
it 'which builds the nested type' do
|
40
29
|
attributes = {
|
41
30
|
name: {
|
42
31
|
givenName: 'John',
|
43
32
|
familyName: 'Smith'
|
44
|
-
},
|
45
|
-
privateName: {
|
46
|
-
givenName: 'Alt John',
|
47
|
-
familyName: 'Alt Smith'
|
48
33
|
}
|
49
34
|
}
|
50
35
|
|
@@ -54,9 +39,6 @@ RSpec.describe Scimitar::Resources::Base do
|
|
54
39
|
expect(resource.name.is_a?(Scimitar::ComplexTypes::Name)).to be(true)
|
55
40
|
expect(resource.name.givenName).to eql('John')
|
56
41
|
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')
|
60
42
|
end
|
61
43
|
|
62
44
|
it 'which builds an array of nested resources' do
|
@@ -119,38 +101,14 @@ RSpec.describe Scimitar::Resources::Base do
|
|
119
101
|
context '#as_json' do
|
120
102
|
it 'renders the json with the resourceType' do
|
121
103
|
resource = CustomResourse.new(name: {
|
122
|
-
givenName:
|
104
|
+
givenName: 'John',
|
123
105
|
familyName: 'Smith'
|
124
106
|
})
|
125
107
|
|
126
108
|
result = resource.as_json
|
127
|
-
|
128
|
-
expect(result['schemas'] ).to eql(['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(['custom-id'])
|
109
|
+
expect(result['schemas']).to eql(['custom-id'])
|
148
110
|
expect(result['meta']['resourceType']).to eql('CustomResourse')
|
149
|
-
expect(result['errors']
|
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
|
111
|
+
expect(result['errors']).to be_nil
|
154
112
|
end
|
155
113
|
end # "context '#as_json' do"
|
156
114
|
|
@@ -292,194 +250,90 @@ RSpec.describe Scimitar::Resources::Base do
|
|
292
250
|
end # "context 'dynamic setters based on schema' do"
|
293
251
|
|
294
252
|
context 'schema extension' do
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
'custom-id'
|
299
|
-
end
|
300
|
-
|
301
|
-
def self.scim_attributes
|
302
|
-
[ Scimitar::Schema::Attribute.new(name: 'name', type: 'string') ]
|
303
|
-
end
|
253
|
+
ThirdCustomSchema = Class.new(Scimitar::Schema::Base) do
|
254
|
+
def self.id
|
255
|
+
'custom-id'
|
304
256
|
end
|
305
257
|
|
306
|
-
|
307
|
-
|
308
|
-
'extension-id'
|
309
|
-
end
|
310
|
-
|
311
|
-
def self.scim_attributes
|
312
|
-
[
|
313
|
-
Scimitar::Schema::Attribute.new(name: 'relationship', type: 'string', required: true),
|
314
|
-
Scimitar::Schema::Attribute.new(name: "userGroups", multiValued: true, complexType: Scimitar::ComplexTypes::ReferenceGroup, mutability: "writeOnly")
|
315
|
-
]
|
316
|
-
end
|
258
|
+
def self.scim_attributes
|
259
|
+
[ Scimitar::Schema::Attribute.new(name: 'name', type: 'string') ]
|
317
260
|
end
|
261
|
+
end
|
318
262
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
def self.endpoint
|
325
|
-
'/gaga'
|
326
|
-
end
|
327
|
-
|
328
|
-
def self.resource_type_id
|
329
|
-
'CustomResource'
|
330
|
-
end
|
331
|
-
end
|
332
|
-
}
|
333
|
-
|
334
|
-
context '#initialize' do
|
335
|
-
it 'allows setting extension attributes' do
|
336
|
-
resource = resource_class.new('extension-id' => {relationship: 'GAGA'})
|
337
|
-
expect(resource.relationship).to eql('GAGA')
|
338
|
-
end
|
339
|
-
|
340
|
-
it 'allows setting complex extension attributes' do
|
341
|
-
user_groups = [{ value: '123' }, { value: '456'}]
|
342
|
-
resource = resource_class.new('extension-id' => {userGroups: user_groups})
|
343
|
-
expect(resource.userGroups.map(&:value)).to eql(['123', '456'])
|
344
|
-
end
|
345
|
-
end # "context '#initialize' do"
|
346
|
-
|
347
|
-
context '#as_json' do
|
348
|
-
it 'namespaces the extension attributes' do
|
349
|
-
resource = resource_class.new(relationship: 'GAGA')
|
350
|
-
hash = resource.as_json
|
351
|
-
expect(hash["schemas"]).to eql(['custom-id', 'extension-id'])
|
352
|
-
expect(hash["extension-id"]).to eql("relationship" => 'GAGA')
|
353
|
-
end
|
354
|
-
end # "context '#as_json' do"
|
355
|
-
|
356
|
-
context '.resource_type' do
|
357
|
-
it 'appends the extension schemas' do
|
358
|
-
resource_type = resource_class.resource_type('http://gaga')
|
359
|
-
expect(resource_type.meta.location).to eql('http://gaga')
|
360
|
-
expect(resource_type.schemaExtensions.count).to eql(1)
|
361
|
-
end
|
362
|
-
|
363
|
-
context 'validation' do
|
364
|
-
it 'validates into custom schema' do
|
365
|
-
resource = resource_class.new('extension-id' => {})
|
366
|
-
expect(resource.valid?).to eql(false)
|
367
|
-
|
368
|
-
resource = resource_class.new('extension-id' => {relationship: 'GAGA'})
|
369
|
-
expect(resource.relationship).to eql('GAGA')
|
370
|
-
expect(resource.valid?).to eql(true)
|
371
|
-
end
|
372
|
-
end # context 'validation'
|
373
|
-
end # "context '.resource_type' do"
|
263
|
+
ExtensionSchema = Class.new(Scimitar::Schema::Base) do
|
264
|
+
def self.id
|
265
|
+
'extension-id'
|
266
|
+
end
|
374
267
|
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
expect(found.name).to eql('name')
|
380
|
-
expect(found.type).to eql('string')
|
381
|
-
end
|
268
|
+
def self.scim_attributes
|
269
|
+
[ Scimitar::Schema::Attribute.new(name: 'relationship', type: 'string', required: true) ]
|
270
|
+
end
|
271
|
+
end
|
382
272
|
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
expect(found.type).to eql('string')
|
388
|
-
end
|
389
|
-
end # "context '.find_attribute' do"
|
390
|
-
end # "context 'of custom schema' do"
|
273
|
+
let(:resource_class) {
|
274
|
+
Class.new(Scimitar::Resources::Base) do
|
275
|
+
set_schema ThirdCustomSchema
|
276
|
+
extend_schema ExtensionSchema
|
391
277
|
|
392
|
-
|
393
|
-
|
394
|
-
def self.id
|
395
|
-
'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User'
|
278
|
+
def self.endpoint
|
279
|
+
'/gaga'
|
396
280
|
end
|
397
281
|
|
398
|
-
def self.
|
399
|
-
|
400
|
-
Scimitar::Schema::Attribute.new(name: 'organization', type: 'string'),
|
401
|
-
Scimitar::Schema::Attribute.new(name: 'department', type: 'string')
|
402
|
-
]
|
282
|
+
def self.resource_type_id
|
283
|
+
'CustomResource'
|
403
284
|
end
|
404
285
|
end
|
286
|
+
}
|
405
287
|
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
'/Users'
|
413
|
-
end
|
414
|
-
|
415
|
-
def self.resource_type_id
|
416
|
-
'User'
|
417
|
-
end
|
418
|
-
end
|
419
|
-
}
|
420
|
-
|
421
|
-
context '#initialize' do
|
422
|
-
it 'allows setting extension attributes' do
|
423
|
-
resource = resource_class.new('urn:ietf:params:scim:schemas:extension:enterprise:2.0:User' => {organization: 'SOMEORG', department: 'SOMEDPT'})
|
288
|
+
context '#initialize' do
|
289
|
+
it 'allows setting extension attributes' do
|
290
|
+
resource = resource_class.new('extension-id' => {relationship: 'GAGA'})
|
291
|
+
expect(resource.relationship).to eql('GAGA')
|
292
|
+
end
|
293
|
+
end # "context '#initialize' do"
|
424
294
|
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
295
|
+
context '#as_json' do
|
296
|
+
it 'namespaces the extension attributes' do
|
297
|
+
resource = resource_class.new(relationship: 'GAGA')
|
298
|
+
hash = resource.as_json
|
299
|
+
expect(hash["schemas"]).to eql(['custom-id', 'extension-id'])
|
300
|
+
expect(hash["extension-id"]).to eql("relationship" => 'GAGA')
|
301
|
+
end
|
302
|
+
end # "context '#as_json' do"
|
429
303
|
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
304
|
+
context '.resource_type' do
|
305
|
+
it 'appends the extension schemas' do
|
306
|
+
resource_type = resource_class.resource_type('http://gaga')
|
307
|
+
expect(resource_type.meta.location).to eql('http://gaga')
|
308
|
+
expect(resource_type.schemaExtensions.count).to eql(1)
|
309
|
+
end
|
434
310
|
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
311
|
+
context 'validation' do
|
312
|
+
it 'validates into custom schema' do
|
313
|
+
resource = resource_class.new('extension-id' => {})
|
314
|
+
expect(resource.valid?).to eql(false)
|
439
315
|
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
expect(resource_type.meta.location).to eql('http://example.com')
|
444
|
-
expect(resource_type.schemaExtensions.count).to eql(1)
|
316
|
+
resource = resource_class.new('extension-id' => {relationship: 'GAGA'})
|
317
|
+
expect(resource.relationship).to eql('GAGA')
|
318
|
+
expect(resource.valid?).to eql(true)
|
445
319
|
end
|
320
|
+
end # context 'validation'
|
321
|
+
end # "context '.resource_type' do"
|
446
322
|
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
userName: 'SOMEUSR',
|
455
|
-
organization: 'SOMEORG',
|
456
|
-
department: 'SOMEDPT'
|
457
|
-
}
|
458
|
-
)
|
459
|
-
|
460
|
-
expect(resource.organization).to eql('SOMEORG')
|
461
|
-
expect(resource.department ).to eql('SOMEDPT')
|
462
|
-
expect(resource.valid? ).to eql(true)
|
463
|
-
end
|
464
|
-
end # context 'validation'
|
465
|
-
end # "context '.resource_type' do"
|
466
|
-
|
467
|
-
context '.find_attribute' do
|
468
|
-
it 'finds in first schema' do
|
469
|
-
found = resource_class().find_attribute('userName') # Defined in Scimitar::Schema::User
|
470
|
-
|
471
|
-
expect(found).to be_present
|
472
|
-
expect(found.name).to eql('userName')
|
473
|
-
expect(found.type).to eql('string')
|
474
|
-
end
|
323
|
+
context '.find_attribute' do
|
324
|
+
it 'finds in first schema' do
|
325
|
+
found = resource_class().find_attribute('name') # Defined in ThirdCustomSchema
|
326
|
+
expect(found).to be_present
|
327
|
+
expect(found.name).to eql('name')
|
328
|
+
expect(found.type).to eql('string')
|
329
|
+
end
|
475
330
|
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
end # "context 'of core schema' do"
|
331
|
+
it 'finds across schemas' do
|
332
|
+
found = resource_class().find_attribute('relationship') # Defined in ExtensionSchema
|
333
|
+
expect(found).to be_present
|
334
|
+
expect(found.name).to eql('relationship')
|
335
|
+
expect(found.type).to eql('string')
|
336
|
+
end
|
337
|
+
end # "context '.find_attribute' do"
|
484
338
|
end # "context 'schema extension' do"
|
485
339
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe Scimitar::Resources::Base do
|
4
|
+
|
4
5
|
context '#valid?' do
|
5
6
|
MyCustomSchema = Class.new(Scimitar::Schema::Base) do
|
6
7
|
def self.id
|
@@ -20,9 +21,6 @@ RSpec.describe Scimitar::Resources::Base do
|
|
20
21
|
),
|
21
22
|
Scimitar::Schema::Attribute.new(
|
22
23
|
name: 'complexNames', complexType: Scimitar::ComplexTypes::Name, multiValued:true, required: false
|
23
|
-
),
|
24
|
-
Scimitar::Schema::Attribute.new(
|
25
|
-
name: 'vdtpTestByEmail', complexType: Scimitar::ComplexTypes::Email, required: false
|
26
24
|
)
|
27
25
|
]
|
28
26
|
end
|
@@ -59,28 +57,5 @@ RSpec.describe Scimitar::Resources::Base do
|
|
59
57
|
expect(resource.valid?).to be(false)
|
60
58
|
expect(resource.errors.full_messages).to match_array(["Complexnames has to follow the complexType format.", "Complexnames familyname has the wrong type. It has to be a(n) string."])
|
61
59
|
end
|
62
|
-
|
63
|
-
context 'configuration of required values in VDTP schema' do
|
64
|
-
around :each do | example |
|
65
|
-
original_configuration = Scimitar.engine_configuration.optional_value_fields_required
|
66
|
-
Scimitar::Schema::Email.instance_variable_set('@scim_attributes', nil)
|
67
|
-
example.run()
|
68
|
-
ensure
|
69
|
-
Scimitar.engine_configuration.optional_value_fields_required = original_configuration
|
70
|
-
Scimitar::Schema::Email.instance_variable_set('@scim_attributes', nil)
|
71
|
-
end
|
72
|
-
|
73
|
-
it 'requires a value by default' do
|
74
|
-
resource = MyCustomResource.new(vdtpTestByEmail: { value: nil }, enforce: false)
|
75
|
-
expect(resource.valid?).to be(false)
|
76
|
-
expect(resource.errors.full_messages).to match_array(['Vdtptestbyemail value is required'])
|
77
|
-
end
|
78
|
-
|
79
|
-
it 'can be configured for optional values' do
|
80
|
-
Scimitar.engine_configuration.optional_value_fields_required = false
|
81
|
-
resource = MyCustomResource.new(vdtpTestByEmail: { value: nil }, enforce: false)
|
82
|
-
expect(resource.valid?).to be(true)
|
83
|
-
end
|
84
|
-
end # "context 'configuration of required values in VDTP schema' do"
|
85
|
-
end # "context '#valid?' do"
|
60
|
+
end
|
86
61
|
end
|