scimitar 2.2.0 → 2.4.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 +27 -7
- data/app/models/scimitar/resources/mixin.rb +73 -1
- 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 +5 -3
- data/spec/apps/dummy/config/routes.rb +10 -6
- data/spec/apps/dummy/db/migrate/20210304014602_create_mock_users.rb +2 -2
- data/spec/apps/dummy/db/migrate/20210308044214_create_join_table_mock_groups_mock_users.rb +8 -3
- data/spec/apps/dummy/db/schema.rb +9 -7
- data/spec/models/scimitar/lists/query_parser_spec.rb +8 -8
- data/spec/models/scimitar/resources/mixin_spec.rb +657 -40
- data/spec/requests/active_record_backed_resources_controller_spec.rb +230 -48
- metadata +3 -5
- data/spec/apps/dummy/db/migrate/20230109012729_add_timestamps_to_mock_user.rb +0 -5
@@ -159,41 +159,67 @@ RSpec.describe Scimitar::Resources::Mixin do
|
|
159
159
|
# =========================================================================
|
160
160
|
|
161
161
|
context '#to_scim' do
|
162
|
-
|
163
|
-
instance
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
162
|
+
context 'with a UUID, renamed primary key column' do
|
163
|
+
it 'compiles instance attribute values into a SCIM representation' do
|
164
|
+
uuid = SecureRandom.uuid
|
165
|
+
|
166
|
+
instance = MockUser.new
|
167
|
+
instance.primary_key = uuid
|
168
|
+
instance.scim_uid = 'AA02984'
|
169
|
+
instance.username = 'foo'
|
170
|
+
instance.first_name = 'Foo'
|
171
|
+
instance.last_name = 'Bar'
|
172
|
+
instance.work_email_address = 'foo.bar@test.com'
|
173
|
+
instance.home_email_address = nil
|
174
|
+
instance.work_phone_number = '+642201234567'
|
175
|
+
|
176
|
+
g1 = MockGroup.create!(display_name: 'Group 1')
|
177
|
+
g2 = MockGroup.create!(display_name: 'Group 2')
|
178
|
+
g3 = MockGroup.create!(display_name: 'Group 3')
|
179
|
+
|
180
|
+
g1.mock_users << instance
|
181
|
+
g3.mock_users << instance
|
182
|
+
|
183
|
+
scim = instance.to_scim(location: "https://test.com/mock_users/#{uuid}")
|
184
|
+
json = scim.to_json()
|
185
|
+
hash = JSON.parse(json)
|
186
|
+
|
187
|
+
expect(hash).to eql({
|
188
|
+
'userName' => 'foo',
|
189
|
+
'name' => {'givenName'=>'Foo', 'familyName'=>'Bar'},
|
190
|
+
'active' => true,
|
191
|
+
'emails' => [{'type'=>'work', 'primary'=>true, 'value'=>'foo.bar@test.com'}, {"primary"=>false, "type"=>"home", "value"=>nil}],
|
192
|
+
'phoneNumbers'=> [{'type'=>'work', 'primary'=>false, 'value'=>'+642201234567'}],
|
193
|
+
'id' => uuid,
|
194
|
+
'externalId' => 'AA02984',
|
195
|
+
'groups' => [{'display'=>g1.display_name, 'value'=>g1.id.to_s}, {'display'=>g3.display_name, 'value'=>g3.id.to_s}],
|
196
|
+
'meta' => {'location'=>"https://test.com/mock_users/#{uuid}", 'resourceType'=>'User'},
|
197
|
+
'schemas' => ['urn:ietf:params:scim:schemas:core:2.0:User']
|
198
|
+
})
|
199
|
+
end
|
200
|
+
end # "context 'with a UUID, renamed primary key column' do"
|
201
|
+
|
202
|
+
context 'with an integer, conventionally named primary key column' do
|
203
|
+
it 'compiles instance attribute values into a SCIM representation' do
|
204
|
+
instance = MockGroup.new
|
205
|
+
instance.id = 42
|
206
|
+
instance.scim_uid = 'GG02984'
|
207
|
+
instance.display_name = 'Some group'
|
208
|
+
|
209
|
+
scim = instance.to_scim(location: 'https://test.com/mock_groups/42')
|
210
|
+
json = scim.to_json()
|
211
|
+
hash = JSON.parse(json)
|
212
|
+
|
213
|
+
expect(hash).to eql({
|
214
|
+
'displayName' => 'Some group',
|
215
|
+
'id' => '42', # Note, String
|
216
|
+
'externalId' => 'GG02984',
|
217
|
+
'members' => [],
|
218
|
+
'meta' => {'location'=>'https://test.com/mock_groups/42', 'resourceType'=>'Group'},
|
219
|
+
'schemas' => ['urn:ietf:params:scim:schemas:core:2.0:Group']
|
220
|
+
})
|
221
|
+
end
|
222
|
+
end # "context 'with an integer, conventionally named primary key column' do"
|
197
223
|
|
198
224
|
context 'with optional timestamps' do
|
199
225
|
context 'creation only' do
|
@@ -405,8 +431,8 @@ RSpec.describe Scimitar::Resources::Mixin do
|
|
405
431
|
'displayName' => 'Foo Group',
|
406
432
|
'members' => [
|
407
433
|
{'type' => 'Group', 'value' => g1.id.to_s},
|
408
|
-
{'type' => 'User', 'value' => u1.
|
409
|
-
{'type' => 'User', 'value' => u3.
|
434
|
+
{'type' => 'User', 'value' => u1.primary_key.to_s},
|
435
|
+
{'type' => 'User', 'value' => u3.primary_key.to_s}
|
410
436
|
],
|
411
437
|
'externalId' => 'GG01536',
|
412
438
|
'meta' => {'location'=>'https://test.com/mock_groups/1', 'resourceType'=>'Group'},
|
@@ -453,8 +479,10 @@ RSpec.describe Scimitar::Resources::Mixin do
|
|
453
479
|
end # "context 'using upper case' do"
|
454
480
|
|
455
481
|
it 'clears things not present in input' do
|
482
|
+
uuid = SecureRandom.uuid
|
483
|
+
|
456
484
|
instance = MockUser.new
|
457
|
-
instance.
|
485
|
+
instance.primary_key = uuid
|
458
486
|
instance.scim_uid = 'AA02984'
|
459
487
|
instance.username = 'foo'
|
460
488
|
instance.first_name = 'Foo'
|
@@ -465,7 +493,7 @@ RSpec.describe Scimitar::Resources::Mixin do
|
|
465
493
|
|
466
494
|
instance.from_scim!(scim_hash: {})
|
467
495
|
|
468
|
-
expect(instance.
|
496
|
+
expect(instance.primary_key ).to eql(uuid)
|
469
497
|
expect(instance.scim_uid ).to be_nil
|
470
498
|
expect(instance.username ).to be_nil
|
471
499
|
expect(instance.first_name ).to be_nil
|
@@ -1202,6 +1230,595 @@ RSpec.describe Scimitar::Resources::Mixin do
|
|
1202
1230
|
|
1203
1231
|
expect(scim_hash).to_not have_key('emails')
|
1204
1232
|
end
|
1233
|
+
|
1234
|
+
# What we expect:
|
1235
|
+
#
|
1236
|
+
# https://www.rfc-editor.org/rfc/rfc7644#section-3.5.2.2
|
1237
|
+
# https://docs.snowflake.com/en/user-guide/scim-intro.html#patch-scim-v2-groups-id
|
1238
|
+
#
|
1239
|
+
# ...vs accounting for the unusual payloads we sometimes get,
|
1240
|
+
# tested here.
|
1241
|
+
#
|
1242
|
+
context 'special cases' do
|
1243
|
+
|
1244
|
+
# https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/use-scim-to-provision-users-and-groups#update-group-remove-members
|
1245
|
+
#
|
1246
|
+
context 'Microsoft-style payload' do
|
1247
|
+
context 'removing a user from a group' do
|
1248
|
+
it 'removes identified user' do
|
1249
|
+
path = [ 'members' ]
|
1250
|
+
value = [ { '$ref' => nil, 'value' => 'f648f8d5ea4e4cd38e9c' } ]
|
1251
|
+
scim_hash = {
|
1252
|
+
'displayname' => 'Mock group',
|
1253
|
+
'members' => [
|
1254
|
+
{
|
1255
|
+
'value' => '50ca93d04ab0c2de4772',
|
1256
|
+
'display' => 'Ingrid Smith',
|
1257
|
+
'type' => 'User'
|
1258
|
+
},
|
1259
|
+
{
|
1260
|
+
'value' => 'f648f8d5ea4e4cd38e9c',
|
1261
|
+
'display' => 'Fred Smith',
|
1262
|
+
'type' => 'User'
|
1263
|
+
},
|
1264
|
+
{
|
1265
|
+
'value' => 'a774d480e8112101375b',
|
1266
|
+
'display' => 'Taylor Smith',
|
1267
|
+
'type' => 'User'
|
1268
|
+
}
|
1269
|
+
]
|
1270
|
+
}.with_indifferent_case_insensitive_access()
|
1271
|
+
|
1272
|
+
@instance.send(
|
1273
|
+
:from_patch_backend!,
|
1274
|
+
nature: 'remove',
|
1275
|
+
path: path,
|
1276
|
+
value: value,
|
1277
|
+
altering_hash: scim_hash
|
1278
|
+
)
|
1279
|
+
|
1280
|
+
expect(scim_hash).to eql({
|
1281
|
+
'displayname' => 'Mock group',
|
1282
|
+
'members' => [
|
1283
|
+
{
|
1284
|
+
'value' => '50ca93d04ab0c2de4772',
|
1285
|
+
'display' => 'Ingrid Smith',
|
1286
|
+
'type' => 'User'
|
1287
|
+
},
|
1288
|
+
{
|
1289
|
+
'value' => 'a774d480e8112101375b',
|
1290
|
+
'display' => 'Taylor Smith',
|
1291
|
+
'type' => 'User'
|
1292
|
+
}
|
1293
|
+
]
|
1294
|
+
})
|
1295
|
+
end
|
1296
|
+
|
1297
|
+
it 'removes multiple identified users' do
|
1298
|
+
path = [ 'members' ]
|
1299
|
+
value = [
|
1300
|
+
{ '$ref' => nil, 'value' => 'f648f8d5ea4e4cd38e9c' },
|
1301
|
+
{ '$ref' => nil, 'value' => '50ca93d04ab0c2de4772' }
|
1302
|
+
]
|
1303
|
+
scim_hash = {
|
1304
|
+
'displayname' => 'Mock group',
|
1305
|
+
'members' => [
|
1306
|
+
{
|
1307
|
+
'value' => '50ca93d04ab0c2de4772',
|
1308
|
+
'display' => 'Ingrid Smith',
|
1309
|
+
'type' => 'User'
|
1310
|
+
},
|
1311
|
+
{
|
1312
|
+
'value' => 'f648f8d5ea4e4cd38e9c',
|
1313
|
+
'display' => 'Fred Smith',
|
1314
|
+
'type' => 'User'
|
1315
|
+
},
|
1316
|
+
{
|
1317
|
+
'value' => 'a774d480e8112101375b',
|
1318
|
+
'display' => 'Taylor Smith',
|
1319
|
+
'type' => 'User'
|
1320
|
+
}
|
1321
|
+
]
|
1322
|
+
}.with_indifferent_case_insensitive_access()
|
1323
|
+
|
1324
|
+
@instance.send(
|
1325
|
+
:from_patch_backend!,
|
1326
|
+
nature: 'remove',
|
1327
|
+
path: path,
|
1328
|
+
value: value,
|
1329
|
+
altering_hash: scim_hash
|
1330
|
+
)
|
1331
|
+
|
1332
|
+
expect(scim_hash).to eql({
|
1333
|
+
'displayname' => 'Mock group',
|
1334
|
+
'members' => [
|
1335
|
+
{
|
1336
|
+
'value' => 'a774d480e8112101375b',
|
1337
|
+
'display' => 'Taylor Smith',
|
1338
|
+
'type' => 'User'
|
1339
|
+
}
|
1340
|
+
]
|
1341
|
+
})
|
1342
|
+
end
|
1343
|
+
|
1344
|
+
it 'removes all users individually without error' do
|
1345
|
+
path = [ 'members' ]
|
1346
|
+
value = [ { '$ref' => nil, 'value' => 'f648f8d5ea4e4cd38e9c' } ]
|
1347
|
+
scim_hash = {
|
1348
|
+
'displayname' => 'Mock group',
|
1349
|
+
'members' => [
|
1350
|
+
{
|
1351
|
+
'value' => 'f648f8d5ea4e4cd38e9c',
|
1352
|
+
'display' => 'Fred Smith',
|
1353
|
+
'type' => 'User'
|
1354
|
+
}
|
1355
|
+
]
|
1356
|
+
}.with_indifferent_case_insensitive_access()
|
1357
|
+
|
1358
|
+
@instance.send(
|
1359
|
+
:from_patch_backend!,
|
1360
|
+
nature: 'remove',
|
1361
|
+
path: path,
|
1362
|
+
value: value,
|
1363
|
+
altering_hash: scim_hash
|
1364
|
+
)
|
1365
|
+
|
1366
|
+
expect(scim_hash).to eql({
|
1367
|
+
'displayname' => 'Mock group',
|
1368
|
+
'members' => []
|
1369
|
+
})
|
1370
|
+
end
|
1371
|
+
|
1372
|
+
it 'can match on multiple attributes' do
|
1373
|
+
path = [ 'members' ]
|
1374
|
+
value = [ { '$ref' => nil, 'value' => 'f648f8d5ea4e4cd38e9c', 'type' => 'User' } ]
|
1375
|
+
scim_hash = {
|
1376
|
+
'displayname' => 'Mock group',
|
1377
|
+
'members' => [
|
1378
|
+
{
|
1379
|
+
'value' => 'f648f8d5ea4e4cd38e9c',
|
1380
|
+
'display' => 'Fred Smith',
|
1381
|
+
'type' => 'User'
|
1382
|
+
}
|
1383
|
+
]
|
1384
|
+
}.with_indifferent_case_insensitive_access()
|
1385
|
+
|
1386
|
+
@instance.send(
|
1387
|
+
:from_patch_backend!,
|
1388
|
+
nature: 'remove',
|
1389
|
+
path: path,
|
1390
|
+
value: value,
|
1391
|
+
altering_hash: scim_hash
|
1392
|
+
)
|
1393
|
+
|
1394
|
+
expect(scim_hash).to eql({
|
1395
|
+
'displayname' => 'Mock group',
|
1396
|
+
'members' => []
|
1397
|
+
})
|
1398
|
+
end
|
1399
|
+
|
1400
|
+
it 'ignores unrecognised users' do
|
1401
|
+
path = [ 'members' ]
|
1402
|
+
value = [ { '$ref' => nil, 'value' => '11b054a9c85216ed9356' } ]
|
1403
|
+
scim_hash = {
|
1404
|
+
'displayname' => 'Mock group',
|
1405
|
+
'members' => [
|
1406
|
+
{
|
1407
|
+
'value' => 'f648f8d5ea4e4cd38e9c',
|
1408
|
+
'display' => 'Fred Smith',
|
1409
|
+
'type' => 'User'
|
1410
|
+
}
|
1411
|
+
]
|
1412
|
+
}.with_indifferent_case_insensitive_access()
|
1413
|
+
|
1414
|
+
@instance.send(
|
1415
|
+
:from_patch_backend!,
|
1416
|
+
nature: 'remove',
|
1417
|
+
path: path,
|
1418
|
+
value: value,
|
1419
|
+
altering_hash: scim_hash
|
1420
|
+
)
|
1421
|
+
|
1422
|
+
# The 'value' mismatched, so the user was not removed.
|
1423
|
+
#
|
1424
|
+
expect(scim_hash).to eql({
|
1425
|
+
'displayname' => 'Mock group',
|
1426
|
+
'members' => [
|
1427
|
+
{
|
1428
|
+
'value' => 'f648f8d5ea4e4cd38e9c',
|
1429
|
+
'display' => 'Fred Smith',
|
1430
|
+
'type' => 'User'
|
1431
|
+
}
|
1432
|
+
]
|
1433
|
+
})
|
1434
|
+
end
|
1435
|
+
|
1436
|
+
it 'ignores a mismatch on (for example) "type"' do
|
1437
|
+
path = [ 'members' ]
|
1438
|
+
value = [ { '$ref' => nil, 'value' => 'f648f8d5ea4e4cd38e9c', 'type' => 'Group' } ]
|
1439
|
+
scim_hash = {
|
1440
|
+
'displayname' => 'Mock group',
|
1441
|
+
'members' => [
|
1442
|
+
{
|
1443
|
+
'value' => 'f648f8d5ea4e4cd38e9c',
|
1444
|
+
'display' => 'Fred Smith',
|
1445
|
+
'type' => 'User'
|
1446
|
+
}
|
1447
|
+
]
|
1448
|
+
}.with_indifferent_case_insensitive_access()
|
1449
|
+
|
1450
|
+
@instance.send(
|
1451
|
+
:from_patch_backend!,
|
1452
|
+
nature: 'remove',
|
1453
|
+
path: path,
|
1454
|
+
value: value,
|
1455
|
+
altering_hash: scim_hash
|
1456
|
+
)
|
1457
|
+
|
1458
|
+
# Type 'Group' mismatches 'User', so the user was not
|
1459
|
+
# removed.
|
1460
|
+
#
|
1461
|
+
expect(scim_hash).to eql({
|
1462
|
+
'displayname' => 'Mock group',
|
1463
|
+
'members' => [
|
1464
|
+
{
|
1465
|
+
'value' => 'f648f8d5ea4e4cd38e9c',
|
1466
|
+
'display' => 'Fred Smith',
|
1467
|
+
'type' => 'User'
|
1468
|
+
}
|
1469
|
+
]
|
1470
|
+
})
|
1471
|
+
end
|
1472
|
+
|
1473
|
+
it 'matches keys case-insensitive' do
|
1474
|
+
path = [ 'members' ]
|
1475
|
+
value = [ { '$ref' => nil, 'VALUe' => 'f648f8d5ea4e4cd38e9c' } ]
|
1476
|
+
scim_hash = {
|
1477
|
+
'displayname' => 'Mock group',
|
1478
|
+
'memBERS' => [
|
1479
|
+
{
|
1480
|
+
'vaLUe' => 'f648f8d5ea4e4cd38e9c',
|
1481
|
+
'display' => 'Fred Smith',
|
1482
|
+
'type' => 'User'
|
1483
|
+
}
|
1484
|
+
]
|
1485
|
+
}.with_indifferent_case_insensitive_access()
|
1486
|
+
|
1487
|
+
@instance.send(
|
1488
|
+
:from_patch_backend!,
|
1489
|
+
nature: 'remove',
|
1490
|
+
path: path,
|
1491
|
+
value: value,
|
1492
|
+
altering_hash: scim_hash
|
1493
|
+
)
|
1494
|
+
|
1495
|
+
expect(scim_hash).to eql({
|
1496
|
+
'displayname' => 'Mock group',
|
1497
|
+
'members' => []
|
1498
|
+
})
|
1499
|
+
end
|
1500
|
+
|
1501
|
+
it 'matches values case-sensitive' do
|
1502
|
+
path = [ 'members' ]
|
1503
|
+
value = [ { '$ref' => nil, 'value' => 'f648f8d5ea4e4cd38e9c', 'type' => 'USER' } ]
|
1504
|
+
scim_hash = {
|
1505
|
+
'displayname' => 'Mock group',
|
1506
|
+
'members' => [
|
1507
|
+
{
|
1508
|
+
'value' => 'f648f8d5ea4e4cd38e9c',
|
1509
|
+
'display' => 'Fred Smith',
|
1510
|
+
'type' => 'User'
|
1511
|
+
}
|
1512
|
+
]
|
1513
|
+
}.with_indifferent_case_insensitive_access()
|
1514
|
+
|
1515
|
+
@instance.send(
|
1516
|
+
:from_patch_backend!,
|
1517
|
+
nature: 'remove',
|
1518
|
+
path: path,
|
1519
|
+
value: value,
|
1520
|
+
altering_hash: scim_hash
|
1521
|
+
)
|
1522
|
+
|
1523
|
+
# USER mismatchs User, so the user was not removed.
|
1524
|
+
#
|
1525
|
+
expect(scim_hash).to eql({
|
1526
|
+
'displayname' => 'Mock group',
|
1527
|
+
'members' => [
|
1528
|
+
{
|
1529
|
+
'value' => 'f648f8d5ea4e4cd38e9c',
|
1530
|
+
'display' => 'Fred Smith',
|
1531
|
+
'type' => 'User'
|
1532
|
+
}
|
1533
|
+
]
|
1534
|
+
})
|
1535
|
+
end
|
1536
|
+
end # "context 'removing a user from a group' do"
|
1537
|
+
|
1538
|
+
context 'generic use' do
|
1539
|
+
it 'removes matched items' do
|
1540
|
+
path = [ 'emails' ]
|
1541
|
+
value = [ { 'type' => 'work' } ]
|
1542
|
+
scim_hash = {
|
1543
|
+
'emails' => [
|
1544
|
+
{
|
1545
|
+
'type' => 'home',
|
1546
|
+
'value' => 'home@test.com'
|
1547
|
+
},
|
1548
|
+
{
|
1549
|
+
'type' => 'work',
|
1550
|
+
'value' => 'work@test.com'
|
1551
|
+
}
|
1552
|
+
]
|
1553
|
+
}.with_indifferent_case_insensitive_access()
|
1554
|
+
|
1555
|
+
@instance.send(
|
1556
|
+
:from_patch_backend!,
|
1557
|
+
nature: 'remove',
|
1558
|
+
path: path,
|
1559
|
+
value: value,
|
1560
|
+
altering_hash: scim_hash
|
1561
|
+
)
|
1562
|
+
|
1563
|
+
expect(scim_hash).to eql({
|
1564
|
+
'emails' => [
|
1565
|
+
{
|
1566
|
+
'type' => 'home',
|
1567
|
+
'value' => 'home@test.com'
|
1568
|
+
}
|
1569
|
+
]
|
1570
|
+
})
|
1571
|
+
end
|
1572
|
+
|
1573
|
+
it 'ignores unmatched items' do
|
1574
|
+
path = [ 'emails' ]
|
1575
|
+
value = [ { 'type' => 'missing' } ]
|
1576
|
+
scim_hash = {
|
1577
|
+
'emails' => [
|
1578
|
+
{
|
1579
|
+
'type' => 'home',
|
1580
|
+
'value' => 'home@test.com'
|
1581
|
+
},
|
1582
|
+
{
|
1583
|
+
'type' => 'work',
|
1584
|
+
'value' => 'work@test.com'
|
1585
|
+
}
|
1586
|
+
]
|
1587
|
+
}.with_indifferent_case_insensitive_access()
|
1588
|
+
|
1589
|
+
@instance.send(
|
1590
|
+
:from_patch_backend!,
|
1591
|
+
nature: 'remove',
|
1592
|
+
path: path,
|
1593
|
+
value: value,
|
1594
|
+
altering_hash: scim_hash
|
1595
|
+
)
|
1596
|
+
|
1597
|
+
expect(scim_hash).to eql({
|
1598
|
+
'emails' => [
|
1599
|
+
{
|
1600
|
+
'type' => 'home',
|
1601
|
+
'value' => 'home@test.com'
|
1602
|
+
},
|
1603
|
+
{
|
1604
|
+
'type' => 'work',
|
1605
|
+
'value' => 'work@test.com'
|
1606
|
+
}
|
1607
|
+
]
|
1608
|
+
})
|
1609
|
+
end
|
1610
|
+
|
1611
|
+
it 'compares string forms' do
|
1612
|
+
path = [ 'test' ]
|
1613
|
+
value = [
|
1614
|
+
{ 'active' => true, 'value' => '12' },
|
1615
|
+
{ 'active' => 'false', 'value' => 42 }
|
1616
|
+
]
|
1617
|
+
scim_hash = {
|
1618
|
+
'test' => [
|
1619
|
+
{
|
1620
|
+
'active' => 'true',
|
1621
|
+
'value' => 12
|
1622
|
+
},
|
1623
|
+
{
|
1624
|
+
'active' => false,
|
1625
|
+
'value' => '42'
|
1626
|
+
}
|
1627
|
+
]
|
1628
|
+
}.with_indifferent_case_insensitive_access()
|
1629
|
+
|
1630
|
+
@instance.send(
|
1631
|
+
:from_patch_backend!,
|
1632
|
+
nature: 'remove',
|
1633
|
+
path: path,
|
1634
|
+
value: value,
|
1635
|
+
altering_hash: scim_hash
|
1636
|
+
)
|
1637
|
+
|
1638
|
+
expect(scim_hash).to eql({'test' => []})
|
1639
|
+
end
|
1640
|
+
|
1641
|
+
it 'handles a singular to-remove value rather than an array' do
|
1642
|
+
path = [ 'emails' ]
|
1643
|
+
value = { 'type' => 'work' }
|
1644
|
+
scim_hash = {
|
1645
|
+
'emails' => [
|
1646
|
+
{
|
1647
|
+
'type' => 'home',
|
1648
|
+
'value' => 'home@test.com'
|
1649
|
+
},
|
1650
|
+
{
|
1651
|
+
'type' => 'work',
|
1652
|
+
'value' => 'work@test.com'
|
1653
|
+
}
|
1654
|
+
]
|
1655
|
+
}.with_indifferent_case_insensitive_access()
|
1656
|
+
|
1657
|
+
@instance.send(
|
1658
|
+
:from_patch_backend!,
|
1659
|
+
nature: 'remove',
|
1660
|
+
path: path,
|
1661
|
+
value: value,
|
1662
|
+
altering_hash: scim_hash
|
1663
|
+
)
|
1664
|
+
|
1665
|
+
expect(scim_hash).to eql({
|
1666
|
+
'emails' => [
|
1667
|
+
{
|
1668
|
+
'type' => 'home',
|
1669
|
+
'value' => 'home@test.com'
|
1670
|
+
}
|
1671
|
+
]
|
1672
|
+
})
|
1673
|
+
end
|
1674
|
+
|
1675
|
+
it 'handles simple values rather than object (Hash) values' do
|
1676
|
+
path = [ 'test' ]
|
1677
|
+
value = 42
|
1678
|
+
scim_hash = {
|
1679
|
+
'test' => [
|
1680
|
+
'21',
|
1681
|
+
'42',
|
1682
|
+
'15'
|
1683
|
+
]
|
1684
|
+
}.with_indifferent_case_insensitive_access()
|
1685
|
+
|
1686
|
+
@instance.send(
|
1687
|
+
:from_patch_backend!,
|
1688
|
+
nature: 'remove',
|
1689
|
+
path: path,
|
1690
|
+
value: value,
|
1691
|
+
altering_hash: scim_hash
|
1692
|
+
)
|
1693
|
+
|
1694
|
+
expect(scim_hash).to eql({
|
1695
|
+
'test' => [
|
1696
|
+
'21',
|
1697
|
+
'15'
|
1698
|
+
]
|
1699
|
+
})
|
1700
|
+
end
|
1701
|
+
end
|
1702
|
+
end # "context 'Microsoft-style payload' do"
|
1703
|
+
|
1704
|
+
# https://help.salesforce.com/s/articleView?id=sf.identity_scim_manage_groups.htm&type=5
|
1705
|
+
#
|
1706
|
+
context 'Salesforce-style payload' do
|
1707
|
+
it 'removes identified user' do
|
1708
|
+
path = [ 'members' ]
|
1709
|
+
value = { 'members' => [ { '$ref' => nil, 'value' => 'f648f8d5ea4e4cd38e9c' } ] }
|
1710
|
+
scim_hash = {
|
1711
|
+
'displayname' => 'Mock group',
|
1712
|
+
'members' => [
|
1713
|
+
{
|
1714
|
+
'value' => '50ca93d04ab0c2de4772',
|
1715
|
+
'display' => 'Ingrid Smith',
|
1716
|
+
'type' => 'User'
|
1717
|
+
},
|
1718
|
+
{
|
1719
|
+
'value' => 'f648f8d5ea4e4cd38e9c',
|
1720
|
+
'display' => 'Fred Smith',
|
1721
|
+
'type' => 'User'
|
1722
|
+
}
|
1723
|
+
]
|
1724
|
+
}.with_indifferent_case_insensitive_access()
|
1725
|
+
|
1726
|
+
@instance.send(
|
1727
|
+
:from_patch_backend!,
|
1728
|
+
nature: 'remove',
|
1729
|
+
path: path,
|
1730
|
+
value: value,
|
1731
|
+
altering_hash: scim_hash
|
1732
|
+
)
|
1733
|
+
|
1734
|
+
expect(scim_hash).to eql({
|
1735
|
+
'displayname' => 'Mock group',
|
1736
|
+
'members' => [
|
1737
|
+
{
|
1738
|
+
'value' => '50ca93d04ab0c2de4772',
|
1739
|
+
'display' => 'Ingrid Smith',
|
1740
|
+
'type' => 'User'
|
1741
|
+
}
|
1742
|
+
]
|
1743
|
+
})
|
1744
|
+
end
|
1745
|
+
|
1746
|
+
it 'matches the "members" key case-insensitive' do
|
1747
|
+
path = [ 'members' ]
|
1748
|
+
value = { 'MEMBERS' => [ { '$ref' => nil, 'value' => 'f648f8d5ea4e4cd38e9c' } ] }
|
1749
|
+
scim_hash = {
|
1750
|
+
'displayname' => 'Mock group',
|
1751
|
+
'members' => [
|
1752
|
+
{
|
1753
|
+
'value' => 'f648f8d5ea4e4cd38e9c',
|
1754
|
+
'display' => 'Fred Smith',
|
1755
|
+
'type' => 'User'
|
1756
|
+
},
|
1757
|
+
{
|
1758
|
+
'value' => 'a774d480e8112101375b',
|
1759
|
+
'display' => 'Taylor Smith',
|
1760
|
+
'type' => 'User'
|
1761
|
+
}
|
1762
|
+
]
|
1763
|
+
}.with_indifferent_case_insensitive_access()
|
1764
|
+
|
1765
|
+
@instance.send(
|
1766
|
+
:from_patch_backend!,
|
1767
|
+
nature: 'remove',
|
1768
|
+
path: path,
|
1769
|
+
value: value,
|
1770
|
+
altering_hash: scim_hash
|
1771
|
+
)
|
1772
|
+
|
1773
|
+
expect(scim_hash).to eql({
|
1774
|
+
'displayname' => 'Mock group',
|
1775
|
+
'members' => [
|
1776
|
+
{
|
1777
|
+
'value' => 'a774d480e8112101375b',
|
1778
|
+
'display' => 'Taylor Smith',
|
1779
|
+
'type' => 'User'
|
1780
|
+
}
|
1781
|
+
]
|
1782
|
+
})
|
1783
|
+
end
|
1784
|
+
|
1785
|
+
it 'ignores unrecognised users' do
|
1786
|
+
path = [ 'members' ]
|
1787
|
+
value = { 'members' => [ { '$ref' => nil, 'value' => '11b054a9c85216ed9356' } ] }
|
1788
|
+
scim_hash = {
|
1789
|
+
'displayname' => 'Mock group',
|
1790
|
+
'members' => [
|
1791
|
+
{
|
1792
|
+
'value' => 'f648f8d5ea4e4cd38e9c',
|
1793
|
+
'display' => 'Fred Smith',
|
1794
|
+
'type' => 'User'
|
1795
|
+
}
|
1796
|
+
]
|
1797
|
+
}.with_indifferent_case_insensitive_access()
|
1798
|
+
|
1799
|
+
@instance.send(
|
1800
|
+
:from_patch_backend!,
|
1801
|
+
nature: 'remove',
|
1802
|
+
path: path,
|
1803
|
+
value: value,
|
1804
|
+
altering_hash: scim_hash
|
1805
|
+
)
|
1806
|
+
|
1807
|
+
# The 'value' mismatched, so the user was not removed.
|
1808
|
+
#
|
1809
|
+
expect(scim_hash).to eql({
|
1810
|
+
'displayname' => 'Mock group',
|
1811
|
+
'members' => [
|
1812
|
+
{
|
1813
|
+
'value' => 'f648f8d5ea4e4cd38e9c',
|
1814
|
+
'display' => 'Fred Smith',
|
1815
|
+
'type' => 'User'
|
1816
|
+
}
|
1817
|
+
]
|
1818
|
+
})
|
1819
|
+
end
|
1820
|
+
end # "context 'Salesforce-style payload' do"
|
1821
|
+
end # "context 'special cases' do"
|
1205
1822
|
end # context 'when prior value already exists' do
|
1206
1823
|
|
1207
1824
|
context 'when value is not present' do
|
@@ -1926,7 +2543,7 @@ RSpec.describe Scimitar::Resources::Mixin do
|
|
1926
2543
|
:from_patch_backend!,
|
1927
2544
|
nature: 'remove',
|
1928
2545
|
path: ['complex[type eq "type1"]', 'data', 'nested[nature eq "nature2"]', 'info'],
|
1929
|
-
value:
|
2546
|
+
value: nil,
|
1930
2547
|
altering_hash: scim_hash
|
1931
2548
|
)
|
1932
2549
|
|