scimitar 1.5.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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/scimitar/active_record_backed_resources_controller.rb +6 -27
  3. data/app/controllers/scimitar/application_controller.rb +9 -29
  4. data/app/models/scimitar/engine_configuration.rb +3 -7
  5. data/app/models/scimitar/error_response.rb +0 -12
  6. data/app/models/scimitar/errors.rb +1 -1
  7. data/app/models/scimitar/lists/query_parser.rb +4 -14
  8. data/app/models/scimitar/resources/base.rb +1 -1
  9. data/app/models/scimitar/resources/mixin.rb +4 -113
  10. data/app/models/scimitar/schema/address.rb +0 -1
  11. data/app/models/scimitar/schema/attribute.rb +1 -1
  12. data/app/models/scimitar/schema/base.rb +3 -1
  13. data/app/models/scimitar/schema/vdtp.rb +1 -1
  14. data/config/initializers/scimitar.rb +70 -86
  15. data/lib/scimitar/version.rb +2 -2
  16. data/spec/apps/dummy/app/controllers/mock_groups_controller.rb +1 -1
  17. data/spec/apps/dummy/app/models/mock_group.rb +1 -1
  18. data/spec/apps/dummy/app/models/mock_user.rb +8 -19
  19. data/spec/apps/dummy/config/application.rb +1 -0
  20. data/spec/apps/dummy/config/environments/test.rb +28 -5
  21. data/spec/apps/dummy/config/initializers/scimitar.rb +9 -44
  22. data/spec/apps/dummy/config/routes.rb +0 -4
  23. data/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb +1 -9
  24. data/spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb +3 -8
  25. data/spec/apps/dummy/db/schema.rb +4 -10
  26. data/spec/controllers/scimitar/application_controller_spec.rb +1 -70
  27. data/spec/controllers/scimitar/schemas_controller_spec.rb +2 -2
  28. data/spec/models/scimitar/complex_types/email_spec.rb +2 -0
  29. data/spec/models/scimitar/lists/query_parser_spec.rb +9 -9
  30. data/spec/models/scimitar/resources/base_spec.rb +66 -161
  31. data/spec/models/scimitar/resources/base_validation_spec.rb +2 -27
  32. data/spec/models/scimitar/resources/mixin_spec.rb +43 -757
  33. data/spec/models/scimitar/resources/user_spec.rb +4 -4
  34. data/spec/models/scimitar/schema/attribute_spec.rb +3 -0
  35. data/spec/models/scimitar/schema/base_spec.rb +1 -1
  36. data/spec/models/scimitar/schema/user_spec.rb +0 -10
  37. data/spec/requests/active_record_backed_resources_controller_spec.rb +40 -309
  38. data/spec/requests/application_controller_spec.rb +3 -17
  39. metadata +7 -7
@@ -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.5.2'
6
+ VERSION = '2.0.0'
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 = '2023-03-21'
11
+ DATE = '2022-03-04'
12
12
 
13
13
  end
@@ -1,4 +1,4 @@
1
- class MockGroupsController < Scimitar::ActiveRecordBackedResourcesController
1
+ class MockUsersController < Scimitar::ActiveRecordBackedResourcesController
2
2
 
3
3
  protected
4
4
 
@@ -58,7 +58,7 @@ class MockGroup < ActiveRecord::Base
58
58
 
59
59
  case type.downcase
60
60
  when 'user'
61
- MockUser.find_by_primary_key(id)
61
+ MockUser.find_by_id(id)
62
62
  when 'group'
63
63
  MockGroup.find_by_id(id)
64
64
  else
@@ -5,7 +5,7 @@ class MockUser < ActiveRecord::Base
5
5
  # ===========================================================================
6
6
 
7
7
  READWRITE_ATTRS = %w{
8
- primary_key
8
+ id
9
9
  scim_uid
10
10
  username
11
11
  first_name
@@ -13,8 +13,6 @@ class MockUser < ActiveRecord::Base
13
13
  work_email_address
14
14
  home_email_address
15
15
  work_phone_number
16
- organization
17
- department
18
16
  }
19
17
 
20
18
  has_and_belongs_to_many :mock_groups
