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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/scimitar/active_record_backed_resources_controller.rb +20 -94
  3. data/app/controllers/scimitar/application_controller.rb +13 -41
  4. data/app/controllers/scimitar/schemas_controller.rb +0 -5
  5. data/app/models/scimitar/complex_types/address.rb +6 -0
  6. data/app/models/scimitar/engine_configuration.rb +5 -13
  7. data/app/models/scimitar/error_response.rb +0 -12
  8. data/app/models/scimitar/lists/query_parser.rb +10 -25
  9. data/app/models/scimitar/resource_invalid_error.rb +1 -1
  10. data/app/models/scimitar/resources/base.rb +4 -17
  11. data/app/models/scimitar/resources/mixin.rb +42 -539
  12. data/app/models/scimitar/schema/address.rb +0 -1
  13. data/app/models/scimitar/schema/attribute.rb +5 -14
  14. data/app/models/scimitar/schema/base.rb +1 -1
  15. data/app/models/scimitar/schema/vdtp.rb +1 -1
  16. data/app/models/scimitar/service_provider_configuration.rb +3 -14
  17. data/config/initializers/scimitar.rb +3 -28
  18. data/lib/scimitar/support/hash_with_indifferent_case_insensitive_access.rb +10 -140
  19. data/lib/scimitar/version.rb +2 -2
  20. data/lib/scimitar.rb +2 -7
  21. data/spec/apps/dummy/app/controllers/mock_groups_controller.rb +1 -1
  22. data/spec/apps/dummy/app/models/mock_group.rb +1 -1
  23. data/spec/apps/dummy/app/models/mock_user.rb +8 -36
  24. data/spec/apps/dummy/config/application.rb +1 -0
  25. data/spec/apps/dummy/config/environments/test.rb +28 -5
  26. data/spec/apps/dummy/config/initializers/scimitar.rb +10 -61
  27. data/spec/apps/dummy/config/routes.rb +7 -28
  28. data/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb +1 -10
  29. data/spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb +3 -8
  30. data/spec/apps/dummy/db/schema.rb +4 -11
  31. data/spec/controllers/scimitar/application_controller_spec.rb +3 -126
  32. data/spec/controllers/scimitar/resource_types_controller_spec.rb +2 -2
  33. data/spec/controllers/scimitar/schemas_controller_spec.rb +2 -10
  34. data/spec/models/scimitar/complex_types/address_spec.rb +4 -3
  35. data/spec/models/scimitar/complex_types/email_spec.rb +2 -0
  36. data/spec/models/scimitar/lists/query_parser_spec.rb +9 -76
  37. data/spec/models/scimitar/resources/base_spec.rb +70 -216
  38. data/spec/models/scimitar/resources/base_validation_spec.rb +2 -27
  39. data/spec/models/scimitar/resources/mixin_spec.rb +129 -1447
  40. data/spec/models/scimitar/schema/attribute_spec.rb +3 -22
  41. data/spec/models/scimitar/schema/base_spec.rb +1 -1
  42. data/spec/models/scimitar/schema/user_spec.rb +0 -10
  43. data/spec/requests/active_record_backed_resources_controller_spec.rb +68 -787
  44. data/spec/requests/application_controller_spec.rb +3 -16
  45. data/spec/spec_helper.rb +0 -8
  46. data/spec/support/hash_with_indifferent_case_insensitive_access_spec.rb +0 -108
  47. metadata +14 -25
  48. data/LICENSE.txt +0 -21
  49. data/README.md +0 -710
  50. data/lib/scimitar/support/utilities.rb +0 -51
  51. data/spec/apps/dummy/app/controllers/custom_create_mock_users_controller.rb +0 -25
  52. data/spec/apps/dummy/app/controllers/custom_replace_mock_users_controller.rb +0 -25
  53. data/spec/apps/dummy/app/controllers/custom_save_mock_users_controller.rb +0 -24
  54. data/spec/apps/dummy/app/controllers/custom_update_mock_users_controller.rb +0 -25
