Friday, January 13, 2012

Sun One Boolean Attributes

Recently while working with the Sun One MA, I came across a problem caused by how FIM interprets boolean data coming from the directory.  In this case, the Sun One directory stores its boolean data as “YES” or “NO”, however when imported by FIM, this data always gets converted to False in the connector space.  (http://social.technet.microsoft.com/Forums/en-US/identitylifecyclemanager/thread/8ffc112e-d945-4916-83b3-78fbba716705)

Now we can’t use an advance import flow to correctly convert the data as it comes into the Metaverse because we have already lost data integrity.  The data that’s in the connector space is basically useless.  This only leaves us with a couple of options, we can write an XMA to correctly handle the data, but this can be fairly complicated.  We can also update the directory schema and use a string instead of a boolean, however, this could cause other downstream issues with other systems that might be consuming this data.  There is one other option, but its completely unsupported.  You could update the FIM database to make the system think this attribute is a string. 

Begin by running the following SQL Statement using the SQL Server Management Studio against your FIM database:

SELECT CAST(ma_schema_xml AS XML)   
  FROM FIMSynchronizationService.dbo.mms_management_agent
 WHERE ma_name = '<Sun One MA Name Here>'

In the results window you will get a single record that can be clicked on to open an xml document containing the schema for your Sun MA. Each attribute in the directory will appear using this syntax:

<attribute-type id="system_assigned_id" single-value="true/false">
     <name>attribute_name</name>
     <syntax>LDAPv3_syntax_oid</syntax>
</attribute-type>

If you do a quick search (Ctrl+F) for your attribute, you can manually update the LDAP Syntax OID from a boolean (1.3.6.1.4.1.1466.115.121.1.7) to a string (1.3.6.1.4.1.1466.115.121.1.15).  In my case, the new XML looked like:

<attribute-type id="Ah" single-value="true">
     <name>isManager</name>
     <syntax>1.3.6.1.4.1.1466.115.121.1.15</syntax>
</attribute-type>

I then used an update statement to write this information back to the database.  After performing a full import on this MA the connector space now reflected this data as a string of “YES” or “NO” just as it appears in the directory.  Now that the connector space had data I could work with, I wrote a quick advanced import flow rule to transform this value to a boolean:

case "isManager":

   //perform conversion for isManager from yes/no to boolean value
   if (csentry["isManager"].IsPresent)
   {
      if (csentry["isManager"].Value.Equals("yes", StringComparison.InvariantCultureIgnoreCase))
      {
         mventry["isManager"].BooleanValue = true;
      }
      else
      {
         mventry["isManager"].BooleanValue = false;
      }
   }
   break;

This approach does have its risks.  It will need to be re-done after performing a schema refresh in FIM and there is no guarantee it will keep working after an upgrade/patch.   The following SQL query could be used to script out this update, just replace the attributeName and SunOneMA variables and you should be good to go:

DECLARE @attributeName AS Varchar(255) = '<Attribute Name Here>'
DECLARE @SunOneMA AS Varchar(255) = '<Sun One MA Name Here>'
DECLARE @newSchemaOID AS Varchar(255) = '1.3.6.1.4.1.1466.115.121.1.15' --Directory String

-- get schema data
DECLARE @schema AS XML

SELECT @schema = CAST(ma_schema_xml as xml)
  FROM FIMSynchronizationService.dbo.mms_management_agent
 WHERE ma_name = @SunOneMA

-- update schema type
SET @schema.modify('
   declare default element namespace http://www.dsml.org/DSML;
   replace value of
      (dsml/directory-schema/attribute-type[name=sql:variable("@attributeName")]/syntax/text())[1]
   with
      sql:variable("@newSchemaOID")
   ')

-- save back to table
UPDATE FIMSynchronizationService.dbo.mms_management_agent
   SET ma_schema_xml = CONVERT(nvarchar(MAX), @schema)
 WHERE ma_name = @SunOneMA