Using the Microsoft Dynamics CRM SDK to Perform Security-Related Operations

The Microsoft Dynamics CRM SDK provides methods for you to programmatically manage your security roles and privileges. It also exposes methods with which you can retrieve roles and privileges for a specific user. In this section, we will discuss how to execute this type of functionality and walk through a few examples.

Programmatically Creating a Security Role and Adding Privileges

If you plan to deploy custom security roles to multiple instances of Microsoft Dynamics CRM, or if you are an independent software vendor (ISV) developing a custom solution that integrates with Microsoft Dynamics CRM, it might make sense for you to create a utility that programmatically creates your custom security roles as part of the installation process.

Example 4-1 shows code that creates a new security role named "My New Role" and then adds the Create privilege for the Account entity. The role is created in the currently logged-on user’s business unit.

Example 4-1. Creating a role and adding privileges source code

const string accountCreatePriv = "D26FE964-230B-42DD-AD93-5CC879DE411E";

CrmService service = CrmServiceUtility.GetCrmService("server_name",
    "organization_name");

WhoAmIRequest whoAmIRequest = new WhoAmIRequest();
WhoAmIResponse currentUser = (WhoAmIResponse)service.Execute(whoAmIRequest);

role newRole = new role();

newRole.name = "My New Role";
newRole.businessunitid = new Lookup();
newRole.businessunitid.Value = currentUser.BusinessUnitId;
newRole.organizationid = new UniqueIdentifier();
newRole.organizationid.Value = currentUser.OrganizationId;

TargetCreateRole target = new TargetCreateRole();
target.Role = newRole;

CreateRequest newRoleRequest = new CreateRequest();
newRoleRequest.Target = target;

CreateResponse newRoleResponse = (CreateResponse)service.Execute(newRoleRequest);

RolePrivilege[] privileges = new RolePrivilege[1];

privileges[0] = new RolePrivilege();
privileges[0].PrivilegeId = new Guid(accountCreatePriv);
privileges[0].Depth = PrivilegeDepth.Global;

AddPrivilegesRoleRequest addPrivRequest = new AddPrivilegesRoleRequest();

addPrivRequest.Privileges = privileges;
addPrivRequest.RoleId = newRoleResponse.id;

AddPrivilegesRoleResponse addPrivResponse = (AddPrivilegesRoleResponse)service.
    Execute(addPrivRequest);

The listing shows creating a record in the same manner as any other entity, but it requires that you set a few fields. First we need to make a WhoAmIRequest to retrieve the currently logged-on user’s ID, business unit, and organization. We then can create a new instance of the role class, populate the necessary attributes, and use the CrmService to create our new role.

Warning

Warning

The user executing this code needs to have the Create and Read privileges set on the Role entity.

After we create the role, we can add all the necessary privileges. In our example we add the Create privilege on the Account entity. The Guid of the privilege we are adding is hard-coded in the accountCreatePriv variable. Notice that we set the Depth property of our privilege to Global. This gives our privilege organization-level rights.

After the code creates the role, it will show up like any other security role in the Microsoft Dynamics CRM user interface (UI). You can then edit the role through the UI. Figure 4-1 shows what the resulting role looks like in the UI.

"My New Role" security role

Figure 4-1. "My New Role" security role

Programmatically Assigning a Security Role

In addition to creating a role programmatically, we can also assign roles programmatically to users. Example 4-2 shows sample code for assigning the sample security role that we just created to a user.

Example 4-2. Assigning a security role

CrmService service = CrmServiceUtility.GetCrmService("server_name", "organization");
// Guid of the user we want to add the role to
Guid userId = new Guid("DC8B2248-191D-DD11-8839-0019B9F8F548");
// Guid of the role we want to add to the user
Guid roleId = new Guid("20404189-9C40-DD11-B751-0019B9F8F548");
AssignUserRolesRoleRequest assign = new AssignUserRolesRoleRequest();
assign.UserId = userId;
assign.RoleIds = new Guid[] { roleId };
AssignUserRolesRoleResponse assigned = (AssignUserRolesRoleResponse)service.
    Execute(assign);

The code is pretty simple—just obtain the Guid of the user and the Guid of the role you want to assign the user, and then use the AssignUserRolesRoleRequest class.

Retrieving Roles and Privileges

At some point, you will probably want to build logic into your custom code that depends on the security roles and privileges of a specific use. For example, let’s say you want a piece of logic to run only for users with the "Salesperson" role. To accomplish this, you can use the CrmService to retrieve security roles and privileges for a given user, and then use this information to determine how your custom code should react. The code for the IsSalesPerson method in Example 4-3 demonstrates how to check the security role of a user to determine if she possesses the Salesperson security role using the Microsoft Dynamics CRM API.

