Skip to content

Commit d9c6da8

Browse files
authored
Merge pull request #4817 from MicrosoftDocs/jdaly-main-cleanup-inherited-access
AB#181012: New article about cleaning up inherited access
2 parents 4c49ac8 + be054bf commit d9c6da8

2 files changed

Lines changed: 264 additions & 0 deletions

File tree

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
---
2+
title: How to clean up inherited access
3+
description: Introduces how to remove inherited access to records when the cascade configuration of a table changes in Microsoft Dataverse.
4+
ms.date: 09/08/2023
5+
author: paulliew
6+
ms.author: paulliew
7+
ms.reviewer: jdaly
8+
search.audienceType:
9+
- developer
10+
search.app:
11+
- PowerApps
12+
- D365CE
13+
contributors:
14+
- JimDaly
15+
- phecke
16+
- SEOKK-MSFT
17+
---
18+
# How to clean up inherited access
19+
20+
This article introduces how to remove inherited access for records when the cascade configuration of a table changes in Microsoft Dataverse.
21+
22+
## Symptoms
23+
24+
After the [cascading behavior of a table relationship](/power-apps/developer/data-platform/configure-entity-relationship-cascading-behavior#reset-cascade-inherited-access) for the **Reparent** or **Share** action is changed to **No Cascade**, you continue to have access to the related records that should be removed.
25+
26+
## How to verify the access to related records
27+
28+
Users may report that they have unexpected access to records. There are two ways that you can verify the access to the related records: using the **Check Access** feature or the `RetrieveAccessOrigin` message.
29+
30+
#### Use the Check Access feature
31+
32+
Use the [Check Access](/power-apps/user/access-checker) feature in model-driven apps to check who has access to a record. Administrators can use this feature to check individual users or all users who have access to a record.
33+
34+
When using the access checker, you see a list of reasons why a user has access. Some of these reasons indicate that the sharing was granted due to access to a related record. For example:
35+
36+
- Record was shared with me because I have access to related record.
37+
- Record was shared with team(s) that I'm a member of because the team has access to related record.
38+
39+
#### Use the RetrieveAccessOrigin message
40+
41+
Developers can use the `RetrieveAccessOrigin` message to detect which users have access to a record. This message returns a sentence describing why the user has the access. Any of the following results indicate that the access was granted due to the sharing of a related record:
42+
43+
```output
44+
PrincipalId is owner of a parent entity of object (<record ID>)
45+
PrincipalId is member of team (<team ID>) who is owner of a parent entity of object (<record ID>)
46+
PrincipalId is member of organization (<organization ID>) who is owner of a parent entity of object (<record ID>)
47+
PrincipalId has access to (<parent record ID>) through hierarchy security. (<parent record ID>) is owner of a parent entity of object (<record ID>)
48+
```
49+
50+
For more information, see [Determine why a user has access with code](/power-apps/developer/data-platform/security-sharing-assigning#determine-why-a-user-has-access).
51+
52+
## Cause
53+
54+
When the cascading behavior for a table relationship changes, Dataverse starts an asynchronous job to remove the access users were previously granted. However, this job may fail, resulting in users retaining access.
55+
56+
## Resolution
57+
58+
The first step to resolve this issue is to recreate the system job to remove access. If the job fails, a developer can use the `ResetInheritedAccess` message to apply the change to a specified set of records.
59+
60+
### Recreate the system job to remove access
61+
62+
Developers can use the `CreateAsyncJobToRevokeInheritedAccess` message to try creating an asynchronous job again.
63+
64+
#### [SDK for .NET](#tab/sdk)
65+
66+
Use the [Microsoft.Xrm.Sdk.Messages.CreateAsyncJobToRevokeInheritedAccessRequest class](xref:Microsoft.Xrm.Sdk.Messages.CreateAsyncJobToRevokeInheritedAccessRequest).
67+
68+
```csharp
69+
/// <summary>
70+
/// Creates and executes an asynchronous cleanup job to revoke inherited access granted through cascading inheritance.
71+
/// </summary>
72+
/// <param name="service">The authenticated IOrganizationService instance to use.</param>
73+
/// <param name="relationshipSchemaName">The schema name of the entity relationship.</param>
74+
public static void CreateAsyncJobToRevokeInheritedAccessExample(IOrganizationService service, string relationshipSchemaName)
75+
{
76+
var request = new Microsoft.Xrm.Sdk.Messages.CreateAsyncJobToRevokeInheritedAccessRequest()
77+
{
78+
RelationshipSchema = relationshipSchemaName
79+
};
80+
81+
service.Execute(request);
82+
}
83+
```
84+
85+
[Learn more about using messages with the SDK for .NET](/power-apps/developer/data-platform/org-service/use-messages?tabs=sdk).
86+
87+
#### [Web API](#tab/webapi)
88+
89+
Use the [CreateAsyncJobToRevokeInheritedAccess action](xref:Microsoft.Dynamics.CRM.CreateAsyncJobToRevokeInheritedAccess).
90+
91+
**Request**:
92+
93+
```http
94+
POST [Organization URI]/api/data/v9.2/CreateAsyncJobToRevokeInheritedAccess
95+
Accept: application/json
96+
Content-Type: application/json; charset=utf-8
97+
OData-MaxVersion: 4.0
98+
OData-Version: 4.0
99+
100+
{
101+
"RelationshipSchema": "<schema name>"
102+
}
103+
```
104+
105+
**Response**:
106+
107+
```http
108+
HTTP/1.1 204 No Content
109+
OData-Version: 4.0
110+
```
111+
112+
[Learn more about Web API actions](/power-apps/developer/data-platform/webapi/use-web-api-actions).
113+
114+
---
115+
116+
The `CreateAsyncJobToRevokeInheritedAccess` action creates a new asynchronous job named `RevokeInheritedAccess`. You can monitor the success of this job. For more information, see [monitoring system jobs](/power-platform/admin/manage-dataverse-auditing#monitoring-system-jobs) or [managing system jobs with code](/power-apps/developer/data-platform/asynchronous-service#managing-system-jobs).
117+
118+
### Reset inherited access
119+
120+
If [recreating the system job to remove access](#recreate-the-system-job-to-remove-access) fails, a developer with system administrator or system customizer privileges can use the `ResetInheritedAccess` message to target a subset of matching records. You may need to use this message several times to remove access to all the records.
121+
122+
# [SDK for .NET](#tab/sdk)
123+
124+
```csharp
125+
/// <summary>
126+
/// Resets the inherited access for the matching records.
127+
/// </summary>
128+
/// <param name="service">The authenticated IOrganizationService instance to use.</param>
129+
/// <param name="fetchXml">The fetchxml query.</param>
130+
public static void OutputResetInheritedAccess(IOrganizationService service, string fetchXml)
131+
{
132+
var parameters = new ParameterCollection()
133+
{
134+
{ "FetchXml", fetchXml}
135+
};
136+
137+
var request = new OrganizationRequest()
138+
{
139+
RequestName = "ResetInheritedAccess",
140+
Parameters = parameters
141+
};
142+
143+
var response = service.Execute(request);
144+
145+
Console.WriteLine(response.Results["ResetInheritedAccessResponse"]);
146+
}
147+
```
148+
149+
[Learn more about using messages with the SDK for .NET](/power-apps/developer/data-platform/org-service/use-messages?tabs=sdk).
150+
151+
# [Web API](#tab/webapi)
152+
153+
**Request**:
154+
155+
```http
156+
GET [Organization URI]/api/data/v9.0/ResetInheritedAccess(FetchXml=@fetchXml)?@fetchXml=%3Cfetch%3E%3Centity%20name%3D%22principalobjectaccess%22%3E%3Cattribute%20name%3D%22principalobjectaccessid%22%2F%3E%3Cfilter%20type%3D%22and%22%3E%3Ccondition%20attribute%3D%22principalid%22%20operator%3D%22eq%22%20value%3D%229b5f621b-584e-423f-99fd-4620bb00bf1f%22%20%2F%3E%3Ccondition%20attribute%3D%22objectid%22%20operator%3D%22eq%22%20value%3D%22B52B7A48-EAFB-ED11-884B-00224809B6C7%22%20%2F%3E%3C%2Ffilter%3E%3C%2Fentity%3E%3C%2Ffetch%3E
157+
Accept: application/json
158+
OData-MaxVersion: 4.0
159+
OData-Version: 4.0
160+
```
161+
162+
**Response**:
163+
164+
```http
165+
HTTP/1.1 200 OK
166+
Content-Type: application/json; odata.metadata=minimal
167+
OData-Version: 4.0
168+
{
169+
"@odata.context": "[Organization URI]/api/data/v9.2/$metadata#Microsoft.Dynamics.CRM.ResetInheritedAccessResponse",
170+
"ResetInheritedAccessResponse": "Resetting the inherited access job is successfully created. ExecutionMode : Sync"
171+
}
172+
```
173+
174+
[Learn more about Web API functions](/power-apps/developer/data-platform/webapi/use-web-api-functions).
175+
176+
---
177+
178+
The `ResetInheritedAccess` message tries to execute synchronously when there aren't many matching records. Then the `ResetInheritedAccessResponse` value ends with `ExecutionMode : Sync`. If there are many matching records, the operation takes longer, and the value ends with `ExecutionMode : Async`. A system job named `Denormalization_PrincipalObjectAccess_principalobjectaccess:<caller ID>` is created, and you can monitor the success of that job. For more information, see [monitoring system jobs](/power-platform/admin/manage-dataverse-auditing#monitoring-system-jobs) or [managing system jobs with code](/power-apps/developer/data-platform/asynchronous-service#managing-system-jobs).
179+
180+
The `ResetInheritedAccess` message requires a FetchXml query to identify the records. This query must meet the following requirements:
181+
182+
- Use the `principalobjectaccess`(POA) table.
183+
- Return only the `principalobjectaccessid` column.
184+
- Must not include any `link-entity` elements. You can't add a join to another table.
185+
- Only filter on columns of the `principalobjectaccess` table.
186+
187+
This table is available to the Web API as the [principalobjectaccess entity type](xref:Microsoft.Dynamics.CRM.principalobjectaccess). It isn't included in the [Dataverse table/entity reference](/power-apps/developer/data-platform/reference/about-entity-reference) because the POA table doesn't support any kind of direct data modification operation. You need to know the columns of this table to compose the FetchXml query.
188+
189+
#### POA table columns
190+
191+
You need to compose a FetchXml query using only these columns.
192+
193+
|Logical name |Type|Description|
194+
|---------|---------|---------|
195+
|`accessrightsmask`|Integer|Contains the combined [AccessRights enum](xref:Microsoft.Dynamics.CRM.AccessRights) member values for the access rights that the principal has directly. |
196+
|`changedon`|DateTime|The last date that the principal's access to the record changed.|
197+
|`inheritedaccessrightsmask`|Integer|Contains the combined [AccessRights enum](xref:Microsoft.Dynamics.CRM.AccessRights) member values for the access rights that are applied due to inheritance.|
198+
|`objectid`|Unique Identifier|The ID of the record that the principal has access to.|
199+
|`objecttypecode`|Integer|The [EntityMetadata.ObjectTypeCode](xref:Microsoft.Xrm.Sdk.Metadata.EntityMetadata.ObjectTypeCode) value that corresponds to the table. This value isn't necessarily the same for different environments. For custom tables, it's assigned based on the order in which the table was created. To get this value, you may need to view the metadata for the table. There are several community tools to find this. Here's a solution from Microsoft: [Browse table definitions in your environment](/power-apps/developer/data-platform/browse-your-metadata).|
200+
|`principalid` |Unique Identifier|The ID of the user or team that has access.|
201+
|`principalobjectaccessid`|Unique Identifier|The primary key of the POA table.|
202+
|`principaltypecode`|Integer|The type code of the principal. `SystemUser` = 8, `Team` = 9.|
203+
204+
The following [AccessRights enum](xref:Microsoft.Dynamics.CRM.AccessRights) member values apply to the `accessrightsmask` and `inheritedaccessrightsmask` columns:
205+
206+
|Access type|Value|Description|
207+
|---------|---------|---------|
208+
|`None`|0|No access.|
209+
|`Read`|1|The right to read a record.|
210+
|`Write`|2|The right to update a record.|
211+
|`Append`|4|The right to append the specified record to another record. |
212+
|`AppendTo`|16|The right to append another record to the specified record. |
213+
|`Create`|32|The right to create a record.|
214+
|`Delete`|65,536|The right to delete a record.|
215+
|`Share`|262,144|The right to share a record.|
216+
|`Assign`|524,288|The right to assign the specified record to another user or team.|
217+
218+
You may see that the `inheritedaccessrightsmask` value is commonly 135,069,719. This value includes all the access types except for `Create`, which isn't necessary because these rights only apply to records already created.
219+
220+
#### FetchXml examples
221+
222+
This section includes some examples of FetchXml queries you might use with the `ResetInheritedAccess` message. For more information, see [Use FetchXML to construct a query](/power-apps/developer/data-platform/use-fetchxml-construct-query).
223+
224+
##### Reset inherited access given to a certain user for a specific account
225+
226+
```xml
227+
<fetch>
228+
<entity name="principalobjectaccess">
229+
<attribute name="principalobjectaccessid"/>
230+
<filter type="and">
231+
<condition attribute="principalid" operator="eq" value="9b5f621b-584e-423f-99fd-4620bb00bf1f" />
232+
<condition attribute="objectid" operator="eq" value="B52B7A48-EAFB-ED11-884B-00224809B6C7" />
233+
</filter>
234+
</entity>
235+
</fetch>
236+
```
237+
238+
##### Reset inherited access given to all child rows for a specified object type
239+
240+
```xml
241+
<fetch>
242+
<entity name="principalobjectaccess">
243+
<attribute name="principalobjectaccessid"/>
244+
<filter type="and">
245+
<condition attribute="objecttypecode" operator="eq" value="10042" />
246+
</filter>
247+
</entity>
248+
</fetch>
249+
```
250+
251+
##### Reset inherited access given to a specified user for all object types
252+
253+
```xml
254+
<fetch>
255+
<entity name="principalobjectaccess">
256+
<attribute name="principalobjectaccessid"/>
257+
<filter type="and">
258+
<condition attribute="principalid" operator="eq" value="9b5f621b-584e-423f-99fd-4620bb00bf1f" />
259+
</filter>
260+
</entity>
261+
</fetch>
262+
```

support/power-platform/power-apps/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ items:
4040
href: create-and-use-apps/no-navigation-when-selecting-button.md
4141
- name: Dataverse
4242
items:
43+
- name: Clean up inherited access
44+
href: dataverse/cleanup-inherited-access.md
4345
- name: Dataverse plug-ins
4446
href: dataverse/dataverse-plug-ins-errors.md
4547
- name: Web API client errors

0 commit comments

Comments
 (0)