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