17 Configuring Synchronization with a Connected Directory

This chapter contains generic instructions for synchronizing the Oracle back-end directory with a connected directory. It contains these topics:

Note:

This chapter assumes that you are familiar with Chapter 16, "Connected Directory Integration Concepts and Considerations".

17.1 Verifying Synchronization Requirements

To prepare for synchronization between the Oracle back-end directory and a connected directory, do the following:

  1. Verify that the Oracle back-end directory and the other directory are running.

  2. Create a user account in the connected directory with sufficient privileges to read and write the relevant entries in the containers that will be synchronized. If the directory supports tombstone, the account should also have sufficient privileges to read tombstone entries.

    • For Import Operations from a Connected Directory: Grant the user account read access privileges to the subtree root. The user account must be able to read all objects under the source container (subtree root) in the connected directory that are to be synchronized with the Oracle Directory Integration Platform. To verify whether a connected directory user account has the necessary privileges to all objects to be synchronized with the Oracle back-end directory, use the command-line ldapsearch utility to perform a subtree search, as follows:

      $ORACLE_HOME/bin/ldapsearch -h directory host-p directory port \
      -b "DN of subtree" -s sub -D binddn "objectclass=*" -q
      

      Note:

      You will be prompted for the password for the privileged directory user.

      The return results from the ldapsearch utility should include all objects of interest, including all attributes and values that will be synchronized.

    • For Export Operations to a Connected Directory: Grant the user account the following privileges to the subtree root that is the parent of all the containers to which the Oracle Directory Integration Platform will export users:

      • Write

      • Create all child objects

      • Delete all child objects

      See Also:

      The connected directory documentation for information about how to grant privileges to user accounts

      You must also ensure that the Oracle back-end directory is running with change logging enabled, and that the change log purge duration is set to a minimum of seven days.

      See Also:

17.2 Creating Import and Export Synchronization Profiles Using expressSyncSetup

The expressSyncSetup command located in the ORACLE_HOME/bin directory allows you to perform the initial migration of data between a connected directory and the Oracle back-end directory for a synchronization profile.

Notes:

  • Best security practice is to provide a password only in response to a prompt from the command.

  • You must set the WLS_HOME and ORACLE_HOME environment variables before executing any of the Oracle Directory Integration Platform commands.

  • The Oracle WebLogic Managed Server where Oracle Directory Integration Platform is deployed must be configured for SSL to execute this command in SSL mode. Refer to the Configuring SSL chapter in Oracle Fusion Middleware Securing Oracle WebLogic Server for more information.

17.2.1 Syntax for expressSyncSetup

expressSyncSetup

expressSyncSetup -h HOST -p PORT -D wlsuser -pf PROFILE 
-conDirType CONNECTED_DIRECTORY_TYPE -conDirURL CONNECTED_DIRECTORY_URL
-conDirBindDN CONNECTED_DIRECTORY_BIND_DN -conDircontainer SYNC_CONTAINER 
[-ssl -keystorePath PATH_TO_KEYSTORE -keystoreType TYPE] [-enableProfiles {true |
false}] [-help]

17.2.2 Arguments for expressSyncSetup

-h | -host

Oracle WebLogic Server host where Oracle Directory Integration Platform is deployed.

-p | -port

Listening port of the Oracle WebLogic Managed Server where Oracle Directory Integration Platform is deployed.

-D | wlsusser

Oracle WebLogic Server login ID

Note:

You will be prompted for the Oracle WebLogic Server login password. You cannot provide the password as a command-line argument. Best security practice is to provide a password only in response to a prompt from the command. If you must execute expressSyncSetup from a script, you can redirect input from a file containing the Oracle WebLogic Server login password. Use file permissions to protect the file and delete it when it is no longer necessary. If you must provide more than one password to expressSyncSetup, put each on a separate line in the file, in the following order: connected directory bind DN password, then Oracle WebLogic Server login password.

-pf | -profile

Profile name. Specify the name of the profile in ASCII characters only, as non-ASCII characters are not supported in the profile name.

-conDirType

Connected directory type. The supported values are ActiveDirectory, EDirectory, iPlanet, OpenLDAP, ADAM, Tivoli, OID, and ExchangeServer2003.

-conDirUrl

URL where the connected directory is running. The format is host:port.

-conDirBindDN

Connected directory server bind DN. For example:

administrator@idm2003.net

cn=orcladmin, cn=Directory Manager

Note:

You will be prompted for the connected directory bind DN password. You cannot provide the password as a command-line argument. Best security practice is to provide a password only in response to a prompt from the command. If you must execute expressSyncSetup from a script, you can redirect input from a file containing the connected directory bind DN password. Use file permissions to protect the file and delete it when it is no longer necessary. If you must provide more than one password to expressSyncSetup, put each on a separate line in the file, in the following order: connected directory bind DN password, then Oracle WebLogic Server login password.

-conDirContainer

The synchronization container. For example:

ou=sales,dc=us,dc=com

OU=Groups,DC=imtest,DC=com

CN=Users,DC=imtest,DC=com

-ssl

Executes the command in SSL mode.

Note:

The Oracle WebLogic Managed Server where Oracle Directory Integration Platform is deployed must be configured for SSL to execute this command in SSL mode. Refer to the Configuring SSL chapter in Oracle Fusion Middleware Securing Oracle WebLogic Server for more information.

-keystorePath

The full path to the keystore.

-keystoreType

The type of the keystore identified by -keystorePath. For example: -keystorePath jks or -keystorePath PKCS12

-enableProfiles

Specify true to enable created profiles, false if not.

-help

Provides command usage help.

17.2.3 Tasks and Examples for expressSyncSetup

expressSyncSetup -h myhost.mycompany.com -p 7005 -D login_ID -pf myProfile \ 
  -conDirType ACTIVEDIRECTORY -conDirUrl server.mycompany.com:5432 \
  -conDirBindDN administrator@idm2003.net -conDirContainer ou=sales,dc=us,dc=com \
  -enableProfiles false \
expressSyncSetup -help 

17.2.4 Understanding the expressSyncSetup Command

The expressSyncSetup command allows you to create two synchronization profiles, one for import and one for export, using predefined assumptions. If the Oracle Directory Integration Platform is already running, then after enabling the profile, you can immediately begin synchronizing users and groups between the containers in which users and groups are stored in the connected directory and the container in the Oracle back-end directory.

Note:

While customizing the synchronization profiles for your environment, you may need to add test users and groups to facilitate your deployment effort. Be sure to remove any test users and groups when you are finished customizing and testing your synchronization profiles.

To simplify the configuration, the expressSyncSetup command assumes the following:

  • Entries for users of the default realm in Oracle Internet Directory are located in the container cn=users,default_realm_DN, whereas users of the default realm in Oracle Unified Directory and Oracle Directory Server Enterprise Edition are located in the container cn=users,default_metadata_suffix.

  • Entries for groups of the default realm are located in the container cn=groups,default_realm_DN for Oracle Internet Directory, and in the container default_metadata_suffix for Oracle Unified Directory and Oracle Directory Server Enterprise Edition.

  • The Oracle Directory Integration Platform master mapping rules files created during installation are located in $ORACLE_HOME/ldap/odi/conf.

  • Master domain mapping rules are located in the $ORACLE_HOME/ldap/odi/conf/ directory.

  • The logon credential is that of an Oracle Directory Integration Platform administrator with sufficient privileges to configure a profile, a realm, and access controls on the Users container in the Oracle directory server. Members of the dipadmingrp have the necessary privileges.

    In Oracle Internet Directory, the Oracle Directory Integration Platform Administrators group is as follows:

    cn=dipadmingrp,cn=dipadmins,cn=directory integration platform,cn=products,cn=oraclecontext

    In Oracle Unified Directory and Oracle Directory Server Enterprise Edition, the Oracle Directory Integration Platform Administrators group is as follows:

    cn=dipadmingrp,cn=dipadmins,cn=directory integration platform,<suffix>

Perform the following steps to run the expressSyncSetup command and verify that users and groups are synchronizing between cn=users,default_naming_context in the connected directory, and cn=users,default_realm in the Oracle back-end directory:

  1. Run express configuration using "Syntax for expressSyncSetup".

  2. The expressSyncSetup command creates two profiles named profile_nameImport and profile_nameExport. By default, both profiles are disabled. Enable the profile_nameImport profile if you need to synchronize from a connected directory to the Oracle back-end directory and enable the profile_nameExport profile if you need to synchronize from the Oracle back-end directory to a connected directory. Enable the profile by using the manageSyncProfiles command with the activate operation.

  3. Wait until the scheduling interval has elapsed and verify that synchronization has started by entering the following command. After executing the command, you will be prompted for the password for privileged directory user.

    $ORACLE_HOME/bin/ldapsearch -h OID host -p OID port \
    -D binddn -q \ 
    -b "orclodipagentname=import profile,cn=subscriber profile,cn=changelog
    subscriber,cn=oracle internet directory" -s base "objectclass=*"
    orclodipsynchronizationstatus orclodiplastsuccessfulexecutiontime
    

    Note:

    The default scheduling interval is 60 seconds (1 minute). You can use Oracle Enterprise Manager Fusion Middleware Control to change the default scheduling interval. See Chapter 7, "Managing Directory Synchronization Profiles" for information about using Oracle Enterprise Manager Fusion Middleware Control.

    When synchronization is successfully started:

    • The value of the Synchronization Status attribute is Synchronization Successful.

    • The value of the Last Successful Execution Time attribute is the specific date and time of that execution. Note that this must be close to the current date and time.

    An example of a result indicating successful synchronization is:

    Synchronization successful 20060515012615
    

    Note:

    • The date and time must be close to current date and time

    • When running the ldapsearch command, you need the dipadmin password, which, as established at installation, is the same as orcladmin password

  4. After verifying that synchronization has started, examine the entries in the Oracle back-end directory and the connected directory to confirm that users and groups are synchronizing between cn=users,default_naming_context in the connected directory, and cn=users,default_realm in the Oracle back-end directory.

CAUTION:

In order to successfully customize your import and export synchronization profiles, do not enable SSL until you have finished with all other configuration tasks.

17.3 Configuring Advanced Integration Options

When you install Oracle Directory Integration Platform, sample import and export synchronization profiles are automatically created for each of the supported Oracle and third-party connected directories. The import and export synchronization profiles created during the install process or with the expressSyncSetup command are only intended as a starting point for you to use when deploying your integration of the Oracle back-end directory and a connected directory. Because the default synchronization profiles are created using predefined assumptions, you must further customize them for your environment, as described in these topics:

See Also:

The individual connected directory integration chapters for information on the sample synchronization profiles that were created during the installation process

Before customizing the sample synchronization profiles that were created during the installation process, be sure to copy them with the copy operation of the manageSyncProfiles command, then enable the copies with the activate operation of the manageSyncProfiles command.

17.3.1 Configuring the Realm

Note:

If your Oracle back-end directory is either Oracle Unified Directory or Oracle Directory Server Enterprise Edition, the default container in those directories is the metadata suffix. Consequently, you may need to add cn=users, <metadata_suffix> and cn=groups,<metadata_suffix> entries and update the domain mapping rules as needed.

To configure the realm, do the following:

  1. Choose the realm DN structure as described in the section "Choose the Structure of the Directory Information Tree", and, more specifically, in the section "Planning the Deployment".

  2. Select the attribute for the login name of the user. This attribute contains the name of the attribute used for logging in. By default, it is uid. For more information, see the section "Select the Attribute for the Login Name".

    • If you are integrating with Microsoft Active Directory, and the userprincipalname attribute is used for logging in, then you would map userprincipalname to the uid attribute in the Oracle back-end directory.

    • If you are integrating with Novell eDirectory or OpenLDAP, and the mail attribute is used for logging in, then you would map mail to the uid attribute in the Oracle back-end directory.

  3. Set up the usersearchbase and groupsearchbase values in the Oracle back-end directory. These values indicate to the various Oracle components where to look for users and groups in the Oracle back-end directory. They are set to default values during installation. However, you may need to reset these values so that they correspond to the DIT structures in the two directories. Be sure to set them correctly. Otherwise, even if the synchronization seems to function properly, components still may be unable to access users and groups in the Oracle back-end directory.

    To illustrate how you might configure the user search base and group search base: In the example in , the value of usersearchbase should be set to cn=users,dc=us,dc=MyCompany,dc=com or one of its parents. Similarly, assuming there is a subtree named groups in the DIT, the multivalued groupsearchbase attribute should be set to both of the following:

    • cn=groups,dc=us,dc=MyCompany,dc=com or one of its parents

    • cn=users,dc=us,dc=MyCompany,dc=com

    To configure the user search base and group search base, use the Oracle Internet Directory Self-Service Console.

  4. Set up the usercreatebase and groupcreatebase values in the Oracle back-end directory. These values indicate to the various Oracle components where users and groups can be created. They are set to default values during installation.

    To illustrate how to configure the user create base and group create base: In the example in , the value of usercreatebase should be set to cn=users,dc=us,dc=MyCompany,dc=com or one of its parents. Similarly, the groupcreatebase should be set to cn=groups,dc=us, dc=MyCompany,dc=com or one of its parents.

    To configure the user create base and group create base, use the Oracle Internet Directory Self-Service Console.

See Also:

The section about modifying configuration settings for an identity management realm in Oracle Fusion Middleware Guide to Delegated Administration for Oracle Identity Management

17.3.2 Customizing Access Control Lists

This section discusses how to customize ACLs for import profiles, export profiles, and for other Oracle components. It contains these topics:

17.3.2.1 Customizing ACLs for Import Profiles

The import profile is the identity used by the Oracle Directory Integration Platform to access the Oracle back-end directory. ACLs must enable the import profile to add, modify, and delete objects in either the users and groups containers or the subtree where entries are accessed. By default, import profiles are part of the Realm Administrators group (cn=RealmAdministrators, cn=groups,cn=OracleContext,realm_DN) in the default realm. This group has privileges to perform all operations on any entry under the DN of the default realm.

Customizing an ACL for Oracle Unified Directory or Oracle Directory Server Enterprise Edition Back-end Directories

If your Oracle back-end directory is either Oracle Unified Directory or Oracle Directory Server Enterprise Edition, the import profile can add, modify, and delete users and groups under the DN of the metadata suffix. For a non-metadata suffix, the ACL has to be set as follows so that the containers can import the users and groups from the other source:

dn: <Container DN>
changetype:modify
add: aci
aci: (target="ldap:///<Container DN>")(version 3.0; acl "Anonymous read-search
access"; allow (read,add,delete,search,write,compare,proxy) 
groupdn="ldap:///cn=dipadmingrp,cn=DIPadmins,cn=Directory Integration
Platform,<metadata suffix>"; allow (read,add,delete,search,write,compare,proxy)  
groupdn="ldap:///cn=odipigroup,cn=DIPadmins,cn=Directory Integration
Platform,<metadata suffix>"; )
-
add: aci
aci: (targetattr="*")(version 3.0; acl "Anonymous read-search access"; 
allow (search,read,write,compare,add)
groupdn="ldap:///cn=dipadmingrp,cn=DIPadmins,cn=Directory Integration
Platform,<metadata suffix>"; allow (search,read,write,compare,add)
groupdn="ldap:///cn=odipigroup,cn=DIPadmins,cn=Directory Integration
Platform,<metadata suffix>";

Customizing an LDIF ACL for Oracle Unified Directory or Oracle Directory Server Enterprise Edition Back-end Directories

Refer to the ACL example given above. As needed, replace <Container DN> with the DN under which the operations are to be performed, and replace <metadata suffix> with the suffix that you specified to store DIP metadata during DIP configuration.

You can upload an LDIF file using the following ldapmodify command:

$ORACLE_HOME/bin/ldapmodify -h OID host -p OID port 
-D binddn -q -v -f realmacl.ldif

After executing the command, you will be prompted for the password for privileged directory user.

Customizing an ACL for an Oracle Internet Directory Back-end Directory

If your Oracle back-end directory is Oracle Internet Directory, you should not need to customize the ACLs for import synchronization with the default realm that is installed with Oracle Internet Directory Release 11g Release 1 (11.1.1). If you are upgrading from an earlier version of Oracle Internet Directory, or if the synchronization is with a nondefault Oracle Internet Directory realm, then be sure that the necessary privileges in the proper subtree or containers are granted to the import profiles handling the synchronization.

Customizing an LDIF ACL for an Oracle Internet Directory Back-end Directory

For an ACL template in LDIF format, see the file $ORACLE_HOME/ldap/schema/oid/oidRealmAdminACL.sbs. If your Oracle back-end directory is Oracle Internet Directory and you have not changed the ACLs on the default realm, then this template file can be applied directly after instantiating the substitution variables, replacing %s_SubscriberDN% with the default realm DN in Oracle Internet Directory, and replacing %s_OracleContextDN% with cn=OracleContext,default_realm_DN respectively.

For example, if realmacl.ldif is the instantiated file, then you can upload it by using the following ldapmodify command:

$ORACLE_HOME/bin/ldapmodify -h OID host -p OID port 
-D binddn -q -v -f realmacl.ldif

After executing the command, you will be prompted for the password for privileged directory user.

17.3.2.2 Customizing ACLs for Export Profiles

To enable the Oracle Directory Integration Platform to access a connected directory, you must create an identity in the connected directory. This identity is configured in each export profile.

To Customize the ACL to Support the Synchronization of User Records Located Outside of the Default Realm

If your Oracle back-end directory is Oracle Internet Directory and you need to synchronize user records located outside of the Oracle Internet Directory default realm, modify the ACL using an LDIF file as follows.

Note:

This ACL change is required to export OID user passwords that are outside of the default realm to connected directories using DIP sync.

  1. Query the ACIs in the root-directory specific entry, and save the output to an LDIF file as a backup:

    ldapsearch -h OID host -p port -D cn=orcladmin -w password -s base -L
    -b "" objectclass=* orclaci orclentrylevelaci > /tmp/orig-root-acis.ldif
    
  2. Find the following ACI:

    orclaci: access to
    attr=(userpkcs12,orclpkcs12hint,userpassword,pwdhistory,orclrevpwd) by
     group="cn=OracleUserSecurityAdmins,cn=Groups,cn=OracleContext"
     (search,read,write,compare) by self (search,read,write,compare) by * (none)
    
  3. Modify the ACI to include the DIP DN and save the file as new-root-acis.ldif.

    Your modified file should look like this:

    orclaci: access to
    attr=(userpkcs12,orclpkcs12hint,userpassword,pwdhistory,orclrevpwd) by
    group="cn=OracleUserSecurityAdmins,cn=Groups,cn=OracleContext"
    (search,read,write,compare) by self (search,read,write,compare) by
    dn="cn=odisrv,cn=Registered Instances,cn=Directory Integration
    Platform,cn=products,cn=oraclecontext" (search,read)* by * (none)
    
  4. Add the following two lines after the first line of the file:

    changetype: modify
    replace: orclaci
    

    The top of your file should read as follows:

    dn: Container DN
    changetype: modify
    replace: orclaci
    orclaci: access to
    ...
    
  5. Use the ldapmodify command to apply the modified ACI:

    $ORACLE_HOME/bin/ldapmodify -h OID host -p OID port -D cn=orcladmin -w password -v -f /tmp/new-root-acis.ldif
    

17.3.2.3 ACLs for Other Oracle Components

Default ACLs enable you to create, modify, and delete users and groups, but only in the users and groups containers under the default realm. To synchronize objects in other containers, you must customize the ACLs.

There are sample ACL files that you can use to customize ACLs for Oracle Components. These sample files are installed in the $ORACLE_HOME/ldap/schema/oid directory. They are:

  • oidUserAdminACL.sbs—Grants necessary rights to the subtree for Oracle components to manage and access users.

  • oidGroupAdminACL.sbs—Grants necessary rights to the subtree for Oracle components to manage and access groups.

  • oidUserAndGroupAdminACL.sbs—Grants the privileges for Oracle components to manage and access users and groups in the subtree.

You can customize your ACL policy to grant privileges on a container-by-container basis with the required rights.

See Also:

The chapter about access controls in Oracle Fusion Middleware Administrator's Guide for Oracle Internet Directory for instructions on customizing ACLs

17.3.3 Customizing Mapping Rules

Mapping rules, an important part of the synchronization profile, determine the directory information to be synchronized and how it is to be transformed when synchronized. You can change mapping rules at run time to meet your requirements.

Each sample synchronization profile includes default mapping rules. These rules contain a minimal set of default user and group attributes configured for out-of-the-box synchronization.

Note:

When a synchronization is underway, it relies on the mapping rules configured prior to any changes in the directory. To ensure consistent mapping, you may need to remove an already synchronized entry or perform a full synchronization.

Mapping rules govern the way data is transformed when a source directory and a destination directory are synchronized. Customize the default mapping rules found in the sample profiles when you need to do the following:

  • Change distinguished name mappings. The distinguished name mappings establish how the connected directory DIT maps to the Oracle back-end directory DIT.

  • Change the attributes that need to be synchronized.

  • Change the transformations (mapping rules) that occur during the synchronization.

You can perform any mapping if the resulting data in the destination directory conforms to the schema in that directory.

See Also:

Once you have established a working synchronization between the Oracle back-end directory and a connected directory, you can customize the attribute mapping rules for your synchronization profiles to meet the needs of your deployment.

To customize the attribute mapping rules for your synchronization profiles:

  1. Make a duplicate of the sample mapping rules file. The sample mapping rules files are stored in the $ORACLE_HOME/ldap/odi/conf directory with the extension of map.master for the various profiles.

  2. Edit the sample mapping rules file to make the previously discussed modifications. You can find instructions for editing mapping rules in "Configuring Mapping Rules".

  3. After the changes are made, use the update operation of the manageSyncProfiles command to update the profile. For example, the following command updates a profile name myImportProfile with a properties file named myPropertiesFile:

    manageSyncProfiles update -profile profile_name -file myPropertiesFile
    

    See Also:

    The manageSyncProfiles section in the Oracle Directory Integration Platform tools chapter of the Oracle Identity Management User Reference.

  4. Wait until the scheduling interval has elapsed, and then check the synchronized users and groups to ensure that the attribute mapping rules meet your requirements.

    Tip:

    You may find it helpful to add test users and groups to the Oracle back-end directory or the connected directory when customizing attribute mapping rules.

17.3.4 Configuring the Connected Directory Connector for Synchronization in SSL Mode

By default, SSL is not enabled for the import and export synchronization profiles created with the expressSyncSetup command. Whether or not you synchronize in the SSL mode depends on your deployment requirements. For example, synchronizing public data does not require SSL, but synchronizing sensitive information such as passwords does. To synchronize password changes between the Oracle back-end directory and a connected directory, you must use SSL server authentication mode.

Note:

Be sure that you can successfully synchronize users in non-SSL mode before attempting to configure your synchronization profiles for SSL.

Securing the channel requires:

  • Enabling SSL between the Oracle back-end directory and the Oracle Directory Integration Platform

  • Enabling SSL between the Oracle Directory Integration Platform and the connected directory

Although you can enable SSL either between the Oracle back-end directory and the Oracle Directory Integration Platform, or between that server and the connected directory, Oracle recommends that you completely secure the channel before you synchronize sensitive information. In certain cases, such as password synchronization, synchronization can occur only over SSL.

Configuring SSL requires the following:

  • Running the Oracle directory server in SSL mode as described in the chapter on Secure Sockets Layer (SSL) in Oracle Fusion Middleware Administrator's Guide for Oracle Internet Directory.

  • Running the Oracle Directory Integration Platform in the SSL mode as described in Chapter 2, "Security Features in Oracle Directory Integration Platform." The SSL mode for Directory Integration Platform must be the same mode used when the the Oracle back-end directory server started. SSL mode 1 is no authentication and SSL mode 2 is server authentication.

    Note:

    Oracle Directory Integration Platform only supports the No Authentication SSL mode (SSL mode 1) if your Oracle back-end directory is Oracle Internet Directory. If Oracle Unified Directory or Oracle Directory Server Enterprise Edition is your Oracle back-end directory, SSL Server Authentication (SSL mode 2) is your only SSL option.

  • Running the connected directory server in SSL mode. Communication with a connected directory over SSL requires SSL server authentication. This requires that both the Oracle back-end directory and the Oracle Directory Integration Platform be run in SSL server authentication mode.

Perform the following steps to configure communication with a connected directory in SSL mode:

  1. Generate a certificate for the connected directory. Only the trust point certificate from the server is required. Put the certificate in the connected directory's certificate store.

  2. Export the trusted Certificate Authority (CA) certificates to Base 64 encoded format.

  3. Import the trusted CA certificates to the Java KeyStore (JKS) using the keytool command. If Oracle Directory Integration Platform is already using an existing JKS, identify the location of it using the -keystore PATH_TO_JKS option. If Oracle Directory Integration Platform does not already have a JKS to use, keytool will create one at the location identified by the -keystore PATH_TO_JKS option.

    For example:

    keytool –importcert –trustcacerts –alias mycert –file PATH_TO_CERTIFICATE \ 
    -keystore PATH_TO_JKS
    

    If this is the first time you are using the JKS identified by the -keystore PATH_TO_JKS option, you must provide its password and also perform the following steps a and b:

    1. Update the Directory Integration Platform configuration with the location and password used in step 3 by using the manageDIPServerConfig command. For example:

      manageDIPServerConfig set -h HOST –p PORT -D WLS_USER \
      -attribute keystorelocation -value PATH_TO_CERTIFICATE
      
    2. Update the credential in the Credential Store Framework (CSF) using the following WLST command and replacing the PASSWORD variable with the password used when the keystore was created:

      createCred(map="dip", key="jksKey", user="jksUser", 
      password="PASSWORD",desc="jks password")
      
  4. Modify the connected directory connection information, including the host name, profile, and connectedDirectoryURL attribute, using the modify operation of the manageSyncProfiles command.

    manageSyncProfiles update -profile profile_name -file myMapFile
    

    When you configure the connectedDirectoryURL attribute, use the following format:

    host:port:sslmode
    

    Supported values for sslmode are as follows:

    Table 17-1 Supported Values for sslmode in connectedDirectoryURL Attribute

    Supported sslmode Value Description

    0

    No SSL mode. Supported for all directory types.

    1

    No Authentication mode. No certificate. Supported only for Oracle Internet Directory.

    2

    Server-Only Authentication mode. Requires certificate. Supported for all directory types.


  5. If you used a new JKS in step 3, you must restart the Oracle Directory Integration Platform in SSL mode. If you used an existing JKS in step 3, go to step 6 now.

  6. Add a test user and verify that it synchronizes successfully. If the test user does not synchronize successfully, then troubleshoot your SSL configuration.

Note:

The Oracle Directory Integration Platform does not support SSL in client/server authentication mode.

17.3.5 Enabling Password Synchronization from the Oracle Back-end Directory to a Connected Directory

Password synchronization to a connected directory from an Oracle Unified Directory back-end directory or an Oracle Directory Server Enterprise Edition back-end directory is not supported.

To synchronize passwords from Oracle Internet Directory to a connected directory, you must enable the password policy and you may have to enable reversible password encryption in the Oracle Internet Directory server.

Enable reversible password encryption in the Oracle Internet Directory server only if the hashing algorithm between Oracle Internet Directory and the connected directory is incompatible or unsupported.

For example, IBM Tivoli Directory Server and Oracle Directory Server Enterprise Edition (previously Sun Java System Directory Server) support similar hashing algorithms as Oracle Internet Directory. Therefore, to synchronize passwords from Oracle Internet Directory to IBM Tivoli Directory Server or Oracle Directory Server Enterprise Edition, you must enable only the password policy in the Oracle Internet Directory server.

However, to synchronize passwords from Oracle Internet Directory to Microsoft Active Directory or Novell eDirectory, which both do not support similar hashing algorithms as Oracle Internet Directory, you must enable the password policy and reversible password encryption in the Oracle Internet Directory server.

Note:

As of Oracle Internet Directory 10g (10.1.4.0.1), Oracle Internet Directory supports multiple password policies in each realm, commonly known as Fine-Grained Password Policies.

Refer to the Oracle Fusion Middleware Administrator's Guide for Oracle Internet Directory for more information about Fine-Grained Password Policies.

To enable the password policy, assign a value of 1 to the orclPwdPolicyEnable attribute in the appropriate container. To enable reversible password encryption in the Oracle Internet Directory server, assign a value of 1 to the orclpwdEncryptionEnable attribute in the appropriate container.

For example, to enable the password policy and reversible password encryption on the default policy for a realm, assign a value of 1 to the orclPwdPolicyEnable and orclpwdEncryptionEnable attributes in the following entry:

cn=default,cn=PwdPolicyEntry,cn=common,cn=products,cn=oraclecontext,Realm_DN

You can do this by using ldapmodify and uploading an LDIF file containing the following entries:

dn: cn=default,cn=PwdPolicyEntry,cn=common,cn=products,cn=oraclecontext,Realm_DN
changetype: modify
replace: orclpwdpolicyenable
orclpwdpolicyenable: 1
-
replace: orclpwdencryptionenable
orclpwdencryptionenable: 1

See Also:

Oracle Fusion Middleware Administrator's Guide for Oracle Internet Directory for information on managing Oracle Internet Directory password policies.

17.3.6 Configuring External Authentication Plug-ins

Oracle Directory Integration Platform supports Java-based external authentication plug-ins. Oracle recommends that you use the Java plug-ins instead of the older, PL/SQL-based plug-ins, which only support Microsoft Active Directory and Oracle Directory Server Enterprise Edition / Sun Java System Directory Server.

The configuration tool for the plug-ins is a Java program called oidexcfg. You use it to configure Java-based external authentication plug-ins for Microsoft Active Directory, Oracle Directory Server Enterprise Edition (Sun Java System Directory Server), Novell eDirectory, IBM Tivoli Directory Server, and OpenLDAP.

Note:

The oidexcfg tool configures an external authentication plug-in to work only with a single domain. You must perform the steps described in "Configuring External Authentication Against Multiple Domains" to set up an external authentication plug-in to work with multiple domains.

To configure an external authentication plug-in, perform the following steps:

  1. (Optional) Perform this step only if you want to use SSL to secure the communication between the authentication plug-in and the external LDAP directory. If you do not want to secure the communication, proceed to step 2 now.

    To secure the communication between the authentication plug-in and the external LDAP directory using SSL, a trusted certificate from the external, authenticating directory must reside in a wallet on the file system. When you configure the plug-in using oidexcfg in step 3, you will be prompted to enter information about the external LDAP directory configuration and you can identify the location of this wallet.

    If you want to use SSL, put the certificate in a new or existing wallet now.

    Note:

    The certificate enables SSL to secure the communication between the authentication plug-in and the external LDAP directory—it does not secure the communication with the Oracle back-end directory when you execute oidexcfg in step 3.

  2. Include oidexcfg.jar and ldapjclnt11.jar in the Java CLASSPATH environment variable. To set the environment variable:

    In UNIX/Linux environments:

    setenv CLASSPATH=$ORACLE_HOME/ldap/jlib/oidexcfg.jar:$ORACLE_HOME/ldap/jlib/ldapjclnt11.jar:$CLASSPATH
    

    In Windows environments:

    set CLASSPATH=%ORACLE_HOME%/ldap/jlib/oidexcfg.jar;%ORACLE_HOME%/ldap/jlib/ldapjclnt11.jar;%CLASSPATH% 
    
  3. Configure the plug-in using oidexcfg by executing the following command. You will be prompted to enter information about the external LDAP directory configuration, including the location of the wallet containing the trusted certificate required for SSL.

    Note:

    You must identify the location of the wallet file using a fully-qualified path, for example:

    /etc/ORACLE_HOME/wallets/ewallet.p12
    

    Execute the following command to configure the plug-in using oidexcfg:

    java -classpath $CLASSPATH oracle.ldap.extplg.oidexcfg -h OID_Host
    -p OID_Port -D BindDN -w password -t Directory_Type
    

    The -t option that identifies the directory type supports the following values:

    • ad for Microsoft Active Directory

    • adam for Microsoft Active Directory Application Mode

    • iplanet for Oracle Directory Server Enterprise Edition and Sun Java System Directory Server

    • edirectory for Novell eDirectory

    • openldap for OpenLDAP

    • tivoli for IBM Tivoli Directory Server

17.3.6.1 Configuring External Authentication Against Multiple Domains

To set up an external authentication plug-in to work with multiple external authentication domains, you must perform some manual instructions after you run the external configuration tool. Proceed as follows:

  1. Configure the external authentication plug-in as described in "Configuring External Authentication Plug-ins".

  2. Search for the plug-in configuration entries created by the configuration tool in step 1, and redirect the search output to a file. Use an ldapsearch command similar to this:

    ldapsearch -p 3060 -D binddn -q -s sub -L \
        -b "cn=plugin,cn=subconfigsubentry" cn="oidexplg_*_ad" >> output.ldif
    

    Note:

    You will be prompted for the password.

    The example shows an Microsoft Active Directory cn. Use the correct plug-in cn for the type of plug-in you configured, as shown in Table 17-2. You can use * as a wildcard, as shown in the example.

    Table 17-2 Distinguished Names of External Authentication Plug-ins

    Plug-in Type DN

    Microsoft Active Directory

    cn=oidexplg_compare_ad, cn=plugin,cn=subconfigsubentry

    cn=oidexplg_bind_ad, cn=plugin,cn=subconfigsubentry

    Oracle Directory Server Enterprise Edition
    (Sun Java System Directory Server)

    cn=oidexplg_compare_iplanet, cn=plugin,cn=subconfigsubentry

    cn=oidexplg_bind_iplanet, cn=plugin,cn=subconfigsubentry

    Novell eDirectory

    cn=oidexplg_compare_Novell eDirectory, cn=plugin,cn=subconfigsubentry

    cn=oidexplg_bind_Novell eDirectory, cn=plugin,cn=subconfigsubentry

    OpenLDAP

    cn=oidexplg_compare_openldap, cn=plugin,cn=subconfigsubentry

    cn=oidexplg_bind_openldap, cn=plugin,cn=subconfigsubentry


  3. Examine the output file. For an Microsoft Active Directory plug-in, the output file resembles the following:

    dn: cn=oidexplg_compare_ad,cn=plugin,cn=subconfigsubentry
    cn: oidexplg_compare_ad
    objectclass: orclPluginConfig
    objectclass: top
    orclpluginname: oidexplg.jar
    orclplugintype: operational
    orclpluginkind: Java
    orclplugintiming: when
    orclpluginldapoperation: ldapcompare
    orclpluginsecuredflexfield;walletpwd: password
    orclpluginsecuredflexfield;walletpwd2: password
    orclpluginversion: 1.0.1
    orclpluginisreplace: 1
    orclpluginattributelist: userpassword
    orclpluginentryproperties: (!(&(objectclass=orcladobject)(objectclass=orcluserv2)))
    orclpluginflexfield;host2: host.domain.com
    orclpluginflexfield;port2: 636
    orclpluginflexfield;isssl2: 1
    orclpluginflexfield;host: host.domain.com
    orclpluginflexfield;walletloc2: /location/wallet
    orclpluginflexfield;port: 389
    orclpluginflexfield;walletloc: /tmp
    orclpluginflexfield;isssl: 0
    orclpluginflexfield;isfailover: 0
    orclpluginclassreloadenabled: 0
    orclpluginenable: 0
    orclpluginsubscriberdnlist: cn=users,dc=us,dc=oracle,dc=com
    
    dn: cn=oidexplg_bind_ad,cn=plugin,cn=subconfigsubentry
    cn: oidexplg_bind_ad
    objectclass: orclPluginConfigobjectclass: top
    orclpluginname: oidexplg.jar
    orclplugintype: operational
    orclpluginkind: Java
    orclplugintiming: when
    orclpluginldapoperation: ldapbind
    orclpluginversion: 1.0.1
    orclpluginisreplace: 1
    orclpluginentryproperties: (!(&(objectclass=orcladobject)(objectclass=orcluserv2)))
    orclpluginclassreloadenabled: 0
    orclpluginflexfield;walletloc2: /location/wallet
    orclpluginflexfield;port: 389
    orclpluginflexfield;walletloc: /tmp
    orclpluginflexfield;isssl: 0
    orclpluginflexfield;isfailover: 0
    orclpluginflexfield;host2: host.domain.com
    orclpluginflexfield;port2: 636
    orclpluginflexfield;isssl2: 1
    orclpluginflexfield;host: host.domain.com
    orclpluginenable: 0
    orclpluginsecuredflexfield;walletpwd: password
    orclpluginsecuredflexfield;walletpwd2: password
    orclpluginsubscriberdnlist:
    cn=users,dc=us,dc=oracle,dc=com
    
  4. Create a new LDIF file from the output file as follows:

    1. Change the entry names. In the example shown in the previous step, you would change cn=oidexplg_compare_ad,cn=plugin, cn=subconfigsubentry to cn=oidexplg_compare_ad1, cn=plugin,cn=subconfigsubentry and cn=oidexplg_bind_ad, cn=plugin,cn=subconfigsubentry to cn=oidexplg_bind_ad1, cn=plugin,cn=subconfigsubentry.

    2. Change the value for orclpluginenable. Use value 1 if you want to enable it, and use value 0 if you want to disable it.

    3. Change the values for orclpluginflexfield;host and orclpluginflexfield;port for the external directory host name and port number.

    4. Change the value for orclpluginflexfield;isssl. Use value 1 if you want to enable the SSL connection against the external directory, and use value 0 if you want to disable. If you use value 1, you will also need to change the value of orclpluginflexfield;walletloc and orclpluginsecuredflexfield;walletpwd for the wallet location and password.

    5. Change orclpluginflexfield;isfailover. Use value 1 if to set up the failover against a backup external directory. If you use value 1, then you must also change the value of orclpluginflexfield;host2, orclpluginflexfield;port2 for the host name and port number. To use an SSL connection against the backup directory server, you must to change the value for orclpluginflexfield;walletloc2 and orclpluginsecuredflexfield;walletpwd2.

    6. Modify orclpluginsubscriberdnlist for the plug-in invocation naming context.

    7. Modify orclPluginRequestGroup for the plug-in request group. If this attribute is missing in the search out put, then just add the attribute and value in the LDIF file.

  5. Add the modified plug-in configuration entries to the Oracle Internet Directory server. Use a command similar to the following:

    $ORACLE_HOME/ldap/bin/ldapadd -h host -p port -D binddn -q \
          -v -f input.ldif
    

    Note:

    You will be prompted for the password.

17.4 Writing Custom Synchronization Connectors

Oracle Directory Integration Platform supports custom synchronization connectors. This topic provides information to help you write custom connectors and contains the following sections:

17.4.1 Inbound Connectors

Perform the following steps to write an inbound connector:

  1. Implement the Reader. The Reader generally extends the target system connector class and implements the DISReadInterface. The different methods of the DISReadInterface are specified in its the javadoc. Refer to "Sample Reader" to see an example Reader implementation.

  2. Create a sample config file. The following is a typical config file:

    [INTERFACEDETAILS]
    Reader: Complete_classname_including_packageName
    SkipErrorToSyncNextChange: false
    SearchDeltaSize: 500
    UpdateSearchCount: 100
    
  3. Create a mapfile containing a set of mapping rules.

  4. Create a properties file by setting the configfile, mapfile, and filter parameters.

To test the inbound connector:

  1. Create a test profile using the register operation of the manageSyncProfiles command. Refer to "Managing Synchronization Profiles Using manageSyncProfiles" for more information.

  2. Verify your logging messages.

  3. Verify synchronization occurred by examining Oracle Internet Directory to see if the appropriate entries were created.

17.4.1.1 Sample Reader

package oracle.ldap.odip.gsi;
import oracle.ldap.odip.engine.AttrHandler;
import oracle.ldap.odip.engine.ChangeRecord;
import oracle.ldap.odip.engine.Connector;
import oracle.ldap.odip.engine.ConfigReader;
import oracle.ldap.odip.engine.Constants;
import oracle.ldap.odip.engine.DISReadInterface;
import oracle.ldap.odip.engine.DISFilterInterface;
import oracle.ldap.odip.engine.ODIException;
import oracle.ldap.odip.engine.Debug;
import oracle.ldap.odip.map.MapRules;
import oracle.ldap.odip.map.OrclFilter;
import oracle.ldap.odip.util.Utils;
 //Imports added for ODLLogger
import oracle.core.ojdl.logging.ODLLogger;
import oracle.dms.context.ExecutionContext;
import oracle.core.ojdl.logging.ODLLevel;
import oracle.core.ojdl.logging.ODLHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
 
import oracle.ldap.odip.DIPLogger;
 
public class SampleReader implements DISReadInterface
{
 
  /*
  ** Member variables used
  */
  protected  NamingEnumeration  mEnumerate;
  protected  Attributes         mAttribs;
  protected  Attribute          mAttrib;
  protected  Attribute          mAttribAllValues;
  protected  SearchResult       mResult;
  protected  MapRules           mMapRules;
  /*
  ** Vector to store the list of required attributes
  */
  protected  Vector             mReqAttrList = new Vector();
 
  /*
  ** List of source attributes whose changes need to be mapped
  */
  protected  Vector             mSrcAttrList = new Vector();
  protected  String             mMapFilter;
  protected  int                mAppliedChangeNum = 0;
  protected  int                mAvailableChangeNum = 700;
  protected  DISFilterInterface mFilter;
 
  /*
  ** LastChangeNumber that is read 
  */
 
  protected  String            mReadChangeNum;
 
  /*
  ** List of attributes to be returned in changelog LDAPSearch 
  */
  protected  String[]           mRetAttribs;
  private    int                mErrorCode = 0;
 
 
  /*
  ** Constructor
  */
  public SampleReader()
  {
  }
 
  /**
  ** Constructor with the connector 
  */
  public SampleReader( Connector conn )
  {
    super(conn);
    
  }
 
  /**
  ** Get the last change key value 
  **
  * @param   boolean Operation is success/failure
  * @return  Object  lastkeyvalue to be stored
  */
  public Object getLastChangeKey(boolean val)
  {
      if ( val == false )
      {
          int nval = Integer.parseInt(mReadChangeNum);
          if ( nval > 0 )
          {  
            nval--;
          }
          mReadChangeNum = String.valueOf(nval);
      }
      return (mReadChangeNum);
  }
 
  /**
  ** Initializes required values from hashtable passed from Profile
  **
  ** @param   Connector   connection details with credentials
  ** @param   Hashtable   with the required parameters
  ** @throws  ODIException Indicating connection failure
  */
  public void initialise(Connector conn,Hashtable pHash)
      throws ODIException
  {
       m_logger.finest ( "Entry: SampleReaders.initialise");
      setValues(conn);
      mMapRules = (MapRules)pHash.get(Constants.MAPRULE_STR);
 
      readCtx = connect();
 
      pHash.put("READCONTEXT", readCtx);      
      pHash.put(Constants.READERCHANGEKEY_STR, Constants.CHANGE_NUM);
      String key = (String)pHash.get(Constants.LASTAPPLIEDCHG_STR);
      String val = null;
      if ( key != null )
          val = (String)pHash.get(key);
      if ( val != null )
          mAppliedChangeNum = Integer.parseInt((String)pHash.get(key));
      mReadChangeNum = (String)pHash.get(key);
      pHash.put(key, mReadChangeNum);
      mFilter = (DISFilterInterface)pHash.get(Constants.MATCHRULE_STR);
      mAvailableChangeNum = Integer.parseInt(initAvailableChgKey());
      mSaveLastChgNum = mAppliedChangeNum;
     
      try {
        SearchControls pControls = new SearchControls();
        pControls.setSearchScope(SearchControls.OBJECT_SCOPE);
        pControls.setReturningAttributes(mRetAttribs);
        pControls.setTimeLimit(3000000);
 
        mEnumerate = mLdapCtx.search("","objectclass=*",pControls);
        while ( mEnumerate.hasMoreElements() )
        {
          mResult = (SearchResult)mEnumerate.nextElement();
          mAttribs = mResult.getAttributes();
        }
        // END INFEASIBLE
        ConfigReader configInfo = (ConfigReader) pHash.get(Constants.CONFINFO_STR);
 
        if (configInfo != null) {
            mUpdateSearchCount = configInfo.getUpdateSearchCount();
            mSearchDelta = configInfo.getSearchDeltaSize();
        }
      } catch (Exception ex)
      // BEGIN INFEASIBLE
      {
           
        throw new ODIException(ODIException.LDAP_INITIALIZATION_EXCEPTION,ex);
      }
      // END INFEASIBLE
      m_logger.finest ( "Exit: SampleReaders.initialise");
  }
 
  /**
  ** Search the changelog 
  ** @throws ODIException
  */
  public int searchChanges()
      throws ODIException
  {
 
        int  temp;
        int searchDelta = (int) mSearchDelta;
        if ( mAvailableChangeNum <= mAppliedChangeNum ) return -1;
        int  minChgNum = mAppliedChangeNum+1;
        if ( mAvailableChangeNum -  mAppliedChangeNum >= searchDelta)
            temp = mAppliedChangeNum + searchDelta;
        else
            temp = mAvailableChangeNum; 
 
        String searchF = "";
        if ( mFilter != null ) {
          searchF = mFilter.getSearchFilter();
          m_logger.log(ODLLevel.NOTIFICATION,"SEARCHF", searchF );
        }
 
        StringBuffer filter = new StringBuffer(300);
 
        /**
         * SearchChanges is called to get all changes 
         *
         */
        try {
 
           mEnumerate = mReadCtx.search( 
                                        filter.toString());
 
        }
        catch ( Exception ex ) 
        // BEGIN INFEASIBLE
        {
            throw ( new ODIException(ODIException.LDAP_SEARCH_EXCEPTION, 
                                      ex) );
        } 
        finally {
        
        m_logger.log(ODLLevel.NOTIFICATION, "SEARCH_SUCCESSFUL" ,new Integer( temp ));
 
        mAppliedChangeNum = temp;
      return mErrorCode;
  }
 
  public boolean hasMore()
      throws ODIException
  {
    boolean  retval = false;
    int count =0;
 
    try {   
      if ( mEnumerate.hasMoreElements() )
      {
        retval = true;
      }
      else
      {
        while ( mAvailableChangeNum > mAppliedChangeNum ) {
          if ( count >= mUpdateSearchCount )
              break;
 
          searchChanges();
          count++;
          if (mEnumerate.hasMoreElements())
          {
            retval = true;
            break;
          }
          else
            mReadChangeNum = String.valueOf(mAppliedChangeNum);
        }
      }
    }
    catch( Exception ex ) 
    // BEGIN INFEASIBLE
    {
      throw (new ODIException(ODIException.LDAP_HASMORE_EXCEPTION,ex));
    }
    // END INFEASIBLE
    if (retval == false) {  // no more results
      mReadChangeNum = (new Integer(mAvailableChangeNum)).toString();
    }
    return retval;
  }
 
 
   /**
  ** Read the next change from the source
  **
  ** @return  Object  the header part of the changes read.
  */
  public Object getNextChange()
      throws ODIException
  {
    try {
 
      if ( mEnumerate.hasMoreElements() )
      {
        mResult = (SearchResult)mEnumerate.nextElement();
        mAttribs = mResult.getAttributes();
        
    }
    catch ( Exception e )
    // BEGIN INFEASIBLE
    {
      throw (new ODIException (ODIException.LDAP_GETNEXT_EXCEPTION, e));
    }
    // END INFEASIBLE
 
    return mAttribs;
  }
 
  /**
  ** Create the change record from the data read from the file.
  **
  ** @returns  ChangeRecord
  */
  public ChangeRecord createChangeRecord(String dn)
      throws ODIException
  {
 
      // Create the changerecord based on the mAttribs which contains all the attributes.
 
  }
 
  public String initAvailableChgKey() throws ODIException
  {
      // set the available changekey value. This reads the value equivalent to the latest changelog number in the ldap world.
 
   }
 
}

17.4.2 Outbound Connectors

Perform the following steps to write an outbound connector:

  1. Implement the Writer. The Writer generally extends the target system connector class and implements the DISWriteInterface. The different methods of the DISWriteInterface are specified in its Javadoc. Refer to "Sample Writer" to see an example Reader implementation.

  2. Create a sample config file. The following is a typical config file:

    [INTERFACEDETAILS]
    Reader: Complete_classname_including_packageName
    SkipErrorToSyncNextChange: false
    SearchDeltaSize: 500
    UpdateSearchCount: 100
    
  3. Create a mapfile containing a set of mapping rules.

  4. Create a properties file by setting the configfile, mapfile, and filter parameters.

To test the outbound connector:

  1. Create a test profile using the register operation of the manageSyncProfiles command. Refer to "Managing Synchronization Profiles Using manageSyncProfiles" for more information.

  2. Verify your logging messages.

  3. Verify synchronization occurred by examining Oracle Internet Directory to see if the appropriate entries were created.

17.4.2.1 Sample Writer

 */
 
 
 
import oracle.ldap.odip.engine.AttrHandler;
import oracle.ldap.odip.engine.ChangeRecord;
import oracle.ldap.odip.engine.ConfigReader;
import oracle.ldap.odip.engine.Connector;
import oracle.ldap.odip.engine.Constants;
import oracle.ldap.odip.engine.DISWriteInterface;
import oracle.ldap.odip.engine.ODIException;
import oracle.ldap.odip.map.MapRules;
import oracle.ldap.odip.util.Utils;
 
import oracle.core.ojdl.logging.ODLLogger;
import oracle.core.ojdl.logging.ODLLevel;
import oracle.core.ojdl.logging.ODLHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
 
import oracle.ldap.odip.DIPLogger;
 
 
public class SampleWriter  implements DISWriteInterface {
    protected Hashtable mProfile;
    protected int mErrorCode = 0;
    protected String mLastKeyValue;
    protected String mLastWrittenKey;
    protected Vector mWriteFilter = new Vector();
    protected MapRules mMapRules;
    protected String mNamingContext = "";
    private String mOrigDstDn = "";
    protected boolean mHandleModAsAdd = false;
 
    /* Constructor */
    public LDAPWriter() {
    }
 
    public LDAPWriter(Connector conn) {
        super(conn);
    }
 
    public void initialise(Connector conn, Hashtable pHash)
        throws ODIException {
            m_logger.finest("Entry: LDAPWriter.initialise");    
        setValues(conn);
        mProfile = pHash;
        mMapRules = (MapRules) pHash.get(Constants.MAPRULE_STR);
        
        connect();
       ConfigReader configInfo = (ConfigReader) pHash.get(Constants.CONFINFO_STR);
 
        if (configInfo != null) {
            //mSearchDelta = configInfo.getSearchDeltaSize();
            mHandleModAsAdd = configInfo.getHandleModAsAdd();
        }
 
        mLastWrittenKey = (String) pHash.get(Constants.READERCHANGEKEY_STR);
        pHash.put("WRITECONTEXT", mLdapCtx);
 
        NamingEnumeration filter = (NamingEnumeration) pHash.get("WriteFilter");
 
        try {
            while (filter.hasMoreElements()) {
                mWriteFilter.add((String) filter.next());
            }
        } catch (Exception ex) {
            //System.out.println("Error in initializing filter");
        }
 
        /*
        ** Get the lastapplied changekey value from the profile
        ** and use that string to determine the 'lastappliedchangenum'
        ** or lastappliedchangetime to be stored as the 'lastkeyvalue'
        **
        ** Each of the insert/modify/delete routines, if the operation is
        ** successful, that lastkeyvalue is updated correspondingly. Otherwise
        ** it has the previous successful operation value
        */
        m_logger.finest ( "Exit: LDAPWriter.initialise" );
    }
 
    public void setChanges(ChangeRecord chgrec) {
        mChanges = chgrec;
    }
 
    public ChangeRecord getChanges() {
        return mChanges;
    }
 
    public String getLastChangeKey() {
        return mLastKeyValue;
    }
 
    public int writeChanges() throws ODIException {
            m_logger.finest("Entry: LDAPWriter.writeChanges");    
        mErrorCode = 0;
 
        m_logger.log(ODLLevel.FINE,
            "\n Output ChangeRecord " + mChanges.toString());
 
        String dn = mChanges.getChangeKey();
   
       if ( mHandleModAsAdd && (mChanges.getChangeType() == Constants.CHGTYPE_MODIFY)) {
            try {
              mLdapCtx.getAttributes( mChanges.getChangeKey() );
 
            }
            catch (NameNotFoundException nnfe) {
              m_logger.log(ODLLevel.ERROR,"ERROR_DN_CONN_DIR");
              mChanges.setChangeType(Constants.CHGTYPE_MODRADD);
            }
            catch (NamingException ne) {
              m_logger.log(ODLLevel.ERROR,"LDAP_WNAMING_EXCEPTION" , ne);
            }
         
       }
        m_logger.log(ODLLevel.FINE, 
                     "Changetype is " + mChanges.getChangeType());
        mChanges.setChangeKey(ndn);
 
        if (dn.length() > 1) {
            //testnew(dn);
            switch (mChanges.getChangeType()) {
            case Constants.CHGTYPE_ADD:
 
                if (mChanges.size() > 0) {
                    insert();
                }
 
                break;
 
            case Constants.CHGTYPE_MODIFY:
                // non-changelog-based changes
                if (mChanges.size() > 0) {
                                     modify();
                }
                else {
                    mErrorCode = -1;
                }
 
                break;
 
            case Constants.CHGTYPE_DELETE:
                delete();
 
                break;
 
            case Constants.CHGTYPE_MODRADD:
 
                // non-changelog-based changes
                if (mChanges.size() > 0) {
                    modifyRadd();
                }
 
                break;
 
            case Constants.CHGTYPE_MODRDN:
                modRDNchangelog(dn);
 
                break;
 
            case Constants.CHGTYPE_MODDN:
                m_logger.log(ODLLevel.FINE,
                             "Processing moddn"); 
                modDNchangelog(dn);
                break;
  
            default:
 
                //INFEASIBLE
                break;
            }
        } else // BEGIN INFEASIBLE
         {
            m_logger.log(ODLLevel.ERROR,
                "ENTRY_NOT_EXISTS_DELETE");
            m_logger.log(ODLLevel.FINE,
                "Synchrozing a deletion, entry to delete is not found. Ignore.");
            mErrorCode = 99;
 
            return mErrorCode;
        }
 
        // END INFEASIBLE
        Object chgInfo = mChanges.getChangeInfo();
 
        try {
            if (chgInfo instanceof Attributes) {
                Attributes attrs = (Attributes) chgInfo;
                mLastKeyValue = (String) ((Attribute) attrs.get(mLastWrittenKey)).get();
            }
        } catch (Exception ex) {
            //System.out.println("Caught the exception here " + mErrorCode);
            if (mErrorCode != 0) {
                m_logger.log(ODLLevel.ERROR,
                    "EXCEPTION_FOR_DN", new Object [] { dn, new Integer ( mErrorCode ) , ex.toString()});
            }
        }
 
        mChanges.setChangeKey(mOrigDstDn);
 
        return mErrorCode;
    }
 
    public void insert() throws ODIException {
            m_logger.finest("Entry: LDAPWriter.insert");    
        String dn = mChanges.getChangeKey();
        Enumeration attrdtls = mChanges.getAll();
 
        m_logger.log(ODLLevel.FINE,
            "Processing Insert Operation ..");
 
        while (attrdtls.hasMoreElements()) {
            AttrHandler temp = (AttrHandler) attrdtls.nextElement();
            attr = attrHandlerToAttr((AttrHandler) temp);
            if (attr != null && temp.getAttrChgType() != Constants.ATTRCHGTYPE_DELETE) {
                attrs.put(attr);
            }
        }
        createEntry(dn, attrs);
        m_logger.finest("Exit: LDAPWriter.insert");  
    }
 
    public void modify() throws ODIException {
            m_logger.finest("Entry: LDAPWriter.modify");  
        String attrname = mChanges.getChangeKey();
 
        m_logger.log(ODLLevel.FINE,
            "Processing Modify Operation ..");
 
        int pos = attrname.indexOf('=');
 
        String naming = null;
 
        if (pos > 0) {
            naming = attrname.substring(0, pos).trim();
        }
 
    }
 
   
    /**
    * Delete the entry
    */
    public void delete() {
            m_logger.finest("Entry: LDAPWriter.delete");  
        try {
            m_logger.log(ODLLevel.FINE,
                "Processing Delete Operation ..");
 
         }
 
    /**
    ** Handle the ModRDN operation
    **
    ** @throws ODIException
    */
    protected void modDNchangelog(String newDn) throws ODIException {
      String newDN = null;
      m_logger.log(ODLLevel.FINE,
            "Processing change log based ModRDN operation .." +
            " DN passed in: " + newDn);
 
      String dn = mChanges.getChangeKey();
      
      
    }
 
    /**
    ** Handle the ModRDN operation
    **
    ** @throws ODIException
    */
    protected void modRDNchangelog(String newDn) throws ODIException {
    
    }
 
    protected void performModDN(String oldDN, String newDN)
        throws ODIException {
    }
 
    /*
    ** First check whether the 'dn' already exists.
    ** If exists,
    **     do a modify.
    ** else
    **     construct objectclasses and do a add
    */
 
    // public void modifyRadd(boolean rdn) throws ODIException
    public void modifyRadd() throws ODIException {
            m_logger.finest("Entry: LDAPWriter.modifyRadd");  
        
    }
 
    /**
    ** Compare the value with the old value, and replace it, if the new value
    ** is different from the old value
    */
    public void checkNReplace(String dn, Attributes attrs)
        throws ODIException {
           
    }
 
    //BEGIN INFEASIBLE
    public int getErrorCode() {
        return mErrorCode;
    }
    
   
    public int getChangeType() {
        return mChanges.getChangeType();
    }
  
    public String getEventType() {
        return "";
    }
 
    //END INFEASIBLE
}