Use your eID to authenticate at web sites, the open source way

For countries that have adopted an Electronic Identification Card (eID), implementing web application authentication based on the eID card is an attractive solution, because the issuer is trustworthy (that's the least we can say) and the proof of identity has a legal value.

This blog describes how to configure OpenSSO (or the Sun supported Access Manager) to provide strong authentication based on the eID certificate.

I made my tests with the Belgium eID card but I suspect other cards to behave similarly.

On the client side, you will need, well an eID, a card reader and the required drivers (aka middleware) usually provided by the card manufacturer or the card issuer.

Once this is installed, you will need to add the Card as a Security Device (Certificate Store) into the list of security devices recognized by your browser.  In the case of the Belgium eID card, Fedict does provide a tutorial for the main browsers, mail readers and office suites.

On the server side, all the softwares I used are all available as open source project or, alternatively, if you're looking for indemnification and 24/7 local support, as a commercial offering from Sun.

Just install Glassfish, OpenSSO using embedded or external OpenDS (I choose Embedded for simplicity).  Instructin to download and install glassfish are posted here.  Instructions to download and install OpenSSO are posted here.

There are two main steps to configure the certificate authentication with OpenSSO : prepare the LDAP backend and configure the Authentication Module. 

Prepare the LDAP

The first step requires you to create an entry for the user in the LDAP server.  Amongst the usual firstname, lastname attributes, this entry will contain the user certificate (it's public key, signed by the Government's key, aka Certificate Authority) and the card serial number, that we will use to uniquely match the card's certificate with a user's LDAP entry.

1. Extract your certificate and the root certificates from your card 

On Linux and Solaris, use can use the pkcs15-tool provided by OpenSC.

On Mac OSX, you start the KeyChain Access application (located under Applications -> Utilities), right click on the certificate name, then select "Export <Certificate Name>" as shown below.

keychain access screenshot

2. Verify your certificate

You can verify the content of the certificate just extracte with the OpenSSL command (adjust file name) :

openssl x509 -inform DER -in  ./Desktop/sst.cer -text

3. Prepare the LDAP entry

You have to create an LDAP entry for the user represented by your eID card.  I used the following LDIF file and the ldapadd command to create the LDAP entry.  Alternatively, you can use any LDAP GUI such as LDABrowser.

dn: uid=sst,ou=People,dc=sun,dc=com
objectClass: person
objectClass: inetorgperson
objectClass: top
objectClass: organizationalperson
sn: Stormacq
userPassword:: e1NTSEF9cnpjNHFEcm9HbTVJV0IvZHJuQW5iVnNkd0crWW9YS0NrWUsxRVE9PQ==
cn: Sebastien Stormacq
uid: sst
givenName: Sebastien

(my password is password)


To Simplify the process of creating new entries, you can also use the following ldapmodify command :

-bash-3.2$ ldapmodify -b -a -D "cn=Directory manager" -w password -p 1389
dn: uid=sst,
objectClass: person
objectClass: inetorgperson
objectClass: top
objectClass: organizationalperson
sn: Stormacq
userPassword: password
cn: Sebastien Stormacq
uid: sst
givenName: Sebastien
serialNumber: 72020412345
userCertificate: /export/home/sst/sst.cer

adding new entry uid=sst,ou=People,dc=opensso,dc=java,dc=net

The -b option of ldapmodify ensures the required magic to read the certificate file and base64 encode it


Test you LDAP entry by issuing the follwoing command (change hostname, port number, password and uid accordingly):

spirou:OpenDS sst$ ldapsearch -h localhost -p 1389 -D "cn=Directory Manager" -w adminadmin -x uid=sst dn
# extended LDIF
# LDAPv3
# base <> with scope subtree
# filter: uid=sst
# requesting: dn

# sst, People,
dn: uid=sst,ou=People,dc=sun,dc=com

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

4. Import the Certificate into the LDAP

The default LDAP schema contains an attribute to store the user's certificate : userCertificate.  This is a binary attribute.  To add this attribute, you have to convert your certificate in BASE64 format and issue an ldapmodify command.

I was lazy and used the LDAPBrowser's GUI instead.  This GUI allows you to load a binary attribute from a file content : right click on the entry, select Add Attribute, type userCertificate as attribute name, select Binary as type, then load the content of your certificate file.

5. Import the SerialNumber in the LDAP

The eID Serial Number will be used as a unique attribute to match the card's certificate and the LDAP entry.  It will also be used to retrieve's the user's profile from the LDAP.  We therefore need to add a serialNumber attribute into the LDAP.  Unfortunately, such an attribute is not defined in the LDAP schema.  We have two options here : the nice and clean way to add the attribute is to modify the LDAP schema to add support for an extra attribute.  The quick and dirty way is to disable schema check on OpenDS.

Guess which option I choose :-) ?

