Reference: How to have bidirectional flow for EmployeeEndDate and AccountExpires

Overview

Recently I worked on a scenario where we had to control the flow of data between EmployeeEndDate and AccountExpires.  This scenario provided some interesting challenges and so I decided to blog about it and share the information and challenges faced.  You will find in this blog a description of the scenario, challenges faced and how I went about to successfully complete this scenario.  In this solution, we needed to rely on extensibility.  We utilized a Management Agent Extension for the Active Directory Management Agent.

Scenario

  • Need to flow EmployeeEndDate from the FIM Portal to accountExpires in Active Directory
    • Need to be able to flow a valid date value from the FIM Portal to Active Directory via the Synchronization Service Engine
    • Need to be able to flow an empty date when the date value is blanked out from the FIM Portal to Active Directory via the Synchronization Service Engine
  • Need to flow accountExpires from Active Directory to EmployeeEndDate in the FIM Portal
    • Need to be able to flow a valid date from Active Directory to the FIM Portal via the Synchronization Service Engine
    • Need to be able to flow the default value of 9223372036854775807 from Active Directory to the FIM Portal via the Synchronization Service Engine
    • Need to be able to flow a 0 from Active Directory to the FIM Portal via the Synchronization Service Engine

Attributes

  • EmployeeEndDate (FIM Portal)
    • FIM Portal: Date Value 
    • FIM Service Management Agent: String
  • employeeEndDate (Synchronization Service Engine - Metaverse)
    • Metaverse: String (Indexed)
  • Additional employeeEndDate Attribute (Synchronization Service Engine - Metaverse)
    • Metaverse: String (Indexed)
  • accountExpires (Active Directory)

Challenges

  • Bidirectional Flow: This is where both data sources, FIM Portal and Active Directory, need to be authoritative.  
    • This will cause a problem because of attribute precedence.  If one management agent connector deletes the metaverse attribute, then attribute precedence will determine what happens to the metaverse attribute and its value.
  • Data Conversion
    • Converting a string to a long integer or int64 data type.
    • Converting the long integer or int64 data type to a string
  • Null Value or Empty String
    • How to handle a Null Value or Empty String from employeeEndDate
  • 0 or 9223372036854775807
    • How to handle the 0 or default value for accountExpires

Solution Outline

The steps outlined below for you were done in a fresh FIM Installation.  You may already have an Active Directory Management Agent and a FIM Service Management Agent in your solution.  You may already have an Active Directory Management Agent Extension.  If you have these things, then you will simply need to modify your solution to implement these steps.

  1. Add a new Metaverse Attribute for a second employeeEndDate Metaverse Attribute.  (e.g. employeeEndDate2)

    1. String (Indexable) and do not check either of the check boxes below for multi-valued and/or indexed.
    2. We will need this attribute to assist when flowing data from the FIM Service Management Agent to the Active Directory Management Agent
  2. Create two management agents (*NOTE: if you already have a FIM Service Management Agent and an Active Directory Management Agent, then you can skip this step! )

    1. Active Directory Management Agent 
    2. FIM Service Management Agent
  3. View the Properties of the Active Directory Management Agent and go to Configure Attribute Flow

  4. Add new attribute flow for the Data Source Object User to the Metaverse Object Person

    1. Import and Export Attribute Flow: Data Source Column: accountExpires to Metaverse Column: employeeEndDate

    2. In between the two list boxes at the bottom, you will see Mapping Type.  There choose Advanced.  This will be for both Import and Export Attribute Flow.

       

    3. For Import Attribute Flow enter the Flow Rule Name: ImportAccountExpires.  (*NOTE: This is what I utilized for this solution. You do not have to use the same wording. It just has to match exactly what you use in your extension code.)

    4. For Export Attribute Flow enter the Flow Rule Name: ExportAccountExpires.   (*NOTE: This is what I utilized for this solution. You do not have to use the same wording. It just has to match exactly what you use in your extension code.)

    5. For Export Attribute Flow, in the Flow Direction box, be sure to check Allow Nulls.

      1. If you do not have Allow Nulls checked, then the flow stops during Export Attribute Flow and does not update the Target Active Directory Management Agent Connector Space.
  5. Click Ok and save the Active Directory Management Agent Properties.

  6. View the Properties of the FIM Service Management Agent and go to Configure Attribute Flows

  7. Expand the Person to Person branch and Add new Import Attribute Flow for EmployeeEndDate to <Your new employeeEndDate metaverse attribute>
    *NOTE: In my example I am using FIMemployeeEndDate.

  8. Click Ok and save the FIM Service Management Agent Properties

  9. Update your Active Directory Management Agent Management Agent Extension in the sections MapAttributesForImport and MapAttributesForExport.
    The sample code illustration is documented below in the section Solution Extension Code.

Solution Extension Code

*NOTE: Please note that the below code is a sample illustration of how this solution can be accomplished. You will most likely have to make some modifications to allow the code to work in your environment according to your business rules.

*IMPORTANT NOTE: Be sure to test the code in your development/testing environment prior to implementing in production. You need to understand how this code will work with the rest of your Identity Management Solution.

MapAttributesForExport ( code that will fire during Export Attribute Flow )

void IMASynchronization.MapAttributesForExport (string FlowRuleName, MVEntry mventry, CSEntry csentry)

        {

//

            // TODO: write your export attribute flow code

            //

             

switch (FlowRuleName)

            {

case "ExportAccountExpires":

 

// 1. Set a variable of data type long to the default integer value for accountExpires in Active Directory

// 2. Check to see if employeeEndDate is available to use.

// If it is available, then grab the value from the employeeEndDate attribute, convert it to a DateTime data type.

// Use ToFileTime to convert the DateTime value to a FileTime setting the value to the variable for the long data type

// 3. Set the connector space accountExpires IntegerValue to the long data type variable

long iFileTime = 9223372036854775807;

if ((mventry["employeeEndDate"].IsPresent) && (mventry["FIMemployeeEndDate"].IsPresent))

                    {

DateTime expTime = Convert.ToDateTime(mventry["employeeEndDate"].Value);

                        iFileTime = expTime.ToFileTime();

                    }

 

                    csentry["accountExpires"].IntegerValue = iFileTime;

break;

 

default:

// TODO: remove the following statement and add your default script here

throw new EntryPointNotImplementedException();

            }

 

        }

 

MapAttributesForImport ( code that will fire during Import Attribute Flow )

void IMASynchronization.MapAttributesForImport( string FlowRuleName, CSEntry csentry, MVEntry mventry)

        {

//

// TODO: write your import attribute flow code

//

             

switch (FlowRuleName)

            {

                     

case "ImportAccountExpires":

long iFileTime = 9223372036854775807;

long iZeroTime = 0;

Int64 ACCTEXPIRE = csentry["accountExpires"].IntegerValue;

string ENDDATE = "employeeEndDate";

Boolean bENDDATE = mventry[ENDDATE].IsPresent;

 

if ((bENDDATE) && (ACCTEXPIRE == iFileTime) || (ACCTEXPIRE == iZeroTime)) { mventry[ENDDATE].Delete(); }

if ((ACCTEXPIRE != iFileTime) && (ACCTEXPIRE != iZeroTime)) { mventry[ENDDATE].Value = DateTime.FromFileTime(ACCTEXPIRE).ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.000'"); }

                     

break;

 

                default:

                    // TODO: remove the following statement and add your default script here

                    throw new EntryPointNotImplementedException();

            }

        }

 

Resource Links