Building an XDS (Extensible Data Security) Policy End-to-End in Dynamics 365 Finance & Operations
Question 59 — Row-level security with a constrained table, policy query and context.
Interview Question
Model Answer (Short)
XDS enforces row-level security by silently adding a filter to every query against a constrained table. To build one you create a security policy object with four key parts: the primary table (the table that drives the restriction, e.g. a worker-to-business-unit mapping), a policy query (built on the primary table, defining which rows are allowed), the constrained table(s) (the tables the filter is applied to), and the context (how the policy is triggered — by role or by application context value). At runtime the framework joins the policy query into every read of the constrained table so users only see permitted rows. Because it adds a join to every query, you must design the primary↔constrained relationship carefully and ensure the fields are indexed to protect performance.
The Four Components
Policy building blocks
- Primary table — the table that determines the constraint (e.g. maps a user/worker to a business unit).
- Policy query — a query on the primary table defining the allowed rows.
- Constrained table(s) — the tables the row filter is enforced on.
- Context — how the policy applies: RoleContext, ContextString (application context), or RoleName.
Context types
- RoleContextType — the policy applies to users assigned specific security roles.
- ContextString — the policy applies based on an application context value set in X++.
- RoleName — the policy is tied to one named role.
End-to-End Build Steps
| Step | Action |
|---|---|
| 1 | Create the primary table (or reuse one) that drives the constraint |
| 2 | Build a query on the primary table for the allowed rows |
| 3 | Create a Security Policy object; set PrimaryTable & Query |
| 4 | Add the constrained table(s) and the relation to the primary |
| 5 | Set the ContextType (Role / ContextString) and enable the policy |
| 6 | Set the context in X++ if using ContextString |
Prerequisites (Rule 5)
- Visual Studio with the Dynamics 365 developer tools.
- A custom model / package for your objects.
- A primary table and a query defining the allowed rows.
- Indexes on the primary↔constrained relation fields.
Code Example — Setting the application context (ContextString)
// When the policy uses ContextType = ContextString, set the context in X++
XDSServices xdsServices = new XDSServices();
// The policy's context string must match what you set here
xdsServices.setXDSContext(
curUserId(),
"BusinessUnitContext"); // matches the policy ContextString
// Now any query on the constrained table is filtered for this context.
Policy query concept (primary table)
// Conceptual: the policy query on the primary table (AbcWorkerBusinessUnit)
// returns the business units the CURRENT user is allowed to see.
// The framework joins this into every read of the constrained table
// (e.g. AbcOrderHeader) on BusinessUnitId.
//
// AbcWorkerBusinessUnit.WorkerId == currentWorker
// AbcWorkerBusinessUnit.BusinessUnitId == AbcOrderHeader.BusinessUnitId
Effect on a normal select (transparent filtering)
AbcOrderHeader header;
// The developer writes a normal select — XDS silently adds the
// policy filter so only permitted business units are returned.
while select header
{
info(header.OrderId); // only allowed rows appear
}
Performance considerations
- Every read of the constrained table gets an extra join to the policy query.
- Ensure the primary↔constrained relation fields are indexed.
- Keep the policy query simple — avoid heavy joins inside it.
- Test with realistic data volumes; XDS can affect query plans.
Points the interviewer wants to hear
- XDS enforces row-level security by joining a policy query into reads.
- Four parts: primary table, policy query, constrained table(s), context.
- Context is Role-based or ContextString (set via
XDSServices). - Filtering is transparent — developers write normal selects.
- Index the relation and keep the policy query lean for performance.
Likely Follow-up Questions
- What are the four components of an XDS policy?
- What is the difference between a Role context and a ContextString?
- How does XDS affect a normal select statement?
- What performance precautions do you take with XDS policies?
Key Takeaway
An XDS policy adds transparent row-level security by joining a policy query (on a primary table) into every read of the constrained table, triggered by a role or ContextString. Design the relationship and indexes carefully, because the added join affects performance on every query.