A typical program in, say, Perl that reads or manipulates the Domino Directory (names.nsf) via LDAP starts off like this:

my $host = 'domino.example.com';
    my $binddn = 'cn=administrator,o=example';
    my $bindpw = 'NotTonightJosephine';
    ...

Code like this has a number of inherent problems:

  • The password you've assigned your administrative LDAP user is hard-coded in the program.
  • Even if your program reads the password from a file, the password is stored in clear text somewhere, and that is bad practice.
  • You can't change the user's password in the directory without breaking all such programs.

You can quite easily use a client X.509 (SSL/TLS) certificate to authenticate your LDAP client programs, and we'll discuss how you implement this. (If you don't yet have a Certification Authority (CA) to issue SSL/TLS certificates, you can use the Lotus Domino certification authority database or use OpenSSL to create your own CA.) The steps you need are:

  1. Create the key file on Lotus Domino. This key file contains the server's private and public keys as well as the CA's certificates.
  2. Configure the Domino server to use that key file to provide SSL/TLS for the LDAP server task.
  3. Issue a client certificate for your application(s).
  4. Create a user in the Domino Directory and associate the client certificate with that user.
  5. Set the Access Control List (ACL) on the Domino Directory to allow your administrative user (with its certificate) to access the directory.
  6. Test your client program. (I'll show you an example in Perl.)

These steps assume you already have a Certification Authority that is able to issue server and client certificates.

1. Create the key file

This step is made very easy by a Lotus Domino database that contains a few forms. Open the Server Certificate Admin database (certsrv.nsf) on your server, and follow the steps in order:

  1. Create a key ring -- a pair of files with names ending in .kyr and .sth. Choose the name carefully and remember it! (Note: the files are created on your workstation (i.e. on your Notes client's drives -- you'll have to copy/move these files to the server's data/ directory when you've finished.) I choose the name fuppskeyfile.kry. You'll need to remember the password in this form to later update the keyring file; apart from that, the password is stored in the stash file, which is used by the Domino server to decrypt the private key upon startup. When creating the key ring, remember that the Common Name of your server must match the DNS domain name of the same.
  2. Then create the Certificate Request which you send to your Certification Authority, either by mail or by copy/paste (recommended). ZZ30DBA06C.jpg While your CA is processing the request, you can follow the rest of the steps. If you are your own CA, just smile and be happy.
  3. Install trusted root certificate into key ring. Here is where you add your CA's root certificate(s) which you should have in PEM format. Choose this step for each of the certificates (including intermediary certificates) you have to import.
  4. Install certificate into the keyring. At this point you should have received your server's SSL certificate from your CA, and you install that into the keyring file. If all goes well, the database tells you that you can proceed with enabling SSL on your server.

Don't forget to copy the keyring (fuppskeyfile.kyr and fuppskeyfile.sth) into the server's data directory!

2. Configure the Domino server

Open your server's configuration document. Choose the Ports and then the Internet Ports tab, and fill in the SSL Key File Name with the name of the .kyr file (the stash file's name is derived from that). ZZ0D845713.jpg Further down on that document, you'll find a tab for Directory: enable the SSL port status and select the kind of authentication you want to allow. ZZ73BA4E64.jpg (If you disable anonymous access, you won't be able to query the root of the DIT anonymously, which means your client programs won't be able to STARTTLS, but that doesn't really matter as Domino doesn't (yet?) support STARTTLS!) After saving the document, restart the LDAP task with an

tel ldap quit
    load ldap

on the Domino server console. If you don't see any errors there, you can attempt your first SSL (or TLS if you prefer) connection:

$ ldapsearch -LLL \
        -x \
        -H ldaps://jp510m.fupps.com \
        -b '' -s base objectclass=* +
    dn:
    subschemasubentry: cn=schema
    ...
    supportedsaslmechanisms: EXTERNAL
    supportedldapversion: 3
    supportedldapversion: 2
    vendorname: IBM Lotus Software
    ...

That looks good. :-) (Remember at this point, that the root CA certificate must be known to your client as well -- in the case of OpenLDAP's ldapsearch, add the chain to your ldap.conf file.) If you've disabled anonymous access and try a search over SSL we get an error: "Can't bind to directory: Failed, Client certificate not found in directory and anonymous access not allowed"; that is quite correct at this point. Well fix that in a moment.

3. Issue a client certificate

In this step I'm going to create a client certificate in my CA. My applications will use this certificate and its corresponding private key to authenticate to the Domino Directory. My client certificate has the following distinguished name and bits set:

Issuer: C=DE, L=Bielefeld, O=Fupps, CN=Fupps CA
    Validity
      Not Before: Feb 18 22:17:53 2009 GMT
      Not After : Oct 10 22:17:53 2011 GMT
    Subject: CN=Jane Jolie/emailAddress=jj@fupps.com
    ...
    X509v3 extensions:
        X509v3 Basic Constraints: critical
            CA:FALSE
        X509v3 Subject Alternative Name: 
            email:jj@fupps.com
        X509v3 Key Usage: 
           Digital Signature, Key Encipherment, Key Agreement
        X509v3 Subject Key Identifier: 
            EF:71:1A:61:06:C1:0A:92:A0:E7:EA:C0:35:25:D4:4E:7E:99:AA:36
        Netscape Cert Type: 
            SSL Client, S/MIME
    ...
        X509v3 Extended Key Usage: 
            TLS Web Client Authentication, E-mail Protection

The Common Name (CN) on the client certificate need not have anything in common with the Lotus Domino user; you can choose whatever Common Name you wish, but you must add the certificate's Common Name to the Domino person's Username entry, because that is how Domino finds the corresponding person's entry. The association between the client certificate and its corresponding Domino user is done by searching the directory for a Username that corresponds to the CN (and only the CN -- no other components of the certificate's distinguished name) presented in the client certificate -- Domino then uses the Username of the corresponding person to check ACLs. (See also Setting up a Person document for an Internet user using SSL client authentication.) In my example above, the client certificate has been issued to Jane Jolie, so I must add that common name to a person entry in the Domino Directory: ZZ32DADE74.jpg

