I have written in the past about Extensible Data Security (XDS) in D365FO, it has been one of my most popular posts. I often get questions about it, but one that I get quite often is wanting to apply XDS based on the current user. The use case is something along the lines of:
- ‘I only want a user to see sales orders/vendors/customers they created’
- ‘Users should only see records where they are the approvers’
In both of these cases we need the XDS applied to go against the current user logged into the system.
Test Scenario
The test scenario I am going to utilize today is that a user should only be able to interact with vendors that they have created themselves.
XDS Setup
The first thing we need to do is set up our query, in this case because we are going to want to compare results against a user Id we need to use a data source table that contains user Id’s. The obvious answer here is the UserInfo table however I found that trying to utilize this table threw an error as X++ deemed this table to be a ‘kernel table’. So instead, I utilized the SysUserInfo table which also includes user Id’s.
Once we set the Data Source as the SysUserInfo, the next step is setting the Range to use. In this case we are going to use the currentUserId() method to obtain the user Id. One thing to note here is that you must surround this value with parenthesis. If you do not do this, the value will be interpreted as a string and will not resolve the user Id.
Also note here that this CreatedByQuery can be reused by other security policies as needed.
The next step is setting up the security policy, in this case we set the Query as the CreatedByQuery created in the previous step and create a Context String so we can apply this to a role later on. We also set the primary table to the SysUserInfo table and be sure to set the Operation field to AllOperations if you want this XDS to be applied to all Read, Update, Create, and Delete functions.
The final piece of setting up the security policy is setting the constrained table, in this case though we will actually create a constrained expression because there is no native table relation between the VendTable and the SysUserInfo table. In the value property, we actually put in the relation clause we want to use to join the tables. Note again that you need to surround this value with parenthesis.
So now we have our query and security policy created, the last piece is applying this XDS policy to a security role. In this case I created a custom role and set the Context String of the role to the Context String I set in the security policy. This means that any user assigned this role automatically gets the XDS policy assigned.
XDS Results for Current User Setup
The role my test user (user Id of ‘fastpath’) is assigned grants full control to all vendor master data, so without XDS applied we can see this user has full access to all vendors in the USSI legal entity.
This user has created only the ‘Test 123’ and ‘Test 456’ vendors within this legal entity:
Once we enable the XDS policy and reload the page, we can see this user can now only interact with those vendors that they have created:
YouTube Video
I created a YouTube video of me going through the steps above, feel free to check it out here:
How to Setup XDS in D365FO for the Current User
If you would like me to make more videos like this please let me know!
Conclusion
I hope this helps to show how powerful the XDS feature is and how it can be used to solve lots of different user requirements. As always, feel free to reach out with any questions.
Great post! Thanks Alex!
Great Post, will this XDS be applied to the Lookups available as part of Query ranges that is available to generate any reports.
Raj,
XDS is applied at the datasource level, I have not tested your exact scenario but I would believe it would impact all queries to a particular datasource regardless of where the query was coming from.
I need to restrict access to the activities in D365FO. Each department (e.g. purchase or sales) should only see activities created by members of the own department. How would you set up this?
Giorgio,
I actually have an example of doing something like this on this blog post: https://alexdmeyer.com/2022/10/03/how-to-approach-advanced-xds-scenarios-in-d365fo/
currentUserId in AOT Static query is not working
Vigneshvaran,
Please provide more detail on what the actual issue you are having is and what your current configuration looks like, otherwise I cannot help troubleshoot.
Hello Alex, thank you for the documentation.
I would like to restrict my VendTable by Site or Location.
If I build it up the 2 ranges in 2 separate queries it works, but I would like to put them both inside the same query (therefore a query with 2 ranges applied to the same table): unfortunately, it doesn’t work in that way.
Have you ever applied 2 different ranges on the same table in a query? Should I join the table with itself to get the chance to apply these 2 different ranges?
Marco,
I have not tried this and would probably recommend performing this in two separate queries.
However, if you did want to try it I believe you would only be able to do this if you could format it in a ‘Constrained Expression’ and have multiple WHERE conditions. If different joins or query logic is required I believe the only option is to do multiple queries.
Please keep us updated if you try this route, I’m curious on the outcome.