spec/models/scimitar/resources/mixin_spec.rb in scimitar-2.3.0 vs spec/models/scimitar/resources/mixin_spec.rb in scimitar-2.4.0
- old
+ new
@@ -1228,10 +1228,599 @@
altering_hash: scim_hash
)
expect(scim_hash).to_not have_key('emails')
end
+
+ # What we expect:
+ #
+ # https://www.rfc-editor.org/rfc/rfc7644#section-3.5.2.2
+ # https://docs.snowflake.com/en/user-guide/scim-intro.html#patch-scim-v2-groups-id
+ #
+ # ...vs accounting for the unusual payloads we sometimes get,
+ # tested here.
+ #
+ context 'special cases' do
+
+ # https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/use-scim-to-provision-users-and-groups#update-group-remove-members
+ #
+ context 'Microsoft-style payload' do
+ context 'removing a user from a group' do
+ it 'removes identified user' do
+ path = [ 'members' ]
+ value = [ { '$ref' => nil, 'value' => 'f648f8d5ea4e4cd38e9c' } ]
+ scim_hash = {
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => '50ca93d04ab0c2de4772',
+ 'display' => 'Ingrid Smith',
+ 'type' => 'User'
+ },
+ {
+ 'value' => 'f648f8d5ea4e4cd38e9c',
+ 'display' => 'Fred Smith',
+ 'type' => 'User'
+ },
+ {
+ 'value' => 'a774d480e8112101375b',
+ 'display' => 'Taylor Smith',
+ 'type' => 'User'
+ }
+ ]
+ }.with_indifferent_case_insensitive_access()
+
+ @instance.send(
+ :from_patch_backend!,
+ nature: 'remove',
+ path: path,
+ value: value,
+ altering_hash: scim_hash
+ )
+
+ expect(scim_hash).to eql({
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => '50ca93d04ab0c2de4772',
+ 'display' => 'Ingrid Smith',
+ 'type' => 'User'
+ },
+ {
+ 'value' => 'a774d480e8112101375b',
+ 'display' => 'Taylor Smith',
+ 'type' => 'User'
+ }
+ ]
+ })
+ end
+
+ it 'removes multiple identified users' do
+ path = [ 'members' ]
+ value = [
+ { '$ref' => nil, 'value' => 'f648f8d5ea4e4cd38e9c' },
+ { '$ref' => nil, 'value' => '50ca93d04ab0c2de4772' }
+ ]
+ scim_hash = {
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => '50ca93d04ab0c2de4772',
+ 'display' => 'Ingrid Smith',
+ 'type' => 'User'
+ },
+ {
+ 'value' => 'f648f8d5ea4e4cd38e9c',
+ 'display' => 'Fred Smith',
+ 'type' => 'User'
+ },
+ {
+ 'value' => 'a774d480e8112101375b',
+ 'display' => 'Taylor Smith',
+ 'type' => 'User'
+ }
+ ]
+ }.with_indifferent_case_insensitive_access()
+
+ @instance.send(
+ :from_patch_backend!,
+ nature: 'remove',
+ path: path,
+ value: value,
+ altering_hash: scim_hash
+ )
+
+ expect(scim_hash).to eql({
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => 'a774d480e8112101375b',
+ 'display' => 'Taylor Smith',
+ 'type' => 'User'
+ }
+ ]
+ })
+ end
+
+ it 'removes all users individually without error' do
+ path = [ 'members' ]
+ value = [ { '$ref' => nil, 'value' => 'f648f8d5ea4e4cd38e9c' } ]
+ scim_hash = {
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => 'f648f8d5ea4e4cd38e9c',
+ 'display' => 'Fred Smith',
+ 'type' => 'User'
+ }
+ ]
+ }.with_indifferent_case_insensitive_access()
+
+ @instance.send(
+ :from_patch_backend!,
+ nature: 'remove',
+ path: path,
+ value: value,
+ altering_hash: scim_hash
+ )
+
+ expect(scim_hash).to eql({
+ 'displayname' => 'Mock group',
+ 'members' => []
+ })
+ end
+
+ it 'can match on multiple attributes' do
+ path = [ 'members' ]
+ value = [ { '$ref' => nil, 'value' => 'f648f8d5ea4e4cd38e9c', 'type' => 'User' } ]
+ scim_hash = {
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => 'f648f8d5ea4e4cd38e9c',
+ 'display' => 'Fred Smith',
+ 'type' => 'User'
+ }
+ ]
+ }.with_indifferent_case_insensitive_access()
+
+ @instance.send(
+ :from_patch_backend!,
+ nature: 'remove',
+ path: path,
+ value: value,
+ altering_hash: scim_hash
+ )
+
+ expect(scim_hash).to eql({
+ 'displayname' => 'Mock group',
+ 'members' => []
+ })
+ end
+
+ it 'ignores unrecognised users' do
+ path = [ 'members' ]
+ value = [ { '$ref' => nil, 'value' => '11b054a9c85216ed9356' } ]
+ scim_hash = {
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => 'f648f8d5ea4e4cd38e9c',
+ 'display' => 'Fred Smith',
+ 'type' => 'User'
+ }
+ ]
+ }.with_indifferent_case_insensitive_access()
+
+ @instance.send(
+ :from_patch_backend!,
+ nature: 'remove',
+ path: path,
+ value: value,
+ altering_hash: scim_hash
+ )
+
+ # The 'value' mismatched, so the user was not removed.
+ #
+ expect(scim_hash).to eql({
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => 'f648f8d5ea4e4cd38e9c',
+ 'display' => 'Fred Smith',
+ 'type' => 'User'
+ }
+ ]
+ })
+ end
+
+ it 'ignores a mismatch on (for example) "type"' do
+ path = [ 'members' ]
+ value = [ { '$ref' => nil, 'value' => 'f648f8d5ea4e4cd38e9c', 'type' => 'Group' } ]
+ scim_hash = {
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => 'f648f8d5ea4e4cd38e9c',
+ 'display' => 'Fred Smith',
+ 'type' => 'User'
+ }
+ ]
+ }.with_indifferent_case_insensitive_access()
+
+ @instance.send(
+ :from_patch_backend!,
+ nature: 'remove',
+ path: path,
+ value: value,
+ altering_hash: scim_hash
+ )
+
+ # Type 'Group' mismatches 'User', so the user was not
+ # removed.
+ #
+ expect(scim_hash).to eql({
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => 'f648f8d5ea4e4cd38e9c',
+ 'display' => 'Fred Smith',
+ 'type' => 'User'
+ }
+ ]
+ })
+ end
+
+ it 'matches keys case-insensitive' do
+ path = [ 'members' ]
+ value = [ { '$ref' => nil, 'VALUe' => 'f648f8d5ea4e4cd38e9c' } ]
+ scim_hash = {
+ 'displayname' => 'Mock group',
+ 'memBERS' => [
+ {
+ 'vaLUe' => 'f648f8d5ea4e4cd38e9c',
+ 'display' => 'Fred Smith',
+ 'type' => 'User'
+ }
+ ]
+ }.with_indifferent_case_insensitive_access()
+
+ @instance.send(
+ :from_patch_backend!,
+ nature: 'remove',
+ path: path,
+ value: value,
+ altering_hash: scim_hash
+ )
+
+ expect(scim_hash).to eql({
+ 'displayname' => 'Mock group',
+ 'members' => []
+ })
+ end
+
+ it 'matches values case-sensitive' do
+ path = [ 'members' ]
+ value = [ { '$ref' => nil, 'value' => 'f648f8d5ea4e4cd38e9c', 'type' => 'USER' } ]
+ scim_hash = {
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => 'f648f8d5ea4e4cd38e9c',
+ 'display' => 'Fred Smith',
+ 'type' => 'User'
+ }
+ ]
+ }.with_indifferent_case_insensitive_access()
+
+ @instance.send(
+ :from_patch_backend!,
+ nature: 'remove',
+ path: path,
+ value: value,
+ altering_hash: scim_hash
+ )
+
+ # USER mismatchs User, so the user was not removed.
+ #
+ expect(scim_hash).to eql({
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => 'f648f8d5ea4e4cd38e9c',
+ 'display' => 'Fred Smith',
+ 'type' => 'User'
+ }
+ ]
+ })
+ end
+ end # "context 'removing a user from a group' do"
+
+ context 'generic use' do
+ it 'removes matched items' do
+ path = [ 'emails' ]
+ value = [ { 'type' => 'work' } ]
+ scim_hash = {
+ 'emails' => [
+ {
+ 'type' => 'home',
+ 'value' => 'home@test.com'
+ },
+ {
+ 'type' => 'work',
+ 'value' => 'work@test.com'
+ }
+ ]
+ }.with_indifferent_case_insensitive_access()
+
+ @instance.send(
+ :from_patch_backend!,
+ nature: 'remove',
+ path: path,
+ value: value,
+ altering_hash: scim_hash
+ )
+
+ expect(scim_hash).to eql({
+ 'emails' => [
+ {
+ 'type' => 'home',
+ 'value' => 'home@test.com'
+ }
+ ]
+ })
+ end
+
+ it 'ignores unmatched items' do
+ path = [ 'emails' ]
+ value = [ { 'type' => 'missing' } ]
+ scim_hash = {
+ 'emails' => [
+ {
+ 'type' => 'home',
+ 'value' => 'home@test.com'
+ },
+ {
+ 'type' => 'work',
+ 'value' => 'work@test.com'
+ }
+ ]
+ }.with_indifferent_case_insensitive_access()
+
+ @instance.send(
+ :from_patch_backend!,
+ nature: 'remove',
+ path: path,
+ value: value,
+ altering_hash: scim_hash
+ )
+
+ expect(scim_hash).to eql({
+ 'emails' => [
+ {
+ 'type' => 'home',
+ 'value' => 'home@test.com'
+ },
+ {
+ 'type' => 'work',
+ 'value' => 'work@test.com'
+ }
+ ]
+ })
+ end
+
+ it 'compares string forms' do
+ path = [ 'test' ]
+ value = [
+ { 'active' => true, 'value' => '12' },
+ { 'active' => 'false', 'value' => 42 }
+ ]
+ scim_hash = {
+ 'test' => [
+ {
+ 'active' => 'true',
+ 'value' => 12
+ },
+ {
+ 'active' => false,
+ 'value' => '42'
+ }
+ ]
+ }.with_indifferent_case_insensitive_access()
+
+ @instance.send(
+ :from_patch_backend!,
+ nature: 'remove',
+ path: path,
+ value: value,
+ altering_hash: scim_hash
+ )
+
+ expect(scim_hash).to eql({'test' => []})
+ end
+
+ it 'handles a singular to-remove value rather than an array' do
+ path = [ 'emails' ]
+ value = { 'type' => 'work' }
+ scim_hash = {
+ 'emails' => [
+ {
+ 'type' => 'home',
+ 'value' => 'home@test.com'
+ },
+ {
+ 'type' => 'work',
+ 'value' => 'work@test.com'
+ }
+ ]
+ }.with_indifferent_case_insensitive_access()
+
+ @instance.send(
+ :from_patch_backend!,
+ nature: 'remove',
+ path: path,
+ value: value,
+ altering_hash: scim_hash
+ )
+
+ expect(scim_hash).to eql({
+ 'emails' => [
+ {
+ 'type' => 'home',
+ 'value' => 'home@test.com'
+ }
+ ]
+ })
+ end
+
+ it 'handles simple values rather than object (Hash) values' do
+ path = [ 'test' ]
+ value = 42
+ scim_hash = {
+ 'test' => [
+ '21',
+ '42',
+ '15'
+ ]
+ }.with_indifferent_case_insensitive_access()
+
+ @instance.send(
+ :from_patch_backend!,
+ nature: 'remove',
+ path: path,
+ value: value,
+ altering_hash: scim_hash
+ )
+
+ expect(scim_hash).to eql({
+ 'test' => [
+ '21',
+ '15'
+ ]
+ })
+ end
+ end
+ end # "context 'Microsoft-style payload' do"
+
+ # https://help.salesforce.com/s/articleView?id=sf.identity_scim_manage_groups.htm&type=5
+ #
+ context 'Salesforce-style payload' do
+ it 'removes identified user' do
+ path = [ 'members' ]
+ value = { 'members' => [ { '$ref' => nil, 'value' => 'f648f8d5ea4e4cd38e9c' } ] }
+ scim_hash = {
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => '50ca93d04ab0c2de4772',
+ 'display' => 'Ingrid Smith',
+ 'type' => 'User'
+ },
+ {
+ 'value' => 'f648f8d5ea4e4cd38e9c',
+ 'display' => 'Fred Smith',
+ 'type' => 'User'
+ }
+ ]
+ }.with_indifferent_case_insensitive_access()
+
+ @instance.send(
+ :from_patch_backend!,
+ nature: 'remove',
+ path: path,
+ value: value,
+ altering_hash: scim_hash
+ )
+
+ expect(scim_hash).to eql({
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => '50ca93d04ab0c2de4772',
+ 'display' => 'Ingrid Smith',
+ 'type' => 'User'
+ }
+ ]
+ })
+ end
+
+ it 'matches the "members" key case-insensitive' do
+ path = [ 'members' ]
+ value = { 'MEMBERS' => [ { '$ref' => nil, 'value' => 'f648f8d5ea4e4cd38e9c' } ] }
+ scim_hash = {
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => 'f648f8d5ea4e4cd38e9c',
+ 'display' => 'Fred Smith',
+ 'type' => 'User'
+ },
+ {
+ 'value' => 'a774d480e8112101375b',
+ 'display' => 'Taylor Smith',
+ 'type' => 'User'
+ }
+ ]
+ }.with_indifferent_case_insensitive_access()
+
+ @instance.send(
+ :from_patch_backend!,
+ nature: 'remove',
+ path: path,
+ value: value,
+ altering_hash: scim_hash
+ )
+
+ expect(scim_hash).to eql({
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => 'a774d480e8112101375b',
+ 'display' => 'Taylor Smith',
+ 'type' => 'User'
+ }
+ ]
+ })
+ end
+
+ it 'ignores unrecognised users' do
+ path = [ 'members' ]
+ value = { 'members' => [ { '$ref' => nil, 'value' => '11b054a9c85216ed9356' } ] }
+ scim_hash = {
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => 'f648f8d5ea4e4cd38e9c',
+ 'display' => 'Fred Smith',
+ 'type' => 'User'
+ }
+ ]
+ }.with_indifferent_case_insensitive_access()
+
+ @instance.send(
+ :from_patch_backend!,
+ nature: 'remove',
+ path: path,
+ value: value,
+ altering_hash: scim_hash
+ )
+
+ # The 'value' mismatched, so the user was not removed.
+ #
+ expect(scim_hash).to eql({
+ 'displayname' => 'Mock group',
+ 'members' => [
+ {
+ 'value' => 'f648f8d5ea4e4cd38e9c',
+ 'display' => 'Fred Smith',
+ 'type' => 'User'
+ }
+ ]
+ })
+ end
+ end # "context 'Salesforce-style payload' do"
+ end # "context 'special cases' do"
end # context 'when prior value already exists' do
context 'when value is not present' do
it 'simple value: does nothing' do
path = [ 'userName' ]
@@ -1952,10 +2541,10 @@
contrived_instance = @contrived_class.new
contrived_instance.send(
:from_patch_backend!,
nature: 'remove',
path: ['complex[type eq "type1"]', 'data', 'nested[nature eq "nature2"]', 'info'],
- value: [{ 'deeper' => 'addition' }],
+ value: nil,
altering_hash: scim_hash
)
expect(scim_hash.dig('complex', 0, 'data', 'nested', 0, 'info').count).to eql(1) # Unchanged
expect(scim_hash.dig('complex', 0, 'data', 'nested', 1, 'info')).to be_nil