scimitar 1.8.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/scimitar/active_record_backed_resources_controller.rb +20 -94
- data/app/controllers/scimitar/application_controller.rb +13 -41
- data/app/controllers/scimitar/schemas_controller.rb +0 -5
- data/app/models/scimitar/complex_types/address.rb +6 -0
- data/app/models/scimitar/engine_configuration.rb +5 -13
- data/app/models/scimitar/error_response.rb +0 -12
- data/app/models/scimitar/lists/query_parser.rb +10 -25
- data/app/models/scimitar/resource_invalid_error.rb +1 -1
- data/app/models/scimitar/resources/base.rb +4 -17
- data/app/models/scimitar/resources/mixin.rb +42 -539
- data/app/models/scimitar/schema/address.rb +0 -1
- data/app/models/scimitar/schema/attribute.rb +5 -14
- data/app/models/scimitar/schema/base.rb +1 -1
- data/app/models/scimitar/schema/vdtp.rb +1 -1
- data/app/models/scimitar/service_provider_configuration.rb +3 -14
- data/config/initializers/scimitar.rb +3 -28
- data/lib/scimitar/support/hash_with_indifferent_case_insensitive_access.rb +10 -140
- data/lib/scimitar/version.rb +2 -2
- data/lib/scimitar.rb +2 -7
- data/spec/apps/dummy/app/controllers/mock_groups_controller.rb +1 -1
- data/spec/apps/dummy/app/models/mock_group.rb +1 -1
- data/spec/apps/dummy/app/models/mock_user.rb +8 -36
- data/spec/apps/dummy/config/application.rb +1 -0
- data/spec/apps/dummy/config/environments/test.rb +28 -5
- data/spec/apps/dummy/config/initializers/scimitar.rb +10 -61
- data/spec/apps/dummy/config/routes.rb +7 -28
- data/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb +1 -10
- data/spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb +3 -8
- data/spec/apps/dummy/db/schema.rb +4 -11
- data/spec/controllers/scimitar/application_controller_spec.rb +3 -126
- data/spec/controllers/scimitar/resource_types_controller_spec.rb +2 -2
- data/spec/controllers/scimitar/schemas_controller_spec.rb +2 -10
- data/spec/models/scimitar/complex_types/address_spec.rb +4 -3
- data/spec/models/scimitar/complex_types/email_spec.rb +2 -0
- data/spec/models/scimitar/lists/query_parser_spec.rb +9 -76
- data/spec/models/scimitar/resources/base_spec.rb +70 -216
- data/spec/models/scimitar/resources/base_validation_spec.rb +2 -27
- data/spec/models/scimitar/resources/mixin_spec.rb +129 -1447
- data/spec/models/scimitar/schema/attribute_spec.rb +3 -22
- data/spec/models/scimitar/schema/base_spec.rb +1 -1
- data/spec/models/scimitar/schema/user_spec.rb +0 -10
- data/spec/requests/active_record_backed_resources_controller_spec.rb +68 -787
- data/spec/requests/application_controller_spec.rb +3 -16
- data/spec/spec_helper.rb +0 -8
- data/spec/support/hash_with_indifferent_case_insensitive_access_spec.rb +0 -108
- metadata +14 -25
- data/LICENSE.txt +0 -21
- data/README.md +0 -710
- data/lib/scimitar/support/utilities.rb +0 -51
- data/spec/apps/dummy/app/controllers/custom_create_mock_users_controller.rb +0 -25
- data/spec/apps/dummy/app/controllers/custom_replace_mock_users_controller.rb +0 -25
- data/spec/apps/dummy/app/controllers/custom_save_mock_users_controller.rb +0 -24
- data/spec/apps/dummy/app/controllers/custom_update_mock_users_controller.rb +0 -25
@@ -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
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
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
|
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:
|
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
|
-
:
|
14
|
-
:
|
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.
|
42
|
-
#
|
43
|
-
#
|
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
|
-
|
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.
|
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
|
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
|
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?
|
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(
|
77
|
+
value = block.call(convert_key(key), self[key], value)
|
208
78
|
end
|
209
|
-
|
79
|
+
regular_writer(convert_key(key), convert_value(value))
|
210
80
|
end
|
211
81
|
end
|
212
82
|
end
|
data/lib/scimitar/version.rb
CHANGED
@@ -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 = '
|
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 = '
|
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
|
-
|
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
|
-
|
21
|
-
@engine_configuration = custom_configuration
|
22
|
-
end
|
17
|
+
@engine_configuration = custom_configuration
|
23
18
|
end
|
24
19
|
|
25
20
|
def self.engine_configuration
|
@@ -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
|
-
|
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: :
|
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
|
-
'
|
119
|
-
'
|
120
|
-
'
|
121
|
-
'
|
122
|
-
'
|
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
|
|
@@ -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
|
-
|
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
|
-
|
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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
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',
|
10
|
-
get 'Users/:id',
|
11
|
-
post 'Users',
|
12
|
-
put 'Users/:id',
|
13
|
-
patch 'Users/:id',
|
14
|
-
delete 'Users/:id',
|
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
|
-
|
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
|
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
|