Updating an Apple Addressbook from an eduPerson Directory

If you work for a company that organize employee data in an open directory and uses a mac, you have probably already configured Apple Addressbook to lookup addresses from the directory, like this:

Then, what you can do is search for users:

Great, but not good enough. You can not list all users, and more importantly you cannot sync them to your iphone.

So I tried to investigate ways of directly importing all employees into the Addressbook. Luckily Addressbook supports importing data form a number of formats, including LDIF and vcards.

I started out with LDIF. Working almost perfect! One command to get the LDIF:

ldapsearch -x -L -h ldap.uninett.no -b cn=internal,cn=people,dc=uninett,dc=no 'eduPersonPrincipalName=*' > ansatte.ldif

In Apple Addressbook I choose import from LDIF:

What is really smooth here is that if you already have entries in your addressbook for some of these contacts, they will be merged with the updated information. You can review all the updated info to verify that it is correct:

Great, but not perfect. I want somehow to know the eduPersonPrincipalName of all users, and I want the jpegPhoto. For some reason I don’t think the LDIF import supports photo. But luckily the vCards import does.

I created a script that created vCards from the LDIF. Here it is:

#! /usr/bin/php
<?php
function pdump($sn, $givenName, $jpeg, $feide) {
    $jpeg  = preg_replace('/\s+/s', "   ", $jpeg);
    echo 'BEGIN:VCARD
VERSION:3.0
N:' . $sn . ';' . $givenName . ';;;
PHOTO;BASE64:
  ';
    echo $jpeg . "\n";
    echo 'NOTE: Feide ID is ' . $feide . "\n";
    echo 'CATEGORIES:All
END:VCARD
';
}

$adr = file_get_contents('/Users/andreas/ansatte.ldif');
$persons = explode('dn: ', $adr);


function findK($p, $key) {
    if(preg_match('/' . $key . ': (.*?)\n/', $p, $matches))
        return $matches[1];
    if(preg_match('/' . $key . ':: (.*?)\n/', $p, $matches))
        return base64_decode($matches[1]);
    throw new Exception('not found [' .  $key . ']');
}

foreach($persons AS $p) {
    try {       
        $sn = findK($p, 'sn');
        $givenName = findK($p, 'givenName');
        $feide = findK($p, 'eduPersonPrincipalName');       
        if(!preg_match('/jpegPhoto:: (.*?)\n([a-z][a-zA-Z]+:|\n)/s', $p, $matches)) 
            continue;
        $jpeg = $matches[1];
        pdump($sn, $givenName, $jpeg, $feide);
    } catch(Exception $e) { }
}

I ran the script from the command line:

./adr.php > uninett.vcf

In the script I populate full name (for merging), a note with eduPersonPrincipalName and the photo in base64.

The output file is in UTF-8, and Apple Addressbook expects vcards to be in UTF-16, so I used BBedit to convert the file.

Now, I import the vcards file in Apple Addressbook and get both photo and eduPersonPrincipalName merged into the cards imported from LDIF. Next, I syncronize my iPhone using MobileMe, and yay, now I see pictures of UNINETT employees when they call. And I can access eduPersonPrincipalNames from my phone as well, and the address and e-mail, and so on.

Leave a Reply