scimitar 1.5.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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