To disable schema check on OpenDS, open the file <opends home>config/config.ldif and change ds-cfg-check-schema: true to ds-cfg-check-schema: false

And restart OpenDS (if you are using the embedded OpenDS, restart Glassfish). Now, we are ready to add our serialNumber attribute.

First, find your serial number in your certificate

spirou:~ sst$ openssl x509 -inform DER -in  ./Desktop/sst.cer -text
        Version: 3 (0x2)
        Serial Number:
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: C=BE, CN=Citizen CA/serialNumber=200715
            Not Before: Dec 13 00:46:02 2007 GMT
            Not After : Dec 10 23:59:59 2012 GMT
        Subject: C=BE, CN=S\\xC3\\xA9bastien Stormacq (Authentication), SN=Stormacq, GN=S\\xC3\\xA9bastien G\\xC3\\xA9rard/serialNumber=72020412345
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (1024 bit)
                Modulus (1024 bit):
                Exponent: 65537 (0x10001)

Then, use ldapmodify or LDAPBrowser's GUI to add an attribute named serialNumber with the appropriate value.

A last ldapsearch will allow us to verify that everything is OK (change hostname, port number, password and uid accordingly) :

spirou:OpenDS sst$ ldapsearch -h localhost -p 1389 -D "cn=Directory Manager" -w adminadmin -x uid=sst
# extended LDIF
# LDAPv3
# base <> with scope subtree
# filter: uid=sst
# requesting: ALL

# sst, People,
dn: uid=sst,ou=People,dc=sun,dc=com
objectClass: person
objectClass: inetorgperson
objectClass: top
objectClass: organizationalperson
sn: Stormacq
userCertificate:: MIID9jCCAt6gAwIBAgIQEAAAAAAA7wyk4sOHeTR2JDANBgkqhkiG9w0BAQUF
userPassword:: e1NTSEF9cnpjNHFEcm9HbTVJV0IvZHJuQW5iVnNkd0crWW9YS0NrWUsxRVE9PQ=
cn: Sebastien Stormacq
serialNumber: 72020412345
givenName: Sebastien
uid: sst
mail: sst-AT-maildomain-DOT-net

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

We are now ready to configure the OpenSSO Certificate Authentication module.

Configure Certificate Authentication in OpenSSO and Glassfish

1. Import Root Certificate into Glassfish certificate store

Glassfish must be able to verify your certificate's authenticity.  You must import the two Root Certificate (Citizen and Belgium) into Glassfish's cacerts.jks certificate database (change file path accordingly) :

  1. keytool -import -alias belgium -file /Users/sst/Desktop/belgium.cer -keystore ./cacerts.jks -storepass changeit
  2. keytool -import -alias citizen -file /Users/sst/Desktop/citizen.cer -keystore ./cacerts.jks -storepass changeit

The cacert file is located under <glassfish home>/domains/<your domain name>/config

2. Change Glassfish's configuration to enable client-side certificate authentication

By default, client-side certificate is disabled on Glassfish, we need to re-enable it : edit the domain.xml file located in the Glassfish's domain configuration directory (same as above), and change.

<http-listener acceptor-threads="1" address="" blocking-enabled="false" default-virtual-server="server" enabled="true" family="inet" id="http-listener-2" port="55181" security-enabled="true" server-name="" xpowered-by="true">
          <ssl cert-nickname="s1as" client-auth-enabled="true" ssl2-enabled="false" ssl3-enabled="true"
               tls-enabled="true" tls-rollback-enabled="true"/>

And restart Glassfish

3. Create a certificate-based authenticaion module

  • Logon on the OpenSSO console (http://your host name:your port number/opensso)
  • Select the realm (default name is sun)
  • Select Authentication tab
  • Under "Module Instances", click new
  • Type a name for the module, i.e. eID
  • Select Certificate in the list
  • Click OK

4. Configure the Authentication Module

Click on the eID module in the list of available modules and configure as show below :

This will tell the Authentication module to use the Certificate's serialNumber attribute to search for a matching certificate in the LDAP data store.

Then specify which attribute will be used to access the user's profile in LDAP (notice that the authentication operation and the profile retrieval operation might use different LDAP attributes)


  • in the "DAP Server Where Certificates are Stored" list, be sure that your LDAP server is referenced, i.e. localhost:50389 when using the embedded OpenDS,
  • Ensure the user name and credentials to access the LDAP store are correct.
  • Ensure the base DN is given in the "LDAP Search Start DN" list (mine is ou=people,dc=sun,dc=com)
Click Save, then Back to Authentication

5. Configure Authentication's Advanced Properties

Open the "Advanced Properties"

Ensure the "User profile" is Required.

Add the serialNumber attribute  in the "Alias Search Attribute Name" as shown below :

This tells OpenSSO to search the LDAP attribute serialNumber for matching serialNumber from the certificate.

6. Configure the Authentication Chain

Finally, we must add our Certificate Authentication module in our authentication chain.  We are adding it in the ldapservice chain, in the first position and with the "Sufficient" attribute, as shown below

This setting will make the Certificate Authentication module the first one to be proposed by OpenSSO.  Should the certificate based authentication fails, OpenSSO will fall back to the traditional LDAP authentication, allowing your user to continue to connect to OpenSSO.

7. Test Test Test

  • Open your favorite browser and point it to OpenSSO, using SSL ! (https://<your host name>:<ssl port number>/opensso)
  • The browser will probably complaint about an invalid or unverifiable server certificate, this is normal, unless you have installed a genuine server side certificate on Glassfish.  You can safely ignore is this warning.
  • The browser will prompt you for your eID PIN code
  • And voila, you should be directed to your users' profile page.

8. Tips

  • When using Firefox, be sure to start Firefox after you plugin the card reader
  • If you have several client side certificates installed under Firefox, it will ask you which certificate you want to use to autehnticate, be sure to use the BPELPIC certifcate (for Belgium eID cards)
  • The OpenDS log file is located under <OpenSSH home>/opends/logs and contains valuable information to understand why you can't login

To deploy this in real life, you just need to deploy an OpenSSO Web or J2EE agent in your favorite container and you will be ready to protect your application with eID authentication !

Should find errors in this blog entry, or some steps I forgot, do not hesitate to leave a comment.


Do you by chance know, how exactly does the Certificate Auth Module work?

Does it use HTTP headers added by an HTTPS-deciphering layer or some local variables and flags in the context of the application server running AMServer/Portal/etc?

We have a project which concerns integration of proprietary cryptography with Sun Portals. There is no stable Java integration yet (the core product is "certified" and unchangeable, and I can only guess it's written in C). Thus we can't use the benefits of Java CryptoAPI to directly decipher the HTTPS data in the App Server context.

Instead, we use a separate program which can decipher these algorithms and forward plaintext HTTP to the backend servers (i.e. through a Sun SRA Gateway to the real-backend App Servers) and encodes the responses for the clients. You can consider it an "SSL Accelerator" or "proxy" in some common terms.

This program can also add HTTP headers (i.e. Certificate numbers chain) to the forwarded stream.

Can the Certificate Auth Module be used in this scenario, or are we bound to creation of a new Auth Module as well?

Posted by Jim Klimov on mars 13, 2008 at 03:53 AM CET #

Our Certificate Authentication Module is implementing the SSL client authentication RFC (I think it RFC 2246 :

Should your configuration respects the standards, then it will work. Otherwise, writing a custom Authentication module is probably the solution.

Posted by Sebastien Stormacq on mars 14, 2008 at 09:13 AM CET #

Thank you.

And is there any good document or blog detailing how the Sun Certificate Authentication Module works? Does it interact with a crypto API directly?

In particular, how does the auth module know which certificate is presented by the visitor - does the module itself participate in TLS handshake, does it process certain HTTP headers set by an SSL gateway (or the web container itself), or are there some Java flags and variables set by the web container?

Posted by Jim Klimov on mars 19, 2008 at 07:15 AM CET #

Bonjour :)

Article très intéressent et assez détailé, j'était un des élèves de la java one after glow :D .

En passant, un merci pour votre présence.


Posted by Flawinne Julien on mai 29, 2008 at 12:08 PM CEST #

We recently tried a similar approach in our test environment to authenticate use the Belgian eID. However, it is not legal to store the serial number (= national number of a person) in a database.

Do you have any suggestions on how to do this without storing this number in plain text (apparantly a salted hash is allowed).

Posted by Jan Van den Bergh on juillet 23, 2009 at 01:03 AM CEST #

Thank Jan for pointing me to this important legal aspect.
Some possibilities :

- Do not store the certificate in the LDAP. The module will check the validity of the certificate and accept whatever valid certificate is presented. This also simplifies the provisioning process as you don't have to copy the certificates to the Directory and maintain revoked, expired etc certificates.

- Use another identifying attribute, if there is such attribute (an email address ?)

- Sublclass (or modify the source code of the) X509 authentication module to create your own. This would allow you to store a hash key of the serial number in the LDAP and search for the hash instead.

Should anyone have other options, let's share and discuss this !

Posted by Sebastien Stormacq on juillet 23, 2009 at 02:07 AM CEST #

Post a Comment:
  • HTML Syntax: NOT allowed

S├ębastien Stormacq is a Senior Software Architect at Sun Microsystems. He uses his 15+ years of professional experience to design large scale, secured and highly transactional architectures based on Sun's middleware solutions.


« avril 2014