@@ -40,7 +38,7 @@ class MockUser < ActiveRecord::Base
40
38
 
41
39
  def self.scim_attributes_map
42
40
  return {
43
- id: :primary_key,
41
+ id: :id,
44
42
  externalId: :scim_uid,
45
43
  userName: :username,
46
44
  name: {
@@ -84,13 +82,7 @@ class MockUser < ActiveRecord::Base
84
82
  }
85
83
  }
86
84
  ],
87
- active: :is_active,
88
-
89
- # Custom extension schema - see configuration in
90
- # "spec/apps/dummy/config/initializers/scimitar.rb".
91
- #
92
- organization: :organization,
93
- department: :department
85
+ active: :is_active
94
86
  }
95
87
  end
96
88
 
@@ -100,14 +92,11 @@ class MockUser < ActiveRecord::Base
100
92
 
101
93
  def self.scim_queryable_attributes
102
94
  return {
103
- 'id' => { column: :primary_key },
104
- 'externalId' => { column: :scim_uid },
105
- 'meta.lastModified' => { column: :updated_at },
106
- 'name.givenName' => { column: :first_name },
107
- 'name.familyName' => { column: :last_name },
108
- 'emails' => { columns: [ :work_email_address, :home_email_address ] },
109
- 'emails.value' => { columns: [ :work_email_address, :home_email_address ] },
110
- 'emails.type' => { ignore: true } # We can't filter on that; it'll just search all e-mails
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
111
100
  }
112
101
  end
113
102
 
@@ -12,6 +12,7 @@ require 'scimitar'
12
12
 
13
13
  module Dummy
14
14
  class Application < Rails::Application
15
+ config.load_defaults 7.0
15
16
  end
16
17
  end
17
18
 
@@ -1,15 +1,38 @@
1
+ require 'active_support/core_ext/integer/time'
2
+
1
3
  Rails.application.configure do
2
4
  config.cache_classes = true
3
5
  config.eager_load = false
4
- config.serve_static_files = true
5
- config.static_cache_control = 'public, max-age=3600'
6
- config.consider_all_requests_local = true
7
6
 
8
- config.action_dispatch.show_exceptions = false
7
+ # Configure public file server for tests with Cache-Control for performance.
8
+ config.public_file_server.enabled = true
9
+ config.public_file_server.headers = {
10
+ 'Cache-Control' => "public, max-age=#{1.hour.to_i}"
11
+ }
9
12
 
13
+ # Show full error reports and disable caching.
14
+ config.consider_all_requests_local = true
10
15
  config.action_controller.perform_caching = false
16
+ config.cache_store = :null_store
17
+
18
+ # Raise exceptions instead of rendering exception templates.
19
+ config.action_dispatch.show_exceptions = false
20
+
21
+ # Disable request forgery protection in test environment.
11
22
  config.action_controller.allow_forgery_protection = false
12
23
 
13
- config.active_support.test_order = :random
24
+ # Print deprecation notices to the stderr.
14
25
  config.active_support.deprecation = :stderr
26
+
27
+ # Raise exceptions for disallowed deprecations.
28
+ config.active_support.disallowed_deprecation = :raise
29
+
30
+ # Tell Active Support which deprecation messages to disallow.
31
+ config.active_support.disallowed_deprecation_warnings = []
32
+
33
+ # Raises error for missing translations.
34
+ config.i18n.raise_on_missing_translations = true
35
+
36
+ # Annotate rendered view with file names.
37
+ # config.action_view.annotate_rendered_view_with_filenames = true
15
38
  end
@@ -1,51 +1,16 @@
1
1
  # Test app configuration.
2
2
  #