@@ -10,7 +10,6 @@ module Scimitar
10
10
  def self.scim_attributes
11
11
  @scim_attributes ||= [
12
12
  Attribute.new(name: 'type', type: 'string'),
13
- Attribute.new(name: 'primary', type: 'boolean'),
14
13
  Attribute.new(name: 'formatted', type: 'string'),
15
14
  Attribute.new(name: 'streetAddress', type: 'string'),
16
15
  Attribute.new(name: 'locality', type: 'string'),
@@ -93,23 +93,14 @@ module Scimitar
93
93
  end
94
94
 
95
95
  def valid_simple_type?(value)
96
- if multiValued
97
- valid = value.is_a?(Array) && value.all? { |v| simple_type?(v) }
98
- errors.add(self.name, "or one of its elements has the wrong type. It has to be an array of #{self.type}s.") unless valid
99
- else
100
- valid = simple_type?(value)
101
- errors.add(self.name, "has the wrong type. It has to be a(n) #{self.type}.") unless valid
102
- end
96
+ valid = (type == 'string' && value.is_a?(String)) ||
97
+ (type == 'boolean' && (value.is_a?(TrueClass) || value.is_a?(FalseClass))) ||
98
+ (type == 'integer' && (value.is_a?(Integer))) ||
99
+ (type == 'dateTime' && valid_date_time?(value))
100
+ errors.add(self.name, "has the wrong type. It has to be a(n) #{self.type}.") unless valid
103
101
  valid
104
102
  end
105
103
 
106
- def simple_type?(value)
107
- (type == 'string' && value.is_a?(String)) ||
108
- (type == 'boolean' && (value.is_a?(TrueClass) || value.is_a?(FalseClass))) ||
109
- (type == 'integer' && (value.is_a?(Integer))) ||
110
- (type == 'dateTime' && valid_date_time?(value))
111
- end
112
-
113
104
  def valid_date_time?(value)
114
105
  !!Time.iso8601(value)
115
106
  rescue ArgumentError
@@ -13,7 +13,7 @@ module Scimitar
13
13
 
14
14
  # Converts the schema to its json representation that will be returned by /SCHEMAS end-point of a SCIM service provider.
15
15
  def as_json(options = {})
16
- @meta.location ||= Scimitar::Engine.routes.url_helpers.scim_schemas_path(name: id)
16
+ @meta.location = Scimitar::Engine.routes.url_helpers.scim_schemas_path(name: id)
17
17
  original = super
18
18
  original.merge('attributes' => original.delete('scim_attributes'))
19
19
  end
@@ -7,7 +7,7 @@ module Scimitar
7
7
  class Vdtp < Base
8
8
  def self.scim_attributes
9
9
  @scim_attributes ||= [
10
- Attribute.new(name: 'value', type: 'string', required: Scimitar.engine_configuration.optional_value_fields_required),
10
+ Attribute.new(name: 'value', type: 'string', required: true),
11
11
  Attribute.new(name: 'display', type: 'string', mutability: 'readOnly'),
12
12
  Attribute.new(name: 'type', type: 'string'),
13
13
  Attribute.new(name: 'primary', type: 'boolean'),
@@ -9,22 +9,11 @@ module Scimitar
9
9
  class ServiceProviderConfiguration
10
10
  include ActiveModel::Model
11
11
 
12
- attr_accessor(
13
- :uses_defaults,
14
- :patch,
15
- :bulk,
16
- :filter,
17
- :changePassword,
18
- :sort,
19
- :etag,
20
- :authenticationSchemes,
21
- :schemas,
22
- :meta,
23
- )
12
+ attr_accessor :patch, :bulk, :filter, :changePassword,
13
+ :sort, :etag, :authenticationSchemes,
14
+ :schemas, :meta
24
15
 
25
16
  def initialize(attributes = {})
26
- @uses_defaults = attributes.empty?
27
-
28
17
  defaults = {
29
18
  bulk: Supportable.unsupported,
30
19
  changePassword: Supportable.unsupported,
@@ -38,10 +38,9 @@ Rails.application.config.to_prepare do # (required for >= Rails 7 / Zeitwerk)
38
38
  Scimitar.engine_configuration = Scimitar::EngineConfiguration.new({
39
39
 
40
40
  # If you have filters you want to run for any Scimitar action/route, you
41
- # can define them here. You can also override any shared controller methods
42
- # here. For example, you might use a before-action to set up some
43
- # multi-tenancy related state, skip Rails CSRF token verification, or
44
- # customise how Scimitar generates URLs:
41
+ # can define them here. For example, you might use a before-action to set
42
+ # up some multi-tenancy related state, or skip Rails CSRF token
43
+ # verification. For example:
45
44
  #
46
45
  # application_controller_mixin: Module.new do
47
46
  # def self.included(base)
@@ -55,10 +54,6 @@ Rails.application.config.to_prepare do # (required for >= Rails 7 / Zeitwerk)
55
54
  # prepend_before_action :setup_some_kind_of_multi_tenancy_data
56
55
  # end
57
56
  # end
58
- #
59
- # def scim_schemas_url(options)
60
- # super(custom_param: 'value', **options)
61
- # end
62
57
  # end, # ...other configuration entries might follow...
63
58
 
64
59
  # If you want to support username/password authentication:
@@ -86,26 +81,6 @@ Rails.application.config.to_prepare do # (required for >= Rails 7 / Zeitwerk)
86
81
  # Note that both basic and token authentication can be declared, with the
87
82
  # parameters in the inbound HTTP request determining which is invoked.
88
83
 
89
- # Scimitar rescues certain error cases and exceptions, in order to return a
90
- # JSON response to the API caller. If you want exceptions to also be
91
- # reported to a third party system such as sentry.io or raygun.com, you can
92
- # configure a Proc to do so. It is passed a Ruby exception subclass object.
93
- # For example, a minimal sentry.io reporter might do this:
94
- #
95
- # exception_reporter: Proc.new do | exception |
96
- # Sentry.capture_exception(exception)
97
- # end
98
- #
99
- # You will still need to configure your reporting system according to its
100
- # documentation (e.g. via a Rails "config/initializers/<foo>.rb" file).
101
-
102
- # Scimilar treats "VDTP" (Value, Display, Type, Primary) attribute values,
103
- # used for e.g. e-mail addresses or phone numbers, as required by default.
104
- # If you encounter a service which calls these with e.g. "null" value data,
105
- # you can configure all values to be optional. You'll need to deal with
106
- # whatever that means for you receiving system in your model code.
107
- #
108
- # optional_value_fields_required: false
109
84
  })
110
85
 
111
86
  end
@@ -23,8 +23,8 @@ class Hash
23
23
  #
24
24
  def self.deep_indifferent_case_insensitive_access(object)
25
25
  if object.is_a?(Hash)
26
- new_hash = Scimitar::Support::HashWithIndifferentCaseInsensitiveAccess.new
27
- object.each do | key, value |
26
+ new_hash = Scimitar::Support::HashWithIndifferentCaseInsensitiveAccess.new(object)
27
+ new_hash.each do | key, value |
28
28
  new_hash[key] = deep_indifferent_case_insensitive_access(value)
29
29
  end
30
30
  new_hash
@@ -49,164 +49,34 @@ module Scimitar
49
49
  # in a case-insensitive fashion too.
50
50
  #
51
51
  # During enumeration, Hash keys will always be returned in whatever case
52
- # they were originally set. Just as with
53
- # ActiveSupport::HashWithIndifferentAccess, though, the type of the keys is
54
- # always returned as a String, even if originally set as a Symbol - only
55
- # the upper/lower case nature of the original key is preserved.
56
- #
57
- # If a key is written more than once with the same effective meaning in a
58
- # to-string, to-downcase form, then whatever case was used *first* wins;
59
- # e.g. if you did hash['User'] = 23, then hash['USER'] = 42, the result
60
- # would be {"User" => 42}.
61
- #
62
- # It's important to remember that Hash#merge is shallow and replaces values
63
- # found at existing keys in the target ("this") hash with values in the
64
- # inbound Hash. If that new value that is itself a Hash, this *replaces*
65
- # the value. For example:
66
- #
67
- # * Original: <tt>'Foo' => { 'Bar' => 42 }</tt>
68
- # * Merge: <tt>'FOO' => { 'BAR' => 24 }</tt>
69
- #
70
- # ...results in "this" target hash's key +Foo+ being addressed in the merge
71
- # by inbound key +FOO+, so the case doesn't change. But the value for +Foo+
72
- # is _replaced_ by the merging-in Hash completely:
73
- #
74
- # * Result: <tt>'Foo' => { 'BAR' => 24 }</tt>
75
- #
76
- # ...and of course we might've replaced with a totally different type, such
77
- # as +true+:
78
- #
79
- # * Original: <tt>'Foo' => { 'Bar' => 42 }</tt>
80
- # * Merge: <tt>'FOO' => true</tt>
81
- # * Result: <tt>'Foo' => true</tt>
82
- #
83
- # If you're intending to merge nested Hashes, then use ActiveSupport's
84
- # #deep_merge or an equivalent. This will have the expected outcome, where
85
- # the hash with 'BAR' is _merged_ into the existing value and, therefore,
86
- # the original 'Bar' key case is preserved:
87
- #
88
- # * Original: <tt>'Foo' => { 'Bar' => 42 }</tt>
89
- # * Deep merge: <tt>'FOO' => { 'BAR' => 24 }</tt>
90
- # * Result: <tt>'Foo' => { 'Bar' => 24 }</tt>
52
+ # they were originally set.
91
53
  #
92
54
  class HashWithIndifferentCaseInsensitiveAccess < ActiveSupport::HashWithIndifferentAccess
93
55
  def with_indifferent_case_insensitive_access
94
56
  self
95
57
  end
96
58
 
97
- def initialize(constructor = nil)
98
- @scimitar_hash_with_indifferent_case_insensitive_access_key_map = {}
99
- super
100
- end
101
-
102
- # It's vital that the attribute map is carried over when one of these
103
- # objects is duplicated. Duplication of this ivar state does *not* happen
104
- # when 'dup' is called on our superclass, so we have to do that manually.
105
- #
106
- def dup
107
- duplicate = super
108
- duplicate.instance_variable_set(
109
- '@scimitar_hash_with_indifferent_case_insensitive_access_key_map',
110
- @scimitar_hash_with_indifferent_case_insensitive_access_key_map
111
- )
112
-
113
- return duplicate
114
- end
115
-
116
- # Override the individual key writer.
117
- #
118
- def []=(key, value)
119
- string_key = scimitar_hash_with_indifferent_case_insensitive_access_string(key)
120
- indifferent_key = scimitar_hash_with_indifferent_case_insensitive_access_downcase(string_key)
121
- converted_value = convert_value(value, conversion: :assignment)
122
-
123
- # Note '||=', as there might have been a prior use of the "same" key in
124
- # a different case. The earliest one is preserved since the actual Hash
125
- # underneath all this is already using that variant of the key.
126
- #
127
- key_for_writing = (
128
- @scimitar_hash_with_indifferent_case_insensitive_access_key_map[indifferent_key] ||= string_key
129
- )
130
-
131
- regular_writer(key_for_writing, converted_value)
132
- end
133
-
134
- # Override #merge to express it in terms of #merge! (also overridden), so
135
- # that merged hashes can have their keys treated indifferently too.
136
- #
137
- def merge(*other_hashes, &block)
138
- dup.merge!(*other_hashes, &block)
139
- end
140
-
141
- # Modifies-self version of #merge, overriding Hash#merge!.
142
- #
143
- def merge!(*hashes_to_merge_to_self, &block)
144
- if block_given?
145
- hashes_to_merge_to_self.each do |hash_to_merge_to_self|
146
- hash_to_merge_to_self.each_pair do |key, value|
147
- value = block.call(key, self[key], value) if self.key?(key)
148
- self[key] = value
149
- end
150
- end
151
- else
152
- hashes_to_merge_to_self.each do |hash_to_merge_to_self|
153
- hash_to_merge_to_self.each_pair do |key, value|
154
- self[key] = value
155
- end
156
- end
157
- end
158
-
159
- self
160
- end
161
-
162
- # =======================================================================
163
- # PRIVATE INSTANCE METHODS
164
- # =======================================================================
165
- #
166
59
  private
167
60
 
168
61
  if Symbol.method_defined?(:name)
169
- def scimitar_hash_with_indifferent_case_insensitive_access_string(key)
170
- key.kind_of?(Symbol) ? key.name : key
62
+ def convert_key(key)
63
+ key.kind_of?(Symbol) ? key.name.downcase : key.downcase
171
64
  end
172
65
  else
173
- def scimitar_hash_with_indifferent_case_insensitive_access_string(key)
174
- key.kind_of?(Symbol) ? key.to_s : key
175
- end
176
- end
177
-
178
- def scimitar_hash_with_indifferent_case_insensitive_access_downcase(key)
179
- key.kind_of?(String) ? key.downcase : key
180
- end
181
-
182
- def convert_key(key)
183
- string_key = scimitar_hash_with_indifferent_case_insensitive_access_string(key)
184
- indifferent_key = scimitar_hash_with_indifferent_case_insensitive_access_downcase(string_key)
185
-
186
- @scimitar_hash_with_indifferent_case_insensitive_access_key_map[indifferent_key] || string_key
187
- end
188
-
189
- def convert_value(value, conversion: nil)
190
- if value.is_a?(Hash)
191
- if conversion == :to_hash
192
- value.to_hash
193
- else
194
- value.with_indifferent_case_insensitive_access
195
- end
196
- else
197
- super
66
+ def convert_key(key)
67
+ key.kind_of?(Symbol) ? key.to_s.downcase : key.downcase
198
68
  end
199
69
  end
200
70
 
201
71
  def update_with_single_argument(other_hash, block)
202
- if other_hash.is_a?(HashWithIndifferentCaseInsensitiveAccess)
72
+ if other_hash.is_a? HashWithIndifferentCaseInsensitiveAccess
203
73
  regular_update(other_hash, &block)
204
74
  else
205
75
  other_hash.to_hash.each_pair do |key, value|
206
76
  if block && key?(key)
207
- value = block.call(self.convert_key(key), self[key], value)
77
+ value = block.call(convert_key(key), self[key], value)
208
78
  end
209
- self.[]=(key, value)
79
+ regular_writer(convert_key(key), convert_value(value))
210
80
  end
211
81
  end
212
82
  end
@@ -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.8.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 = '2024-03-27'
11
+ DATE = '2022-03-04'
12
12
 
13
13
  end
data/lib/scimitar.rb CHANGED
@@ -1,13 +1,10 @@
1
1
  require 'scimitar/version'
2
2
  require 'scimitar/support/hash_with_indifferent_case_insensitive_access'
3
- require 'scimitar/support/utilities'
4
3
  require 'scimitar/engine'
5
4
 
6
5
  module Scimitar
7
6
  def self.service_provider_configuration=(custom_configuration)
8
- if @service_provider_configuration.nil? || ! custom_configuration.uses_defaults
9
- @service_provider_configuration = custom_configuration
10
- end
7
+ @service_provider_configuration = custom_configuration
11
8
  end
12
9
 
13
10
  def self.service_provider_configuration(location:)
@@ -17,9 +14,7 @@ module Scimitar
17
14
  end
18
15
 
19
16
  def self.engine_configuration=(custom_configuration)
20
- if @engine_configuration.nil? || ! custom_configuration.uses_defaults
21
- @engine_configuration = custom_configuration
22
- end
17
+ @engine_configuration = custom_configuration
23
18
  end
24
19
 
25
20
  def self.engine_configuration
@@ -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
@@ -1,24 +1,18 @@
1
1
  class MockUser < ActiveRecord::Base
2
2
 
3
- self.primary_key = :primary_key
4
-
5
3
  # ===========================================================================
6
4
  # TEST ATTRIBUTES - see db/migrate/20210304014602_create_mock_users.rb etc.
7
5
  # ===========================================================================
8
6
 
9
7
  READWRITE_ATTRS = %w{
10
- primary_key
8
+ id
11
9
  scim_uid
12
10
  username
13
- password
14
11
  first_name
15
12
  last_name
16
13
  work_email_address
17
14
  home_email_address
18
15
  work_phone_number
19
- organization
20
- department
21
- mock_groups
22
16
  }
23
17
 
24
18
  has_and_belongs_to_many :mock_groups
@@ -44,10 +38,9 @@ class MockUser < ActiveRecord::Base
44
38
 
45
39
  def self.scim_attributes_map
46
40
  return {
47
- id: :primary_key,
41
+ id: :id,
48
42
  externalId: :scim_uid,
49
43
  userName: :username,
50
- password: :password,
51
44
  name: {
52
45
  givenName: :first_name,
53
46
  familyName: :last_name
@@ -89,23 +82,7 @@ class MockUser < ActiveRecord::Base
89
82
  }
90
83
  }
91
84
  ],
92
- active: :is_active,
93
-
94
- # Custom extension schema - see configuration in
95
- # "spec/apps/dummy/config/initializers/scimitar.rb".
96
- #
97
- organization: :organization,
98
- department: :department,
99
- userGroups: [
100
- {
101
- list: :mock_groups,
102
- find_with: ->(value) { MockGroup.find(value["value"]) },
103
- using: {
104
- value: :id,
105
- display: :display_name
106
- }
107
- }
108
- ]
85
+ active: :is_active
109
86
  }
110
87
  end
111
88
 
@@ -115,16 +92,11 @@ class MockUser < ActiveRecord::Base
115
92
 
116
93
  def self.scim_queryable_attributes
117
94
  return {
118
- 'id' => { column: :primary_key },
119
- 'externalId' => { column: :scim_uid },
120
- 'meta.lastModified' => { column: :updated_at },
121
- 'name.givenName' => { column: :first_name },
122
- 'name.familyName' => { column: :last_name },
123
- 'groups' => { column: MockGroup.arel_table[:id] },
124
- 'groups.value' => { column: MockGroup.arel_table[:id] },
125
- 'emails' => { columns: [ :work_email_address, :home_email_address ] },
126
- 'emails.value' => { columns: [ :work_email_address, :home_email_address ] },
127
- '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
128
100
  }
129
101
  end
130
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,67 +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
- # Further, https://github.com/RIPAGlobal/scimitar/pull/54 fixed warning
13
- # messages in a way that worked on Rails 6+ but, for V1 Scimitar, it would
14
- # break existing working setups that didn't use the +to_prepare+ wrapper. Their
15
- # application configuration would be written *first* but then *overwritten* by
16
- # the default +to_prepare+ block in Scimitar itself, since that runs later. The
17
- # file below does *not* use +to_prepare+ in order to test the workaround that
18
- # was produced; it should work on all Ruby versions as-is.
19
- #
20
- Scimitar.engine_configuration = Scimitar::EngineConfiguration.new({
21
-
22
- application_controller_mixin: Module.new do
23
- def self.included(base)
24
- base.class_eval do
25
- def test_hook; end
26
- before_action :test_hook
3
+ Rails.application.config.to_prepare do
4
+ Scimitar.engine_configuration = Scimitar::EngineConfiguration.new({
5
+
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
27
12
  end
28
13
  end
29
14
 
30
- def scim_schemas_url(options)
31
- super(test: 1, **options)
32
- end
33
-
34
- def scim_resource_type_url(options)
35
- super(test: 1, **options)
36
- end
37
- end
38
-
39
- })
40
-
41
- module ScimSchemaExtensions
42
- module User
43
- class Enterprise < Scimitar::Schema::Base
44
- def initialize(options = {})
45
- super(
46
- name: 'ExtendedUser',
47
- description: 'Enterprise extension for a User',
48
- id: self.class.id,
49
- scim_attributes: self.class.scim_attributes
50
- )
51
- end
52
-
53
- def self.id
54
- 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User'
55
- end
56
-
57
- def self.scim_attributes
58
- [
59
- Scimitar::Schema::Attribute.new(name: 'organization', type: 'string'),
60
- Scimitar::Schema::Attribute.new(name: 'department', type: 'string')
61
- ]
62
- end
63
- end
64
- end
15
+ })
65
16
  end
66
-
67
- Scimitar::Resources::User.extend_schema ScimSchemaExtensions::User::Enterprise
@@ -6,38 +6,17 @@
6
6
  Rails.application.routes.draw do
7
7
  mount Scimitar::Engine, at: '/'
8
8
 
9
- get 'Users', to: 'mock_users#index'
10
- get 'Users/:id', to: 'mock_users#show'
11
- post 'Users', to: 'mock_users#create'
12
- put 'Users/:id', to: 'mock_users#replace'
13
- patch 'Users/:id', to: 'mock_users#update'
14
- delete 'Users/:id', to: 'mock_users#destroy'
9
+ get 'Users', to: 'mock_users#index'
10
+ get 'Users/:id', to: 'mock_users#show'
11
+ post 'Users', to: 'mock_users#create'
12
+ put 'Users/:id', to: 'mock_users#replace'
13
+ patch 'Users/:id', to: 'mock_users#update'
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
- # For testing blocks passed to ActiveRecordBackedResourcesController#create,
21
- # #update, #replace and #destroy.
16
+ # For testing blocks passed to ActiveRecordBackedResourcesController#destroy
22
17
  #
23
- post 'CustomCreateUsers', to: 'custom_create_mock_users#create'
24
- patch 'CustomUpdateUsers/:id', to: 'custom_update_mock_users#update'
25
- put 'CustomReplaceUsers/:id', to: 'custom_replace_mock_users#replace'
26
18
  delete 'CustomDestroyUsers/:id', to: 'custom_destroy_mock_users#destroy'
27
19
 
28
- # Needed because the auto-render of most of the above includes a 'url_for'
29
- # call for a 'show' action, so we must include routes (implemented in the
30
- # base class) for the "show" endpoint.
31
- #
32
- get 'CustomCreateUsers/:id', to: 'custom_create_mock_users#show'
33
- get 'CustomUpdateUsers/:id', to: 'custom_update_mock_users#show'
34
- get 'CustomReplaceUsers/:id', to: 'custom_replace_mock_users#show'
35
-
36
- # For testing blocks passed to ActiveRecordBackedResourcesController#save!
37
- #
38
- post 'CustomSaveUsers', to: 'custom_save_mock_users#create'
39
- get 'CustomSaveUsers/:id', to: 'custom_save_mock_users#show'
40
-
41
20
  # For testing environment inside Scimitar::ApplicationController subclasses.
42
21
  #
43
22
  get 'CustomRequestVerifiers', to: 'custom_request_verifiers#index'
@@ -1,24 +1,15 @@
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
- t.text :password
11
7
  t.text :first_name
12
8
  t.text :last_name
13
9
  t.text :work_email_address
14
10
  t.text :home_email_address
15
11
  t.text :work_phone_number
16
12
 
17
- # Support the custom extension schema - see configuration in
18
- # "spec/apps/dummy/config/initializers/scimitar.rb".
19
- #
20
- t.text :organization
21
- t.text :department
22
13
  end
23
14
  end
24
15
  end