Synchronize Zimbra Mailboxes with Identity Manager 3.5.1

Synchronize Zimbra Mailboxes with Identity Manager 3.5.1

By Sylvain Maertchik

Problem:

The problem is to synchronize Zimbra mailboxes with Identity Manager 3.5.1. Zimbra architecture is not based on LDAP directory for the mailboxes management and the LDAP driver cannot make the job.

In the other hand, Zimbra provides a powerful command line called zmprov that performs almost all mailboxes management tasks. This command will be used with the subscriber channel of the scripting driver.

Solution:

For the publisher channel, we are also missing a kind of changelog on Zimbra side we could use to detect any event and its content. The following poll.sh example use a small script to update a text file when a new mailbox is created. Then we read the entries in the text file and we update the email address in eDirectory through the publisher channel.

A loopback driver is also used to update some special attributes like the ZimbraCosid required for Zimbra mailbox management.

Environment:

Identity Manager 3.5.1 is running on SLES10 sp1 and the Scripting Driver runs on Linux RedHat server.

Example:

Initial version of the Scripting driver does not work correctly and the idm351unixscripting1 patch must be applied. The latest idm351scriptdir5 patch was applied but removed because it gives some problems.

Here are the different script files used with the driver:

ADD.SH

#!/bin/sh
#
# DESCRIPTION company 16 oct 07 - sma
#
# This script implements the add command for the external Linux/UNIX
# application.
#
# The add command is an input command. The IDM engine sends an add command
# to the subscriber shim to request that the external application add an
# entry.
#
#
# VARIABLES
#
# SRC_DN
# Specifies the distinguished name of the entry to add, in the name space
# of eDirectory. When the IDM engine sends the add command, the subscriber
# should copy the SRC_DN attribute to the outgoing DEST_DN command.
#
# SRC_ENTRY_ID
# Specifies the entry ID of the entry that generated the add event. It is
# specified in the name space of eDirectory. When the IDM engine sends
# the add command, the subscriber should copy the SRC_ENTRY_ID attribute
# to the outgoing DEST_ENTRY_ID command.
#
# CLASS_NAME
# Specifies the base class of the entry being added.
#
# TEMPLATE_DN
# Specifies the distinguished name, in the subscriber's name space, of the
# template to use when creating the entry.
#
# EVENT_ID
# Specifies an identifier used to identify a particular instance of the
# command.
#
# ADD_<ATTR_NAME>
# Specifies an attribute name/value to add with the entry, where
# <ATTR_NAME> is literally replaced by the name of the attribute being
# added.
#
# PASSWORD
# Specifies the initial password for the entry.
#
#
# REPLY FORMAT
#
# The receiving application should respond to the add with a STATUS_LEVEL
# and if the add suceeded, the subscriber must also return an ASSOCIATION.
# Optionally, a STATUS_MESSAGE may also be returned to pass string messages
# to the IDM engine for processing and logging.
#
# If the add event does not contain values for all attributes defined in
# the create rules, the IDM engine discards the add command for the entry.
# When a modify command is received for this entry, IDM queries eDirectory
# for the missing attributes. If all attributes now have values, IDM
# changes the modify into an add command.
#
# The format for returning ASSOCIATION, DEST_DN, DEST_ENTRY_ID, EVENT_ID,
# STATUS, STATUS_MESSAGE are as follows:
#
# IDMSETVAR ASSOCIATION <association>
# IDMSETVAR DEST_DN <dest_dn>
# IDMSETVAR DEST_ENTRY_ID <dest_entry_id>
# IDMSETVAR EVENT_ID <event_id>
#
# STATUS_<LEVEL> "<optional message>"
#
# <LEVEL> may be one of the following values:
# * SUCCESS
# * WARNING
# * ERROR
# * RETRY
# * FATAL
#
# Note: FATAL will shutdown the driver, RETRY will retry the event
# later on.
#

# include the IDM Library
. $IDMLIB

LOGGER -p $TRACEPRIO " *** "`$BASENAME $0`" *** "
TRACE " *** "`$BASENAME $0`" *** "

CLASS_NAME=`IDMGETVAR CLASS_NAME`