3
- # Note that as a result of https://github.com/RIPAGlobal/scimitar/issues/48,
4
- # tests include a custom extension of the core User schema. A shortcoming of
5
- # some of the code from which Scimitar was originally built is that those
6
- # extensions are done with class-level ivars, so it is largely impossible (or
7
- # at least, impractical in tests) to avoid polluting the core class itself
8
- # with the extension.
9
- #
10
- # All related schema tests are written with this in mind.
11
- #
12
- Scimitar.engine_configuration = Scimitar::EngineConfiguration.new({
3
+ Rails.application.config.to_prepare do
4
+ Scimitar.engine_configuration = Scimitar::EngineConfiguration.new({
13
5
 
14
- application_controller_mixin: Module.new do
15
- def self.included(base)
16
- base.class_eval do
17
- def test_hook; end
18
- before_action :test_hook
6
+ application_controller_mixin: Module.new do
7
+ def self.included(base)
8
+ base.class_eval do
9
+ def test_hook; end
10
+ before_action :test_hook
11
+ end
19
12
  end
20
13
  end
21
- end
22
-
23
- })
24
-
25
- module ScimSchemaExtensions
26
- module User
27
- class Enterprise < Scimitar::Schema::Base
28
- def initialize(options = {})
29
- super(
30
- name: 'ExtendedUser',
31
- description: 'Enterprise extension for a User',
32
- id: self.class.id,
33
- scim_attributes: self.class.scim_attributes
34
- )
35
- end
36
14
 
37
- def self.id
38
- 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User'
39
- end
40
-
41
- def self.scim_attributes
42
- [
43
- Scimitar::Schema::Attribute.new(name: 'organization', type: 'string'),
44
- Scimitar::Schema::Attribute.new(name: 'department', type: 'string')
45
- ]
46
- end
47
- end
48
- end
15
+ })
49
16
  end
50
-
51
- Scimitar::Resources::User.extend_schema ScimSchemaExtensions::User::Enterprise
@@ -13,10 +13,6 @@ Rails.application.routes.draw do
13
13
  patch 'Users/:id', to: 'mock_users#update'
14
14
  delete 'Users/:id', to: 'mock_users#destroy'
15
15
 
16
- get 'Groups', to: 'mock_groups#index'
17
- get 'Groups/:id', to: 'mock_groups#show'
18
- patch 'Groups/:id', to: 'mock_groups#update'
19
-
20
16
  # For testing blocks passed to ActiveRecordBackedResourcesController#destroy
21
17
  #
22
18
  delete 'CustomDestroyUsers/:id', to: 'custom_destroy_mock_users#destroy'
@@ -1,10 +1,7 @@
1
1
  class CreateMockUsers < ActiveRecord::Migration[6.1]
2
2
  def change
3
- create_table :mock_users, id: :uuid, primary_key: :primary_key do |t|
4
- t.timestamps
3
+ create_table :mock_users do |t|
5
4
 
6
- # Support part of the core schema
7
- #
8
5
  t.text :scim_uid
9
6
  t.text :username
10
7
  t.text :first_name
@@ -13,11 +10,6 @@ class CreateMockUsers < ActiveRecord::Migration[6.1]
13
10
  t.text :home_email_address
14
11
  t.text :work_phone_number
15
12
 
16
- # Support the custom extension schema - see configuration in
17
- # "spec/apps/dummy/config/initializers/scimitar.rb".
18
- #
19
- t.text :organization
20
- t.text :department
21
13
  end
22
14
  end
23
15
  end
@@ -1,13 +1,8 @@
1
1
  class CreateJoinTableMockGroupsMockUsers < ActiveRecord::Migration[6.1]
2
2
  def change
3
- create_table :mock_groups_users, id: false do | t |
4
- t.references :mock_group, foreign_key: true, type: :int8, index: true, null: false
5
- t.references :mock_user, type: :uuid, index: true, null: false, primary_key: :primary_key
6
-
7
- # The 'foreign_key:' option (used above) only works for 'id' column names
8
- # but the test data has a column named 'primary_key' for 'mock_users'.
9
- #
10
- t.foreign_key :mock_users, primary_key: :primary_key
3
+ create_join_table :mock_groups, :mock_users do |t|
4
+ t.index [:mock_group_id, :mock_user_id]
5
+ t.index [:mock_user_id, :mock_group_id]
11
6
  end
12
7
  end
13
8
  end
@@ -24,14 +24,12 @@ ActiveRecord::Schema.define(version: 2021_03_08_044214) do
24
24
 
25
25
  create_table "mock_groups_users", id: false, force: :cascade do |t|
26
26
  t.bigint "mock_group_id", null: false
27
- t.uuid "mock_user_id", null: false
28
- t.index ["mock_group_id"], name: "index_mock_groups_users_on_mock_group_id"
29
- t.index ["mock_user_id"], name: "index_mock_groups_users_on_mock_user_id"
27
+ t.bigint "mock_user_id", null: false
28
+ t.index ["mock_group_id", "mock_user_id"], name: "index_mock_groups_users_on_mock_group_id_and_mock_user_id"
29
+ t.index ["mock_user_id", "mock_group_id"], name: "index_mock_groups_users_on_mock_user_id_and_mock_group_id"
30
30
  end
31
31
 
32
- create_table "mock_users", primary_key: "primary_key", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
33
- t.datetime "created_at", precision: 6, null: false
34
- t.datetime "updated_at", precision: 6, null: false
32
+ create_table "mock_users", force: :cascade do |t|
35
33
  t.text "scim_uid"
36
34
  t.text "username"
37
35
  t.text "first_name"
@@ -39,10 +37,6 @@ ActiveRecord::Schema.define(version: 2021_03_08_044214) do
39
37
  t.text "work_email_address"
40
38
  t.text "home_email_address"
41
39
  t.text "work_phone_number"
42
- t.text "organization"
43
- t.text "department"
44
40
  end
45
41
 
46
- add_foreign_key "mock_groups_users", "mock_groups"
47
- add_foreign_key "mock_groups_users", "mock_users", primary_key: "primary_key"
48
42
  end
@@ -169,74 +169,5 @@ RSpec.describe Scimitar::ApplicationController do
169
169
  expect(parsed_body).to include('status' => '500')
170
170
  expect(parsed_body).to include('detail' => 'Bang')
171
171
  end
172
-
173
- context 'with an exception reporter' do
174
- around :each do | example |
175
- original_configuration = Scimitar.engine_configuration.exception_reporter
176
- Scimitar.engine_configuration.exception_reporter = Proc.new do | exception |
177
- @exception = exception
178
- end
179
- example.run()
180
- ensure
181
- Scimitar.engine_configuration.exception_reporter = original_configuration
182
- end
183
-
184
- context 'and "internal server error"' do
185
- it 'is invoked' do
186
- get :index, params: { format: :scim }
187
-
188
- expect(@exception).to be_a(RuntimeError)
189
- expect(@exception.message).to eql('Bang')
190
- end
191
- end
192
-
193
- context 'and "not found"' do
194
- controller do
195
- def index
196
- handle_resource_not_found(ActiveRecord::RecordNotFound.new(42))
197
- end
198
- end
199
-
200
- it 'is invoked' do
201
- get :index, params: { format: :scim }
202
-
203
- expect(@exception).to be_a(ActiveRecord::RecordNotFound)
204
- expect(@exception.message).to eql('42')
205
- end
206
- end
207
-
208
- context 'and bad JSON' do
209
- controller do
210
- def index
211
- begin
212
- raise 'Hello'
213
- rescue
214
- raise ActionDispatch::Http::Parameters::ParseError
215
- end
216
- end
217
- end
218
-
219
- it 'is invoked' do
220
- get :index, params: { format: :scim }
221
-
222
- expect(@exception).to be_a(ActionDispatch::Http::Parameters::ParseError)
223
- expect(@exception.message).to eql('Hello')
224
- end
225
- end
226
-
227
- context 'and a bad content type' do
228
- controller do
229
- def index; end
230
- end
231
-
232
- it 'is invoked' do
233
- request.headers['Content-Type'] = 'text/plain'
234
- get :index
235
-
236
- expect(@exception).to be_a(Scimitar::ErrorResponse)
237
- expect(@exception.message).to eql('Only application/scim+json type is accepted.')
238
- end
239
- end
240
- end # "context 'exception reporter' do"
241
- end # "context 'error handling' do"
172
+ end
242
173
  end
@@ -14,9 +14,9 @@ RSpec.describe Scimitar::SchemasController do
14
14
  get :index, params: { format: :scim }
15
15
  expect(response).to be_ok
16
16
  parsed_body = JSON.parse(response.body)
