Handling a composite type request for multivalued attributes

Introduction

In this blog post, we will discuss an approach we took to handle composite type requests. The approach uses a custom action workflow activity that stores request details in a simple database. Then, a command line utility will process the records in the database, and execute appropriate actions. We will discuss this further more in the following sections.

Composite Type Requests

A composite type request is generated when the Synchronization Engine detects that multiple transactions should be propagated to the FIM Service. Therefore, it aggregates those requests together into one composite request.

This feature was added for the first time in the latest version of FIM, FIM 2010 R2, to speed up the export operation between the Synchronization Engine and the FIM Service and database.

What is special about these composite requests? and why do they need special attention?

Based on FIM 2010 R2 release notes: "A new resource type CompositeType has been introduced for A Request issued by the Build-in Synchronization Account. It may interfere with any custom Action workflows that parse request targets. To find the actual targets you will need to modify these workflows to parse the Request Parameters of a CompositeType."

In our implementation, we were trying to execute action activities that target the members added to and/or removed from groups such as:

  • Update few of their attributes
  • Run a powershell script to enable Lync accounts or create an Exchange mailbox
  • Send email notification to group/application owners

The challenge

We went ahead and developed those custom workflow activities. During testing, and when the Synchronization Engine runs, it submits a composite type request that contains a fully detailed request parameters for the entire individual requests that were aggregated. The request parameter will look something like this:

1.<Requestparameter xsi:type="UpdateRequestParameter">
2.    <Target>263ae811-748f-42f6-8bd1-f8ae68397d0f</Target>
3.    <Calculated>false</Calculated>
4.    <PropertyName>ExplicitMember</PropertyName>
5.    <Value xsi:type="q1:guid">f5588f39-edb0-4668-a0aa-590488a6fba4</Value>
6.    <Operation>Create</Operation>
7.    <Mode>Add</Mode>
8.</RequestParameter>

For each request parameter in the compositeType request, a "System Event Requests" will be created.

Figure 1. System Events

The issue was with the parameters of the "System Event Request". It didn't include the information that we needed to execute the action workflow correctly. The request parameters looked like this:

1.<RequestParameter xmlns:q1="http://microsoft.com/wsdl/types/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="SystemEventRequestParameter">
2.  <Target>09f4b1f5-401f-4d46-8ae7-327a776e737b</Target>
3.  <Calculated>false</Calculated>
4.  <WorkflowDefinition>
5.    <Value>14678a3c-4e4f-4d8a-9d85-6ed36c9065a9</Value>
6.  </WorkflowDefinition>
7.</RequestParameter>

Where target is the group name, and Value is the workflow instance.

Since we were unable to resolve [//Delta/ExplicitMember/Added] or [//Delta/ExplicitMember/Removed] from the request parameters, we were unable to pass any GUID to the readResourceActivity, and we were unable to execute any actions correctly.

Suggested Solutions

To solve this problem, we could have modified the MIISServer.exe.config under "C:\Program Files\Microsoft Forefront Identity Manager\2010\Synchronization Service\Bin" by changing the aggregate property to false under resourceSynchronizationClient. This will not aggregate the request all together, and will submit individual requests to FIM Service.

The other approach is discussed below:

In order not to compromise the speed of data flow between the Synchronization engine and the FIM Service, we kept the aggregate value set to true and took another approach in dealing with this issue.

We created a new custom action workflow activity that is triggered whenever the Synchronization Engine tries to add or remove a member from a group in the FIM Service. This new activity will be executed on the System Event Requests that we mentioned earlier.

In this newly created custom activity, read the request parameters of the parent request of this System Event Request.

1.if (this.GetCurrentRequest.CurrentRequest.ParentRequest != null)
2. this.ReadParentRequest.ResourceId = this.GetCurrentRequest.CurrentRequest.ParentRequest.GetGuid();

The request parameter of the parent request contains all the information we needed, which includes the group GUID, the user GUID, and the operation (Add/Remove).

1.string targetGroup = requestXDocument.Root.Element("Target").Value;
2.string mode = requestXDocument.Root.Element("Mode").Value;
3.string targetPerson = requestXDocument.Root.Element("Value").Value;

Then, we dumped those three attributes to a simple database along with the parent request ID.

1.this.DumpRequestToDataBase(this.ReadParentRequest.ResourceId.ToString(), targetGroup, targetPerson, mode);

After the data is dumped in the database, a scheduled task will extract distinct rows and execute desired actions depending on which group the user is being added to or removed from using the FIM Default Client.

The following image depicts the flow of data

First Approach VS Second Approach:

It is obvious that the first approach is easier and would consume significantly less time to implement, which makes it more rational if you have custom action activities already implemented in you system.

However, if you want to boost up your system or you are implementing FIM for the first time in your organization, we recommend that you keep the aggregate feature set to true and try to use this approach.