# INSERT CUSTOM CODE HERE
#
# Retrieve additional information about the event and send back an
# association for this object along with a status document
#
#
CN=`IDMGETVAR "CN"`
ZDOMAIN="company.com"
FIRSTNAME=`IDMGETVAR "Firstname"`
SURNAME=`IDMGETVAR "Surname"`
TITLE=`IDMGETVAR "Title"`
TELEPHONE=`IDMGETVAR TelephoneNumber`
SRC_DN=`IDMGETVAR "SRC_DN"`
DESTDNCLEAN=`echo $SRC_DN | cut -d '\' -f 1,3,5,7,9,11,13,15,17,19`
PASSWORD=`IDMGETVAR PASSWORD`
ZIMBRACOSID=`IDMGETVAR zimbraCOSid`
FULLNAME=`IDMGETVAR Fullname`
DESCRIPTION=`IDMGETVAR Description`

if [ -z "$CLASS_NAME" -o -z "$CN" ]; then
STATUS_ERROR "Add event: missing CLASS_NAME and/or CN"
else
if [ "$CLASS_NAME" = "User" ]; then
COMMAND="su - zimbra -c \"zmprov createAccount $CN@$ZDOMAIN $PASSWORD gn '$FIRSTNAME' sn '$SURNAME' title '$TITLE' description '$TITLE' zimbraCOSId $ZIMBRACOSID telephoneNumber '$TELEPHONE' zimbraPrefCalendarFirstDayOfWeek 1 displayName '$FULLNAME' zimbraPrefMailSignatureEnabled TRUE zimbraPrefMailSignatureStyle outlook\""
EXEC $COMMAND
RC=$?
if [ $RC -eq 0 ]; then
IDMSETVAR "COMMAND" "ADD_ASSOCIATION"
IDMSETVAR "CLASS_NAME" $CLASS_NAME
IDMSETVAR "ASSOCIATION" "$CN@$ZDOMAIN"
IDMSETVAR "DEST_DN" $DESTDNCLEAN
IDMSETVAR "ATTR_CN" $CN
IDMSETVAR "SRC_DN" $SRC_DN
COMMAND2="echo $CN@$ZDOMAIN >> newuser.txt"
EXEC $COMMAND2
STATUS_SUCCESS "Add User event succeed for user $CN"
else
STATUS_ERROR "Add event failed with error code $RC"
fi
# We are now creating Distribution List
elif [ "$CLASS_NAME" = "Group" ]; then
COMMAND="su - zimbra -c \"zmprov createDistributionList $CN@$ZDOMAIN description '$DESCRIPTION'\""
EXEC $COMMAND
RC=$?
if [ $RC -eq 0 ]; then
IDMSETVAR "COMMAND" "ADD_ASSOCIATION"
IDMSETVAR "ASSOCIATION" "$CN@$ZDOMAIN"
IDMSETVAR "DEST_DN" $DESTDNCLEAN
STATUS_SUCCESS "Add Group event succeed for group $CN"
else
STATUS_ERROR "Add event failed with error code $RC"
fi
else
STATUS_WARNING " end of add event for $CN"
fi
fi

# For the skeleton script, simply return a "Not Implemented" status
#STATUS_WARNING "Not Implemented"

================================================


DELETE.SH

#!/bin/sh
#
# DESCRIPTION company 17 dec 07 - sma
#
# This script implements the delete command for the external Linux/UNIX
# application.
#
# The delete command is an input command. The IDM engine sends the delete
# command to the subscriber to request that the external application delete
# an entry. The delete command must contain an ASSOCIATION element.
#
#
# VARIABLES
#
# SRC_DN
# Specifies the distinguished name of the entry to delete, in the name
# space of eDirectory.
#
# DEST_DN
# Spceifies the distinguished name of the entry in the name space of the
# receiver.
#
# DEST_ENTRY_ID
# Spceifies the entry ID for the entry in the name space of the receiver.
#
# CLASS_NAME
# Specifies the base class of the entry being deleted.
#
# EVENT_ID
# Specifies an identifier used to identify a particular instance of the
# command.
#
# ASSOCIATION
# Specifies the unique identifier for the entry in the external application.
#
#
# REPLY FORMAT
#
# The receiving application should respond to the modify with a STATUS
# and an optional STATUS_MESSAGE which can be returned for IDM engine
# processing and logging facilities.
#
# The format for returning STATUS and STATUS_MESSAGE are as follows:
#
# STATUS_<LEVEL> "<optional message>"
#
# <LEVEL> may be one of the following values:
# * SUCCESS
# * WARNING
# * ERROR
# * RETRY
# * FATAL
#
# Note: FATAL will shutdown the driver, RETRY will retry the event
# later on.
#


# include the IDM Library
. $IDMLIB

LOGGER -p $TRACEPRIO " *** "`$BASENAME $0`" *** "
TRACE " *** "`$BASENAME $0`" *** "