4. Create a user Domino user and set its certificate

I recommend you create a simple user (Add person) with no mail (Mail System: none). ZZ38383F9D.jpg As soon as you have the user entry, choose Actions->Import Internet Certificates to attach an X.509 public certificate to this user's directory entry. This public key must correspond to the private key we'll be using in our client program. (Note, that there appears to be a bug, at least in 7.0.3 in that, if an entry has more than one certificate, the Examine Internet Certificates button disappears from the form as well as from the Actions menu.) I choose to use a DER-encoded certificate (file extension is .cer because when importing base-64-encoded PEM certificates Lotus Notes erroneously asked me for an import password! If you don't readily have a DER format, you can easily convert a PEM encoded certificate to a DER encoded format with:

openssl x509 -in user.pem -out user.cer -outform der

ZZ66ADF969.jpg (Note that it can take some time until the LDAP task picks up the changes in names.nsf.)

5. Set the ACL on names.nsf

So far, the user can't do more or less than if she'd authenticated anonymously, but I want to change that: the user should be able to maintain (i.e. modify) the directory. I change the ACL of the names.nsf and add our newly created Directory Manager to its ACL. If I want this user to be able to manipulate users, I additionally set the NetCreator roles.

6. Test your client program

Since we now have administrative access to the Domino directory, we can manipulate entries therein via LDAP operations. This includes modifying, deleting and adding users. Do note, however, that you'll be doing this at your own risk: this can massively screw up your Domino directory! Lets see an example of how to add a user entry:

#!/usr/bin/perl
use strict;
use Net::LDAP;
use Net::LDAPS;
use Authen::SASL qw(Perl);

use constant {
    LDAPHOST => 'localhost',
    CERTFILE => 'janejolie.crt',
    KEYFILE      => 'janejolie.key',
    ROOTCHAIN    => 'fupps.crt',
};

my $ldap = Net::LDAP->new("ldaps://".LDAPHOST.":636",
    verify => 'require',
    clientcert => CERTFILE,
    clientkey => KEYFILE,
    cafile => ROOTCHAIN,
    );

my $sasl = Authen::SASL->new( mechanism => 'EXTERNAL',
    callback => { user => '' }) or die "$@";

my $msg = $ldap->bind( sasl => $sasl, version => 3 );
bailout("Can't bind to directory.", $msg) if $msg->code();

$msg = $ldap->search(
    base    => '',
    scope   => 'sub',
    deref    => 'always',
    filter  => "(uid=jmens)",
);
bailout("Search failed.", $msg) if $msg->code();

my $e = Net::LDAP::Entry->new;
my ($first, $last) = ('John', 'Doe');

$e->dn("cn=$first $last,o=fupps.com");
$e->add('objectclass' => [ qw(person inetOrgPerson dominoPerson organizationalPerson top) ]);
$e->add('cn'     => "$first $last");
$e->add('sn'     => $last);
$e->add('givenname'  => $first);
$e->add('uid'        => "$first.$last");
$e->add('mailsystem' => '100');

$e->dump();

$msg = $e->update($ldap);
$msg->code && bailout("Can't add", $msg);

$ldap->unbind();
exit;

sub bailout {
    my ($t, $msg) = @_;

    print $t;
    print ("\terror number: " . $msg->code . "\n");
    print ("\terror: " . $msg->error_text . "\n");
    printf ("\tis_error: 0x%X\n", $msg->is_error);
    exit;
}

The nice bit about this is: no clear- text password to be seen anywhere. But of course, you must now carefully protect your client certificate and key: anybody obtaining access to those is the master.

Flattr this
LDAP, DomiNotes, Linux, Security, and CLI :: 28 Feb 2009 :: e-mail

Comments

blog comments powered by Disqus