scimitar 1.8.1 → 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 -14
- data/app/models/scimitar/resources/mixin.rb +13 -140
- 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/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 -208
- data/spec/models/scimitar/resources/base_validation_spec.rb +2 -27
- data/spec/models/scimitar/resources/mixin_spec.rb +43 -790
- 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 +66 -709
- data/spec/requests/application_controller_spec.rb +3 -16
- data/spec/spec_helper.rb +0 -8
- 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
@@ -220,8 +220,13 @@ module Scimitar
|
|
220
220
|
# allow for different client searching "styles", given ambiguities in RFC
|
221
221
|
# 7644 filter examples).
|
222
222
|
#
|
223
|
-
# Each value is a
|
224
|
-
#
|
223
|
+
# Each value is a Hash with Symbol keys ':column', naming just one simple
|
224
|
+
# column for a mapping; ':columns', with an Array of column names that you
|
225
|
+
# want to map using 'OR' for a single search on the corresponding SCIM
|
226
|
+
# attribute; or ':ignore' with value 'true', which means that a fitler on
|
227
|
+
# the matching attribute is ignored rather than resulting in an "invalid
|
228
|
+
# filter" exception - beware possibilities for surprised clients getting a
|
229
|
+
# broader result set than expected. Example:
|
225
230
|
#
|
226
231
|
# def self.scim_queryable_attributes
|
227
232
|
# return {
|
@@ -229,27 +234,10 @@ module Scimitar
|
|
229
234
|
# 'name.familyName' => { column: :last_name },
|
230
235
|
# 'emails' => { columns: [ :work_email_address, :home_email_address ] },
|
231
236
|
# 'emails.value' => { columns: [ :work_email_address, :home_email_address ] },
|
232
|
-
# 'emails.type' => { ignore: true }
|
233
|
-
# 'groups.value' => { column: Group.arel_table[:id] }
|
237
|
+
# 'emails.type' => { ignore: true }
|
234
238
|
# }
|
235
239
|
# end
|
236
240
|
#
|
237
|
-
# Column references can be either a Symbol representing a column within
|
238
|
-
# the resource model table, or an <tt>Arel::Attribute</tt> instance via
|
239
|
-
# e.g. <tt>MyModel.arel_table[:my_column]</tt>.
|
240
|
-
#
|
241
|
-
# === Queryable SCIM attribute options
|
242
|
-
#
|
243
|
-
# +:column+:: Just one simple column for a mapping.
|
244
|
-
#
|
245
|
-
# +:columns+:: An Array of columns that you want to map using 'OR' for a
|
246
|
-
# single search of the corresponding entity.
|
247
|
-
#
|
248
|
-
# +:ignore+:: When set to +true+, the matching attribute is ignored rather
|
249
|
-
# than resulting in an "invalid filter" exception. Beware
|
250
|
-
# possibilities for surprised clients getting a broader result
|
251
|
-
# set than expected, since a constraint may have been ignored.
|
252
|
-
#
|
253
241
|
# Filtering is currently limited and searching within e.g. arrays of data
|
254
242
|
# is not supported; only simple top-level keys can be mapped.
|
255
243
|
#
|
@@ -418,11 +406,8 @@ module Scimitar
|
|
418
406
|
def from_scim_patch!(patch_hash:)
|
419
407
|
frozen_ci_patch_hash = patch_hash.with_indifferent_case_insensitive_access().freeze()
|
420
408
|
ci_scim_hash = self.to_scim(location: '(unused)').as_json().with_indifferent_case_insensitive_access()
|
421
|
-
operations = frozen_ci_patch_hash['operations']
|
422
|
-
|
423
|
-
raise Scimitar::InvalidSyntaxError.new("Missing PATCH \"operations\"") unless operations
|
424
409
|
|
425
|
-
operations.each do |operation|
|
410
|
+
frozen_ci_patch_hash['operations'].each do |operation|
|
426
411
|
nature = operation['op' ]&.downcase
|
427
412
|
path_str = operation['path' ]
|
428
413
|
value = operation['value']
|
@@ -458,30 +443,9 @@ module Scimitar
|
|
458
443
|
ci_scim_hash = { 'root' => ci_scim_hash }.with_indifferent_case_insensitive_access()
|
459
444
|
end
|
460
445
|
|
461
|
-
# Handle extension schema. Contributed by @bettysteger and
|
462
|
-
# @MorrisFreeman via:
|
463
|
-
#
|
464
|
-
# https://github.com/RIPAGlobal/scimitar/issues/48
|
465
|
-
# https://github.com/RIPAGlobal/scimitar/pull/49
|
466
|
-
#
|
467
|
-
# Note the ":" separating the schema ID (URN) from the attribute.
|
468
|
-
# The nature of JSON rendering / other payloads might lead you to
|
469
|
-
# expect a "." as with any complex types, but that's not the case;
|
470
|
-
# see https://tools.ietf.org/html/rfc7644#section-3.10, or
|
471
|
-
# https://tools.ietf.org/html/rfc7644#section-3.5.2 of which in
|
472
|
-
# particular, https://tools.ietf.org/html/rfc7644#page-35.
|
473
|
-
#
|
474
|
-
paths = []
|
475
|
-
self.class.scim_resource_type.extended_schemas.each do |schema|
|
476
|
-
path_str.downcase.split(schema.id.downcase + ':').drop(1).each do |path|
|
477
|
-
paths += [schema.id] + path.split('.')
|
478
|
-
end
|
479
|
-
end
|
480
|
-
paths = path_str.split('.') if paths.empty?
|
481
|
-
|
482
446
|
self.from_patch_backend!(
|
483
447
|
nature: nature,
|
484
|
-
path:
|
448
|
+
path: (path_str || '').split('.'),
|
485
449
|
value: value,
|
486
450
|
altering_hash: ci_scim_hash
|
487
451
|
)
|
@@ -652,19 +616,7 @@ module Scimitar
|
|
652
616
|
attrs_map_or_leaf_value.each do | scim_attribute, sub_attrs_map_or_leaf_value |
|
653
617
|
next if scim_attribute&.to_s&.downcase == 'id' && path.empty?
|
654
618
|
|
655
|
-
|
656
|
-
# @MorrisFreeman via:
|
657
|
-
#
|
658
|
-
# https://github.com/RIPAGlobal/scimitar/issues/48
|
659
|
-
# https://github.com/RIPAGlobal/scimitar/pull/49
|
660
|
-
#
|
661
|
-
attribute_tree = []
|
662
|
-
resource_class.extended_schemas.each do |schema|
|
663
|
-
attribute_tree << schema.id and break if schema.scim_attributes.any? { |attribute| attribute.name == scim_attribute.to_s }
|
664
|
-
end
|
665
|
-
attribute_tree << scim_attribute.to_s
|
666
|
-
|
667
|
-
sub_scim_hash_or_leaf_value = scim_hash_or_leaf_value&.dig(*attribute_tree)
|
619
|
+
sub_scim_hash_or_leaf_value = scim_hash_or_leaf_value&.dig(scim_attribute.to_s)
|
668
620
|
|
669
621
|
self.from_scim_backend!(
|
670
622
|
attrs_map_or_leaf_value: sub_attrs_map_or_leaf_value,
|
@@ -949,89 +901,10 @@ module Scimitar
|
|
949
901
|
else
|
950
902
|
altering_hash[path_component] = value
|
951
903
|
end
|
952
|
-
|
953
904
|
when 'replace'
|
954
|
-
|
955
|
-
dot_pathed_value = value.inject({}) do |hash, (k, v)|
|
956
|
-
hash.deep_merge!(::Scimitar::Support::Utilities.dot_path(k.split('.'), v))
|
957
|
-
end
|
958
|
-
altering_hash[path_component].deep_merge!(dot_pathed_value)
|
959
|
-
else
|
960
|
-
altering_hash[path_component] = value
|
961
|
-
end
|
962
|
-
|
963
|
-
# The array check handles payloads seen from e.g. Microsoft for
|
964
|
-
# remove-user-from-group, where contrary to examples in the RFC
|
965
|
-
# which would imply "payload removes all users", there is the
|
966
|
-
# clear intent to remove just one.
|
967
|
-
#
|
968
|
-
# https://tools.ietf.org/html/rfc7644#section-3.5.2.2
|
969
|
-
# https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/use-scim-to-provision-users-and-groups#update-group-remove-members
|
970
|
-
#
|
971
|
-
# Since remove-all in the face of remove-one is destructive, we
|
972
|
-
# do a special check here to see if there's an array value for
|
973
|
-
# the array path that the payload yielded. If so, we can match
|
974
|
-
# each value against array items and remove just those items.
|
975
|
-
#
|
976
|
-
# There is an additional special case to handle a bad example
|
977
|
-
# from Salesforce:
|
978
|
-
#
|
979
|
-
# https://help.salesforce.com/s/articleView?id=sf.identity_scim_manage_groups.htm&type=5
|
980
|
-
#
|
905
|
+
altering_hash[path_component] = value
|
981
906
|
when 'remove'
|
982
|
-
|
983
|
-
|
984
|
-
# Handle bad Salesforce example. That might be simply a
|
985
|
-
# documentation error, but just in case...
|
986
|
-
#
|
987
|
-
value = value.values.first if (
|
988
|
-
path_component&.downcase == 'members' &&
|
989
|
-
value.is_a?(Hash) &&
|
990
|
-
value.keys.size == 1 &&
|
991
|
-
value.keys.first&.downcase == 'members'
|
992
|
-
)
|
993
|
-
|
994
|
-
# The Microsoft example provides an array of values, but we
|
995
|
-
# may as well cope with a value specified 'flat'. Promote
|
996
|
-
# such a thing to an Array to simplify the following code.
|
997
|
-
#
|
998
|
-
value = [value] unless value.is_a?(Array)
|
999
|
-
|
1000
|
-
# For each value item, delete matching array entries. The
|
1001
|
-
# concept of "matching" is:
|
1002
|
-
#
|
1003
|
-
# * For simple non-Hash values (if possible) just delete on
|
1004
|
-
# an exact match
|
1005
|
-
#
|
1006
|
-
# * For Hash-based values, only delete if all 'patch' keys
|
1007
|
-
# are present in the resource and all values thus match.
|
1008
|
-
#
|
1009
|
-
# Special case to ignore '$ref' from the Microsoft payload.
|
1010
|
-
#
|
1011
|
-
# Note coercion to strings to account for SCIM vs the usual
|
1012
|
-
# tricky case of underlying implementations with (say)
|
1013
|
-
# integer primary keys, which all end up as strings anyway.
|
1014
|
-
#
|
1015
|
-
value.each do | value_item |
|
1016
|
-
altering_hash[path_component].delete_if do | item |
|
1017
|
-
if item.is_a?(Hash) && value_item.is_a?(Hash)
|
1018
|
-
matched_all = true
|
1019
|
-
value_item.each do | value_key, value_value |
|
1020
|
-
next if value_key == '$ref'
|
1021
|
-
if ! item.key?(value_key) || item[value_key]&.to_s != value_value&.to_s
|
1022
|
-
matched_all = false
|
1023
|
-
end
|
1024
|
-
end
|
1025
|
-
matched_all
|
1026
|
-
else
|
1027
|
-
item&.to_s == value_item&.to_s
|
1028
|
-
end
|
1029
|
-
end
|
1030
|
-
end
|
1031
|
-
else
|
1032
|
-
altering_hash.delete(path_component)
|
1033
|
-
end
|
1034
|
-
|
907
|
+
altering_hash.delete(path_component)
|
1035
908
|
end
|
1036
909
|
end
|
1037
910
|
end
|
@@ -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
|
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'
|