Example 4-3. IsSalesPerson method

public bool IsSalesPerson(Guid systemUserId)
{
    bool isSalesPerson = false;
    CrmService service = CrmServiceUtility.GetCrmService("server_name",
        "organization");
    QueryExpression query = new QueryExpression();
    query.EntityName = "role";
    query.ColumnSet = new AllColumns();
    LinkEntity userRole = new LinkEntity();
    userRole.LinkFromEntityName = EntityName.role.ToString();
    userRole.LinkFromAttributeName = "roleid";
    userRole.LinkToEntityName = EntityName.systemuserroles.ToString();
    userRole.LinkToAttributeName = "roleid";
    ConditionExpression userCondition = new ConditionExpression();
    userCondition.AttributeName = "systemuserid";
    userCondition.Operator = ConditionOperator.Equal;
    userCondition.Values = new object[] { systemUserId };
    userRole.LinkCriteria = new FilterExpression();
    userRole.LinkCriteria.Conditions.Add(userCondition);
    query.LinkEntities.Add(userRole);

    BusinessEntityCollection roles = service.RetrieveMultiple(query);
    foreach (BusinessEntity be in roles.BusinessEntities)
    {
        role currentRole = (role)be;
        if (currentRole.name == "Salesperson")
        {
            isSalesPerson = true;
            break;
        }
    }
    return isSalesPerson;
}

The QueryExpression used in Example 4-3 queries the Role entity. Because we are trying to determine whether the current user has a certain security role, we need to add a LinkEntity that links role to systemuserrole and a condition to return records only for the current user.

Tip

Tip

During development you might want to quickly reference information stored in the Microsoft Dynamics CRM database. In the preceding example, it would be helpful to quickly query for all roles assigned to a specified user to verify that your code is functioning correctly. The roles for all system users are stored in the SystemUserRoles table.

You can retrieve the privileges for a user by using RetrieveUserPrivilegesRequest. By setting the UserId property and then executing the request, you can retrieve an array of RolePrivilege objects. Each RolePrivilege object contains the depth (see Table 4-1) and the Guid of the privilege. The following code provides a quick example of using RetrieveUserPrivilegeRequest:

CrmService service = CrmServiceUtility.GetCrmService("server_name", "organization");
WhoAmIRequest userRequest = new WhoAmIRequest();
WhoAmIResponse user = (WhoAmIResponse)service.Execute(userRequest);
RetrieveUserPrivilegesRequest retrieve = new RetrieveUserPrivilegesRequest();
retrieve.UserId = user.UserId;
RetrieveUserPrivilegesResponse retrieved = (RetrieveUserPrivilegesResponse)service.
    Execute(retrieve);

Sharing Records

If a system user possesses the Share privilege on an entity, she can then share records of that entity type with another system user or a team. The depth of the sharing privileges in the sharing user’s security role determines which users and teams are available for her to share with. When you are sharing a record, you can specify what access rights you want to grant to the users participating in the share. For example, you may want to assign a Lead record to two users but give only one of them access to update the record.

Note

Note

You cannot give a user sharing rights that the user would not normally have based on his or her privileges. For example, if a user does not have Read privileges to Lead records and you share a Lead with him, he will still not be able to read the Lead record.

If your business requirements dictate that users frequently share records, manually sharing them can be a tedious process for users and prone to error if users forget to share their records. In this section we will demonstrate how to add a plug-in to automatically share Lead records with a team when those records are created. Example 4-4 contains the source code for the plug-in.

Note

Note

See Chapter 5 for more details on adding the plug-in code file and deploying the plug-in.

Example 4-4. LeadSharer source code

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Crm.Sdk;
using ProgrammingWithDynamicsCrm4.Plugins.Attributes;
using Microsoft.Crm.SdkTypeProxy;
namespace ProgrammingWithDynamicsCrm4.Plugins
{
    [PluginStep("Create",
                PluginStepStage.PostEvent,
                Description = "Shares the lead with a team",
                StepId = "LeadPostCreate",
                PrimaryEntityName = "lead",
                Mode = PluginStepMode.Synchronous,
                SupportedDeployment = PluginStepSupportedDeployment.ServerOnly)]
    public class LeadSharer : IPlugin
    {
        public void Execute(IPluginExecutionContext context)
        {
            // This Guid is the id of the team we will share the lead with
            Guid teamId = new Guid("376A5F7E-5341-DD11-B751-0019B9F8F548");
            ICrmService crmService = context.CreateCrmService(true);
            SecurityPrincipal principal = new SecurityPrincipal();
            principal.Type = SecurityPrincipalType.Team;
            principal.PrincipalId = teamId;
            PrincipalAccess principalAccess = new PrincipalAccess();
            principalAccess.Principal = principal;
            principalAccess.AccessMask = AccessRights.ReadAccess | AccessRights.
                WriteAccess;
            TargetOwnedLead target = new TargetOwnedLead();
            target.EntityId = new Guid(context.OutputParameters[ParameterName.Id].
                ToString());
            GrantAccessRequest grantAccessRequest = new GrantAccessRequest();
            grantAccessRequest.PrincipalAccess = principalAccess;
            grantAccessRequest.Target = target;
            GrantAccessResponse grantAccessResponse =
              (GrantAccessResponse)crmService.Execute(grantAccessRequest);
        }
     }
  }

