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