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
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.
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.