scimitar 1.10.0 → 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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/scimitar/active_record_backed_resources_controller.rb +23 -98
  3. data/app/controllers/scimitar/application_controller.rb +13 -41
  4. data/app/controllers/scimitar/resource_types_controller.rb +2 -0
  5. data/app/controllers/scimitar/resources_controller.rb +2 -0
  6. data/app/controllers/scimitar/schemas_controller.rb +3 -366
  7. data/app/controllers/scimitar/service_provider_configurations_controller.rb +1 -0
  8. data/app/models/scimitar/complex_types/address.rb +6 -0
  9. data/app/models/scimitar/engine_configuration.rb +5 -15
  10. data/app/models/scimitar/error_response.rb +0 -12
  11. data/app/models/scimitar/lists/query_parser.rb +13 -113
  12. data/app/models/scimitar/resource_invalid_error.rb +1 -1
  13. data/app/models/scimitar/resources/base.rb +9 -53
  14. data/app/models/scimitar/resources/mixin.rb +59 -646
  15. data/app/models/scimitar/schema/address.rb +0 -1
  16. data/app/models/scimitar/schema/attribute.rb +5 -14
  17. data/app/models/scimitar/schema/base.rb +1 -1
  18. data/app/models/scimitar/schema/name.rb +2 -2
  19. data/app/models/scimitar/schema/user.rb +10 -10
  20. data/app/models/scimitar/schema/vdtp.rb +1 -1
  21. data/app/models/scimitar/service_provider_configuration.rb +3 -14
  22. data/config/initializers/scimitar.rb +3 -69
  23. data/lib/scimitar/engine.rb +12 -57
  24. data/lib/scimitar/support/hash_with_indifferent_case_insensitive_access.rb +10 -140
  25. data/lib/scimitar/version.rb +2 -2
  26. data/lib/scimitar.rb +2 -7
  27. data/spec/apps/dummy/app/controllers/mock_groups_controller.rb +1 -1
  28. data/spec/apps/dummy/app/models/mock_group.rb +1 -1
  29. data/spec/apps/dummy/app/models/mock_user.rb +9 -52
  30. data/spec/apps/dummy/config/application.rb +1 -0
  31. data/spec/apps/dummy/config/environments/test.rb +28 -5
  32. data/spec/apps/dummy/config/initializers/scimitar.rb +10 -90
  33. data/spec/apps/dummy/config/routes.rb +7 -28
  34. data/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb +1 -11
  35. data/spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb +3 -8
  36. data/spec/apps/dummy/db/schema.rb +4 -12
  37. data/spec/controllers/scimitar/application_controller_spec.rb +3 -126
  38. data/spec/controllers/scimitar/resource_types_controller_spec.rb +2 -2
  39. data/spec/controllers/scimitar/schemas_controller_spec.rb +48 -344
  40. data/spec/models/scimitar/complex_types/address_spec.rb +4 -3
  41. data/spec/models/scimitar/complex_types/email_spec.rb +2 -0
  42. data/spec/models/scimitar/lists/query_parser_spec.rb +9 -146
  43. data/spec/models/scimitar/resources/base_spec.rb +71 -217
  44. data/spec/models/scimitar/resources/base_validation_spec.rb +5 -43
  45. data/spec/models/scimitar/resources/mixin_spec.rb +129 -1508
  46. data/spec/models/scimitar/schema/attribute_spec.rb +3 -22
  47. data/spec/models/scimitar/schema/base_spec.rb +1 -1
  48. data/spec/models/scimitar/schema/user_spec.rb +2 -12
  49. data/spec/requests/active_record_backed_resources_controller_spec.rb +66 -1016
  50. data/spec/requests/application_controller_spec.rb +3 -16
  51. data/spec/requests/engine_spec.rb +0 -75
  52. data/spec/spec_helper.rb +1 -9
  53. data/spec/support/hash_with_indifferent_case_insensitive_access_spec.rb +0 -108
  54. metadata +26 -37
  55. data/LICENSE.txt +0 -21
  56. data/README.md +0 -717
  57. data/lib/scimitar/support/utilities.rb +0 -111
  58. data/spec/apps/dummy/app/controllers/custom_create_mock_users_controller.rb +0 -25
  59. data/spec/apps/dummy/app/controllers/custom_replace_mock_users_controller.rb +0 -25
  60. data/spec/apps/dummy/app/controllers/custom_save_mock_users_controller.rb +0 -24
  61. data/spec/apps/dummy/app/controllers/custom_update_mock_users_controller.rb +0 -25