SCR_DN=`IDMGETVAR SRC_DN`
CLASS_NAME=`IDMGETVAR CLASS_NAME`
ASSOCIATION=`IDMGETVAR "ASSOCIATION"`
ZDOMAIN="company.com"
NEWDOMAIN="company.test"
TODAY=`date +%Y%m%d`
CN=`echo $ASSOCIATION| cut -d@ -f1`

# INSERT CUSTOM CODE HERE
#
# Retrieve additional information about the event and send back a
# status document indicating the level of success for this delete.
#
if [ "$CLASS_NAME" = "User" ]; then
COMMAND="su - zimbra -c \"zmprov modifyAccount $ASSOCIATION zimbraAccountStatus closed\""
COMMAND1="su - zimbra -c \"zmprov renameAccount $ASSOCIATION $CN"_"$TODAY@$NEWDOMAIN\""
EXEC $COMMAND
EXEC $COMMAND1
RC=$?
if [ $RC -eq 0 ]; then
STATUS_SUCCESS " User $ASSOCIATION renamed to $CN"_"$TODAY@$NEWDOMAIN on zimbra"
else
STATUS_ERROR " User $ASSOCIATION could not be rename"
fi
fi
if [ "$CLASS_NAME" = "Group" ]; then
COMMAND="su - zimbra -c \"zmprov deleteDistributionList $ASSOCIATION\""
EXEC $COMMAND
RC=$?
if [ $RC -eq 0 ]; then
STATUS_SUCCESS " Group $ASSOCIATION deleted on zimbra"
else
STATUS_WARNING " Group $ASSOCIATION could not be deleted"
fi
fi
# For the skeleton script, simply return a "Not Implemented" status
#STATUS_WARNING "Not Implemented"


================================================



MODIFIY.SH

#!/bin/sh
#
# DESCRIPTION company 16 oct 07 - sma
#
# This script implements the modify command for the external Linux/UNIX
# application.
#
# The modify command is an input command. The IDM engine sends a modify
# command to the subscriber to request that the external application modify
# an entry. The modify command must contain an ASSOCIATION element.
#
#
# VARIABLES
#
# SRC_DN
# Specifies the distinguished name of the entry to modify in the name
# space of eDirectory.
#
# CLASS_NAME
# Specifies the base class of the entry being modified. This attribute
# is required for modify events.
#
# EVENT_ID
# Specifies an identifier to identify a particular instance of the command.
#
# ASSOCIATION
# Specifies the unique identifier for the entry in the external
# application. This element is required for modify events.
#
# ADD_<ATTR_NAME>
# Specifies one or more values to add to <ATTR_NAME>, where <ATTR_NAME> is
# literally replaced by the name of the attribute being modified.
#
# REMOVE_<ATTR_NAME>
# Specifies one or more values to remove to <ATTR_NAME>, where <ATTR_NAME>
# is literally replaced by the name of the attribute being modified.
#
# REMOVE_ALL_<ATTR_NAME>
# Instructs to remove all values associated with <ATTR_NAME>, where
# <ATTR_NAME> is literally replaced by the name of the attribute being
# modified.
#
#
# REPLY FORMAT
#
# The receiving application should respond to the modify with a STATUS
# and an optional STATUS_MESSAGE which can be returned for IDM engine
# processing and logging facilities.
#
# The format for returning STATUS and STATUS_MESSAGE are as follows:
#
# STATUS_<LEVEL> "<optional message>"
#
# <LEVEL> may be one of the following values:
# * SUCCESS
# * WARNING
# * ERROR
# * RETRY
# * FATAL
#
# Note: FATAL will shutdown the driver, RETRY will retry the event
# later on.
#

# include the IDM Library
. $IDMLIB

LOGGER -p $TRACEPRIO " *** "`$BASENAME $0`" *** "
TRACE " *** "`$BASENAME $0`" *** "

ASSOCIATION=`IDMGETVAR ASSOCIATION`
CLASS_NAME=`IDMGETVAR CLASS_NAME`
ADDTITLE=`IDMGETVAR ADD_Title`
ADDFIRSTNAME=`IDMGETVAR ADD_Firstname`
ADDSURNAME=`IDMGETVAR ADD_Surname`
ZIMBRACOSID=`IDMGETVAR ADD_zimbraCOSid`
ADDTELEPHONE=`IDMGETVAR ADD_TelephoneNumber`
ADDFULLNAME=`IDMGETVAR ADD_Fullname`
ZDOMAIN="company.com"

