This is a follow up blog post to one I had a few weeks ago about being able to grant/revoke the SysAdmin role for testing purposes. One of the things I called out there was that before implementing this solution there needed to be a logging functionality to be able to audit when a user was granted or revoked this access. Here’s how I added this functionality.
Design
The first thing I needed to do was to create a table to store when a user was assigned or revoked the SysAdmin role. I included the user impacted, the action being performed, and I added a reason field so that you could potentially add in an explanation on why this assignment change was occurring.
Next we needed to be able to capture when this change was occurring, in this case I used the table events on the SecurityUserRole table and listened for only changes where the SysAdmin role was being assigned/revoked:
The updating and deleting table events are slightly different as I had to utilize the Common object to get the data being updated and had to take into account the RoleAssignmentStatus parameter potentially changing.
To be able to allow for user input on why the SysAdmin role was assigned/revoked a custom form needed to be developed. The next step was to design the AmSysAdminReason form that is called in the above code. I chose a simple dialog to prompt the user for input. (Note: This field is not required to be filled and clicking the Submit button will close the form).
The code for the form was fairly straight forward, but I think should be improved. On the form init() we consume the parameters passed in and then store them to a static variable so that when the Submit button is pressed we can get this data add in the Reason information provided by the user and save it to our custom table. I do not like using this method and am completely aware that there is a potential of multiple users having this form open at once and overwriting each others data, but I could not think of another way to be able to pass arguments to this form while also allowing the data to be passed to a subsequent event handler without making the value static. While this does work, if there are any X++ developers that can help come up with a better solution I’m open to suggestions here.
Testing Solution
So let’s see what this looks like in the application, if we go back to revoke the SysAdmin role from our using using the functionality found at System Administration -> Alex Meyer’s Security Toolkit:
When we click on the button to assign / revoke the SysAdmin role another form is presented to prompt the user for the reason this change:
And because the event listeners are done at the table level, this will also work for the normal user role assignment done via the System Administration -> User form:
Reporting
Once we have this information logged, the next thing we would want to do is report on this logged data. In the System Administration -> Alex Meyer’s Security Toolkit menu path I added a new entry for the reporting:
This then takes you to the SysAdmin log report which shows when the role change occurred, the user it was assigned/revoked to, the reason (if provided), the action being performed, and the user that this was modified by.
One thing to note here is that if the User field and Modified By user field are the same then that means this process was done via the ‘Assign/Revoke SysAdmin’ feature from the previous blog post. If the users are different, it means that the process was done via the System Administration -> Users form.
Next Steps
After getting to this point, and having some discussions with other MVPs I think it would probably be best to get this solution on GitHub and open it up to the community. Be on the lookout in the upcoming weeks as I transition this over to being a public GitHub project.
There are a lot of really cool ideas that I have heard coming up from this and I’m excited to see the future of it!
Feel free to comment below or reach out with any questions, feedback, or ideas for the solution!
Hi Alex,
Great idea. Be careful that security assigment can be managed by data management so opening a form in this context would throw and error depending of the DMF setup or maybe some ISVs can manage security in X++.
Some ideas :
* Create a custom class that manage all logging processes with dynamic dialog instead of a form
* Manage open dialog only if called from FormDataSource
* Factorise code with 2 parameters UserId and Action
* Log all security role modifications
Have a nice day
Mikael,
Good call out on the DMF changes, definitely need to take that into consideration.
Also interesting take on dynamically creating a dialog instead of a form – what advantage does that give over the form option?
As far as logging all security role changes, this is a great idea and goes to a larger topic of change tracking in general. There are other ISVs in the market that specialize in this area so if you want that type of functionality I would recommend taking a look at them.
Hi Alex,
For this kind of simple form/dialog, I prefer use a dynamic dialog to avoid manage code in form side and some times in caller side but it is a personal habit. The biggest advantage of a dedicated class will be to regroup code and reduce code in insert/update/delete.
Mikael,
Appreciate the follow up, and agree with the benefits you listed of creating a dedicated class.