ImmutableID – mS-DS-ConsistencyGuid – AADSync

Paul Williams talked in his blog about using another attribute from on-premises Ad’s to act as the ImmutableID for Azure Active Directory (http://blog.msresource.net/2014/03/10/windows-azure-active-directory-connector-part-3-immutable-id/)

While making a very detailed blog entry on why and which attribute to choose, there wasn’t a guide on how to make this work in AADSync.

[update 21-Aug-2017: The latest version of Azure AD Connect have the functionality built-in to select the ImmutableID. There is no need to hack the rules manually anymore.. read more about it at: http://blog.azureinfra.com/2017/08/21/immutableid-ms-ds-consistencyguid-adconnect-final-part/]

So a recent project got me thinking about this. In this particular scenario there is already a forest (1 domain) using DirSync to replicate their users to AAD, and the requirement is to prepare for an AD migration, while also adding other users to the same AAD tenant. As usual, user objects might be duplicate between the two forests and we want to use the mS-DS-ConsistencyGuid attribute to be the immutableID.

1

NOTE: As you can see, some of the text is blue, some of it is black.. the blue text indicates the instructions also to be used when using AD Connect. For more info see the AD Connect Immutable ID post

So in the picture above we have Domain A using regular DirSync, as you can see, the regular objectGuid is used to form the immutableID (base64 encoding of the objectID). The objectID value is copied into the metaverse as the SourceAnchorBinary and from that the sourceAnchor is derived.

In my case what I wanted to do was to ensure that the new domain (forest) will use the ConsistencyGuid and automatically fill this if it is not present. This allows me to achieve two things:

  1. Map AAD users in domainA to users in domainB and allow seamless migration of Cloud services
  2. Autofill ConsistencyGuid for future usage

!DISCLAIMER prior to implementing, please test this through and through.. and don’t blame me if it doesn’t work, instead, if changes are required, if you feel other values, workflows or other items need to be changed, send me an email and I can update this post and together we can help others..!

So the following schema will be used for the new architecture:

2

So within the AADSync engine, we need to create some rules that allow for the functionality displayed. Basically it comes down to:

  1. If mS-DS-ConsistencyGuid is filled, use that as the SourceAnchor
  2. Is mS-DS-ConsistencyGuid is NOT filled, copy the objectGuid value into it

Everyone will see, that once rule 2 has been applied, rule 1 will automatically kick in on the second replication.

So before we create some rules in AADSync we first need to make some preparations. AADSync has two consoles that we are going to use, firstly the SynEngine and secondly the RulesEditor. They can be found on the following location:

C:\Program Files\Microsoft Azure AD Sync\UIShell\miisclient.exe C:\Program Files\Microsoft Azure AD Sync\UIShell\SyncRulesEditor.exe

Preparing the MetaVerse and Management Agents

In order to prepare the AADSync for the mS-DS-ConsistencyGuid usage we need to do 2 things, firstly make it known in the metaverse (sort of schema update) and secondly we need to enable the connectors to AD to actually import the value too.

To start with the first one, open missClient.exe and browse to the MetaVerse Designer. In there you will see two object types, person and group.

Select person and on the bottom right under the Actions window select Add Attribute

3

In the window shown type the attribute Name as it will have in the MetaVerse (msConsistencyGuid), set the type to be Binary (indexable) and click ok

Repeat the above procedure and add also the sourceObjectGuid (Binary indexable) which may come in handy later on.

Next go to the connectors page and select the AD connector and open the properties. On the left side, choose Select Attributes and then on the right side, enable the Show All checkbox. Finally in the list shown, scroll down to select mS-DS-ConsistencyGuid and click ok

4

The above procedures will ensure that we now have a new value in the metaverse that we can fill, and we called it msConsistencyGuid. Secondly we have a new attribute called sourceObjectGuid which we can use to reflect the original actual objectGuid of each object in case the ConsistencyGuid is not kept the same all the time (troubleshooting purposes).

Create the rules

We need to create a few rules in order to achieve what we want. And we need to make a few….

msConsistencyGuid is present use as SourceAnchor 1

The first rule will be the rule to provision a user based on the mS-DS-ConsistencyGuid if this field is present. The flow of information if as followed:

5

In order to do this, we are adding a new Inbound rule:

<edit>If you have the latest version of AD Connect, and rule 100 does not exist, do not 1;1 follow these instructions. An update will be made soon on this blog for the latest versions as the product team made some (big) changes.</edit>

Name In from AD – CGUID
Connected System (AD Connector)
Connected System Object Type User
Metaverse Object Type Person
Link Type Provision
Precedence 99

 

In the next window, ensure that

isCriticalSystemObject is set to NOTEQUAL is TRUE mS-DS-ConsistencyGuid is set to ISNOTNULL

6

In the next window, the actual join is performed, in this case we want to ensure that the mS-DS-ConsistencyGuid is used as the sourceAnchor(Binary) if a matching object can be found.

7

If no matching object can be found, the provisioning should be based on the mS-DS-ConsistencyGuid if the object is not cloud filtered. Therefore in the Transformations page the following should be added:

FlowType Target Attribute Source Action
Expression cloudFiltered (see below) Update
Direct sourceAnchorBinary mS-DS-ConsistencyGuid Update
Direct sourceObjectGuid objectGUID Update

(source value in Expression)

IIF(IsPresent([isCriticalSystemObject]) || IsPresent([sAMAccountName]) = False || [sAMAccountName] = “SUPPORT_388945a0” || Left([mailNickname], 14) = “SystemMailbox{” || Left([sAMAccountName], 4) = “AAD_” || (Left([mailNickname], 4) = “CAS_” && (InStr([mailNickname], “}”) > 0)) || (Left([sAMAccountName], 4) = “CAS_” && (InStr([sAMAccountName], “}”) > 0)) || Left([sAMAccountName], 5) = “MSOL_” || CBool(IIF(IsPresent([msExchRecipientTypeDetails]),BitAnd([msExchRecipientTypeDetails],&H21C07000) > 0,NULL)) || CBool(InStr(DNComponent(CRef([dn]),1),”\\0ACNF:”)>0), True, NULL)

8

msConsistencyGuid is present use as SourceAnchor 2

As we created the rule above (99) we also need to make sure that other rules are NOT applied anymore if the mS-DS-ConsistencyGuid is present. In order to do so, we need to enable filtering on other rules.

Open rule 100 (In from AD – User Join) and select scoping filters

In this window, select add clause and browse for the mS-DS-ConsistencyGuid attribute and set the operator not ISNULL

9

The above will ensure that this rule will only be applied IF the mS-DS-ConsistencyGuid is empty.

ObjectGuid to msConsistencyGuid

The next rule is to fill the msConsistencyGuid with the objectGuid, IF there wasn’t already an mS-DS-consistencyGuid value. This is to ensure the following scenario:

Say that I already pre-filled the mS-DS-ConsistencyGuid with a value from another domain (because I want to merge two accounts). In that case, the mS-DS-ConsistencyGuid will be filled with a GUID that is different than the objectGuid. In that particular case, we want to ensure that the msConsistencyGuid in the metaverse is filled with the manually entered values of mS-DS-ConsistencyGuid and in order to ensure we can still find the objects related to eachother, we also fill the sourceObjectGuid with the actual objectGuid.

We already know that my rule 100 will only be applied if mS-DS-ConsistencyGuid is empty, so open rule 100 and in the transformations page add

FlowType Target Attribute Source Action
Direct msConsistencyGuid objectGuid Update

10

msConsistencyGuid to mS-DS-ConsistencyGuid

In rule 100 and 99 we ensured that msConsistencyGuid in the metaverse is filled with a value (either a copy of the objectGuid or our manually entered value). We can now ensure that we replicate this value back into AD’s mS-DS-ConsistencyGuid (just in case it was empty).

11

In order to create this rule, open the rules editor and select Outgoing

Select Add new rule in the top corner and make the following:

 

Name Out to AD – CGUID
Connected System (AD Connector)
Connected System Object Type User
Metaverse Object Type Person
Link Type Join
Precedence 102

 

On the next page, add the scoping filter, by adding a clause and choosing the attribute msConsistencyGuid and set the operator to ISNOTNULL

12

 

[UPDATED 20/5/2015]

On the Join page we need to link the objects together so an update flow can happen. Now we know that the original objectGuid for our connected system is stored in our previously created attribute: sourceObjectGuid in the metaverse. So we can now connect the object in AADSync to the on-premises user to join the two together: sourceObjectGuid==objectGuid

D

[/UPDATED 20/5/2015]

On the next page, make a direct link between the ms-DS-ConsistencyGuid (Target Attribute) and the msConsistencyGuid (source) and set the merge type to Update

13

mS-DS-ConsistencyGuid as SourceAnchor

Now that we have ensured that mS-DS-ConsistencyGuid is always filled we can use it as the ImmutableID value. In order to do so, we need to change a few rules in the Inbound section of the editor.

If we open for example rule 102 (In from AD – User AccountEnable) we can see on the transformations tab, the following entry:

14

The expression is actually the following:

IIF(IsPresent([msExchRecipientTypeDetails]),IIF([msExchRecipientTypeDetails]=2,NULL,IIF(IsString([objectGUID]),CStr([objectGUID]),ConvertToBase64([objectGUID]))),IIF(IsString([objectGUID]),CStr([objectGUID]),ConvertToBase64([objectGUID])))

The above expression takes the objectGuid and re-encodes it with Base64 and places it in the sourceAnchor attribute in the metaverse. In our case we want to ensure that not objectGuid is re-encoded, but that mS-DS-ConsistencyGuid is used.

So we need to change the expression to:

IIF(IsPresent([msExchRecipientTypeDetails]),IIF([msExchRecipientTypeDetails]=2,NULL,IIF(IsString([mS-DS-ConsistencyGuid]),CStr([mS-DS-ConsistencyGuid]),ConvertToBase64([mS-DS-ConsistencyGuid]))),IIF(IsString([mS-DS-ConsistencyGuid]),CStr([mS-DS-ConsistencyGuid]),ConvertToBase64([mS-DS-ConsistencyGuid])))

However, this expression is used more than once, and thus, it needs to be changed on every rule that applies to user objects.

102 In from AD – User AccountEnable
106 In from AD – User Common

And that should be it! If you are connecting to multiple forests, ensure that you select the right rules (there will be an In from AD – User AccountEnable for every domain).

15

Updates to this article are expected as I’m testing and implementing this.

also see the updated version at: http://studioblog.azurewebsites.net/immutableid-ms-ds-consistencyguid-adconnect/

(and the latest update from Paul Williams on why and how to configure the ADFS to use mS-DS-ConsistencyGuid on Revisiting the Microsoft Online immutable ID design decision)

(and thanks to T.Onyszko for all the help….- [advertorial]GO PREDICA! – [/advertorial]…. )

Tagged , , , , , , ,