Hello All,
TLDR; Upon deleting ALL entries of a multivalued reference attribute, the Generic SQL connector does not export the changes. Removing only some of the entries works fine. Reproduction steps at the end.
We have 3 management agents:
- MA connected to an authorative datasource for users
- Access Management MA connected to Bhold for Role Based Access Control
- Generic SQL MA connected to the destination datasource which is also the source of 'permissions' (being groups in MV & BHOLD)
We provide users from the first MA, and permissions from the Generic SQL MA. Then we use BHOLD to assign these permissions to the user roles. In the MetaVerse BHOLD permissions are translated into group objects. The users that have these permissions are stored in a multivalued reference attribute (called UserID) of each corresponding group object.
These group objects later update their permissions in the Generic SQL connectorspace via a basic attribute flow (allow nulls is checked). Afterwards they get exported to the destination datasource and we can verify that the permissions are assigned to the users.
Everything works like a charm except when we remove a certain permission from ALL users in BHOLD (removing the permissions from some users works fine). In the MetaVerse this translates in the removal of all values from the multivalued reference field (and again, leaving just 1 or more values present works fine).
This works like a charm and propagates properly to the datasource
This does not work (note that this screenshot was taken after we removed the first two entries shown in the screenshot above thus only one entry is present).
We expect the cause to be a not implemented scenario (bug?) in the Generic SQL connector. Upon debugging the code of the generic SQL connector using reflection we encountered the code below. Since we have a multivalued attribute we enter the first (highlighted) if-statement. Once inside it counts the 'ValueChanges' of the attribute, but apparently this count returns zero, causing the code to pass the two next if statements.
A result of this is represented in the export run profile logfile you can find below. The former logfile removes all but one entry of the reference field and the latter removes all of them. As you can see the '<dn-attr>' element in the latter is empty (which according to us is originating in the code above).
Export log file upon removing some entries:
<?xml version="1.0" encoding="UTF-16"?><mmsml xmlns="http://www.microsoft.com/mms/mmsml/v2" step-type="export"><directory-entries><delta operation="update" dn="CN=G01,OBJECT=role"><anchor encoding="base64">CAAAAEcAMAAxAAAACgAAAHIAbwBsAGUAAAA=</anchor><dn-attr name="UserID" operation="update" multivalued="true"><dn-value operation="delete"><dn>CN=U02,OBJECT=user</dn><anchor encoding="base64">CAAAAFUAMAAyAAAACgAAAHUAcwBlAHIAAAA=</anchor></dn-value><dn-value operation="delete"><dn>CN=U03,OBJECT=user</dn><anchor encoding="base64">CAAAAFUAMAAzAAAACgAAAHUAcwBlAHIAAAA=</anchor></dn-value></dn-attr></delta></directory-entries></mmsml>
Export log file upon removing ALL entries:
<?xml version="1.0" encoding="UTF-16"?><mmsml xmlns="http://www.microsoft.com/mms/mmsml/v2" step-type="export"><directory-entries><delta operation="update" dn="CN=G01,OBJECT=role"><anchor encoding="base64">CAAAAEcAMAAxAAAACgAAAHIAbwBsAGUAAAA=</anchor><dn-attr name="UserID" operation="delete" multivalued="true"></dn-attr></delta></directory-entries></mmsml>
Is this some mistake or a not implemented scenario in the Generic SQL connector, and if so, where do i report this? Since we only got part of the code using reflection is it possible to obtain the source code for the Generic SQL Connector so we can investigate further?
Reproduction Steps :
- Create accounts in the source system
- Create permissions in the destination system
- Import both the accounts and the permissions
- Synchronize both accounts and permissions to the MV (they will get provisioned to BHOLD through a MV-extension)
- Export to BHOLD
- Assign a couple of roles to the permissions in BHOLD
- Import from BHOLD
- Synchronize BHOLD MA (groups will contain their member ID's in the destination CS)
- Export the destination MA (+ confirming import)
- Remove all roles from the BHOLD permission
- Import from BHOLD (group objects will have no members in BHOLD CS)
- Synchronize BHOLD MA (group objects will have no members in the MV and destination CS)
- Export the destination MA