# INSERT CUSTOM CODE HERE
# Retrieve additional information about the event and send back a
# status document indicating the level of success for this modify.
#
if [ "$CLASS_NAME" = "User" ]; then
REMMEMBERS=`IDMGETVAR REMOVE_REF_Groupmembership`
ADDMEMBERS=`IDMGETVAR ADD_REF_Groupmembership`
if [ -n "$ADDTITLE" ]; then
COMMAND="su - zimbra -c \"zmprov modifyAccount $ASSOCIATION Title '$ADDTITLE' description '$ADDTITLE'\""
EXEC $COMMAND
elif [ -n "$ZIMBRACOSID" ]; then
COMMAND="su - zimbra -c \"zmprov setAccountCOS $ASSOCIATION $ZIMBRACOSID\""
EXEC $COMMAND
elif [ -n "$ADDFIRSTNAME" ]; then
COMMAND="su - zimbra -c \"zmprov modifyAccount $ASSOCIATION givenName '$ADDFIRSTNAME'\""
EXEC $COMMAND
elif [ -n "$ADDSURNAME" ]; then
COMMAND="su - zimbra -c \"zmprov modifyAccount $ASSOCIATION sn '$ADDSURNAME'\""
EXEC $COMMAND
elif [ -n "$ADDFULLNAME" ]; then
COMMAND="su - zimbra -c \"zmprov modifyAccount $ASSOCIATION displayName '$ADDFULLNAME'\""
EXEC $COMMAND
elif [ -n "$ADDTELEPHONE" ]; then
COMMAND="su - zimbra -c \"zmprov modifyAccount $ASSOCIATION telephoneNumber '$ADDTELEPHONE'\""
EXEC $COMMAND
elif [ -n "$REMMEMBERS" ]; then
COMMAND="su - zimbra -c \"zmprov removeDistributionListMember $REMMEMBERS $ASSOCIATION\""
EXEC $COMMAND
RC=$?
if [ $RC -eq 0 ]; then
STATUS_SUCCESS " Modify : Distibution list $REMMEMBERS member $ASSOCIATION removed"
else
STATUS_ERROR " Modifiy : Error modifying list $REMMEMBERS"
fi
elif [ -n "$ADDMEMBERS" ]; then
COMMAND="su - zimbra -c \"zmprov addDistributionListMember $ADDMEMBERS $ASSOCIATION\""
EXEC $COMMAND
RC=$?
if [ $RC -eq 0 ]; then
STATUS_SUCCESS " Modify : Distibution list $ADDMEMBERS member $ASSOCIATION added"
else
STATUS_ERROR " Modifiy : Error modifying list $ADDMEMBERS"
fi
fi
fi
if [ "$CLASS_NAME" = "Group" ]; then
REMMEMBERS=`IDMGETVAR REMOVE_REF_Member`
ADDMEMBERS=`IDMGETVAR ADD_REF_Member`
if [ -n "$ADDMEMBERS" ]; then
for ADDMEMBER in $ADDMEMBERS; do
STATUS_SUCCESS " Distibution list $ASSOCIATION member $ADDMEMBER modification already made for class user"
done
elif [ -n "$REMMEMBERS" ]; then
for REMMEMBER in $REMMEMBERS; do
STATUS_SUCCESS " Distrbution list $ASSOCIATION member $REMMEMBER modification already made for class user"
done
fi
fi
# For the skeleton script, simply return a "Not Implemented" status
#STATUS_WARNING "Not Implemented"

==================================================


POLL.SH

#!/bin/sh
#

if [ -z "$INSTALL_PATH" ]
then
# cannot determine the installation path
printf "**Error: Unable to continue without an installation path\n"
exit 255
fi

# include the IDM Library
. ${INSTALL_PATH}/scripts/idmlib.sh

SCRIPT_DIR=${INSTALL_PATH}scripts/; export SCRIPT_DIR;

# call out to globals script
. $INSTALL_PATH/scripts/globals.sh

# log a message to the system log
LOGGER -p $TRACEPRIO " **** "`$BASENAME $0`" *** "


#
# Insert custom code here to poll for events and submit
# them to the change log, using the $CHANGELOG tool
FILENAME=newuser.txt
FILENAME1=renameuser.txt

#check is file newuser not empty
test -s $FILENAME
rc=$?
if [ $rc -eq 0 ]; then
NEWUSER=`tail -1 $FILENAME`
/opt/novell/usdrv/bin/usclh -t modify -c User -a $NEWUSER <<EOF
ADD_Emailaddr=$NEWUSER
EOF
mv $FILENAME newuser1.txt
sed '$d' newuser1.txt > $FILENAME
else
rm -f newuser1.txt
fi

