A PRACTICAL SCENARIO OF USING EXPORT_PASSWORD ATTRIBUTE


This posting is provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at http://www.microsoft.com/info/cpyright.htm


 


If you have been working with MIIS for some time then you probably noticed that each connector space receives an attribute called export_password. Intuitively I knew that this attribute must have something to do with the password synchronization capabilities of MIIS, but unfortunately I could not find any good documentation to help me better understand the role this attribute plays or scenarios in which we could be leveraging this attribute.  Luckily while working on my extMA for Oracle principals, I found myself in a situation where I needed to resolve an issue with setting initial Oracle user passwords, which prompted me start asking questions about this attribute.  Many thanks to Tomasz Onyszko who helped me understand the role of export_password attribute and how to utilize it in my extMA. In this blog I will show how I used the export_password attribute to solve what I believe to be a very common scenario of setting-up initial password via extensible Management Agent (extMA).


 


THE PROBLEM


Undoubtedly, most of the systems for which you will be writing an extMA will require a password attribute to be set for each identity that you create on that system.  Furthermore, the password value that you submit during the creation of the user identity will be most likely hashed by the system. For example Oracle maintains PASSWORD attribute field in the DBA_USERS system view, but the value of the PASSWORD attribute is the result of proprietary hashing function performed by Oracle on the password value that extMA provides during user creation (see sample entry below).


USERNAME                       PASSWORD


------------------------------ ------------------------------


ALEXTC                         9220D38B94449548


So for example, while provisioning ALEXTC to Oracle I may execute something like this in the provisioning code:


ManagementAgent = mventry.ConnectedMAs(“oraPrincipals”)


Connectors = ManagementAgent.Connectors.Count


Anchor = mventry("uid").Value


 


If 0 = Connectors Then


   csentry = ManagementAgent.Connectors.StartNewConnector("user")


   csentry("USERNAME").Value = "" & Anchor.ToUpper & ""


   csentry("DEFAULT_TABLESPACE").Value = "SYSTEM"


   csentry("TEMPORARY_TABLESPACE").Value = "TEMP"


   csentry("PROFILE").Value = "DEFAULT"


   csentry("PASSWORD").Value = mventry["initialPassword"].Value


   csentry.CommitNewConnector()


Once execution of the provisioning logic completes the value of PASSWORD attribute in the Connector Space (CS) will be set to the value stored in mventry under the initial password attribute (for example “password”), but after exporting this entry to Oracle the value of the PASSWORD attribute on ORACLE will be 9220D38B94449548, the hashed value of “password”  (at least in my test environment).  Since MIIS needs to re-import all the exported changes in order to confirm successful export you will get the infamous warning “export-entry-not-reimported” for each newly exported user. Mind you that this warning does prevent us from provisioning a user to Oracle but, clearly we can’t have warnings like this in production environment. Additionally storing hashes of passwords in the CS is not considered to be a good security practice (violates the principal of reduction of surface of attack). Therefore we must find a better approach of setting-up that initial password.


 


THE NEED FOR EXPORT-ONLY ATTRIBUTE IN CS


So if we analyzed the problem described above then a simple solution would be to tell MIIS that the PASSWORD attribute is export-only and don’t bother re-importing it. Unfortunately or fortunately, MIIS does not have a facility to designate a specific attribute as export-only, but as you may have guessed, this is where the export_password attribute comes to the rescue. This attribute is generated by MIIS for each entry in the CS and by design is export-only; therefore it is a perfect candidate for storing those initial passwords. So let us recode the provisioning logic as such:


ManagementAgent = mventry.ConnectedMAs(“oraPrincipals”)


Connectors = ManagementAgent.Connectors.Count


Anchor = mventry("uid").Value


 


If 0 = Connectors Then


   csentry = ManagementAgent.Connectors.StartNewConnector("user")


   csentry("USERNAME").Value = "" & Anchor.ToUpper & ""


   csentry("DEFAULT_TABLESPACE").Value = "SYSTEM"


   csentry("TEMPORARY_TABLESPACE").Value = "TEMP"


   csentry("PROFILE").Value = "DEFAULT"


   csentry("export_password").Value = mventry["initialPassword"].Value


