scimitar 1.5.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 +6 -27
- data/app/controllers/scimitar/application_controller.rb +9 -29
- data/app/models/scimitar/engine_configuration.rb +3 -7
- data/app/models/scimitar/error_response.rb +0 -12
- data/app/models/scimitar/errors.rb +1 -1
- data/app/models/scimitar/lists/query_parser.rb +4 -14
- data/app/models/scimitar/resources/base.rb +1 -1
- data/app/models/scimitar/resources/mixin.rb +4 -113
- data/app/models/scimitar/schema/address.rb +0 -1
- data/app/models/scimitar/schema/attribute.rb +1 -1
- data/app/models/scimitar/schema/base.rb +3 -1
- data/app/models/scimitar/schema/vdtp.rb +1 -1
- data/config/initializers/scimitar.rb +70 -86
- data/lib/scimitar/version.rb +2 -2
- 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 -19
- 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 +9 -44
- data/spec/apps/dummy/config/routes.rb +0 -4
- data/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb +1 -9
- 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 -10
- data/spec/controllers/scimitar/application_controller_spec.rb +1 -70
- data/spec/controllers/scimitar/schemas_controller_spec.rb +2 -2
- data/spec/models/scimitar/complex_types/email_spec.rb +2 -0
- data/spec/models/scimitar/lists/query_parser_spec.rb +9 -9
- data/spec/models/scimitar/resources/base_spec.rb +66 -161
- data/spec/models/scimitar/resources/base_validation_spec.rb +2 -27
- data/spec/models/scimitar/resources/mixin_spec.rb +43 -757
- data/spec/models/scimitar/resources/user_spec.rb +4 -4
- data/spec/models/scimitar/schema/attribute_spec.rb +3 -0
- 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 +40 -309
- data/spec/requests/application_controller_spec.rb +3 -17
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95a2166cc921a400959f9d8d4398f6bf8ecb772f8d7a0a0a73950892e85d808a
|
4
|
+
data.tar.gz: cdf5aab3812f10f69c96304e738a150f4208850267527b66d36eeb99548d7b1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f0925517599b107e44fd93db9be142aebe608892c2c5069c50d22b353c51238290710474b062a002fdb010be3d783c4dea3b314f72f47b4aca3c2385a8fc1377
|
7
|
+
data.tar.gz: eef6eebfc64bb2d4adabfca110f26e3a6c9e227f47387da6fb384925899ddf0ae260cf68176f24040a6bb356cf34f6576c920bd44264d4a1fee415aeadc237e6
|
@@ -21,8 +21,6 @@ module Scimitar
|
|
21
21
|
|
22
22
|
rescue_from ActiveRecord::RecordNotFound, with: :handle_resource_not_found # See Scimitar::ApplicationController
|
23
23
|
|
24
|
-
before_action :obtain_id_column_name_from_attribute_map
|
25
|
-
|
26
24
|
# GET (list)
|
27
25
|
#
|
28
26
|
def index
|
@@ -39,13 +37,12 @@ module Scimitar
|
|
39
37
|
pagination_info = scim_pagination_info(query.count())
|
40
38
|
|
41
39
|
page_of_results = query
|
42
|
-
.order(@id_column => :asc)
|
43
40
|
.offset(pagination_info.offset)
|
44
41
|
.limit(pagination_info.limit)
|
45
42
|
.to_a()
|
46
43
|
|
47
44
|
super(pagination_info, page_of_results) do | record |
|
48
|
-
|
45
|
+
record.to_scim(location: url_for(action: :show, id: record.id))
|
49
46
|
end
|
50
47
|
end
|
51
48
|
|
@@ -54,7 +51,7 @@ module Scimitar
|
|
54
51
|
def show
|
55
52
|
super do |record_id|
|
56
53
|
record = self.find_record(record_id)
|
57
|
-
|
54
|
+
record.to_scim(location: url_for(action: :show, id: record_id))
|
58
55
|
end
|
59
56
|
end
|
60
57
|
|
@@ -66,7 +63,7 @@ module Scimitar
|
|
66
63
|
record = self.storage_class().new
|
67
64
|
record.from_scim!(scim_hash: scim_resource.as_json())
|
68
65
|
self.save!(record)
|
69
|
-
|
66
|
+
record.to_scim(location: url_for(action: :show, id: record.id))
|
70
67
|
end
|
71
68
|
end
|
72
69
|
end
|
@@ -79,7 +76,7 @@ module Scimitar
|
|
79
76
|
record = self.find_record(record_id)
|
80
77
|
record.from_scim!(scim_hash: scim_resource.as_json())
|
81
78
|
self.save!(record)
|
82
|
-
|
79
|
+
record.to_scim(location: url_for(action: :show, id: record.id))
|
83
80
|
end
|
84
81
|
end
|
85
82
|
end
|
@@ -92,7 +89,7 @@ module Scimitar
|
|
92
89
|
record = self.find_record(record_id)
|
93
90
|
record.from_scim_patch!(patch_hash: patch_hash)
|
94
91
|
self.save!(record)
|
95
|
-
|
92
|
+
record.to_scim(location: url_for(action: :show, id: record.id))
|
96
93
|
end
|
97
94
|
end
|
98
95
|
end
|
@@ -140,14 +137,7 @@ module Scimitar
|
|
140
137
|
# +record_id+:: Record ID (SCIM schema 'id' value - "our" ID).
|
141
138
|
#
|
142
139
|
def find_record(record_id)
|
143
|
-
self.storage_scope().
|
144
|
-
end
|
145
|
-
|
146
|
-
# DRY up controller actions - pass a record; returns the SCIM
|
147
|
-
# representation, with a "show" location specified via #url_for.
|
148
|
-
#
|
149
|
-
def record_to_scim(record)
|
150
|
-
record.to_scim(location: url_for(action: :show, id: record.send(@id_column)))
|
140
|
+
self.storage_scope().find(record_id)
|
151
141
|
end
|
152
142
|
|
153
143
|
# Save a record, dealing with validation exceptions by raising SCIM
|
@@ -186,16 +176,5 @@ module Scimitar
|
|
186
176
|
end
|
187
177
|
end
|
188
178
|
|
189
|
-
# Called via +before_action+ - stores in @id_column the name of whatever
|
190
|
-
# model column is used to store the record ID, via
|
191
|
-
# Scimitar::Resources::Mixin::scim_attributes_map.
|
192
|
-
#
|
193
|
-
# Default is <tt>:id</tt>.
|
194
|
-
#
|
195
|
-
def obtain_id_column_name_from_attribute_map
|
196
|
-
attrs = storage_class().scim_attributes_map() || {}
|
197
|
-
@id_column = attrs[:id] || :id
|
198
|
-
end
|
199
|
-
|
200
179
|
end
|
201
180
|
end
|
@@ -25,12 +25,10 @@ module Scimitar
|
|
25
25
|
#
|
26
26
|
# ...to "globally" invoke this handler if you wish.
|
27
27
|
#
|
28
|
+
# +_exception+:: Exception instance (currently unused).
|
28
29
|
#
|
29
|
-
|
30
|
-
|
31
|
-
#
|
32
|
-
def handle_resource_not_found(exception)
|
33
|
-
handle_scim_error(NotFoundError.new(params[:id]), exception)
|
30
|
+
def handle_resource_not_found(_exception)
|
31
|
+
handle_scim_error(NotFoundError.new(params[:id]))
|
34
32
|
end
|
35
33
|
|
36
34
|
# This base controller uses:
|
@@ -40,22 +38,9 @@ module Scimitar
|
|
40
38
|
# ...to "globally" invoke this handler for all Scimitar errors (including
|
41
39
|
# subclasses).
|
42
40
|
#
|
43
|
-
# Mandatory parameters are:
|
44
|
-
#
|
45
41
|
# +error_response+:: Scimitar::ErrorResponse (or subclass) instance.
|
46
42
|
#
|
47
|
-
|
48
|
-
#
|
49
|
-
# *exception+:: If a Ruby exception was the reason this method is being
|
50
|
-
# called, pass it here. Any configured exception reporting
|
51
|
-
# mechanism will be invokved with the given parameter.
|
52
|
-
# Otherwise, the +error_response+ value is reported.
|
53
|
-
#
|
54
|
-
def handle_scim_error(error_response, exception = error_response)
|
55
|
-
unless Scimitar.engine_configuration.exception_reporter.nil?
|
56
|
-
Scimitar.engine_configuration.exception_reporter.call(exception)
|
57
|
-
end
|
58
|
-
|
43
|
+
def handle_scim_error(error_response)
|
59
44
|
render json: error_response, status: error_response.status
|
60
45
|
end
|
61
46
|
|
@@ -70,7 +55,7 @@ module Scimitar
|
|
70
55
|
# +exception+:: Exception instance.
|
71
56
|
#
|
72
57
|
def handle_bad_json_error(exception)
|
73
|
-
handle_scim_error(ErrorResponse.new(status: 400, detail: "Invalid JSON - #{exception.message}")
|
58
|
+
handle_scim_error(ErrorResponse.new(status: 400, detail: "Invalid JSON - #{exception.message}"))
|
74
59
|
end
|
75
60
|
|
76
61
|
# This base controller uses:
|
@@ -83,7 +68,7 @@ module Scimitar
|
|
83
68
|
#
|
84
69
|
def handle_unexpected_error(exception)
|
85
70
|
Rails.logger.error("#{exception.message}\n#{exception.backtrace}")
|
86
|
-
handle_scim_error(ErrorResponse.new(status: 500, detail: exception.message)
|
71
|
+
handle_scim_error(ErrorResponse.new(status: 500, detail: exception.message))
|
87
72
|
end
|
88
73
|
|
89
74
|
# =========================================================================
|
@@ -97,17 +82,12 @@ module Scimitar
|
|
97
82
|
# request and subclass processing.
|
98
83
|
#
|
99
84
|
def require_scim
|
100
|
-
|
101
|
-
|
102
|
-
if request.media_type.nil? || request.media_type.empty?
|
103
|
-
request.format = :scim
|
104
|
-
request.headers['CONTENT_TYPE'] = scim_mime_type
|
105
|
-
elsif request.media_type.downcase == scim_mime_type
|
85
|
+
if request.content_type&.downcase == Mime::Type.lookup_by_extension(:scim).to_s
|
106
86
|
request.format = :scim
|
107
87
|
elsif request.format == :scim
|
108
|
-
request.headers['CONTENT_TYPE'] =
|
88
|
+
request.headers['CONTENT_TYPE'] = Mime::Type.lookup_by_extension(:scim).to_s
|
109
89
|
else
|
110
|
-
handle_scim_error(ErrorResponse.new(status: 406, detail: "Only #{
|
90
|
+
handle_scim_error(ErrorResponse.new(status: 406, detail: "Only #{Mime::Type.lookup_by_extension(:scim)} type is accepted."))
|
111
91
|
end
|
112
92
|
end
|
113
93
|
|
@@ -9,17 +9,13 @@ module Scimitar
|
|
9
9
|
|
10
10
|
attr_accessor :basic_authenticator,
|
11
11
|
:token_authenticator,
|
12
|
-
:application_controller_mixin
|
13
|
-
:exception_reporter,
|
14
|
-
:optional_value_fields_required
|
12
|
+
:application_controller_mixin
|
15
13
|
|
16
14
|
def initialize(attributes = {})
|
17
15
|
|
18
|
-
#
|
16
|
+
# No defaults yet - reserved for future use.
|
19
17
|
#
|
20
|
-
defaults = {
|
21
|
-
optional_value_fields_required: true
|
22
|
-
}
|
18
|
+
defaults = {}
|
23
19
|
|
24
20
|
super(defaults.merge(attributes))
|
25
21
|
end
|
@@ -16,17 +16,5 @@ module Scimitar
|
|
16
16
|
data['scimType'] = scimType if scimType
|
17
17
|
data
|
18
18
|
end
|
19
|
-
|
20
|
-
# Originally Scimitar used attribute "detail" for exception text; it was
|
21
|
-
# only for JSON responses at the time, but in hindsight was a bad choice.
|
22
|
-
# It should have been "message" given inheritance from StandardError, which
|
23
|
-
# then works properly with e.g. error reporting services.
|
24
|
-
#
|
25
|
-
# The "detail" attribute is still present, for backwards compatibility with
|
26
|
-
# any client code that might be using this class.
|
27
|
-
#
|
28
|
-
def message
|
29
|
-
self.detail
|
30
|
-
end
|
31
19
|
end
|
32
20
|
end
|
@@ -78,7 +78,7 @@ module Scimitar
|
|
78
78
|
# method's return value here.
|
79
79
|
#
|
80
80
|
def initialize(attribute_map)
|
81
|
-
@attribute_map = attribute_map
|
81
|
+
@attribute_map = attribute_map
|
82
82
|
end
|
83
83
|
|
84
84
|
# Parse SCIM filter query into RPN stack
|
@@ -605,16 +605,6 @@ module Scimitar
|
|
605
605
|
|
606
606
|
raise Scimitar::FilterError unless all_supported
|
607
607
|
|
608
|
-
unless case_sensitive
|
609
|
-
lc_scim_attribute = scim_attribute.downcase()
|
610
|
-
|
611
|
-
case_sensitive = (
|
612
|
-
lc_scim_attribute == 'id' ||
|
613
|
-
lc_scim_attribute == 'externalid' ||
|
614
|
-
lc_scim_attribute.start_with?('meta.')
|
615
|
-
)
|
616
|
-
end
|
617
|
-
|
618
608
|
column_names.each.with_index do | column_name, index |
|
619
609
|
arel_column = arel_table[column_name]
|
620
610
|
arel_operation = case scim_operator
|
@@ -643,7 +633,7 @@ module Scimitar
|
|
643
633
|
when 'pr'
|
644
634
|
arel_table.grouping(arel_column.not_eq_all(['', nil]))
|
645
635
|
else
|
646
|
-
raise Scimitar::FilterError
|
636
|
+
raise Scimitar::FilterError
|
647
637
|
end
|
648
638
|
|
649
639
|
if index == 0
|
@@ -666,10 +656,10 @@ module Scimitar
|
|
666
656
|
# +scim_attribute+:: SCIM attribute from a filter string.
|
667
657
|
#
|
668
658
|
def activerecord_columns(scim_attribute)
|
669
|
-
raise Scimitar::FilterError
|
659
|
+
raise Scimitar::FilterError if scim_attribute.blank?
|
670
660
|
|
671
661
|
mapped_attribute = self.attribute_map()[scim_attribute]
|
672
|
-
raise Scimitar::FilterError
|
662
|
+
raise Scimitar::FilterError if mapped_attribute.blank?
|
673
663
|
|
674
664
|
if mapped_attribute[:ignore]
|
675
665
|
return []
|
@@ -138,7 +138,7 @@ module Scimitar
|
|
138
138
|
end
|
139
139
|
|
140
140
|
def as_json(options = {})
|
141
|
-
self.meta = Meta.new unless self.meta
|
141
|
+
self.meta = Meta.new unless self.meta
|
142
142
|
meta.resourceType = self.class.resource_type_id
|
143
143
|
original_hash = super(options).except('errors')
|
144
144
|
original_hash.merge!('schemas' => self.class.schemas.map(&:id))
|
@@ -443,30 +443,9 @@ module Scimitar
|
|
443
443
|
ci_scim_hash = { 'root' => ci_scim_hash }.with_indifferent_case_insensitive_access()
|
444
444
|
end
|
445
445
|
|
446
|
-
# Handle extension schema. Contributed by @bettysteger and
|
447
|
-
# @MorrisFreeman via:
|
448
|
-
#
|
449
|
-
# https://github.com/RIPAGlobal/scimitar/issues/48
|
450
|
-
# https://github.com/RIPAGlobal/scimitar/pull/49
|
451
|
-
#
|
452
|
-
# Note the ":" separating the schema ID (URN) from the attribute.
|
453
|
-
# The nature of JSON rendering / other payloads might lead you to
|
454
|
-
# expect a "." as with any complex types, but that's not the case;
|
455
|
-
# see https://tools.ietf.org/html/rfc7644#section-3.10, or
|
456
|
-
# https://tools.ietf.org/html/rfc7644#section-3.5.2 of which in
|
457
|
-
# particular, https://tools.ietf.org/html/rfc7644#page-35.
|
458
|
-
#
|
459
|
-
paths = []
|
460
|
-
self.class.scim_resource_type.extended_schemas.each do |schema|
|
461
|
-
path_str.downcase.split(schema.id.downcase + ':').drop(1).each do |path|
|
462
|
-
paths += [schema.id] + path.split('.')
|
463
|
-
end
|
464
|
-
end
|
465
|
-
paths = path_str.split('.') if paths.empty?
|
466
|
-
|
467
446
|
self.from_patch_backend!(
|
468
447
|
nature: nature,
|
469
|
-
path:
|
448
|
+
path: (path_str || '').split('.'),
|
470
449
|
value: value,
|
471
450
|
altering_hash: ci_scim_hash
|
472
451
|
)
|
@@ -637,19 +616,7 @@ module Scimitar
|
|
637
616
|
attrs_map_or_leaf_value.each do | scim_attribute, sub_attrs_map_or_leaf_value |
|
638
617
|
next if scim_attribute&.to_s&.downcase == 'id' && path.empty?
|
639
618
|
|
640
|
-
|
641
|
-
# @MorrisFreeman via:
|
642
|
-
#
|
643
|
-
# https://github.com/RIPAGlobal/scimitar/issues/48
|
644
|
-
# https://github.com/RIPAGlobal/scimitar/pull/49
|
645
|
-
#
|
646
|
-
attribute_tree = []
|
647
|
-
resource_class.extended_schemas.each do |schema|
|
648
|
-
attribute_tree << schema.id and break if schema.scim_attributes.any? { |attribute| attribute.name == scim_attribute.to_s }
|
649
|
-
end
|
650
|
-
attribute_tree << scim_attribute.to_s
|
651
|
-
|
652
|
-
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)
|
653
620
|
|
654
621
|
self.from_scim_backend!(
|
655
622
|
attrs_map_or_leaf_value: sub_attrs_map_or_leaf_value,
|
@@ -934,86 +901,10 @@ module Scimitar
|
|
934
901
|
else
|
935
902
|
altering_hash[path_component] = value
|
936
903
|
end
|
937
|
-
|
938
904
|
when 'replace'
|
939
|
-
|
940
|
-
altering_hash[path_component].merge!(value)
|
941
|
-
else
|
942
|
-
altering_hash[path_component] = value
|
943
|
-
end
|
944
|
-
|
945
|
-
# The array check handles payloads seen from e.g. Microsoft for
|
946
|
-
# remove-user-from-group, where contrary to examples in the RFC
|
947
|
-
# which would imply "payload removes all users", there is the
|
948
|
-
# clear intent to remove just one.
|
949
|
-
#
|
950
|
-
# https://tools.ietf.org/html/rfc7644#section-3.5.2.2
|
951
|
-
# https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/use-scim-to-provision-users-and-groups#update-group-remove-members
|
952
|
-
#
|
953
|
-
# Since remove-all in the face of remove-one is destructive, we
|
954
|
-
# do a special check here to see if there's an array value for
|
955
|
-
# the array path that the payload yielded. If so, we can match
|
956
|
-
# each value against array items and remove just those items.
|
957
|
-
#
|
958
|
-
# There is an additional special case to handle a bad example
|
959
|
-
# from Salesforce:
|
960
|
-
#
|
961
|
-
# https://help.salesforce.com/s/articleView?id=sf.identity_scim_manage_groups.htm&type=5
|
962
|
-
#
|
905
|
+
altering_hash[path_component] = value
|
963
906
|
when 'remove'
|
964
|
-
|
965
|
-
|
966
|
-
# Handle bad Salesforce example. That might be simply a
|
967
|
-
# documentation error, but just in case...
|
968
|
-
#
|
969
|
-
value = value.values.first if (
|
970
|
-
path_component&.downcase == 'members' &&
|
971
|
-
value.is_a?(Hash) &&
|
972
|
-
value.keys.size == 1 &&
|
973
|
-
value.keys.first&.downcase == 'members'
|
974
|
-
)
|
975
|
-
|
976
|
-
# The Microsoft example provides an array of values, but we
|
977
|
-
# may as well cope with a value specified 'flat'. Promote
|
978
|
-
# such a thing to an Array to simplify the following code.
|
979
|
-
#
|
980
|
-
value = [value] unless value.is_a?(Array)
|
981
|
-
|
982
|
-
# For each value item, delete matching array entries. The
|
983
|
-
# concept of "matching" is:
|
984
|
-
#
|
985
|
-
# * For simple non-Hash values (if possible) just delete on
|
986
|
-
# an exact match
|
987
|
-
#
|
988
|
-
# * For Hash-based values, only delete if all 'patch' keys
|
989
|
-
# are present in the resource and all values thus match.
|
990
|
-
#
|
991
|
-
# Special case to ignore '$ref' from the Microsoft payload.
|
992
|
-
#
|
993
|
-
# Note coercion to strings to account for SCIM vs the usual
|
994
|
-
# tricky case of underlying implementations with (say)
|
995
|
-
# integer primary keys, which all end up as strings anyway.
|
996
|
-
#
|
997
|
-
value.each do | value_item |
|
998
|
-
altering_hash[path_component].delete_if do | item |
|
999
|
-
if item.is_a?(Hash) && value_item.is_a?(Hash)
|
1000
|
-
matched_all = true
|
1001
|
-
value_item.each do | value_key, value_value |
|
1002
|
-
next if value_key == '$ref'
|
1003
|
-
if ! item.key?(value_key) || item[value_key]&.to_s != value_value&.to_s
|
1004
|
-
matched_all = false
|
1005
|
-
end
|
1006
|
-
end
|
1007
|
-
matched_all
|
1008
|
-
else
|
1009
|
-
item&.to_s == value_item&.to_s
|
1010
|
-
end
|
1011
|
-
end
|
1012
|
-
end
|
1013
|
-
else
|
1014
|
-
altering_hash.delete(path_component)
|
1015
|
-
end
|
1016
|
-
|
907
|
+
altering_hash.delete(path_component)
|
1017
908
|
end
|
1018
909
|
end
|
1019
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'),
|
@@ -26,7 +26,9 @@ module Scimitar
|
|
26
26
|
#
|
27
27
|
def self.valid?(resource)
|
28
28
|
cloned_scim_attributes.each do |scim_attribute|
|
29
|
-
|
29
|
+
unless scim_attribute.valid?(resource.send(scim_attribute.name))
|
30
|
+
resource.add_errors_from_hash(errors_hash: scim_attribute.errors.to_hash)
|
31
|
+
end
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
@@ -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'),
|
@@ -2,101 +2,85 @@
|
|
2
2
|
#
|
3
3
|
# For supporting information and rationale, please see README.md.
|
4
4
|
|
5
|
-
#
|
6
|
-
# SERVICE PROVIDER CONFIGURATION
|
7
|
-
# =============================================================================
|
8
|
-
#
|
9
|
-
# This is a Ruby abstraction over a SCIM entity that declares the capabilities
|
10
|
-
# supported by a particular implementation.
|
11
|
-
#
|
12
|
-
# Typically this is used to declare parts of the standard unsupported, if you
|
13
|
-
# don't need them and don't want to provide subclass support.
|
14
|
-
#
|
15
|
-
Scimitar.service_provider_configuration = Scimitar::ServiceProviderConfiguration.new({
|
5
|
+
Rails.application.config.to_prepare do # (required for >= Rails 7 / Zeitwerk)
|
16
6
|
|
17
|
-
#
|
7
|
+
# ===========================================================================
|
8
|
+
# SERVICE PROVIDER CONFIGURATION
|
9
|
+
# ===========================================================================
|
18
10
|
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# that filters are not supported so that calling clients shouldn't use them:
|
11
|
+
# This is a Ruby abstraction over a SCIM entity that declares the
|
12
|
+
# capabilities supported by a particular implementation.
|
22
13
|
#
|
23
|
-
#
|
14
|
+
# Typically this is used to declare parts of the standard unsupported, if you
|
15
|
+
# don't need them and don't want to provide subclass support.
|
16
|
+
#
|
17
|
+
Scimitar.service_provider_configuration = Scimitar::ServiceProviderConfiguration.new({
|
24
18
|
|
25
|
-
|
19
|
+
# See https://tools.ietf.org/html/rfc7643#section-8.5 for properties.
|
20
|
+
#
|
21
|
+
# See Gem file 'app/models/scimitar/service_provider_configuration.rb'
|
22
|
+
# for defaults. Define Hash keys here that override defaults; e.g. to
|
23
|
+
# declare that filters are not supported so that calling clients shouldn't
|
24
|
+
# use them:
|
25
|
+
#
|
26
|
+
# filter: Scimitar::Supported.unsupported
|
26
27
|
|
27
|
-
|
28
|
-
# ENGINE CONFIGURATION
|
29
|
-
# =============================================================================
|
30
|
-
#
|
31
|
-
# This is where you provide callbacks for things like authorisation or mixins
|
32
|
-
# that get included into all Scimitar-derived controllers (for things like
|
33
|
-
# before-actions that apply to all Scimitar controller-based routes).
|
34
|
-
#
|
35
|
-
Scimitar.engine_configuration = Scimitar::EngineConfiguration.new({
|
28
|
+
})
|
36
29
|
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
# For example:
|
42
|
-
#
|
43
|
-
# application_controller_mixin: Module.new do
|
44
|
-
# def self.included(base)
|
45
|
-
# base.class_eval do
|
30
|
+
# ===========================================================================
|
31
|
+
# ENGINE CONFIGURATION
|
32
|
+
# ===========================================================================
|
46
33
|
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
34
|
+
# This is where you provide callbacks for things like authorisation or mixins
|
35
|
+
# that get included into all Scimitar-derived controllers (for things like
|
36
|
+
# before-actions that apply to all Scimitar controller-based routes).
|
50
37
|
#
|
51
|
-
|
52
|
-
# prepend_before_action :setup_some_kind_of_multi_tenancy_data
|
53
|
-
# end
|
54
|
-
# end
|
55
|
-
# end, # ...other configuration entries might follow...
|
38
|
+
Scimitar.engine_configuration = Scimitar::EngineConfiguration.new({
|
56
39
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
40
|
+
# If you have filters you want to run for any Scimitar action/route, you
|
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:
|
44
|
+
#
|
45
|
+
# application_controller_mixin: Module.new do
|
46
|
+
# def self.included(base)
|
47
|
+
# base.class_eval do
|
48
|
+
#
|
49
|
+
# # Anything here is written just as you'd write it at the top of
|
50
|
+
# # one of your controller classes, but it gets included in all
|
51
|
+
# # Scimitar classes too.
|
52
|
+
#
|
53
|
+
# skip_before_action :verify_authenticity_token
|
54
|
+
# prepend_before_action :setup_some_kind_of_multi_tenancy_data
|
55
|
+
# end
|
56
|
+
# end
|
57
|
+
# end, # ...other configuration entries might follow...
|
67
58
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
#
|
79
|
-
# Note that both basic and token authentication can be declared, with the
|
80
|
-
# parameters in the inbound HTTP request determining which is invoked.
|
59
|
+
# If you want to support username/password authentication:
|
60
|
+
#
|
61
|
+
# basic_authenticator: Proc.new do | username, password |
|
62
|
+
# # Check username/password and return 'true' if valid, else 'false'.
|
63
|
+
# end, # ...other configuration entries might follow...
|
64
|
+
#
|
65
|
+
# The 'username' and 'password' parameters come from Rails:
|
66
|
+
#
|
67
|
+
# https://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Basic.html
|
68
|
+
# https://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Basic/ControllerMethods.html#method-i-authenticate_with_http_basic
|
81
69
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
70
|
+
# If you want to support HTTP bearer token (OAuth-style) authentication:
|
71
|
+
#
|
72
|
+
# token_authenticator: Proc.new do | token, options |
|
73
|
+
# # Check token and return 'true' if valid, else 'false'.
|
74
|
+
# end, # ...other configuration entries might follow...
|
75
|
+
#
|
76
|
+
# The 'token' and 'options' parameters come from Rails:
|
77
|
+
#
|
78
|
+
# https://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html
|
79
|
+
# https://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token/ControllerMethods.html#method-i-authenticate_with_http_token
|
80
|
+
#
|
81
|
+
# Note that both basic and token authentication can be declared, with the
|
82
|
+
# parameters in the inbound HTTP request determining which is invoked.
|
94
83
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
# you can configure all values to be optional. You'll need to deal with
|
99
|
-
# whatever that means for you receiving system in your model code.
|
100
|
-
#
|
101
|
-
# optional_value_fields_required: false
|
102
|
-
})
|
84
|
+
})
|
85
|
+
|
86
|
+
end
|