==================================================



QUERY.SH


#!/bin/sh
#
# DESCRIPTION company le 16 oct 07 - sma
#
# This script implements the query for the external application, Linux/UNIX.
#
# The query command is an input command or event. A query is used to find
# and read information about entries in the external application, therefore
# it is both a "search" and a "read" operation.
#
#
# VARIABLES
#
# SCOPE
# Specifies the extent of the search. This attribute supports
# the following values:
# * subtree - indicates to search the base entry and all entries
# in its branch of the directory tree. If no scoope is specified,
# subtree is used as the default value.
# * subordinates - indicates to search the immediate subordinates of
# the base entry (the base entry is not searched).
# * entry - indicates to search just the base entry.
# For scopes other than entry, the selected entries can be further
# limited by the SEARCH_CLASSES and SEARCH_ATTR_ elements. For scopes of
# entry, the SEARCH_CLASSES and SEARCH_ATTR_ elements are ignored.
#
# DEST_DN
# Specifies the distinguished name for the starting point for the search.
# If both the DEST_DN attribute and ASSOCIATION have values, the
# ASSOCIATION value is used as the starting point for the search. If
# neither have values, the search begins at the root of the directory.
#
# CLASS_NAME
# Specififes the base class of the DEST_DN attribute.
#
# EVENT_ID
# Specifies an identifier used to identify a particular instance of the
# command or event.
#
# ASSOCIATION
# Specifies the unique identifier for the entry where the search begins.
# If both the DEST_DN attribute and the ASSOCIATION have values, the
# ASSOCIATION value is used as the starting point for the search. If
# neither have values, the search begins at the root of the directory.
#
# SEARCH_CLASSES
# Specifies the search filter for object classes. If the query contains no
# SEARCH_CLASSES elements, all entries matching the scope and the
# SEARCH_ATTR_ elements are returned.
#
# SEARCH_ATTRS
# Contains a list of the SEARCH_ATTR_ attribute names.
#
# SEARCH_ATTR_<ATTR_NAME>
# Specifies the search filter for attribute values. If more than one
# SEARCH_ATTR_ element is specified, the entry must match all attributes
# to be returned.
#
# <ATTR_NAME> will be replaced by the literal name of the attribute,
# upper-cased and non-printable characters converted to underscores.
#
# READ_ATTRS
# Specifies which attribute values are returned with entries that match
# the search filters.
#
# ALL_READ_ATTRS
# Specifies that all readable attributes should be returned.
#
# NO_READ_ATTRS
# Specifies that no attributes are to be returned.
#
# READ_PARENT
# Specifies whether the parent of the entry is returned with the entry.
#
#
# REPLY FORMAT
#
# The receiving application should respond to the query with an INSTANCE
# command for each entry returned. The response should also include a
# status indicating whether the query was processed successfully.
# A query should return a successful status even when no entries exist
# that match the search criteria.
#
# The format for the INSTANCE command is as follows:
#
# RETVAR COMMAND INSTANCE (zero or more)
# RETVAR CLASS_NAME class-name (mandatory)
# RETVAR SRC_DN src-dn (optional)
# RETVAR ASSOCIATION association (optional)
# RETVAR PARENT parent (optional)
# RETVAR ATTR_attribute value (zero or more)
#
# The format for returning STATUS and STATUS_MESSAGE are as follows:
#
# STATUS_<LEVEL> "<optional message>"
#
# <LEVEL> may be one of the following values:
# * SUCCESS
# * WARNING
# * ERROR
# * RETRY
# * FATAL
#
# Note: FATAL will shutdown the driver, RETRY will retry the event
# later on.
#

# include the IDM Library
. $IDMLIB

LOGGER -p $TRACEPRIO " *** "`$BASENAME $0`" *** "
TRACE " *** "`$BASENAME $0`" *** "

# retrieve information from the query event
SCOPE=`IDMGETVAR SCOPE`
ZDOMAIN="company.com"
CLASS_NAME=`IDMGETVAR "CLASS_NAME"`;export CLASS_NAME
ASSOCIATION=`IDMGETVAR "ASSOCIATION"`; export ASSOCIATION
DEST_DN=`IDMGETVAR "DEST_DN"`; export DEST_DN
SEARCH_CLASSES=`IDMGETVAR "SEARCH_CLASSES"`; export SEARCH_CLASSES
CN=`IDMGETVAR "SEARCH_ATTR_CN"`;export CN
EVENT_ID=`IDMGETVAR "EVENT_ID"`


