Sun Java System Identity Synchronization for Windows 6.0 Deployment Planning Guide

Periodic idsync resync Operation for Primary Installation

As Global Telco uses Identity Manager to provision users and has not configured Identity Synchronization for Windows to synchronize the creation of new users, idsync resync must be run periodically to establish links between recently created users. If these users are not linked, then modifications to their passwords will not synchronize. Running a full idsync resync operation for 500 thousand users could take a few hours because synchronization of new changes is delayed during a idsync resync operation. It is unacceptable to have Identity Synchronization for Windows off-line for so long, so Global Telco uses Active Directory's usnCreated attribute to synchronize only those users that have been created recently. They use the resync-recent.pl script given below, which is run every hour, to synchronize users that have been created in the last three days. This script is run over users created in the last three days instead of only the last hour because a new employee might not have a Directory Server account until a few days after the Active Directory account is created.

The script is run periodically with the following arguments, using cron:

resync-recent.pl ad1-us.gt.com usnCreated 
-f /var/opt/SUNWisw/samples/linkusers-simple-gt.cfg 
-i NEW_LINKED_USERS -b -w - -q - < /var/opt/SUNWisw/passwords

The first argument is the name of the Active Directory domain controller that the connector communicates with, the second argument determines whether the idsync resync command should be only run on entries that were created recently, and the remaining arguments are passed directly to resync. In this case, the Directory Server password is reset for all users that are newly linked. The - value used for the two password options directs the idsync resync command to read the values from STDIN; it prevents passwords from appearing in the command line and being available to anyone on the system via commands such as ps. The configuration directory password and the configuration password are written to /var/opt/SUNWisw/passwords, and this file is then protected with the strictest file system permissions.


            
resync-recent.pl script:
#!/usr/bin/perl

# This sample script shows how to run idsync resync only on users
# that have changed recently and can be used to reduce the
 # impact of running resync frequently.  By default it
 # only resync's users that were modified or created in
 # the last three days.  The script stores a daily history
 # of Active Directory's highestCommittedUSN attribute.
  #
# The arguments of the command are
#
   #  <Active Directory-domain-controller-name\>
 #  (usnChanged|usnCreated)
#  [args-for-resync]
#
# To link users that were created recently run the command
#  ad.example.com usnCreated -k -f link.cfg -q <pw\> -q <pw\>
#
# To synchronize all users that were modified recently
#  ad.example.com usnChanged -q <pw\> -q <pw\>
#
 # To prime the object cache for users that were modified recently
#  ad.example.com usnChanged -u -q <pw\> -q <pw\>
#
 # NOTE: this script is only provided as a guide.
# It must be adapted to the specific Identity
 # Synchronization for Windows environment by
 # changing the paths and options below as appropriate
# and adding additional error handling code.
#
my $USAGE = "USAGE: resync-recent.pl “.
    “<Active Directory-domain-controller-name\> ".
    "(usnChanged|usnCreated) [args-for-resync]\\n";

my $IDSYNC = "/opt/SUNWisw/bin/idsync";
my $USN_FILE = "/opt/SUNWisw/bin/usnHistory";
my $MAX_DAYS_HISTORY = 3;

         

#
# SCRIPT BEGIN
#

#
# Argument parsing
#
my $adDomainController = shift @ARGV or die "$USAGE";
my $usnSearchAttr = shift @ARGV or die "$USAGE";
$usnSearchAttr =~ /usnChanged/i or
     $usnSearchAttr =~ /usnCreated/i or
    die "$USAGE\\n";
my $resyncArgs = getArgsAsString(@ARGV);

#
# Read the highestCommittedUSN history and add today's
# date to it if not it's there and then write the history
# out.
#
my %usnHistory = readUsnHistory();
my $today = getCurrentDate();
if (!$usnHistory{$today}) {
    $usnHistory{$today} = getHighestUsn($adDomainController);
}
writeUsnHistory(%usnHistory);

#
# Run the resync command based on the oldest usnChanged
# value in the history.
#
my $oldestUsn = getOldestUsn(%usnHistory);
my $filter = "($usnSearchAttr\>=$oldestUsn)";
my $resyncCmd = "$IDSYNC resync -a \\"$filter\\" $resyncArgs";
print "Running $resyncCmd\\n";
system($resyncCmd);

#
# SCRIPT END
#

         

#
# Return the current date as a string, e.g. 2004/03/04
#
sub getCurrentDate {
    my ($day, $month, $year) = (localtime(time))[3,4,5];
    $month++;
    $year += 1900;
    return sprintf "%d/%02d/%02d", $year, $month, $day;
}
#
# Searches the root DSE at the specified host and returns
# the highestCommittedUSN value.
#
sub getHighestUsn {
    my $adHost = shift @_;
    my $cmd = "ldapsearch -h $adHost -b \\"\\" -s base ".
        "\\"(objectclass=*)\\" highestCommittedUSN | ".
        "grep highestCommittedUSN | sed \\"s/[^0-9]//g\\"";
    my $highestUsn = '$cmd';
    chomp $highestUsn;
    print "highestCommittedUSN at $adHost is $highestUsn.\\n";
    return $highestUsn;
}

#
# Converts the command line args into a string.
#
sub getArgsAsString {
    my $args = "";
    for my $arg (@_) {
        $args .= " \\"$arg\\"";
    }
    return $args;
}

#
# Returns the oldest usnChanged value from the history.
#
sub getOldestUsn {
    my %usnHistory = @_;

         

    my @dates = getHistoryDates(%usnHistory);

        # Return the last element.
    return $usnHistory{$dates[$#dates]};
}

#
# Return a sorted list of the dates in the history.
#
sub getHistoryDates {
    my %history = @_;
    return reverse sort(keys %usnHistory);
}

#
# Writes the most recent daily history of highestCommittedUSN.
# No more than $MAX_DAYS_HISTORY days history is recorded.
#
sub writeUsnHistory {
    my %usnHistory = @_;
    if (!open(OUT, "\>$USN_FILE")) {
        print STDERR "Could not open $USN_FILE for writing.\\n";
        return;
    }

        # Write the history up to the last $MAX_DAYS_HISTORY days.
    my @dates = getHistoryDates(%usnHistory);
    for (my $i = 0;
         $i <= $#dates and $i < $MAX_DAYS_HISTORY;
         $i++)
     {
        my $date = $dates[$i];
        print OUT "$date:$usnHistory{$date}\\n";
            }

    close(OUT);
}

#
# Reads the daily history of highestCommittedUSN
#

         

sub readUsnHistory {
    my %usnHistory = ();
    if (!open(IN, "<$USN_FILE")) {
        print STDERR "Could not read history from $USN_FILE.\\n";
        return %usnHistory;
    }

    while (my $line = <IN\>) {
        chomp $line;
        my ($date, $usn) = split /:/, $line;
        $usnHistory{$date} = $usn;
    }
    close(IN);

    return %usnHistory
}

         

An alternative to running resync periodically is to modify the provisioning process to set the necessary link information when the Directory Server entry is provisioned. The process is straightforward: