Thursday, March 21, 2013

FIM: Understanding and handling "accountExpires" with care

Through much research, trial, and LOTS of error, I have, what I believe, a very good solution for processing the flow of values of the "accountExpires" attribute from Active Directory on through to the FIM portal, and vice versa.  I found that the portal and Active Directory handle both the values and the states of these attributes quite differently.

To clarify, this is specifically the "accountExpires" attribute bound to the user object type in Active Directory.

First, to really understand "accountExpires" from a technical standpoint, I recommend reading the following link: http://www.rlmueller.net/AccountExpires.htm

This really opened my eyes to what administrators actually see in ADUC, although not necessarily the truth.  What is golden, though, is that the integer value found in Active Directory is, in fact, correct.  To bad we can't read it!

Moving on, we have a defined attribute in the FIM portal schema known as "ExpirationTime" that we will use to mirror the same values and purposes of "accountExpires" in AD.  This, differing from the attribute type in AD, is a DateTime attribute and not a 64-bit (large) integer. 

Next, we define the "expirationTime" attribute in the metaverse designer for the person object as String(indexed), yet the check box to actually index is left unchecked (you want to indicate indexing on attributes that are used for joining objects from directory sources to existing metaverse objects). 

NOTE: When your import rules are defined for the required MAs for this attribute, you will then want to set this attribute's flow precedence to equal precedence (in our solution, there was a need to be able to change the expiration time from the portal, our HR system, or AD.  Here, however, we focus on the portal and AD only.

Thus, we end up with flow rules that, at a high level, state the following:

Basic idea of flow rules for accountExpires configured in Sync Manager

 
Specifically, I have my FIM-MA flow rules for ExpirationTime as follows:
 
ExpirationTime (portal) <-- expirationTime (MV)  [Allow Nulls]
ExpirationTime (portal) --> expirationTime (MV)
 
Both rules are direct rules by nature of the FIM-MA.  Next, I have my AD management agent configured as follows:
 
accountExpires (AD) <-- expirationTime (MV)
accountExpires (AD) --> expirationTime (MV)
 
Both of these rules have advanced mapping type with rules extension.  I have called the flow rule name "expirationTime" in both cases as the code segregates both import and export rules.
 
Now that we have established the configurations required in the FIM Sync engine, we now move on to the fun part: the required rules extensions for AD.
 
The following code is defined for our import and export rule extensions:
 
Public Sub MapAttributesForImport(ByVal FlowRuleName As String, ByVal csentry _ As CSEntryByVal mventry As MVEntry) Implements IMASynchronization.MapAttributesForImport
 
Dim dtFileTime As DateTime
 
Select Case FlowRuleName
 
   Case "expirationTime"
     If Not csentry("accountExpires").ToString() = "" And _
        Not csentry("accountExpires").IntegerValue = 9223372036854775807 Then
           dtFileTime = DateTime.FromFileTime(csentry("accountExpires").IntegerValue)
           If dtFileTime.ToString("yyyy") = "1600" Then
                If mventry.Item("expirationTime").IsPresent Then
                     mventry.Item("expirationTime").Delete()
                End If
           Else
               mventry.Item("expirationTime").Value = _
               dtFileTime.ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.000'")
               '("yyyy-MM-ddT" + "00:00:00.000")
           End If
      Else
         If csentry("accountExpires").IntegerValue = 9223372036854775807 Then
             If mventry.Item("expirationTime").IsPresent Then
                   mventry.Item("expirationTime").Delete()
             End If
         End If
      End If
 
Public Sub MapAttributesForExport(ByVal FlowRuleName As String, ByVal mventry As MVEntry, _ ByVal csentry As CSEntry) Implements IMASynchronization.MapAttributesForExport

Dim provider As CultureInfo = CultureInfo.InvariantCulture
Dim dtFileTime As DateTime
 
Select Case FlowRuleName
 
    Case "expirationTime"
        If mventry.Item("expirationTime").IsPresent Then
             If Not mventry.Item("expirationTime").Value.ToString() = "" Then
                 If Not mventry.Item("expirationTime").Value = Nothing Then
                    dtFileTime = _
                    DateTime.ParseExact(mventry.Item("expirationTime").Value, _
                      "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.000'", provider)
                    csentry("accountExpires").IntegerValue = dtFileTime.ToFileTimeUtc()
                 End If
             Else
                 csentry("accountExpires").IntegerValue = 0
             End If
         End If
 
There is one more moving piece, but, with all that said, let me explain why I arrived at the above.
 
When it comes to converting dates and integers, the above tends to get it done.  I will go into some details on that, but the interesting part is setting the account to never expire (AD), or removing the date in the portal.
 
I noticed in Active Directory that, when you set an account to never expire, the integer value becomes zero or the max value (9223372036854775807). However, truthfully, we do not want to flow a "datetime" value when this is the case, since now it will never expire.  In fact, we want to remove the fact that a date is there at all.  Thus, we delete the attribute and value all together in the metaverse, which in turn flows and deletes the attribute and value on the object in the portal.  This is possible because we are allowing nulls to export into the portal.
 
Now, the real interesting part happens when you try to remove the value in the portal.  I noticed at that point that FIM actually removes the attribute right then and there!  So the next thought might be, "Well, just set the AD export rule to allow nulls as well.  Simple!"  NOT.  The operation of deleting the attribute from Active Directory is not allowed and you get the lovely "cd-error Illegal modify operation" error.
 
 
In short, adding a second, remaining attribute to the export flow rule would maintain the processing of the rules extension.  However, I found issues with that, and some folks stating that it would help to add an attribute that would change with it.  All this was very messy.  So, I opted for a different approach.
 
What I came up with was to execute a script using the portal workflow/MPR/set transition method.  The set would include all those with an expiration time defined.  The criteria for the set was basically ExpirationTime prior to today and after today.  Weird, but it works.  Upon leaving the set (blanking the ExpirationTime value out via the portal), the workflow would kick off, running a script against AD to set the account to never expire.  This way, the account IMMEDIATELY is set, and the change will flow as expected, deleting the attribute across the metaverse and the portal.
 
So, that's how I dealt with setting accounts to never expire, but what about the actual time values?
 
Long story short (the above still makes this a LONG story...thanks for holding on!), the metaverse value is read as UTC time.  So, if I am in CST (GMT -6) (and I am) as set in the portal configuration, while the portal would read 3/21/2013 12:00 AM, the metaverse value would read 2013-03-21T05:00:000, and the integer value in AD would be 130083156000000000.  This is why if you set the time to expire in AD, it states "End of:", as in midnight the day after you set in ADUC.
 
Using the above solution, I am able to flow all of my times and lack thereof flawlessly.  I noted that, after performing all of this research and testing, there was not any one concise place to find all of this.  Thus, this post.
 
Hope this helps someone out there!
 
Best regards,
 
jose the admin


Wednesday, March 20, 2013

Hello, again...

So, it has been a long while since I updated this blog site, but I plan on ramping back up.  I feel that I have been making lots of very helpful discoveries, as well as accumulating lots of obscure knowledge, that could be helpful to many folks out there.

What kind of knowledge, you may ask?  Why, of course I am referring to all things Microsoft, as well as some networking and security tidbits from time to time.  Currently, I am spending most of my time working with Microsoft Forefront Identity Manager 2010, and, as a result, work very closely with Active Directory, Exchange, and the like.  However, I am also beginning to explore Server 2012 and Windows 8 (late) in detail.

I will be updating my pages regularly as time allows, so stay tuned.  Also, feel free to follow me on twitter @josel_garza.

Look forward to your comments and questions!

Regards,

jose the admin