if [ "$SCOPE" = "entry" ]; then
# entry scope queries ask about a particular object
# check for an association, if the object has already
# been associated
SEARCH_BASE=""
if [ -n "$ASSOCIATION" ]; then
# the association was created by the scripts and should
# be sufficient in determining this particular object's
# class type (CLASS_NAME).
# the search base for our query is the association for
# the sample skeleton scripts
SEARCH_BASE=$ASSOCIATION;
else
# without an association, we can use the DEST_DN field to
# determine the search base for our query
SEARCH_BASE="$DEST_DN@$ZDOMAIN";
fi
# now we should have a search base determined
if [ -n "$SEARCH_BASE" ]; then
STATUS_WARNING " search base : $SEARCH_BASE"
CN=`echo $SEARCH_BASE | cut -d '@' -f 1`
# INSERT CUSTOM CODE HERE
if [ "$CLASS_NAME" = "User" ]; then
COMMAND="su - zimbra -c \"zmprov getAccount $SEARCH_BASE \""
EXEC $COMMAND
RC=$?
if [ $RC -eq 0 ]; then
# We have found a user
# Read the object $SEARCH_BASE which identifies the object
# name we're interested in reading. Create an association
# string for this object that can be used to uniquely identify
# the object.
#
# If the object is found, return:
IDMSETVAR "COMMAND" "INSTANCE"
IDMSETVAR "SRC_DN" $SEARCH_BASE
IDMSETVAR "CLASS_NAME" $CLASS_NAME
IDMSETVAR "ASSOCIATION" $SEARCH_BASE
IDMSETVAR "ATTR_CN" $CN
IDMSETVAR "ATTR_Emailaddr" $SEARCH_BASE
STATUS_SUCCESS "Association created for user $DEST_DN"
else
STATUS_WARNING "$CLASS_NAME does not exist, we create it"
fi
elif [ "$CLASS_NAME" = "Group" ]; then
STATUS_WARNING "class name = $CLASS_NAME CN = $CN SEARCHBASE = $SEARCH_BASE"
COMMAND="su - zimbra -c \"zmprov getDistributionList $SEARCH_BASE \""
EXEC $COMMAND
RC=$?
if [ $RC -eq 0 ]; then
# We have found a user
# Read the object $SEARCH_BASE which identifies the object
# name we're interested in reading. Create an association
# string for this object that can be used to uniquely identify
# the object.
#
# If the object is found, return:
IDMSETVAR "COMMAND" "INSTANCE"
IDMSETVAR "SRC_DN" $SEARCH_BASE
IDMSETVAR "CLASS_NAME" $CLASS_NAME
IDMSETVAR "ASSOCIATION" $SEARCH_BASE
IDMSETVAR "ATTR_CN" $CN
STATUS_SUCCESS "Association created for group $DEST_DN"
else
STATUS_WARNING " $CLASS_NAME does not exist , we go to creation rule"
fi
fi
# check for which attributes to return (read)
#ALL_READ_ATTRS=`IDMGETVAR "ALL_READ_ATTRS"`
#if [ "$ALL_READ_ATTRS" = "true" ]; then
# return all attributes that can be read
# TOFILL="just to fill the line"
# INSERT CUSTOM CODE HERE
#else
# return only those attributes which are requested
# READ_ATTRS=`IDMGETVAR "READ_ATTRS"`
# IFS=,
# for READ_ATTR in $READ_ATTRS; do
#
# INSERT CUSTOM CODE HERE
# INSERT CUSTOM CODE HERE
# if [ "$READ_ATTR" = "Emailaddr" ]; then
# IDMSETVAR "ATTR_Emailaddr" $SEARCH_BASE
# elif [ "$READ_ATTR" = "GIVEN NAME" ]; then
# IDMSETVAR "ATTR_Givenname" $GIVENAME
# fi
#done
#fi
#else
# No class name user
STATUS_WARNING " class_name = $CLASS_NAME"
#fi
else
# No search base could be made
STATUS_ERROR "Could not derive a search base"
fi
else
STATUS_WARNING " just to fill the line"
# subtree or subordinate query
#IFS=,
#export IFS
#for SEARCH_CLASS in $SEARCH_CLASSES; do
# INSERT CUSTOM CODE HERE
#
# Search for the object defined by this particular
# SEARCH_CLASS and SEARCH_ATTRS. Return zero or more
# instances along with a status document indicating the
# level of success.
#
# retrieve the search attributes/values to search on
# SEARCH_ATTR_attr1=`IDMGETVAR "SEARCH_ATTR_attr1"`
# SEARCH_ATTR_attr2=`IDMGETVAR "SEARCH_ATTR_attr2"`
# For each entry that matches, return an instance document:
#
#IDMSETVAR"COMMAND" "instance"
#IDMSETVAR "EVENT_ID" $EVENT_ID
#IDMSETVAR "SRC_DN" $SEARCH_BASE
#IDMSETVAR "CLASS_NAME" $CLASS_NAME
#IDMSETVAR "ASSOCIATION" $ASSOCIATION
#
# with each instance document, return all read attrs that were
# requested by the query:
# check for which attributes to return (read)
#ALL_READ_ATTRS=`IDMGETVAR "ALL_READ_ATTRS"`
#if [ "$ALL_READ_ATTRS" = "true" ]; then
# return all attributes that can be read
#
# INSERT CUSTOM CODE HERE
STATUS_WARNING " scope: $SCOPE readattr: $READ_ATTR"
#IDMSETVAR "ATTR_attr1" "value1"
#IDMSETVAR "ATTR_attr2" "value2"
#else
# return only those attributes which are requested
# for READ_ATTR in $READ_ATTRS; do
#
# INSERT CUSTOM CODE HERE
#
# if [ "$READ_ATTR" eq "attr1" ]; then
# IDMSETVAR "ATTR_attr1" "value1"
# elif [ "$READ_ATTR" = "attr2" ]; then
# IDMSETVAR "ATTR_attr1" "value1"
# fi
# done
# fi
#done
#IFS=$IFSSAVE; export IFS
fi

