FIM 2010 R2: WAAD Connector - Managing the SourceAnchor field in a Multi-Forest Exchange organization


Introduction

The FIM Windows Azure Active Directory (WAAD) connector uses the SourceAnchor field as the identifier of the Azure object. The SourceAnchor field is derived in WAAD via attribute flow extension from the Objectguid of the user object. In a multi-forest Exchange organization where linked mailboxes are used, the user will have an account in the Exchange forest (disabled) and an account in the user forest. It is important that the objectGuid from the user forest is used when single sign on (SSO) is also use for cloud authentication. The SSO application will pass the SourceAnchor as the ImmutableID to the user’s forest.

If you have a perfect Exchange resource forest model where there are no user accounts in the Exchange forest that need to be synced to the Azure then the sync and SSO works well. If you have user accounts or mailboxes in the Exchange forest that also need to be synced then it becomes challenging controlling which objectGuid will be used to create the SourceAnchor for the user and you may begin to see users complaining about SSO issues. The scenario below is an example of such a case and offers a solution or how to mitigate the issue. 


Case Overview

Contoso is a multi-forest Exchange organization. There is an Exchange forest and three user account forests. The Exchange forest is known as Contoso and it also contains user accounts. There are mailboxes for users in the Contoso forests and linked mailboxes for users in other forests. Contoso uses FIM Windows Azure Active Directory (WAAD) connector to synch all its forests with Azure. ADFS Federation is used for single sign on (SSO). The WAAD SourceAnchor field from the user home forest is used as the ADFS ImmutableID. 

Contoso would like the following requirements for the synchronization of linked mailboxes

  1. If the user forest has not been connected to FIM, the user mailbox in Contoso forest should be projected into the MV and provisioned to Azure so that the user appears in the cloud GAL. The SourceAnchor will be derived from the Contoso forest objectguid. The msexchMasterAccountSid will be imported into the MV.
  2. When the user forest is later connected to Azure, the user will be joined to (Use CS.Objectguid to MV.msExchMasteraccountSID for join) the MV object from (1). The SourceAnchor in the MV will be updated to the value derived from the user forest. In the WAAD CS since the SourceAnchor is the anchor field in the WAAD MA, it cannot be changed, so there will be a delete of the old user and the provision of a new user.
  3. If a new linked mailbox is created for a user in the newly connected forest, the user can be projected into the MV from either the Contoso or user forest. If FIM imports from the user forest then the user is projected from the user forest first, the SourceAnchor in the MV and WAAD MA would be derived from objectguid in the user forest. When the Contoso user is created and imported into FIM later, it will be joined to the MV object via the CS.msexchMasterAccountSID. The SourceAnchor in the MV and WAAD MA will not be changed.
  4. If a new linked mailbox is created for a user in the newly connected forest, the user can be projected into the MV from either the Contoso or user forest. If FIM imports from the Contoso forest then the user is projected from the Contoso forest first, the SourceAnchor in the MV and WAAD MA would be derived from objectguid in the Contoso forest. When the user in the user forest is created and imported into FIM later, it will be joined to the MV object via the CS.ObjectSID. The SourceAnchor in the MV and WAAD MA will be changed.

           


Solution requirement

  1. We want the CS.msexchMasterAccountSid from Contoso imported into MV
  2. We want a join between CS.Objectguid in the user forest and MV. msexchMasterAccountSid
  3. We want to be able to identifying when the MV.SourceAnchor value has changed
  4. We want to no changes to MV.SourceAnchor if the Contoso data comes in after the import from the user forest.

 


Solution design

  1. We want the CS.msexchMasterAccountSid from Contoso imported into MV
  • Create a binary field in MV for person Object called msExchMasterAccountSid
  • Add a direct attribute flow in Contoso to flow CS.msExchMasterAccountSid to MV.msExchMasterAccountSid
  1. We want a join between CS.Objectguid in the user forest and MV. msexchMasterAccountSid
  • Create a join in the user forest CS.Objectguid to MV.msexchMasterAccountSid
  1. We want to be able to identifying when the SourceAnchor value has changed
  • Create a Boolean field in MV for person Object called SAChangeStatus
  • Add an advanced attribute flow in Contoso and user forest to flow CS. objectSid to MV.SAChangeStatus. The name of the flow rule name is “CheckSAStatus”. Update the template MA xml file for user forest and Contoso.
  1. We want to no changes to SourceAnchor if the Contoso data comes in after the import from the user forest.
  • Go to Metaverse designer, Person object, Source Anchor, in the attribute flow precedence set Contoso to the bottom of the list. Remember to do this when you connect a new user forest.

 


