The Extensible Data Security (XDS) framework is a feature in D365FO and AX 2012 that allows users to supplement role based security and allow access to tables to be restricted by a policy. This feature was an evolution of the record-level security that existed in previous versions of Dynamics AX.
In simple terms, XDS is placing a WHERE (or ON) statement on any SQL SELECT, UPDATE, DELETE, or INSERT statement done to a table based on parameters from another related table.
Data Security Policy Concepts
Before we jump into how the functionality works we need to have an overview of some of the concepts and terms. In the below terms I’m going to use the example of wanting to secure the SalesOrder table based on the customer group.
- Constrained table – is the table(s) given a security policy from which data is filtered or secured, based on the associated policy query. In the above example, the SalesOrder table would be the constrained table.
- Primary table – is used to secure the content of the related constrained table. In the above example, the CustTable would be the primary table. The primary table must have an explicit relationship to the constrained table.
- Policy query – the query used to secure the constrained table contents via the primary table contents
- Context – the piece of information that controls the circumstances that a given policy is applicable. Contexts have two categories:
- Role Context – enables a policy based on the role(s) the user is assigned
- Application Context – enables a policy based on information set by the application
Developing an Extensible Data Security Policy
Before you begin developing XDS policies there are a couple things understand/keep in mind:
- Understand the scenario requirement/use case of why you are using XDS
- Identify the constrained and primary tables and analyze the relationships between them
- Analyze the data access patterns, table size/record counts, and existing indexes of the constrained and primary tables
Demo Scenario
If we take the scenario that we want to limit the customers a particular user sees based on a specific customer group, how would we set that up?
- The first thing to do is to determine your Constraint and Primary tables, in this case the CustTable table is our constraint table and the CustGroup table is our primary table.
- Next we create the policy query around our CustGroup, we want this query to return the results that we want to restrict the constraint table with
- Create a new Query, set the data source of the query to the primary table and then perform any filtering or other joins that need to be done for this query to return the results you want to filter by
- In our case we are limiting the user to only be able to see customers that have a CustGroup of ’10’ and Name of ‘Major Customers’
- Now we can create our Security Policy, we set the following parameters
- We then add a constrained table to the policy, in our case CustTable and set the following parameters
- Now if we build the solution and do a database sync of our project our XDS policy becomes live, to show what this does I did a before and after using a user assigned the FpTestRole to show the affect of the XDS policy
User access without XDS policy applied
User access after applying XDS policy
Now one question I had is, how do you apply an XDS policy against a group of roles? Well this is where the Context Type and Context String parameter on the policy comes into play. The Context Type parameter determines how the Context String parameter is handled. The Context Type has 3 different values:
- ContextString – should be set if you want to change the value of the Context String parameter via X++ code (via the XDS::SetContext method)
- RoleName – should be set if you want this policy to be assigned to a single role, this has the same effect as setting the Role Name field
- RoleProperty – allows for applying the policy to multiple roles via the Context String value, if a role has the same Context String then that role will have the XDS policy applied
If we set the Context Type to RoleProperty, then any role with a context string of the value we input in the Context String parameter will be assigned the XDS policy. So if we set the Context String value as CustGroup_XDSPolicy,
and then we set the same Context String value on a role, any user assigned that role will have the XDS policy applied to them.
Ensuring Efficient XDS Policies
Using XDS within D365FO will have an impact on the performance of queries on a table, the goal is to minimize this impact. There a couple things to keep in mind:
- Follow standard best practices of developing SQL queries (using indexes on join conditions, correct primary keys, etc)
- Simplify queries as much as possible, don’t have unnecessary joins
How to Debug/Troubleshoot Issues
If while using XDS you come across an instance where a user has more or less rows from a constrained table than you think they should you will have to try and debug the XDS policy. There are two ways of doing that:
- Execute a snippet of X++ code to see the SQL statement generated for a particular XDS policy (an example of this can be found in the white paper resource link below)
- Run a SELECT statement against the ModelSecPolRuntimeEx table to see the human readable query stored for this XDS policy
- For example, if we look for the CustomerGroupPolicy from the example above in the table the ModeledQueryDebugInfo column shows the SQL query
Another issue that you may see is a performance impact once XDS policies have been applied. In this case you will need to review the simplicity of your queries, the indexes on your tables, the proper joins are being used, and take into account the number of rows within each table you are using.
Conclusion
I hope this gave an overview on how to use the Extensible Data Security framework to extend your role based security to allow for fine grained control of user access. As always, feel free to reach out with any questions.
Hi Alex,
Would it be possible to exclude a from from it’s underlying security policy? To be specific, we need to apply different warehouse security policies on Transfer Order form as the “from warehouse” and “to warehouse” have different business rules and should provide different list of warehouses to the user to choose from.
Azad,
You should be able to do this, the idea would be you have to designate a constrained table and policy table. In your case the ‘business rules’ for a user would be your policy (not sure what these entail) but then your constrained table would be your user warehouses.
So users would be assigned access to all warehouses and then XDS would limit which warehouses they could actually see/interact with.
Feel free to reach out if you have any further questions!
Thanks a bunch Alex.
how can I setup the framework to deploy my XDS
Mnoia,
The blog post shows how to set this up in the AOT, the XDS framework is enabled by default in all AX/D365FO environments. The end user just has to set up if they want to implement any XDS policies and then set them up in the AOT.
Hi Alex,
Thanks for a very nice description of the XDS framework!
I have a scenario where I need to restrict the ability to edit certain records. My scenario is very similar to your example, only I don’t want to filter the restricted records out. I only what to restrict if a user can edit the records.
In your scenario that would correspond to not allowing the users to edit the sales orders with CustGroup 10, but they can still view those orders.
I see a property “Operation” on the Policy in your example, which is set to Select. Is this were you would instead set Operation = Update?
Mette,
Yes, if you wanted to change the action that XDS should be applied on you can do it from the Operation parameter. It supports Insert, Update, Create, Delete, InsertUpdateDelete, and AllOperations and these actions follow the same hierarchy as security does. For example, if you set it as Select then XDS would not be applied to Update, Create, or Delete actions for those records. So you need to be sure you are applying XDS in conjunction with security to only allow for the changes to objects you would like.
Hi Alex,
Thank you for your response. I think then, if I want users to be able to view, but not modify, then the Operation to choose would be InsertUpdateDelete.
One more question:
Say you have the policy restricting viewing of sales orders for customers with customer group 10. This policy is applied for Role1.
Another role, Role2, also has access to view Sales orders. The policy is not applied for this role, so a user with only Role2 is able to view all sales orders.
If a user has both roles, which permissons come into force? Does the restriction from the policy applied for Role1 “win” over the permissions given by Role2? In other words, can this user see sales orders for customers with customer group 10?
Mette,
You are correct, the the Operation to choose to affect Inserts, Updates, and Deletes should be the InsertUpdateDelete good catch!
If you have multiple roles assigned the user with one having XDS and one without, the most restrictive access will be granted.
Is it possible to use XDS to restrict the value returning for a particular financial dimension, except if users are using the dimension lookup in the expense management module, where we want all users to be able to see all dimension values?
KG,
If XDS is applied to a role, then the restriction will execute every time the underlying resource is accessed. And since it is done in code, there really isn’t a way to easily turn if on/off. If the users should be able to see all dimension values in one area of D365FO then they would be able to see those dimension values in another area. I will say that you can put different restrictions on the XDS, so maybe the user can see all of the dimensions but is restricted to Create/Update/Delete only certain ones.
EDIT: Trying to fix indentions, because spaces have been trunated.
We have a XDS policy that constrains table A, and there is table B added to the policy, too, as a constrained table of table A. So the policy looks something like this:
|- Policy
|—— constrainted table A
|————-|—— constrained table B (using relation R1)
Basically this works fine. But when we have a form where we use table A and join table B to it using relation R1 (same relation that has been unsed in XDS), the XDS framework will add the securing query to table A (which is good), but in addition will also add table A to table B (as an additional join, due to the XDS policy) and then also add the XDS query to that additionally joined query. So we end up with a query like this:
NON-XDS users:
|- Table A
|——|—— Table B (inner join, relation R1)
XDS users:
|- Table A
|—–|— XDS-Query added to first table A
|—–|—Table B (inner join, relation R1)
|————-|— Table A (added to table B
|———————-|— XDS-Query added to second table A
This is obviously not optimal. I think the optimal query would be this:
|- Table A
|—–|— XDS-Query added to first table A
|—–|—Table B (inner join, relation R1)
Is there a way to tell XDS that it should only apply itself to table A in a form, and not being applied to table B in order to improve the performance?
Mark,
How the SQL is generated for all AOT objects is abstracted away from the end user, I don’t know of any way to modify how it is created. The only option I could think of trying would be to create a view of Table A and the join to Table B then create another XDS policy using this view as the table parameter. I have not tested to see if this will generate different SQL but I think treating the query as a singular object (as a SQL view) might help.
Hi Alex,
thank you for this great post.
Hi Alex,
Great post !
How would it work if instead of the user only viewing CustGroup 10 they want to view all except CustGroup 10?
O Lanz,
Yes you absolutely can, we just have to change the query value. So if we have a list of customers like this:
And we want to show all customers that do not have a CustGroup of 10, we change the query to be:

And now if we go back to Customers we can see all customers except those with a CustGroup of 10:

You actually can use any formats that you use in QueryBuildDataSource logic in that Value parameter.
More information can be found here: https://community.dynamics.com/ax/b/axdaily/posts/and-33-operators-in-query-ranges
Fantastic, thank you so much Alex !
What are the oData (restAPI) service end points to create the security policies?
Hello,
There isn’t an OData endpoint to hit to create/modify XDS policies, XDS policies must be created in code via Visual Studio.
Hello,
My requirement is to show the data on budget analysis form ( Navigation: Budgeting >>inquiry and reports>> budget control>> budget analysis) according to current user.
Saiyada,
I think your requirement might be easier to achieve through extending X++ code on the form load compared to XDS.