# For the skeleton script, simply return a "Not Implemented" status
#STATUS_WARNING "Not Implemented"

==================================================



RENAME.SH

#!/bin/sh
#
# DESCRIPTION company 18 dec 07 - sma
#
# This script implements the rename command for the external Linux/UNIX
# application.
#
# The rename command is an input command. It renames the entry; it cannot
# move an entry from one container to another in a hierarchical database.
# The IDM engine sends the rename command to the subscriber to request
# that the external application rename an entry. The rename command must
# contain an ASSOCIATION element.
#
#
# VARIABLES
#
# SRC_DN
# Specifies the distinguished name of the entry in the name space of
# eDirectory.
#
# OLD_SRC_DN
# Spceifies the old distinguished name of the entry in the name space of
# eDirectory.
#
# REMOVE_OLD_NAME
# Specifies whether the old relative distinguished name should be deleted
# or retained. If not specififed, defaults to "true" which removes the
# old name.
#
# CLASS_NAME
# Specifies the base class of the entry being moved.
#
# EVENT_ID
# Specifies an identifier used to identify a particular instance of the
# command.
#
# ASSOCIATION
# Specifies the unique identifier for the entry in the external application.
#
# NEW_NAME
# Specifies the new relative distinguished name for the entry.
#
#
# REPLY FORMAT
#
# The receiving application should respond to the modify with a STATUS
# and an optional STATUS_MESSAGE which can be returned for IDM engine
# processing and logging facilities.
#
# The format for returning STATUS and STATUS_MESSAGE are as follows:
#
# STATUS_<LEVEL> "<optional message>"
#
# <LEVEL> may be one of the following values:
# * SUCCESS
# * WARNING
# * ERROR
# * RETRY
# * FATAL
#
# Note: FATAL will shutdown the driver, RETRY will retry the event
# later on.
#

# include the IDM Library
. $IDMLIB

LOGGER -p $TRACEPRIO " *** "`$BASENAME $0`" *** "
TRACE " *** "`$BASENAME $0`" *** "

CLASS_NAME=`IDMGETVAR CLASS_NAME`
ASSOCIATION=`IDMGETVAR ASSOCIATION`
CN=`IDMGETVAR CN`
SRC_DN=`IDMGETVAR SRC_DN`
DESTDNCLEAN=`echo $SRC_DN | cut -d '\' -f 1,3,5,7,9,11,13,15,17,19`
NEWNAME=`echo $DESTDNCLEAN | rev | cut -d '\' -f1 | rev`
ZDOMAIN="company.com"

