Importing Contacts from Thunderbird Addressbook into LDAP

1) As described in the previous post – Setting up LDAP (slapd) on Mac OS X (non-server edition) – you need to download mozillaOrgPerson.schema and reference it on slapd.conf. This page describes the process:

http://applications.linux.com/applications/05/05/18/1248224.shtml?tid=37

along with the following instructions

2) Before you do an export, I would advise creating a dummy contact in your address book, and filling in every field with a message that echoes that field’s name – for instance First Name: “myFirstName”, Last Name: “myLastName” etc, etc. This will make it much easier to map fields to names for troubleshooting later. Don’t put non-numeric characters in phone number fields though, since this will cause import errors in LDAP (ask me how I know…)

Now export the Thunderbird address book as an ldif file (open Thunderbird, then go “Tools->export”), and use this perl script (instead of the one on the above-linked page) to convert the ldif export file to the correct format. Note you need to edit either the script or your input filename so they match, and you need to edit the script to add your domain name:

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

#!/usr/bin/perl -pi
# Perl script to convert my LDIFs from Mozilla into a format which
# can be imported successfully into OpenLDAP, using the Moz v0.6
# schema.
# Johny Agotnes (mozilla@agotnes.com) – June 2003
use MIME::Base64;

# Variables to change block
# Handle the different dn strings

### NEED TO EDIT THIS ###
$dnVariable = “ou=addressbook, dc=my-domain, dc=com”;
### NEED TO EDIT THIS ###

### NEED TO EDIT THIS ###
$inPutFile = “ThunderbirdAddressBook.ldif” ;
### NEED TO EDIT THIS ###

# END of Variables to change block

if ( ! open(MYINPUTFILE, $inPutFile)) {
print (“File < ” . $inPutFile . “> not found!”) ;
exit 1 ;
} ;

while(<myinputfile>)
{
# Good practice to store $_ value because
# subsequent operations may change it.
my($line) = $_;

# Good practice to always strip the trailing
# newline from the line, change from DOS eol first.
# $line =~ s/.$// ;
chomp($line);

# ‘dn’ handling, ick ick, it seems :: indicates base64 encoding
if ($line =~ /^dn::/) {
# Strip off the ‘dn:: ‘ part so that decode_base64 will work
$line =~ s/^dn:: //;
$line = decode_base64($line) ;
$line = cleanDN($line) ;
# Second param to stop linebreaks
$line = encode_base64($line, “”) ;

# Prepend ‘dn:: ‘ to make it correct again
$line = “dn:: ” . $line ;
# encode_base64 adds a newline, so we get rid of it again.
chomp($line) ;
} elsif ( $line =~ /^dn:/) {
$line = cleanDN($line) ;
}

# Correct Syntactic Export errors
$line =~ s/mozillaAbPersonObsolete/mozillaOrgPerson/;
$line =~ s/^modifytimestamp.*$/doNotPrintThisLine/ ;
$line =~ s/^xmozillanickname.*$/doNotPrintThisLine/ ;
$line =~ s/workurl/mozillaWorkUrl/;

# Start Black Magic
# If no sn, set sn from org name
$done = 0 ;
if ((/^dn:/…/^o:/) && ($done==0) ){
goto Cont if /^sn:/;
goto Replcn if /cn:/;
goto Repl if /o:/;
goto nada ;
Cont:
$done=1; goto nada;
Replcn:
my($line) = $_;

# $line =~ s/.$// ;
$line =~ s/cn:/sn:/;
print $line ;
$done=1; goto nada;
Repl:
my($line) = $_;
# $line =~ s/.$// ;
$line =~ s/o:/sn:/;
print $line ;
nada:
}
if (/^$/) {
$done = 0 ;
}
# End Black Magic

# Print the line to the screen and add a newline if we’re not
# told not to by the contents of the line
if ($line ne “doNotPrintThisLine” ) {
print “$linen”;
}
}

sub cleanDN
{
# Surely there are better ways of doing this for subroutines?
my $dnString = $_[0] ;
$dnString =~ s/,mail.*$//;
$dnString =~ s/,*//;
$dnString =~ s/.*$/$&, $dnVariable/;

return $dnString ;
}

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

I got this file from Mozilla’s site – it was an attachment to a bugzilla bug (#116692) – but note that I had to edit it to get the correct output for my setup. I think that to actually run it, I had to redirect its output to a file, something like:
pt.pl > outputfile.ldif
- otherwise it sent its output to stdout.

This didn’t get rid of commas within the fields (for example – Dr A Jones, MD) – which mess up the import – so I manually did a search & replace on all commas after I ran the above perl script. I know perl does this kind of thing in its sleep, but I despise perl, and didn’t want to spend more time than necessary debugging it, so I just fired up my favorite editor…

Follow the instructions on the above-linked page to complete the import into LDAP. Other import errors I had included the presence of non-numeric values in phone # fields. Just edit by hand and start again. Tedious, but it works eventually.

I found phpLDAPAdmin (http://phpldapadmin.sourceforge.net/) invaluable – just drop it in your /Library/Webserver/Documents directory, edit the config file to point it at your server, edit your httpd.conf file to enable php (basically uncomment all the lines that mention using php), then restart Apache, and away you go

THUNDERBIRD TWEAKS REQUIRED:

Some of The LDAP field names that Thunderbird uses in its exported contacts are different from the ones that the addressbook actually looks for when connectign to an LDAP server – pretty frustrating. Anyway, if you do the following, all shoudl be well:

Download Thunderbird 1.5beta1 from:

http://www.mozilla.org/products/thunderbird/releases/1.5beta1.html

older versions do not have the ldap mappings in the preferences

—————————-

After installing it and firing it up, look under preferences (or Tools -> Options on windows), go to advanced and select “general” tab, then click “Config Editor” button.
In config editor, change these existing keys to the values shown:

ldap_2.servers.default.attrmap.HomeAddress -> mozillaHomeStreet,homePostalAddress
ldap_2.servers.default.attrmap.HomeAddress2 -> mozillaHomeStreet2,mozillaHomePostalAddress2
ldap_2.servers.default.attrmap.WorkAddress -> street,streetaddress,postOfficeBox,postalAddress
ldap_2.servers.default.attrmap.WorkAddress2 -> mozillaWorkStreet2,mozillaPostalAddress2

These will ensure that the first and second lines of the home address and work address appear as they should.

Next, make this change:

ldap_2.autoComplete.directoryServer -> ldap_2.servers.myLDAPserver

(where “myLDAPserver” should be changed to the name of your ldap server, AS DEFINED IN THE PREFERENCS ENTRIES, under ldap_2.servers.***)

This will make thunderbird do an LDAP lookup to autocomplete any email addresses or names you are typing in the To: Cc: or Bcc: fields of new emails – fantastic!

restart thunderbird, and enjoy!

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

In case anyone has problems connecting to the LDAP server with their username/bind address and password – I found this useful info in a discussion archive at http://www.openldap.org/lists/openldap-software/200301/msg00715.html

CONNECTION TIP – SASL vs SIMPLE

> Seems something wrong with my slapd instance. (Maybe the setup process
> wasn’t completed.) It always report,
> /SASL [conn=0] Error: unable to open Berkeley db /etc/sasldb2: No such
> file or directory/
> Then I touch a file /etc/sasldb2 but of cause it didn’t work.

I note that the ldapadd command you use is not using the right set of
flags for SASL bind. If you want to use SASL you need to specify
‘-U <username>’ rather than ‘-D <binddn>’. If you do not want SASL
then you need ‘-W -x’.

Assuming you want SASL…

This seems rather important:

> additional info: SASL(-13): user not found: no secret in database

If you want to use SASL bind then you need some SASL secrets for the
user concerned. SLAPD cannot update the SASL database – it must be
done by other means.

Try this as root:

saslpasswd2 -c <username>

where <username> is the SASL username that you want to create. There
is no connection with Unix usernames.

Then make sure that /etc/sasldb2 is non-zero and is readable by the
user that slapd runs as. It should not be globally readable, as SASL
secrets are effectively stored in clear.

With 2.1.x versions it is possible to store SASL secrets in the
directory itself. See section 10.2 of the manual for details.

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

Setting up LDAP (slapd) on Mac OS X (non-server edition)

I have been wanting a centralized address book/contacts solution for a long time, and was looking for something that used open standards, and saved stuff in plain text, or could export to plain text. If Thunderbird could also access it directly, that would be perfect, but what hope was there? I looked at Synckolab (http://www.gargan.org/extensions/synckolab.html) – which is an excellent idea, but not ready for primetime. I poked around for a long time, knowing at the back of my mind that LDAP was probably the best way to go, but I just didn’t want to go through the pain of installing and setting it all up, only to have to do it all again next time I upgrade my operating system (I’d just been through similar pain with my mail server setup, converting from OS X Panther to OS X Tiger – non-server versions). The whole reason I got a mac to use as my server (mac mini, 1.25GHz, 512MB RAM) was so I didn’t have to deal with Linux – life’s too short.

However, my research indicated that even the non-server version of Mac OS X ships with an LDAP server (but no UI tools for setup/admin). Furthermore, all the parts you need can also be downloaded, installed and updated via Fink (http://fink.sourceforge.net/). Having seen posts from people who had problems getting the mac-shipped version to work, I decided to go the Fink route.

So here it is – pretty straightforward, really…

First – download and install Fink (http://fink.sourceforge.net/) and then FinkCommander (http://finkcommander.sourceforge.net/), and do selfupdate and update-all (see the “source” menu)

1) in FinkCommander, install:

openssl097 0.9.7d-1 Secure Sockets Layer and general crypto library
openssl097-shlibs 0.9.7d-1 Secure Sockets Layer and general crypto library

openldap-ssl 2.1.22-25 LDAP directory services implementation
openldap-ssl-shlibs 2.1.22-25 Shared libraries for LDAP

cyrus-sasl2-shlibs 2.1.21-3 Cyrus Simple Auth. and Security Layer Library
cyrus-sasl2 2.1.21-3 Cyrus Simple Auth. and Security Layer Library
cyrus-sasl2-doc 2.1.21-3 Cyrus Simple Auth. and Security Layer Library

If you don’t see these, there’s a setting in the preferences, on the fink tab, that says: “use unstable packages” – mine’s checked, but I’m not sure if these fell into that category or or not)

2) in terminal, type:

sudo vim /sw/etc/openldap/slapd.conf

and scroll down to find this:

include /sw/etc/openldap/schema/core.schema

and beneath it, add:

# ADD THESE: ##
include /sw/etc/openldap/schema/cosine.schema
include /sw/etc/openldap/schema/inetorgperson.schema
include /sw/etc/openldap/schema/mozillaOrgPerson.schema
##############

(IMPORTANT: don’t forget to get a copy of mozillaOrgPerson.schema and put it in the above location. It can be downloaded via a google search. I used version 0.6.3)

Now scroll down to find this:

#######################################################################
# ldbm database definitions
#######################################################################


database bdb
suffix "dc=my-domain,dc=com"
rootdn "cn=Manager,dc=my-domain,dc=com"

Replace “my-domain” with your real domain name. (For other settings, if required, see “man slapd.conf”).

Save & exit.

To test whether the configuration file is correct or not, type:

sudo /sw/sbin/slapd -d 5 -t

which tests the config file (with level 5 debugging, to tell you why it’s failing, if it is)

3) AS ROOT, start ldap (slapd) with *lots* of console debugging:

/sw/sbin/slapd -d 255

Also see “man slapd”

4) AS ROOT, set up using these instructions:

http://www.onlamp.com/pub/a/onlamp/2003/03/27/ldap_ab.html

My install differed from this in the following ways (refer to the above-linked page to understand how these fit in):

Here’s my directory.ldif file:

dn: dc=my-domain,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
dc: my-domain
o: my-domain

dn: ou=addressbook,dc=my-domain,dc=com
objectClass: top
objectClass: organizationalUnit
ou: addressbook

***NOTE*** – MUST have the blank line between “o: my-domain” and “dn: ou=addressbook…etc”

Here’s the command line to add it to the directory:

ldapadd -D 'cn=Manager, dc=my-domain, dc=com' -x -f directory.ldif -W

(Had to add the -W -x -D ‘cn=…’ option to bind as that name, otherwise it tries to use SASL)

Command line to do initial search:

ldapsearch -W -x -D 'cn=Manager, dc=my-domain, dc=com' -b 'dc=my-domain, dc=com'
'objectclass=*'

(Had to add the -W -x -D ‘cn=…’ option to bind as that name, otherwise it tries to use SASL)

TO ADD AN ENTRY:

cn=Test User,cn=Test User,ou=addressbook,dc=my-domain,dc=com
givenName Test
sn User
cn Test User
street 123 Main St
o myCompany
l My Town
st CA
postalCode 50005
telephoneNumber 888 888 8888
mobile no mobile
facsimileTelephoneNumber 888 888 8888
mail me@my-domain.com

…next post – Importing Contacts from Thunderbird Addressbook into LDAP – will show how to export existing address book contacts from mozilla thunderbird and import them into your LDAP server…