17
- expect(parsed_body.length).to eql(3)
17
+ expect(parsed_body.length).to eql(2)
18
18
  schema_names = parsed_body.map {|schema| schema['name']}
19
- expect(schema_names).to match_array(['User', 'ExtendedUser', 'Group'])
19
+ expect(schema_names).to match_array(['User', 'Group'])
20
20
  end
21
21
 
22
22
  it 'returns only the User schema when its id is provided' do
@@ -18,4 +18,6 @@ RSpec.describe Scimitar::ComplexTypes::Email do
18
18
  expect(described_class.new(value: 'a@b.c').as_json).to eq('value' => 'a@b.c')
19
19
  end
20
20
  end
21
+
21
22
  end
23
+
@@ -405,19 +405,19 @@ RSpec.describe Scimitar::Lists::QueryParser do
405
405
  query = @instance.to_activerecord_query(MockUser.all)
406
406
 
407
407
  expect(query.count).to eql(1)
408
- expect(query.pluck(:primary_key)).to eql([user_1.id])
408
+ expect(query.pluck(:id)).to eql([user_1.id])
409
409
 
410
410
  @instance.parse('name.givenName sw J') # First name starts with 'J'
411
411
  query = @instance.to_activerecord_query(MockUser.all)
412
412
 
413
413
  expect(query.count).to eql(2)
414
- 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])
415
415
 
416
416
  @instance.parse('name.familyName ew he') # Last name ends with 'he'
417
417
  query = @instance.to_activerecord_query(MockUser.all)
418
418
 
419
419
  expect(query.count).to eql(1)
420
- expect(query.pluck(:primary_key)).to eql([user_2.primary_key])
420
+ expect(query.pluck(:id)).to eql([user_2.id])
421
421
 
422
422
  # Test presence
423
423
 
@@ -425,7 +425,7 @@ RSpec.describe Scimitar::Lists::QueryParser do
425
425
  query = @instance.to_activerecord_query(MockUser.all)
426
426
 
427
427
  expect(query.count).to eql(2)
428
- 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])
429
429
 
430
430
  # Test a simple not-equals, but use a custom starting scope. Note that
431
431
  # the query would find "user_3" *except* there is no first name defined
@@ -435,7 +435,7 @@ RSpec.describe Scimitar::Lists::QueryParser do
435
435
  query = @instance.to_activerecord_query(MockUser.where.not('first_name' => 'John'))
436
436
 
437
437
  expect(query.count).to eql(1)
438
- expect(query.pluck(:primary_key)).to match_array([user_1.primary_key])
438
+ expect(query.pluck(:id)).to match_array([user_1.id])
439
439
  end
440
440
 
441
441
  context 'when mapped to multiple columns' do
@@ -499,7 +499,7 @@ RSpec.describe Scimitar::Lists::QueryParser do
499
499
  query = @instance.to_activerecord_query(MockUser.all)
500
500
 
501
501
  expect(query.count).to eql(1)
502
- expect(query.pluck(:primary_key)).to match_array([user_2.primary_key])
502
+ expect(query.pluck(:id)).to match_array([user_2.id])
503
503
  end
504
504
  end # "context 'simple AND' do"
505
505
 
@@ -520,7 +520,7 @@ RSpec.describe Scimitar::Lists::QueryParser do
520
520
  query = @instance.to_activerecord_query(MockUser.all)
521
521
 
522
522
  expect(query.count).to eql(2)
523
- 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])
524
524
  end
525
525
  end # "context 'simple OR' do"
526
526
 
@@ -546,7 +546,7 @@ RSpec.describe Scimitar::Lists::QueryParser do
546
546
  query = @instance.to_activerecord_query(MockUser.all)
547
547
 
548
548
  expect(query.count).to eql(3)
549
- 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])
550
550
  end
551
551
  end # "context 'combined AND and OR' do"
552
552
 
@@ -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, 'userName') }.to raise_error(Scimitar::FilterError)
593
+ expect { @instance.send(:activerecord_columns, 'externalId') }.to raise_error(Scimitar::FilterError)
594
594
  end
595
595
 
596
596
  it 'complains about malformed declarations' do