# INSERT CUSTOM CODE HERE
#
# Retrieve additional information about the event and send back a
# status document indicating the level of success for this modify.
#
if [ "$CLASS_NAME" = "User" ]; then
COMMAND="su - zimbra -c \"zmprov renameAccount $ASSOCIATION $NEWNAME@$ZDOMAIN\""
EXEC $COMMAND
RC=$?
if [ $RC -eq 0 ]; then
STATUS_SUCCESS " User $ASSOCIATION renamed to $NEWNAME@$ZDOMAIN on zimbra"
IDMSETVAR "COMMAND" "MODIFY_ASSOCIATION"
IDMSETVAR "ASSOCIATION" "$ASSOCIATION"
IDMSETVAR "ASSOCIATION" "$NEWNAME@$ZDOMAIN"
IDMSETVAR "DEST-DN" "$DESTDNCLEAN"
COMMAND1="echo $NEWNAME@$ZDOMAIN >> newuser.txt"
EXEC $COMMAND1
else
STATUS_ERROR " User $ASSOCIATION could not be renamed"
fi
fi


# For the skeleton script, simply return a "Not Implemented" status
#STATUS_WARNING "Not Implemented"

==================================================



SCHEMA.DEF

##############################################################################
# Linux/UNIX Driver Schema File
#
# Uses the RFC2307 Unix Profile schema
# company 16 octobre 07 - sma
# Syntax:
# SCHEMA [HIERARCHICAL]
#
# HIERARCHICAL defines whether the schema has a hierarchy.
# Default is false.
#
# CLASS <class-name> [CONTAINER]
#
# CONTAINER defines whether the class is a container class.
# Default is false.
#
# ATTRIBUTE <attribute-name> [CASESENSITIVE] [MULTIVALUED] [NAMING]
# [READONLY] [REQUIRED] [STRING] [INTEGER]
# [STATE] [DN]
#
# CASESENSITIVE defines this attribute to be case sensitive.
# Default is false.
#
# MULTIVALUED defines this attribute to be multivalue.
# Default is false.
#
# NAMING defines this attribute as the class naming attribute.
# Default is false.
#
# READONLY defines this attribute to be read-only.
# Default is false.
#
# REQUIRED defines this attribute to be required for class definition.
# Default is false.
#
# STRING defines this attribute to be of type string.
# String is the default type.
#
# INTEGER defines this attribute to be of type integer.
# String is the default type.
#
# STATE defines this attribute to be of type Boolean (TRUE or FALSE)
# String is the default type.
#
# DN defines this attribute to be a distinguished name (referential)
# String is the default type.
#
##############################################################################

SCHEMA

CLASS User

ATTRIBUTE CN NAMING REQUIRED
ATTRIBUTE Surname
ATTRIBUTE Firstname
ATTRIBUTE Title
ATTRIBUTE Emailaddr
ATTRIBUTE Groupmembership MULTIVALUED
ATTRIBUTE TelephoneNumber
ATTRIBUTE Fullname

CLASS Group

ATTRIBUTE CN NAMING REQUIRED
ATTRIBUTE Member MULTIVALUED
ATTRIBUTE Description
===============================================


DISCLAIMER:

Some content on Community Tips & Information pages is not officially supported by Micro Focus. Please refer to our Terms of Use for more detail.
Comments
The article does not name what each file should be called. It is easy to guess in most cases, but would be nice to label them.

Also, could you please attach the scripts as files to the article to make it easier to download?

Could you attach a driver export of your Scripting driver/Loopback driver to show the rules you used to process the events, once th
A pdf files with schema is included that describres the data flow and architecture.
Looking over the pdf in your zip file we see how the data should flow however we will have some questions. Is it possible to get an export of the drivers you have working?
Hello,

The Scripting driver is the default imported driver as everything is managed through the shell scripts published in this bulletin.

The Loopback driver has nothing special in it as it only updates needed attributes on manual events. You could look at this coolsolution if you need more informations about the loopback driver :

Using the loopback driver :

http://www.novell.com/coolsolutions/tip/8631.html

thanks
Top Contributors
Version history
Revision #:
1 of 1
Last update:
‎2008-06-19 00:46
Updated by:
 
The opinions expressed above are the personal opinions of the authors, not of Micro Focus. By using this site, you accept the Terms of Use and Rules of Participation. Certain versions of content ("Material") accessible here may contain branding from Hewlett-Packard Company (now HP Inc.) and Hewlett Packard Enterprise Company. As of September 1, 2017, the Material is now offered by Micro Focus, a separately owned and operated company. Any reference to the HP and Hewlett Packard Enterprise/HPE marks is historical in nature, and the HP and Hewlett Packard Enterprise/HPE marks are the property of their respective owners.