Notice that in the code we create an instance of the SecurityPrincipal class. The Type property on the SecurityPrincipal object can be set to a user or a team. Table 4-4 lists the values for the SecurityPrincipalType enumeration. Next we create a PrincipalAccess object and set its Principal property to our SecurityPrincipal object. The PrincipalAccess object’s AccessMask property determines the access rights that are given to the team or user we are sharing the entity instance with. Table 4-5 describes the possible values for the AccessMask property.

Table 4-4. SecurityPrincipalType Enumeration

Name

Value

Description

Team

1

The security principal is a team.

User

0

The security principal is a system user.

Table 4-5. AccessRights Enumeration

Name

Value

Description

AppendAccess

4

Gives the security principal rights to append the entity instance to another entity instance

AppendToAccess

8

Gives the security principal rights to append another entity instance to the entity instance

AssignAccess

0x80

Gives the security principal rights to assign the entity instance to another security principal

CreateAccess

0x10

Gives the security principal rights to create an entity instance

DeleteAccess

0x20

Gives the security principal rights to delete an entity instance

ReadAccess

1

Gives the security principal rights to read entity instances

ShareAccess

0x40

Gives the security principal rights to share an entity instance

WriteAccess

2

Gives the security principal rights to update an entity instance

A quick way to verify that your record has been shared is to check it against the Microsoft Dynamics CRM user interface.

Verifying that a record is shared

  1. Open Microsoft Dynamics CRM in your Web browser.

  2. Navigate to the entity grid view of the record.

    AccessRights Enumeration
  3. Click More Actions and select Sharing.

You will see a window containing all the users or teams that the record is shared with, along with their access writes on the instance (Figure 4-2).

Shared Lead record.

Figure 4-2. Shared Lead record.

Assigning Records

We talked about sharing records with teams and users, but sometimes you will want to actually change ownership of an entity instance. In these cases you need to use the Microsoft Dynamics CRM SDK’s assign message. Programmatically assigning a record triggers the same functionality as assigning a record through the user interface. The ownerid attribute of the entity instance is updated to the Guid of the assignee. If CascadeAssign is turned on for the relationships between the assigned object and associated objects, any associated objects that have the same owner as the instance being assigned will also be assigned to the new owner. The user making the call needs the Assign privilege for the entity type and assign access rights for the entity being assigned. Example 4-5 shows some sample code for assigning an Account instance to another system user.

Example 4-5. Assigning a record

CrmService service = CrmServiceUtility.GetCrmService("serverName", "orgName");
Guid accountId = new Guid("3963176C-0E2C-DD11-8A81-0019D13DDA0E");
// Guid of the user we are assigning the account to
Guid systemUserId = new Guid("237D2B4E-191D-DD11-8839-0019B9F8F548");
SecurityPrincipal assignee = new SecurityPrincipal();
assignee.Type = SecurityPrincipalType.User;
assignee.PrincipalId = systemUserId;
TargetOwnedAccount target = new TargetOwnedAccount();
target.EntityId = accountId;
AssignRequest assign = new AssignRequest();
assign.Assignee = assignee;
assign.Target = target;
AssignResponse assignResponse = (AssignResponse)service.Execute(assign);

When assigning a record, we create a new SecurityPrincipal object the same way we did when sharing a record. (See Table 4-4 for a description of the SecurityPrincipalType enumeration.) The next class we use is TargetOwnedAccount. Each entity type has its own target class. The naming convention is TargetOwned followed by the entity’s name. (These class names all use Pascal case.) The target’s EntityId property is then set to the Guid of the Account record we are assigning. Finally we create the AssignRequest and execute it.

Tip

Tip

If you are using a dynamic entity, the target class is TargetOwnedDynamic.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset