My general negativity about FIM codeless sync aka “declarative provisioning” aka “Synchronization Rule Provisioning” is, I think, reasonably well-known by now. While Markus wrote an excellent document about importing AD groups into the FIM Portal using the codeless rules, I think there are still plenty of reasons to go old skool, and here’s how you’d do it.
Custom sync rules do involve .NET coding, so you’re going to need Visual Studio installed on the Sync server. My example code in is VB.NET so you’ll need the Visual Basic libraries installed to use them.
And it’s only a minusculey tiny bit of code, okay?
I will assume you’ve already managed to create your AD and FIM management agents, and that you have already sucessfully imported or joined the group members – ie the users and contacts.
The “member” attribute is relational, meaning it effectively points to other objects that it also knows about. To maintain the referential relationship from AD through to the FIM Portal you must satisfy the following requirements:
- The groups and their member objects must exist within the connector space of the same AD MA. You can’t import groups from one MA and users from another – you have to have the groups and users together.
- The groups and their members must be joined to their metaverse counterparts, either through Join or Projection rules.
- The groups and their members must be exported through the same FIM MA to the FIM Portal (though AFAIK you can only have one FIM MA anyway).
Step 1: Importing the AD Groups into the Metaverse
|First make sure that the OU(s) containing the groups are within the scope of your MA.|
|Next check the “group” object type.Note I also have my potential group member object types selected, and within the scope of the MA – see the comment above about maintaining references in the prereqs section above.|
|And make sure the following attributes are selected: displayName, domain, groupType, member, sAMAccountName, (and for Distrubution Lists) mail, mailNickname.|
|Create a Projection Rule. This will project AD groups as new group objects in the Metaverse. Note the following points:
|Next create Direct import flow rules for the following attributes: displayName → displayName
sAMAccountName → accountName
member → member
mail → mail
mailNickname → mailNickname
|At this point you can actually save the MA and go ahead and run an Import-Sync. What you should see is some group objects projected into the Metaverse.If you’ve already mapped the group object type in the FIM MA you should see objects created there too, but don’t try to export them yet, we need to add a few more attributes.|
|Now go back into your AD MA and add the following Advanced import flow rules: Constant: your NETBIOS domain name → domain
Constant: “Owner Approval” → membershipAddWorkflow
Constant: “false” → membershipLocked
groupType → Rules Extension: “import_scope” → scope
groupType → Rules Extension: “import_type” → type
|When you try and save the MA now you should get this error:
“Rules Extension validation error: Please specify a valid rules extension name.”When you click OK you will be taken to the place where you can specify the name of the dll where those two advanced rules (import_scope and import_type) are to be found. In fact we haven’t written the dll yet, but that’s ok, just accept the default name.
|Now it is time to create the extension project.Select your MA and click Create Extension Project. You want to create a project of type “Rules Extension”.Check the default name – it should be the same as already set in the MA in the previous step (if it somehow isn’t don’t worry, you can always change the dll referenced in the MA later).
The only thing you might want to change is the folder where the project will be created.
When you’re ready, click OK and the new project will be created and opened in Visual Studio for you (assuming you installed Visual Studio on the server).
|Now fill in the MapAttributesForImport section of the project as shown here.Once you’ve done that you can compile the code. The dll shoud be put straight into the correct folder for you (normally C:\Program Files\Microsoft Forefront Identity Manager\2010\Synchronization Service\Extensions).||
Public Sub MapAttributesForImport(ByVal FlowRuleName As String, ByVal csentry As CSEntry, ByVal mventry As MVEntry) Implements IMASynchronization.MapAttributesForImport Select Case FlowRuleName Case "import_type" Select Case csentry("groupType").IntegerValue Case 2, 4, 8 mventry("type").Value = "Distribution" Case Else mventry("type").Value = "Security" End Select Case "import_scope" Select Case csentry("groupType").IntegerValue Case 2, -2147483646 mventry("scope").Value = "Global" Case 4, -2147483644 mventry("scope").Value = "DomainLocal" Case Else mventry("scope").Value = "Universal" End Select Case Else Throw New EntryPointNotImplementedException() End Select End Sub
|Now you should be able to Sync the AD MA and check how the group objects look in the Metaverse.|
Step 2: Exporting the Groups from the Metaverse to the FIM Portal
|There are a couple of Portal MPRs that must be enabled to allow the Sync Service to create groups in the Portal.|
|If you haven’t already done so, select the group object type in your FIM MA.|
|And add the mapping to the Metaverse group type.|
|Now all you should need to do is add simple export flow rules for these attributes: accountName, displayName, domain, scope, type, membershipAddWorkflow, membershipLocked, member, (and for Distribution groups) mail, mailNickname .|
|Run another Sync on the AD MA and now you should be able to see the group objects in the FIM connector space, ready to export.|
|After running an Export from the FIM MA the groups should be in the Portal, and you can start to manage them there.Note there is an error being reported about selecting a manger. If you do happen to have the group manager field populated in AD then by all means go ahead and import it from AD through to the Portal. Otherwise you will have to chose a manager directly in the Portal.|
Troubleshooting FIM MA export errors
The FIM MA can give you some rather cryptic looking failed-creation-via-web-services messages, but usually if you read them properly you can work out the problem.
1. Missing Required Attribute
Here I have forgotten to populate the “Domain” attribute
Fault Reason: The request message contains errors that prevent processing the request.
Fault Details: <RepresentationFailures xmlns="http://schemas.microsoft.com/2006/11/ResourceManagement" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><AttributeRepresentationFailure><AttributeType>Domain</AttributeType>
<AttributeValue></AttributeValue><FailureMessage>An attribute is required to complete the operation.</FailureMessage>
2. Incorrect Attribute Value
Some attributes in the Portal Schema have validation strings listing which values are allowed. Here I’ve tried to export a type of “Distribution List” instead of “Distribution”, and that has been blocked.
Fault Reason: The request message contains errors that prevent processing the request.
Fault Details: <RepresentationFailures xmlns="http://schemas.microsoft.com/2006/11/ResourceManagement" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><AttributeRepresentationFailure><AttributeType>Type</AttributeType>
<AttributeValue>Distribution List</AttributeValue><FailureMessage>The specified attribute value does not satisfy the regular expression.</FailureMessage><AttributeFailureCode>ValueViolatesRegularExpression</AttributeFailureCode></AttributeRepresentationFailure></RepresentationFailures>
3. Permissions failure
Your MPRs need to allow the Built-In Synchronization account to create Group objects in the Portal. In this rather long-winded messages there are a few immediate giveaways.
There is an error executing a web service object creation request.
Message: Fault Reason: Policy prohibits the request from completing.
Stack Trace: Microsoft.ResourceManagement.WebServices.Exceptions.PermissionDeniedException: ManagementPolicyRule —> System.Data.SqlClient.SqlException: Reraised Error 50000, Level 16, State 1, Procedure DoEvaluateRequestInner, Line 462, Message: Permission denied.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
at Microsoft.ResourceManagement.Data.DataAccess.DoRequestCreation(RequestType request, Guid cause, Guid requestMarker, Boolean doEvaluation, Int16 serviceId, Int16 servicePartitionId)
— End of inner exception stack trace —
at Microsoft.ResourceManagement.WebServices.RequestDispatcher.CreateRequest(CreateRequestDispatchParameter dispatchParameter)
at Microsoft.ResourceManagement.WebServices.RequestDispatcher.CreateRequest(UniqueIdentifier requestor, UniqueIdentifier targetIdentifier, OperationType operation, String businessJustification, List`1 requestParameters, CultureInfo locale, Boolean isChildRequest, Guid cause, Boolean doEvaluation, Nullable`1 serviceId, Nullable`1 servicePartitionId)
at Microsoft.ResourceManagement.WebServices.RequestDispatcher.CreateRequest(UniqueIdentifier requestor, UniqueIdentifier targetIdentifier, OperationType operation, String businessJustification, List`1 requestParameters, CultureInfo locale, Boolean isChildRequest, Guid cause, Boolean doEvaluation)
at Microsoft.ResourceManagement.WebServices.ResourceManagementService.Create(Message request)ManagementPolicyRule
Stack Trace: at Microsoft.ResourceManagement.WebServices.ResourceFactoryClient.Create(Message request)
at Microsoft.ResourceManagement.WebServices.ResourceFactoryClient.Create(Create createBody)
Inner Exception: Policy prohibits the request from completing.