@@ -60,15 +60,6 @@ RSpec.describe Scimitar::Lists::QueryParser do
60
60
  expect(%Q("O'Malley")).to eql(tree[2])
61
61
  end
62
62
 
63
- it "extended attribute equals" do
64
- @instance.parse(%Q(primaryEmail eq "foo@bar.com"))
65
-
66
- rpn = @instance.rpn
67
- expect('primaryEmail').to eql(rpn[0])
68
- expect(%Q("foo@bar.com")).to eql(rpn[1])
69
- expect('eq').to eql(rpn[2])
70
- end
71
-
72
63
  it "user name starts with" do
73
64
  @instance.parse(%Q(userName sw "J"))
74
65
 
@@ -346,67 +337,6 @@ RSpec.describe Scimitar::Lists::QueryParser do
346
337
  result = @instance.send(:flatten_filter, 'emails[type eq "work" and value co "@example.com" ] or userType eq "Admin" or ims[type eq "xmpp" and value co "@foo.com"]')
347
338
  expect(result).to eql('emails.type eq "work" and emails.value co "@example.com" or userType eq "Admin" or ims.type eq "xmpp" and ims.value co "@foo.com"')
348
339
  end
349
-
350
- it 'handles an example previously described as unsupported in README.md' do
351
- result = @instance.send(:flatten_filter, 'filter=userType eq "Employee" and emails[type eq "work" and value co "@example.com"]')
352
- expect(result).to eql('filter=userType eq "Employee" and emails.type eq "work" and emails.value co "@example.com"')
353
- end
354
-
355
- # https://github.com/RIPAGlobal/scimitar/issues/116
356
- #
357
- context 'with schema IDs (GitHub issue #116)' do
358
- it 'handles simple attributes' do
359
- result = @instance.send(:flatten_filter, 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:employeeId eq "gsar"')
360
- expect(result).to eql('employeeId eq "gsar"')
361
- end
362
-
363
- it 'handles dotted attribute paths' do
364
- result = @instance.send(:flatten_filter, 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:imaginary.path eq "gsar"')
365
- expect(result).to eql('imaginary.path eq "gsar"')
366
- end
367
-
368
- it 'replaces all examples' do
369
- result = @instance.send(:flatten_filter, 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:employeeId eq "gsar" or urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:imaginary.path eq "gsar"')
370
- expect(result).to eql('employeeId eq "gsar" or imaginary.path eq "gsar"')
371
- end
372
-
373
- it 'handles the square bracket form with schema ID at the root' do
374
- result = @instance.send(:flatten_filter, 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User[employeeId eq "gsar"')
375
- expect(result).to eql('employeeId eq "gsar"')
376
- end
377
-
378
- it 'handles the square bracket form with schema ID and attribute at the root' do
379
- result = @instance.send(:flatten_filter, 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:imaginary[path eq "gsar"')
380
- expect(result).to eql('imaginary.path eq "gsar"')
381
- end
382
- end
383
-
384
- # https://github.com/RIPAGlobal/scimitar/issues/115
385
- #
386
- context 'broken filters from Microsoft (GitHub issue #115)' do
387
- it 'work with "eq"' do
388
- result = @instance.send(:flatten_filter, 'emails[type eq "work"].value eq "foo@bar.com"')
389
- expect(result).to eql('emails.type eq "work" and emails.value eq "foo@bar.com"')
390
- end
391
-
392
- it 'work with "ne"' do # (just check a couple of operators, not all!)
393
- result = @instance.send(:flatten_filter, 'emails[type eq "work"].value ne "foo@bar.com"')
394
- expect(result).to eql('emails.type eq "work" and emails.value ne "foo@bar.com"')
395
- end
396
-
397
- it 'preserve input case' do
398
- result = @instance.send(:flatten_filter, 'emaiLs[TYPE eq "work"].valUE eq "FOO@bar.com"')
399
- expect(result).to eql('emaiLs.TYPE eq "work" and emaiLs.valUE eq "FOO@bar.com"')
400
- end
401
-
402
- # At the time of writing, this was used in a "belt and braces" request
403
- # spec in 'active_record_backed_resources_controller_spec.rb'.
404
- #
405
- it 'handles more complex, hypothetical cases' do
406
- result = @instance.send(:flatten_filter, 'name[givenName eq "FOO"].familyName pr and emails ne "home_1@test.com"')
407
- expect(result).to eql('name.givenName eq "FOO" and name.familyName pr and emails ne "home_1@test.com"')
408
- end
409
- end # "context 'broken filters from Microsoft' do"
410
340
  end # "context 'when flattening is needed' do"
411
341
 
412
342
  context 'with bad filters' do
@@ -475,19 +405,19 @@ RSpec.describe Scimitar::Lists::QueryParser do
475
405
  query = @instance.to_activerecord_query(MockUser.all)
476
406
 
477
407
  expect(query.count).to eql(1)
478
- expect(query.pluck(:primary_key)).to eql([user_1.primary_key])
408
+ expect(query.pluck(:id)).to eql([user_1.id])
479
409
 
480
410
  @instance.parse('name.givenName sw J') # First name starts with 'J'
481
411
  query = @instance.to_activerecord_query(MockUser.all)
482
412
 
483
413
  expect(query.count).to eql(2)
484
- expect(query.pluck(:primary_key)).to match_array([user_1.primary_key, user_2.primary_key])
414
+ expect(query.pluck(:id)).to match_array([user_1.id, user_2.id])
485
415
 
486
416
  @instance.parse('name.familyName ew he') # Last name ends with 'he'
487
417
  query = @instance.to_activerecord_query(MockUser.all)
488
418
 
489
419
  expect(query.count).to eql(1)
490
- expect(query.pluck(:primary_key)).to eql([user_2.primary_key])
420
+ expect(query.pluck(:id)).to eql([user_2.id])
491
421
 
492
422
  # Test presence
493
423
 
@@ -495,7 +425,7 @@ RSpec.describe Scimitar::Lists::QueryParser do
495
425
  query = @instance.to_activerecord_query(MockUser.all)
496
426
 
497
427
  expect(query.count).to eql(2)
498
- expect(query.pluck(:primary_key)).to match_array([user_1.primary_key, user_2.primary_key])
428
+ expect(query.pluck(:id)).to match_array([user_1.id, user_2.id])
499
429
 
500
430
  # Test a simple not-equals, but use a custom starting scope. Note that
501
431
  # the query would find "user_3" *except* there is no first name defined
@@ -505,7 +435,7 @@ RSpec.describe Scimitar::Lists::QueryParser do
505
435
  query = @instance.to_activerecord_query(MockUser.where.not('first_name' => 'John'))
506
436
 
507
437
  expect(query.count).to eql(1)
508
- expect(query.pluck(:primary_key)).to match_array([user_1.primary_key])
438
+ expect(query.pluck(:id)).to match_array([user_1.id])
509
439
  end
510
440
 
511
441
  context 'when mapped to multiple columns' do
@@ -551,66 +481,6 @@ RSpec.describe Scimitar::Lists::QueryParser do
551
481
  end
552
482
  end # "context 'when instructed to ignore an attribute' do"
553
483
 
554
- context 'when an arel column is mapped' do
555
- let(:scope_with_groups) { MockUser.left_joins(:mock_groups) }
556
-
557
- context 'with binary operators' do
558
- it 'reads across all using OR' do
559
- @instance.parse('groups eq "12345"')
560
- query = @instance.to_activerecord_query(scope_with_groups)
561
-
562
- expect(query.to_sql).to eql(<<~SQL.squish)
563
- SELECT "mock_users".*
564
- FROM "mock_users"
565
- LEFT OUTER JOIN "mock_groups_users" ON "mock_groups_users"."mock_user_id" = "mock_users"."primary_key"
566
- LEFT OUTER JOIN "mock_groups" ON "mock_groups"."id" = "mock_groups_users"."mock_group_id"
567
- WHERE "mock_groups"."id" ILIKE 12345
568
- SQL
569
- end
570
-
571
- it 'works with other query elements using correct precedence' do
572
- @instance.parse('groups eq "12345" and emails eq "any@test.com"')
573
- query = @instance.to_activerecord_query(scope_with_groups)
574
-
575
- expect(query.to_sql).to eql(<<~SQL.squish)
576
- SELECT "mock_users".*
577
- FROM "mock_users"
578
- LEFT OUTER JOIN "mock_groups_users" ON "mock_groups_users"."mock_user_id" = "mock_users"."primary_key"
579
- LEFT OUTER JOIN "mock_groups" ON "mock_groups"."id" = "mock_groups_users"."mock_group_id"
580
- WHERE "mock_groups"."id" ILIKE 12345 AND ("mock_users"."work_email_address" ILIKE 'any@test.com' OR "mock_users"."home_email_address" ILIKE 'any@test.com')
581
- SQL
582
- end
583
- end # "context 'with binary operators' do"
584
-
585
- context 'with unary operators' do
586
- it 'reads across all using OR' do
587
- @instance.parse('groups pr')
588
- query = @instance.to_activerecord_query(scope_with_groups)
589
-
590
- expect(query.to_sql).to eql(<<~SQL.squish)
591
- SELECT "mock_users".*
592
- FROM "mock_users"
593
- LEFT OUTER JOIN "mock_groups_users" ON "mock_groups_users"."mock_user_id" = "mock_users"."primary_key"
594
- LEFT OUTER JOIN "mock_groups" ON "mock_groups"."id" = "mock_groups_users"."mock_group_id"
595
- WHERE ("mock_groups"."id" != NULL AND "mock_groups"."id" IS NOT NULL)
596
- SQL
597
- end
598
-
599
- it 'works with other query elements using correct precedence' do
600
- @instance.parse('name.familyName eq "John" and groups pr')
601
- query = @instance.to_activerecord_query(scope_with_groups)
602
-
603
- expect(query.to_sql).to eql(<<~SQL.squish)
604
- SELECT "mock_users".*
605
- FROM "mock_users"
606
- LEFT OUTER JOIN "mock_groups_users" ON "mock_groups_users"."mock_user_id" = "mock_users"."primary_key"
607
- LEFT OUTER JOIN "mock_groups" ON "mock_groups"."id" = "mock_groups_users"."mock_group_id"
608
- WHERE "mock_users"."last_name" ILIKE 'John' AND ("mock_groups"."id" != NULL AND "mock_groups"."id" IS NOT NULL)
609
- SQL
610
- end
611
- end # "context 'with unary operators' do
612
- end # "context 'when an arel column is mapped' do"
613
-
614
484
  context 'with complex cases' do
615
485
  context 'using AND' do
616
486
  it 'generates expected SQL' do
@@ -629,7 +499,7 @@ RSpec.describe Scimitar::Lists::QueryParser do
629
499
  query = @instance.to_activerecord_query(MockUser.all)
630
500
 
631
501
  expect(query.count).to eql(1)
632
- expect(query.pluck(:primary_key)).to match_array([user_2.primary_key])
502
+ expect(query.pluck(:id)).to match_array([user_2.id])
633
503
  end
634
504
  end # "context 'simple AND' do"
635
505
 
@@ -650,7 +520,7 @@ RSpec.describe Scimitar::Lists::QueryParser do
650
520
  query = @instance.to_activerecord_query(MockUser.all)
651
521
 
652
522
  expect(query.count).to eql(2)
653
- expect(query.pluck(:primary_key)).to match_array([user_1.primary_key, user_2.primary_key])
523
+ expect(query.pluck(:id)).to match_array([user_1.id, user_2.id])
654
524
  end
655
525
  end # "context 'simple OR' do"
656
526
 
@@ -662,13 +532,6 @@ RSpec.describe Scimitar::Lists::QueryParser do
662
532
  expect(query.to_sql).to eql(%q{SELECT "mock_users".* FROM "mock_users" WHERE "mock_users"."first_name" ILIKE 'Jane' AND ("mock_users"."last_name" ILIKE '%avi%' OR "mock_users"."last_name" ILIKE '%ith')})
663
533
  end
664
534
 
665
- it 'combined parentheses generates expected SQL' do
666
- @instance.parse('(name.givenName eq "Jane" OR name.givenName eq "Jaden") and (name.familyName co "avi" or name.familyName ew "ith")')
667
- query = @instance.to_activerecord_query(MockUser.all)
668
-
669
- expect(query.to_sql).to eql(%q{SELECT "mock_users".* FROM "mock_users" WHERE ("mock_users"."first_name" ILIKE 'Jane' OR "mock_users"."first_name" ILIKE 'Jaden') AND ("mock_users"."last_name" ILIKE '%avi%' OR "mock_users"."last_name" ILIKE '%ith')})
670
- end
671
-
672
535
  it 'finds expected items' do
673
536
  user_1 = MockUser.create(username: '1', first_name: 'Jane', last_name: 'Davis') # Match
674
537
  user_2 = MockUser.create(username: '2', first_name: 'Jane', last_name: 'Smith') # Match
@@ -683,7 +546,7 @@ RSpec.describe Scimitar::Lists::QueryParser do
683
546
  query = @instance.to_activerecord_query(MockUser.all)
684
547
 
685
548
  expect(query.count).to eql(3)
686
- expect(query.pluck(:primary_key)).to match_array([user_1.primary_key, user_2.primary_key, user_3.primary_key])
549
+ expect(query.pluck(:id)).to match_array([user_1.id, user_2.id, user_3.id])
687
550
  end
688
551
  end # "context 'combined AND and OR' do"
689
552
 
@@ -727,7 +590,7 @@ RSpec.describe Scimitar::Lists::QueryParser do
727
590
  end
728
591
 
729
592
  it 'complains if there is no column mapping available' do
730
- expect { @instance.send(:activerecord_columns, 'userName') }.to raise_error(Scimitar::FilterError)
593
+ expect { @instance.send(:activerecord_columns, 'externalId') }.to raise_error(Scimitar::FilterError)
731
594
  end
732
595
 
733
596
  it 'complains about malformed declarations' do
@@ -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
- 'urn:ietf:params:scim:schemas:custom-id'
7
+ 'custom-id'
8
8
  end
9
9
 
10
10
  def self.scim_attributes
@@ -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: 'John',
104
+ givenName: 'John',
123
105
  familyName: 'Smith'
124
106
  })
125
107
 
126
108
  result = resource.as_json
127
-
128
- expect(result['schemas'] ).to eql(['urn:ietf:params:scim:schemas:custom-id'])
109
+ expect(result['schemas']).to eql(['custom-id'])
129
110
  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'])
148
- expect(result['meta']['resourceType']).to eql('CustomResourse')
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
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
- context 'of custom schema' do
296
- ThirdCustomSchema = Class.new(Scimitar::Schema::Base) do
297
- def self.id
298
- 'urn:ietf:params:scim:schemas: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
- ExtensionSchema = Class.new(Scimitar::Schema::Base) do
307
- def self.id
308
- 'urn:ietf:params:scim:schemas:extension'
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
- let(:resource_class) {
320
- Class.new(Scimitar::Resources::Base) do
321
- set_schema ThirdCustomSchema
322
- extend_schema ExtensionSchema
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('urn:ietf:params:scim:schemas:extension' => {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('urn:ietf:params:scim:schemas:extension' => {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(['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')
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('urn:ietf:params:scim:schemas:extension' => {})
366
- expect(resource.valid?).to eql(false)
367
-
368
- resource = resource_class.new('urn:ietf:params:scim:schemas:extension' => {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
- context '.find_attribute' do
376
- it 'finds in first schema' do
377
- found = resource_class().find_attribute('name') # Defined in ThirdCustomSchema
378
- expect(found).to be_present
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
- it 'finds across schemas' do
384
- found = resource_class().find_attribute('relationship') # Defined in ExtensionSchema
385
- expect(found).to be_present
386
- expect(found.name).to eql('relationship')
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
- context 'of core schema' do
393
- EnterpriseExtensionSchema = Class.new(Scimitar::Schema::Base) do
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.scim_attributes
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
- let(:resource_class) {
407
- Class.new(Scimitar::Resources::Base) do
408
- set_schema Scimitar::Schema::User
409
- extend_schema EnterpriseExtensionSchema
410
-
411
- def self.endpoint
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
- expect(resource.organization).to eql('SOMEORG')
426
- expect(resource.department ).to eql('SOMEDPT')
427
- end
428
- end # "context '#initialize' do"
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
- context '#as_json' do
431
- it 'namespaces the extension attributes' do
432
- resource = resource_class.new(organization: 'SOMEORG', department: 'SOMEDPT')
433
- hash = resource.as_json
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
- expect(hash['schemas']).to eql(['urn:ietf:params:scim:schemas:core:2.0:User', 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User'])
436
- expect(hash['urn:ietf:params:scim:schemas:extension:enterprise:2.0:User']).to eql('organization' => 'SOMEORG', 'department' => 'SOMEDPT')
437
- end
438
- end # "context '#as_json' do"
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
- context '.resource_type' do
441
- it 'appends the extension schemas' do
442
- resource_type = resource_class.resource_type('http://example.com')
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
- context 'validation' do
448
- it 'validates into custom schema' do
449
- resource = resource_class.new('urn:ietf:params:scim:schemas:extension:enterprise:2.0:User' => {})
450
- expect(resource.valid?).to eql(false)
451
-
452
- resource = resource_class.new(
453
- 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User' => {
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
- it 'finds across schemas' do
477
- found = resource_class().find_attribute('organization') # Defined in EnterpriseExtensionSchema
478
- expect(found).to be_present
479
- expect(found.name).to eql('organization')
480
- expect(found.type).to eql('string')
481
- end
482
- end # "context '.find_attribute' do"
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,23 +1,11 @@
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
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
+ 'custom-id'
21
9
  end
22
10
 
23
11
  def self.scim_attributes
@@ -29,13 +17,10 @@ RSpec.describe Scimitar::Resources::Base do
29
17
  name: 'enforce', type: 'boolean', required: true
30
18
  ),
31
19
  Scimitar::Schema::Attribute.new(
32
- name: 'complexName', complexType: NameWithRequirementsComplexType, required: false
33
- ),
34
- Scimitar::Schema::Attribute.new(
35
- name: 'complexNames', complexType: Scimitar::ComplexTypes::Name, multiValued: true, required: false
20
+ name: 'complexName', complexType: Scimitar::ComplexTypes::Name, required: false
36
21
  ),
37
22
  Scimitar::Schema::Attribute.new(
38
- name: 'vdtpTestByEmail', complexType: Scimitar::ComplexTypes::Email, required: false
23
+ name: 'complexNames', complexType: Scimitar::ComplexTypes::Name, multiValued:true, required: false
39
24
  )
40
25
  ]
41
26
  end
@@ -72,28 +57,5 @@ RSpec.describe Scimitar::Resources::Base do
72
57
  expect(resource.valid?).to be(false)
73
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."])
74
59
  end
75
-
76
- context 'configuration of required values in VDTP schema' do
77
- around :each do | example |
78
- original_configuration = Scimitar.engine_configuration.optional_value_fields_required
79
- Scimitar::Schema::Email.instance_variable_set('@scim_attributes', nil)
80
- example.run()
81
- ensure
82
- Scimitar.engine_configuration.optional_value_fields_required = original_configuration
83
- Scimitar::Schema::Email.instance_variable_set('@scim_attributes', nil)
84
- end
85
-
86
- it 'requires a value by default' do
87
- resource = MyCustomResource.new(vdtpTestByEmail: { value: nil }, enforce: false)
88
- expect(resource.valid?).to be(false)
89
- expect(resource.errors.full_messages).to match_array(['Vdtptestbyemail value is required'])
90
- end
91
-
92
- it 'can be configured for optional values' do
93
- Scimitar.engine_configuration.optional_value_fields_required = false
94
- resource = MyCustomResource.new(vdtpTestByEmail: { value: nil }, enforce: false)
95
- expect(resource.valid?).to be(true)
96
- end
97
- end # "context 'configuration of required values in VDTP schema' do"
98
- end # "context '#valid?' do"
60
+ end
99
61
  end