Code logic

The WAAD connector package comes with some default extension files which will be referenced.

  1. In the file ManagementAgentRules.cs under mapAttributesforImport create a flow rule name call it CheckSAStatus.
  • Check if the MV.SourceAnchor is present and CS Management agent is not Contoso then check if the SourceAnchor value from the Azure is different from what is derived from the CS.Objectguid. if different then set MV.SAChangeStatus to TRUE else MV.SAChangeStatus is false
  1. In the file for ManagementAgentRules.cs under mapAttributesforImport update the flow rule name called “import::ad:objectGUID->mv:SourceAnchor”, update the MV.sourceAnchor if it is
  • First time import/projection
  • If not first time (if MV.SourceAnchor already exists) then check if the CS Management agent is not Contoso and if the SourceAnchor value from the CS is different from what is in the MV.
  1. In the file for WAADSyncRulesCommon.cs under ProvisionWAAD object function, for case “person”
  • Check if MV.SAChangeStatus is TRUE. If so, then deprovision the Azure object.

 


Code

Management Rules Extension.cs
 

case "CheckSAStatus":  
  
//TODO determine Where to get sourceAnchor from  
  
string OldSourceAnchor = null; 
  
string newSourceAnchor = null; 
  
string nameofCSMA = csentry.MA.Name; 
  
ConnectedMA controllerMA = mventry.ConnectedMAs["WAADMA"]; 
  
mventry["SAChangeStatus"].BooleanValue = false; 
  
if (mventry["sourceAnchor"].IsPresent & nameofCSMA != "CONTOSOADMA")  
  
  { 
  
   CSEntry WAADcsentry = controllerMA.Connectors.ByIndex[0]; 
  
   OldSourceAnchor = WAADcsentry["sourceAnchor"].StringValue; 
  
   newSourceAnchor = Convert.ToBase64String(csentry["objectGuid"].BinaryValue); 
  
   if (OldSourceAnchor != newSourceAnchor) 
  
     { 
  
     //set the mventry for change in SourceAnchor to true. 
  
     mventry["SAChangeStatus"].BooleanValue = true; 
  
     } 
  
  }  
  
   break; 
  
case "import::ad:objectGUID->mv:sourceAnchor": 
  
//TODO determine Where to get sourceAnchor from  
  
//Only process if it is not from the Exchange Forest and the SourceAnchor is different  
  
//meaning that Exchange forest has already projected first  
  
string nameoftheCSMA = csentry.MA.Name; 
  
if (mventry["sourceAnchor"].IsPresent & nameoftheCSMA != "CONTOSOADMA")  
  
  { 
  
   string TheOldSourceAnchor = mventry["sourceAnchor"].StringValue; 
  
   string ThenewSourceAnchor = Convert.ToBase64String(csentry["objectGuid"].BinaryValue); 
  
   if (TheOldSourceAnchor != ThenewSourceAnchor) 
  
      { 
  
       //set the mventry SourceAnchor. 
  
mventry["sourceAnchor"].StringValue = Convert.ToBase64String(csentry["objectGuid"].BinaryValue); 
  
       } 
  
  } 
  
   //If the user does not exist in MV - first time projection 
  
    if (!mventry["sourceAnchor"].IsPresent) 
  
       { 
  
        mventry["sourceAnchor"].StringValue = convert.ToBase64String(csentry["objectGuid"].BinaryValue); 
  
       }break;  

 WAADSyncRulesCommon.cs

case "person": 
  
//check if the SAChangeStatus is true, if so deprovision the WAAD csentry  
  
   if (mvEntry["SAChangeStatus"].BooleanValue) 
  
      { 
  
       ConnectedMA controllerMA = mvEntry.ConnectedMAs["WAADMA"]; 
  
       CSEntry WAADcsentry = controllerMA.Connectors.ByIndex[0]; 
  
       WAADcsentry.Deprovision(); 
  
       //set the SAChangeStatus to false 
  
       mvEntry["SAChangeStatus"].BooleanValue = false; 
  
      }break;