‘ you may also consider writing a function that generates the initial   ‘password based on the business logic appropriate to your scenario


   csentry.CommitNewConnector()


 I also removed the Oracle PASSWORD attribute from flowing into CS, we simply don’t need it anymore. Now for each provisioned Oracle account I have the value of its initial password stored in export_password attribute. Next we will look at how to get this value into remote system (Oracle in my case)


 


RELATIONSHIP BETWEEN EXPORT_PASSWORD AND CUSTOM PASSWORD EXTENSION


My initial thought of using the export_password attribute was to simply access it during the exportEntry routine in my extMA and passing its value to the method that creates an Oracle account. But I realized that export_password attribute is not accessible in the exportEntry sub. This is where I started to ask questions, and was explained that the export_password attribute is special in some other way then being just export-only.


Specifically, by setting the export_password attribute in provisioning code, we trigger the execution of SetPassword routine of our custom password extension after the entry is exported to the connected system. So in my custom password extension for the Oracle Principals I have the following implementation of SetPassword function:


Public Sub SetPassword(ByVal csentry As CSEntry, ByVal NewPassword As String) Implements Microsoft.MetadirectoryServices.IMAPasswordManagement.SetPassword


 


Dim cmd As New OracleCommand


Dim UserName As String = csentry("USERNAME").Value


Dim Password As String = NewPassword


Dim SQLString As String = "alter user " & UserName & " identified by " & Password


 


        Try



            cmd.CommandText = SQLString


            cmd.Connection = OracleConnection


            cmd.ExecuteNonQuery()


            cmd.Dispose() 


        Catch ex As Exception



            EventLogger.WriteToEventLog(ex.Message, EventLogEntryType.Error)


            cmd.Dispose()


            Throw New Exception(ex.Message) 


        End Try 



    End Sub


Note that one of the arguments that the SetPassword takes is NewPassword, which comes from the export_password attribute.


 


SEQUENCE OF EVENTS


Just to tie this all together let’s walk through the process of provisioning a new user to Oracle.


1.       Provisioning code executes and sets the value of export_password to some value


                csentry("export_password").Value = "password"


 


2.  The entry is exported to Oracle.


We need to make an important note here. Since the SetPassword routine can only execute after the account is created on Oracle (you can’t set a password on account that does not exist yet) we need to provide some logic within our extMA to set the initial password to some complex and random value so that Oracle would allow us to create that account. The reason for making password copmlex and random is to protect the account just in case step 3 fails.


Public Shared Function createUser(ByVal userName As String, _


                               ByVal defaultTableSpace As String, _


                               ByVal tempTableSpace As String, _


                               ByVal profile As String, _


                               ByVal expired As Boolean, _


                               ByVal locked As Boolean, _


                               ByVal quota() As String, _


                               ByVal dbConnection As OracleConnection)


 


Dim password As String = randomOraPassword.Generate


Dim identifiedClause As String = "identified by “ & password


      Dim sql As String


 


sql = "CREATE USER " & userName.ToUpper & " " &   identifiedClause & _


" DEFAULT TABLESPACE " & defaultTableSpace & _


" TEMPORARY TABLESPACE " & tempTableSpace & _


" PROFILE " & profile


 


Notice that in my createUser call I generate some random password which allows me to create that initial account. Nobody should know what this random password is, since it will be overwritten shortly.


 


3.       After the entry is exported the SetPassword sub is called and sets the user password to the value stored in export_password


 


CONCLUSION


If the system that you are working with requires passwords and also hashes them, you need to ensure that your extMA has also has a custom password extension attached to it, with the appropriate logic for SetPassword function. Then leverage the export_password attribute to propagate the initial value of the password to the SetPassword routine.


RESOURCES:


Tomasz’s blog on this topic


MIIS Developer Reference – Using password extensions


Walkthrough: How to build an extensible management agent for MIIS


Synchronizing Active Directory and Oracle security principals using Microsoft Identity Integration Server (MIIS)

Skip to main content