Data entities within D365FO allow for external applications to interact with D365FO data. One data entity that I use both professionally and in my personal projects fairly regularly is SecurityUserRoleOrganization. This data entity is utilized to restrict a user role assignment to specific organizations within a D365FO environment. In most cases this is a legal entity or organization hierarchy but you can also place restrictions based on things such as operating units.
During some code testing I was notified that the SecurityUserRoleCondition table was not being populated correctly based on assignments that were happening via the SecurityUserRoleOrganization data entity.
I first went into the AOT to see the datasource of the SecurityUserRoleOrganization data entity. I found that it utilizes the OmUserRoleOrganization table as its main data source.
If I go into D365FO and assign a user a role with no organization restrictions:
Then run the following SQL query I can validate that there is a record in the SecurityUserRole table, but no associated results in the OmUserRoleOrganization or SecurityUserRoleCondition tables:
Now if I go in and place a legal entity restriction on the user role assignment but do not close the form and then rerun my query from above I get a very interesting result:
I can still see the entry in the SecurityUserRole table, and I can now see the entry in the OmUserRoleOrganization but no entry in the SecurityUserRoleCondition table.
Now if I go ahead and close the form, I can finally see entry in the SecurityUserRoleCondition table:
So let’s take a deeper look at the form itself to see what actually performs the organization assignment, if we right click on the form and go to Form Information we can see it is the SysSecRoleAssignOM form.
If we go and look in the AOT and look at the code for the form, we can see that there is a call to SysSecurityDynamicRoleAssignment::synchronize() during the closing of the form:
In a subsequent test, I used the DMF/DIXF to load data using the SecurityUserRoleOrganization data entity and was able to verify the correct data in the OmUserRoleOrganization as well as the SecurityUserRoleCondition table. Looking at the code within the data entity we can see a similar call to SysSecurityDynamicRoleAssignment::synchronize() on the postTargetProcess method (which executes once the data has been successfully loaded).
If we go and look at the SysSecurityDynamicRoleAssignment class itself we can see buried within this class is the process that actually populates the SecurityUserRoleCondition table:
While looking at the SysSecurityDynamicRoleAssignment class, you may notice that it is set up to execute as a batch job. If we do a search of the available out of the box batch jobs we can see one called ‘Automatic Role Assignment’ which executes the same SysSecurityDynamicRoleAssignment::synchronize() method.
The root cause of this issue in my case was that this SysSecurityDynamicRoleAssignment batch job was disabled and not executing, this was causing the SysSecurityDynamicRoleAssignment::synchronize() method to never get called which means the OMUserRoleOrganization and SecurityUserRoleCondition tables could become out of sync.
The easiest solution in this case is if you are an ISV or other application making use of this SecurityUserRoleOrganization data entity that you make sure that the SysSecurityDynamicRoleAssignment batch job is enabled and set to a ‘Waiting’ status with a periodic execution status. This will ensure that the OMUserRoleOrganization and SecurityUserRoleCondition tables are kept in sync with each other.