scimitar 2.7.2 → 2.7.3
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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7524696efa05186edcbba9876a3309d3c8a8d51772e3ac0a009a9e83d8f25d16
|
4
|
+
data.tar.gz: e6cad46dc8754981f1d85cc9bcc98f73f9edddfa0d0386497b710acd11ad666c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d040bbf693140f5e62dea569d02d977cb5fd966d2464c0a722bea449428de097901471a2f4b0c2380cf935c424195336d7eed4f469a8ebd019d4277dbe90c629
|
7
|
+
data.tar.gz: 15616cedc7fffc3df69dcc1b2f35e9bd3c5408e12f8cccd536d724ce2925c72e4aa9a8f63732135ba3a71d23438dc02e8835978ff37977722cd23cab63c1ee28
|
@@ -483,26 +483,14 @@ module Scimitar
|
|
483
483
|
ci_scim_hash = { 'root' => ci_scim_hash }.with_indifferent_case_insensitive_access()
|
484
484
|
end
|
485
485
|
|
486
|
-
#
|
487
|
-
#
|
486
|
+
# Split the path into an array of path components, in a way
|
487
|
+
# which is aware of extension schemas. See documentation of
|
488
|
+
# Scimitar::Support::Utilities.path_str_to_array for details.
|
488
489
|
#
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
# The nature of JSON rendering / other payloads might lead you to
|
494
|
-
# expect a "." as with any complex types, but that's not the case;
|
495
|
-
# see https://tools.ietf.org/html/rfc7644#section-3.10, or
|
496
|
-
# https://tools.ietf.org/html/rfc7644#section-3.5.2 of which in
|
497
|
-
# particular, https://tools.ietf.org/html/rfc7644#page-35.
|
498
|
-
#
|
499
|
-
paths = []
|
500
|
-
self.class.scim_resource_type.extended_schemas.each do |schema|
|
501
|
-
path_str.downcase.split(schema.id.downcase + ':').drop(1).each do |path|
|
502
|
-
paths += [schema.id] + path.split('.')
|
503
|
-
end
|
504
|
-
end
|
505
|
-
paths = path_str.split('.') if paths.empty?
|
490
|
+
paths = ::Scimitar::Support::Utilities.path_str_to_array(
|
491
|
+
self.class.scim_resource_type.extended_schemas,
|
492
|
+
path_str
|
493
|
+
)
|
506
494
|
|
507
495
|
self.from_patch_backend!(
|
508
496
|
nature: nature,
|
@@ -740,9 +728,17 @@ module Scimitar
|
|
740
728
|
# https://github.com/RIPAGlobal/scimitar/issues/48
|
741
729
|
# https://github.com/RIPAGlobal/scimitar/pull/49
|
742
730
|
#
|
731
|
+
# Note the shortcoming that attribute names within extensions
|
732
|
+
# must be unique, as this mechanism basically just pulls out
|
733
|
+
# extension attributes to the top level, losing what amounts
|
734
|
+
# to the namespace that the extension schema ID provides.
|
735
|
+
#
|
743
736
|
attribute_tree = []
|
744
737
|
resource_class.extended_schemas.each do |schema|
|
745
|
-
|
738
|
+
if schema.scim_attributes.any? { |attribute| attribute.name == scim_attribute.to_s }
|
739
|
+
attribute_tree << schema.id
|
740
|
+
break # NOTE EARLY LOOP EXIT
|
741
|
+
end
|
746
742
|
end
|
747
743
|
attribute_tree << scim_attribute.to_s
|
748
744
|
|
@@ -950,7 +946,11 @@ module Scimitar
|
|
950
946
|
end
|
951
947
|
|
952
948
|
found_data_for_recursion.each do | found_data |
|
953
|
-
attr_map =
|
949
|
+
attr_map = if path_component.to_sym == :root
|
950
|
+
with_attr_map
|
951
|
+
else
|
952
|
+
with_attr_map[path_component.to_sym]
|
953
|
+
end
|
954
954
|
|
955
955
|
# Static array mappings need us to find the right map entry that
|
956
956
|
# corresponds to the SCIM data at hand and recurse back into the
|
@@ -1091,9 +1091,27 @@ module Scimitar
|
|
1091
1091
|
# at key 'members' with the above, rather than adding.
|
1092
1092
|
#
|
1093
1093
|
value.keys.each do | key |
|
1094
|
+
|
1095
|
+
# Handle the Azure (Entra) case where keys might use
|
1096
|
+
# dotted paths - see:
|
1097
|
+
#
|
1098
|
+
# https://github.com/RIPAGlobal/scimitar/issues/123
|
1099
|
+
#
|
1100
|
+
# ...along with keys containing schema IDs - see:
|
1101
|
+
#
|
1102
|
+
# https://is.docs.wso2.com/en/next/apis/scim2-patch-operations/#add-user-attributes
|
1103
|
+
#
|
1104
|
+
# ...and scroll down to example 3 of "Complex singular
|
1105
|
+
# attributes".
|
1106
|
+
#
|
1107
|
+
subpaths = ::Scimitar::Support::Utilities.path_str_to_array(
|
1108
|
+
self.class.scim_resource_type.extended_schemas,
|
1109
|
+
key
|
1110
|
+
)
|
1111
|
+
|
1094
1112
|
from_patch_backend!(
|
1095
1113
|
nature: nature,
|
1096
|
-
path: path +
|
1114
|
+
path: path + subpaths,
|
1097
1115
|
value: value[key],
|
1098
1116
|
altering_hash: altering_hash,
|
1099
1117
|
with_attr_map: with_attr_map
|
@@ -1106,7 +1124,12 @@ module Scimitar
|
|
1106
1124
|
when 'replace'
|
1107
1125
|
if path_component == 'root'
|
1108
1126
|
dot_pathed_value = value.inject({}) do |hash, (k, v)|
|
1109
|
-
|
1127
|
+
subpaths = ::Scimitar::Support::Utilities.path_str_to_array(
|
1128
|
+
self.class.scim_resource_type.extended_schemas,
|
1129
|
+
k
|
1130
|
+
)
|
1131
|
+
|
1132
|
+
hash.deep_merge!(::Scimitar::Support::Utilities.dot_path(subpaths, v))
|
1110
1133
|
end
|
1111
1134
|
|
1112
1135
|
altering_hash[path_component].deep_merge!(dot_pathed_value)
|
@@ -46,6 +46,61 @@ module Scimitar
|
|
46
46
|
hash[array.shift()] = self.dot_path(array, value)
|
47
47
|
end
|
48
48
|
end
|
49
|
+
|
50
|
+
# Schema ID-aware splitter handling ":" or "." separators. Adapted from
|
51
|
+
# contribution by @bettysteger and @MorrisFreeman in:
|
52
|
+
#
|
53
|
+
# https://github.com/RIPAGlobal/scimitar/issues/48
|
54
|
+
# https://github.com/RIPAGlobal/scimitar/pull/49
|
55
|
+
#
|
56
|
+
# +schemas:: Array of extension schemas, e.g. a SCIM resource class'
|
57
|
+
# <tt>scim_resource_type.extended_schemas</tt> value. The
|
58
|
+
# Array should be empty if there are no extensions.
|
59
|
+
#
|
60
|
+
# +path_str+:: Path string, e.g. <tt>"password"</tt>, <tt>"name.givenName"</tt>,
|
61
|
+
# <tt>"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"</tt> (special case),
|
62
|
+
# <tt>"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:organization"</tt>
|
63
|
+
#
|
64
|
+
# Returns an array of components, e.g. <tt>["password"]</tt>, <tt>["name",
|
65
|
+
# "givenName"]</tt>,
|
66
|
+
# <tt>["urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"]</tt> (special case),
|
67
|
+
# <tt>["urn:ietf:params:scim:schemas:extension:enterprise:2.0:User", "organization"]</tt>.
|
68
|
+
#
|
69
|
+
# The called-out special case is for a schema ID without any appended
|
70
|
+
# path components, which is returned as a single element ID to aid in
|
71
|
+
# traversal particularly of things like PATCH requests. There, a "value"
|
72
|
+
# attribute might have a key string that's simply a schema ID, with an
|
73
|
+
# object beneath that's got attribute-name pairs, possibly nested, in a
|
74
|
+
# path-free payload.
|
75
|
+
#
|
76
|
+
def self.path_str_to_array(schemas, path_str)
|
77
|
+
components = []
|
78
|
+
|
79
|
+
# Note the ":" separating the schema ID (URN) from the attribute.
|
80
|
+
# The nature of JSON rendering / other payloads might lead you to
|
81
|
+
# expect a "." as with any complex types, but that's not the case;
|
82
|
+
# see https://tools.ietf.org/html/rfc7644#section-3.10, or
|
83
|
+
# https://tools.ietf.org/html/rfc7644#section-3.5.2 of which in
|
84
|
+
# particular, https://tools.ietf.org/html/rfc7644#page-35.
|
85
|
+
#
|
86
|
+
if path_str.include?(':')
|
87
|
+
schemas.each do |schema|
|
88
|
+
attributes_after_schema_id = path_str.downcase.split(schema.id.downcase + ':').drop(1)
|
89
|
+
|
90
|
+
if attributes_after_schema_id.empty?
|
91
|
+
components += [schema.id]
|
92
|
+
else
|
93
|
+
attributes_after_schema_id.each do |component|
|
94
|
+
components += [schema.id] + component.split('.')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
components = path_str.split('.') if components.empty?
|
101
|
+
return components
|
102
|
+
end
|
103
|
+
|
49
104
|
end
|
50
105
|
end
|
51
106
|
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 = '2.7.
|
6
|
+
VERSION = '2.7.3'
|
7
7
|
|
8
8
|
# Date for VERSION. If this changes, be sure to re-run "bundle install"
|
9
9
|
# or "bundle update".
|
10
10
|
#
|
11
|
-
DATE = '2024-
|
11
|
+
DATE = '2024-06-11'
|
12
12
|
|
13
13
|
end
|
@@ -764,6 +764,106 @@ RSpec.describe Scimitar::ActiveRecordBackedResourcesController do
|
|
764
764
|
expect(@u2.password).to eql('oldpassword')
|
765
765
|
end
|
766
766
|
|
767
|
+
context 'which' do
|
768
|
+
shared_examples 'it handles not-to-spec in-value Azure/Entra dotted attribute paths' do | operation |
|
769
|
+
it "and performs operation" do
|
770
|
+
payload = {
|
771
|
+
Operations: [
|
772
|
+
{
|
773
|
+
op: 'add',
|
774
|
+
value: {
|
775
|
+
'name.givenName' => 'Foo!',
|
776
|
+
'name.familyName' => 'Bar!',
|
777
|
+
'name.formatted' => 'Foo! Bar!' # Unrecognised; should be ignored
|
778
|
+
},
|
779
|
+
},
|
780
|
+
]
|
781
|
+
}
|
782
|
+
|
783
|
+
payload = spec_helper_hupcase(payload) if force_upper_case
|
784
|
+
patch "/Users/#{@u2.primary_key}", params: payload.merge(format: :scim)
|
785
|
+
|
786
|
+
expect(response.status ).to eql(200)
|
787
|
+
expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
|
788
|
+
|
789
|
+
@u2.reload
|
790
|
+
result = JSON.parse(response.body)
|
791
|
+
|
792
|
+
expect(@u2.first_name).to eql('Foo!')
|
793
|
+
expect(@u2.last_name ).to eql('Bar!')
|
794
|
+
end
|
795
|
+
end
|
796
|
+
|
797
|
+
it_behaves_like 'it handles not-to-spec in-value Azure/Entra dotted attribute paths', 'add'
|
798
|
+
it_behaves_like 'it handles not-to-spec in-value Azure/Entra dotted attribute paths', 'replace'
|
799
|
+
|
800
|
+
shared_examples 'it handles schema ID value keys without inline attributes' do | operation |
|
801
|
+
it "and performs operation" do
|
802
|
+
payload = {
|
803
|
+
Operations: [
|
804
|
+
{
|
805
|
+
op: operation,
|
806
|
+
value: {
|
807
|
+
'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User': {
|
808
|
+
'organization' => 'Foo Bar!',
|
809
|
+
'department' => 'Bar Foo!'
|
810
|
+
},
|
811
|
+
},
|
812
|
+
},
|
813
|
+
]
|
814
|
+
}
|
815
|
+
|
816
|
+
@u2.update!(organization: 'Old org')
|
817
|
+
payload = spec_helper_hupcase(payload) if force_upper_case
|
818
|
+
patch "/Users/#{@u2.primary_key}", params: payload.merge(format: :scim)
|
819
|
+
|
820
|
+
expect(response.status ).to eql(200)
|
821
|
+
expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
|
822
|
+
|
823
|
+
@u2.reload
|
824
|
+
result = JSON.parse(response.body)
|
825
|
+
|
826
|
+
expect(@u2.organization).to eql('Foo Bar!')
|
827
|
+
expect(@u2.department ).to eql('Bar Foo!')
|
828
|
+
end
|
829
|
+
end
|
830
|
+
|
831
|
+
it_behaves_like 'it handles schema ID value keys without inline attributes', 'add'
|
832
|
+
it_behaves_like 'it handles schema ID value keys without inline attributes', 'replace'
|
833
|
+
|
834
|
+
shared_examples 'it handles schema ID value keys with inline attributes' do
|
835
|
+
it "and performs operation" do
|
836
|
+
payload = {
|
837
|
+
Operations: [
|
838
|
+
{
|
839
|
+
op: 'add',
|
840
|
+
value: {
|
841
|
+
'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:organization' => 'Foo Bar!',
|
842
|
+
'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User:department' => 'Bar Foo!'
|
843
|
+
},
|
844
|
+
},
|
845
|
+
]
|
846
|
+
}
|
847
|
+
|
848
|
+
@u2.update!(organization: 'Old org')
|
849
|
+
payload = spec_helper_hupcase(payload) if force_upper_case
|
850
|
+
patch "/Users/#{@u2.primary_key}", params: payload.merge(format: :scim)
|
851
|
+
|
852
|
+
expect(response.status ).to eql(200)
|
853
|
+
expect(response.headers['Content-Type']).to eql('application/scim+json; charset=utf-8')
|
854
|
+
|
855
|
+
@u2.reload
|
856
|
+
result = JSON.parse(response.body)
|
857
|
+
|
858
|
+
expect(@u2.organization).to eql('Foo Bar!')
|
859
|
+
expect(@u2.department ).to eql('Bar Foo!')
|
860
|
+
end
|
861
|
+
end
|
862
|
+
|
863
|
+
it_behaves_like 'it handles schema ID value keys with inline attributes', 'add'
|
864
|
+
it_behaves_like 'it handles schema ID value keys with inline attributes', 'replace'
|
865
|
+
end
|
866
|
+
|
767
867
|
it 'which patches "returned: \'never\'" fields' do
|
768
868
|
payload = {
|
769
869
|
Operations: [
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scimitar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.7.
|
4
|
+
version: 2.7.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- RIPA Global
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-06-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|