Cache strategy for OpenDJ LDAP directory server

System administrators that are familiar with legacy LDAP directory servers know that one of the key for the best performance is caching the data. With Sun Directory Server or OpenLDAP, there are 3 levels of caching that could be done : the filesystem level, the database level and the entries level. The filesystem level cache is managed by the OS and cannot be controlled by the application. Using the filesystem cache is good when the directory server is the only process on the machine, and/or for initial performance. The database level cache allows faster read or write operations, and also includes the indexes. The later cache is the higher level cache, and usually the one that provides the best performances as it requires the least processing from the server to return entries to the applications, and it has the least contention.

OpenDJ has a different design for its database and core server, and thus the caching strategy needs to be different.

By default, OpenDJ does have a database cache enabled, and 3 different kind of entry caches, all disabled. The reason for the 3 entry caches is that they are implementing for different needs and access patterns. But all have in common a specific filter to select which entries to cache, and some settings as to how much memory to use. During our stress and performance tests, we noticed that using an entry cache for all accessed entries added a lot of pressure on the garbage collector, and also caused more garbage collection from the old generation, often leading to either fragmentation of the memory, or more frequent full GC (also known as “Stop the world GC”). This resulted in an overall lower consistent average response time and throughput.

So, we recommend that you favor the database cache, and do not setup an entry cache, except for specific needs (and do not try to activate all 3 entry caches, this may lead to some really strange behavior).

The default settings with OpenDJ 2.4 is that 10 % of the JVM heap space will be used for the database cache. With OpenDJ 2.5 (soon to be released), we have bumped the default to 50% of the heap space. If you’re tuning the heap size and make it larger than 2GB, we recommend that you keep that 50% ratio or even increase it if the heap size exceeds the 3GB.

If you do have a few very specific entries that are very often accessed, like large static groups that are constantly used for ACI or group membership by application, then the entry cache becomes handy, and then you want to set a filter so only these specific entries are cached.

For example, if you want to cache at most 5 entries, that are groupOfNames, you can use the following dsconfig command:

bin/dsconfig set-entry-cache-prop --cache-name FIFO
 --set include-filter:\(objectclass=GroupOfNames\)
 --set max-entries:5 --set max-memory-percent:90 --set enabled:true
 -h localhost -p 4444 -D "cn=Directory Manager" -w secret12 -X -n

Otherwise, you’d better of running with no entry cache. OpenDJ read performance are such that the directory server can respond to tens of thousands if not hundred of thousands searches per second with average response time in the order of a milli-second. This should be good enough for most applications !

OpenDJ 2.4.5 is now available

I’m happy to announce that a new revision of OpenDJ, the open source LDAP directory server in Java has just been released. OpenDJ 2.4.5 is an update release of the OpenDJ project and improves reliability with SSL connections, replication meta-data indexes and Java 7. The full details about the release have been posted in the OpenDJ 2.4.5 Release Notes. Note that if you upgrade from a previous version, the ds-sync-hist index must be rebuilt, prior to restart the server.

The release is built out of revision 7743 of the b2.4 branch of the code repository.

As usual, you can find every thing on the OpenDJ Downloads page:

The draft documentation for OpenDJ, and more specifically the Administration Guide, has been updated on the OpenDJ project site, still on the track for an accurate, reviewed version for OpenDJ 2.5.

Feedback is important to us and you can participate on the IRC channel, the mailing lists or join our community.

Enjoy !

OpenDJ: Extensible indexes for Internationalization.

While taming the subject of indexes, we recently had some discussion with one of our users who complained about long response times with some language specific search filter such as (cn:fr.6:=*John*).

These extended filters rely on I18N Collation matching rules and indexes that I’ve described in an old post for OpenDS.

It turned out that he had defined the matching rule for the index, and rebuilt it, but had missed an important part: the index-type did not include “extensible”.

The proper command to create an extensible index is the following :

dsconfig set-local-db-index-prop --backend-name userRoot --index-name cn \
 --set index-extensible-matching-rule:fr.6 \
 --add index-type:extensible \
 --hostname localhost --port 4444 \
 --bindDN cn=Directory\ Manager --bindPassword ****** \
 -X -n

fr.6 is the shortcut for the French substring collation matching rule which full OID is 1.3.6.1.4.1.42.2.27.9.4.76.1

Note that if you don’t specify the extensible index-type, the server will not build the index for the extensible matching rule. The use of the index-type is consistent with the other types of index, equality or else, and allows you to disable and re-enable extensible indexes without having to re-enter all  OIDs.

OpenDJ Tips: More on troubleshooting indexes and search performances

In a previous post I talked about analyzing search filters and indexes. Matt added in a comment that OpenDJ has another mean of understanding how indexes are used in a search. Here’s a detailed post.

The OpenDJ LDAP directory server supports a “magic” operational attribute that allows an administrator to get from the server information about the processing of indexes for a specific search query: debugsearchindex.

If the attribute is set in the requested attributes in a search operation, the server will not return all entries as expected, but a single result entry with a fixed distinguished name and a single valued attribute debugsearchindex that contains the information related to the index processing, including the number of candidate entries per filter component, the overall number of candidate, and whether any or all of the search is indexed.

$ bin/ldapsearch -h localhost -p 1389 -D "cn=Directory Manager" -b "dc=example,dc=com" "(&(mail=user.*)(cn=*Denice*))" debugsearchindex
Password for user 'cn=Directory Manager': *******
dn: cn=debugsearch
debugsearchindex: filter=(&(mail=user.*)[INDEX:mail.substring][COUNT:2000](cn=*Denice*)[INDEX:cn.substring][COUNT:1])[COUNT:1] final=[COUNT:1]

$ bin/ldapsearch -h localhost -p 1389 -D "cn=Directory Manager" -b "dc=example,dc=com" "objectclass=*" debugsearchindex
Password for user 'cn=Directory Manager': *********
dn: cn=debugsearchdebugsearchindex: filter=(objectClass=*)[NOT-INDEXED] scope=wholeSubtree[COUNT:2007] final=[COUNT:2007]

$ bin/ldapsearch -h localhost -p 1389 -D "cn=Directory Manager" -b "dc=example,dc=com" "mail=user.1*" debugsearchindex
Password for user 'cn=Directory Manager': *********
dn: cn=debugsearch
debugsearchindex: filter=(mail=user.1*)[INDEX:mail.substring][COUNT:1111] scope=wholeSubtree[COUNT:2007] final=[COUNT:1111]

Note that sometimes, OpenDJ tries to optimize the query and use some other index than the regular one for the query. For example, it might use the equality index for an initial substring filter. The index used during the search does appear in the debugsearchindex attribute. Also, once the result set has been narrowed down to very few entries, it will stop using index and evaluate directly the entry set, as for the example below:

$ bin/ldapsearch -h localhost -p 1389 -D "cn=Directory Manager" -b "dc=example,dc=com" "(&(cn=Denice*)(mail=user.9*))" debugsearchindex
Password for user 'cn=Directory Manager':
dn: cn=debugsearch
debugsearchindex: filter=(&(cn=Denice*)[INDEX:cn.equality][COUNT:1])[COUNT:1] final=[COUNT:1]

A limited special offer…

As I’ve posted last week, we organize a training on OpenDJ in Paris from Jan 24 to 27, 2012.

I’ve been told that there is a special one time offer on this training. If you book the training by Friday January 13th, there is a 20 % discount on the course fee, which bring down the price of the 4 days course down to 2350€.

Don’t wait and register today at training@forgerock.com.

And if you still hesitate, here’s a couple of quotes from the people involved in the review of the materials :

“Firstly, I’m pretty blown away by the quantity and quality of the material. It is extremely impressive, well done! :-)”

“Hell, this is going to be a GREAT directory server course!”

OpenDJ Training in Paris Jan 24-27 2012.

Material Cover Page.The OpenDJ Administration, Maintenance and Tuning (FR-462) training is taking place in Paris from Tuesday January 24th to Friday January 27th 2012.

The course is mix of lecture and labs and is designed for system administrators, integrators, consultants, architects and developers that will be installing, configuring, administering and maintaining ForgeRock OpenDJ LDAP directory server. I’ve been reviewing the course materials, and I must say I’m really excited by it. The amount of information available in the materials is huge, and the hands-on exercises are very detailed and practical.

The training is definitely a must for anyone who is or will be deploying and managing OpenDJ. And as this is the first training for OpenDJ in Europe, I will be attending it as an observer, gathering feedback on both product and course, also possibly as an assistant to the trainer Bill Nelson.

The session will be hosted in Astec training facilities, right in the heart of Paris, close to Gare Saint Lazare and Boulevard Haussmann.

There are still some slots available, so enroll quickly by email to training@forgerock.com.

Benchmark proves OpenDJ fastest directory server !

Isode has just released a benchmark of their M-Vault R15.1 directory server, and has run some comparative tests against OpenLDAP and OpenDJ.

While the benchmark demonstrates that M-Vault is one of the best directory server out there (the new release has some really impressive search performance) , I paid more attention to the write performance, and I really like those results that are showing the OpenDJ is the fastest directory server for write operations, even when modifications are mixed with searches.

Benchmark write performance summary

Captured from Isode benchmark white-paper.

Thanks Isode for running those tests, and making those numbers publicly available.

OpenDJ success story : Ziggo

A few months ago, we worked with Ziggo in Netherland, to help them transition their legacy environment to ForgeRock I3 Open Platform. Part of the transition, they’ve replaced Sun Directory Server Enterprise Edition (DSEE) with OpenDJ, running in 3 data-centers (and different sites), and over 2.5 Million entries, in a very smooth and well controlled migration process.

They’ve now been running OpenDJ and OpenAM in production for a few months and we’re really happy to be able to share the details of the story with you. Get the Ziggo Case Study (PDF).

You can find more details about OpenDJ on ForgeRock web site.

OpenDJ 2.4.4 is now available

Months goes by, but the pace of releases remains. Today, I’m happy to announce that a new revision of OpenDJ, the open source LDAP directory server in Java has just been released. OpenDJ 2.4.4 is an update release of the OpenDJ project and improves reliability  by resolving issues found around the External Change Log, Replication, Password Policy and GSSAPI. It also resolves a memory leak that occurred with specific LDAP extended operations, such as the Password Modify Extended Operation. The full details about the release have been posted in the OpenDJ 2.4.4 Release Notes.

The release is built out of revision 7357 of the b2.4 branch of the code repository.

As usual, you can find every thing on the OpenDJ Downloads page:

The draft documentation for OpenDJ, and more specifically the Administration Guide, has been updated on the OpenDJ project site, still on the track for an accurate, reviewed version for OpenDJ 2.5.

Feedback is important to us and you can participate on the IRC channel, the mailing lists or join our community.

Enjoy !

LDAPCon 2011 program is available

LDAPCon 2011, the 3rd International Conference on LDAP, has finalized its program and the registration is open.

The program looks awesome with the participation of many active developers of open source projects, as well as directory vendors and deployment specialists. This year, I have the immense honor to open the conference with a presentation titled: “Is LDAP dead ?” which will be followed by a short general discussion. You don’t want to miss it !

I will also present where we are with the OpenDJ project which is continuing what Sun initiated with OpenDS to replace its aging Sun Directory Server Enterprise Edition product.

The conference will take place on October 10-11 2011, in Heidelberg, Germany. Don’t wait until the last minute, register NOW.

 

LDAP: Matching against the current time in OpenDJ

In LDAP, attributes have different syntaxes. The one used to indicate date and time is the GeneralizedTime, a string representation of the date and time, typically expressed in GMT time. For example, when an entry is modified, the server maintains the modifytimestamp attribute and sets a value like 20110825120001Z (for 2011, Aug 25, 12:00:01 GMT).

LDAP client applications often have to search for entries based on these date and time attributes, whether it is to find the entries that have been modified , or had the password changed recently… The way it is typically done, is the following: get from the system the current date, add or substract some fixed time (for example if you want to know the entries modified in the last 10 minutes), transform  to a GeneralizedTime, use that string in a search filter: (modifyTimestamp >= 20110825130000Z). If the application repeats that search a minute later, it has to recompute the value again, and again…

Ideally what application writers would like is to express the filter as an expression like (modifyTimestamp>=${CurrentTime} – 10 mn). However this is not compliant with LDAP. The proper way to solve this is to use extensible matching rules, and for that purpose, we’ve added 2 “relative time” matching rules in OpenDJ, the Open source LDAP Directory services for Java: one for “lower than” and one for “greater than”.

matchingrules: ( 1.3.6.1.4.1.26027.1.4.6 NAME ( 'relativeTimeLTOrderingMatch' 'relativeTimeOrderingMatch.lt' )
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )
matchingrules: ( 1.3.6.1.4.1.26027.1.4.5 NAME ( 'relativeTimeGTOrderingMatch' 'relativeTimeOrderingMatch.gt' )
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )

The way the matching rules work is pretty simple : (attribute:MatchingRule:=Offset), where the offset is a signed integer follow by its unit, either s for seconds, m for minutes, h for hours, d for days or w for weeks.

You can translate a statement to “is Attribute greater than (or lower than) CurrentTime +/- Offset”

(lastLoginTime:1.3.6.1.4.1.26027.1.4.6:=-4w) will match all entries who have a lastLoginTime value smaller than the Current Time minus 4 weeks, i.e. all entries who have a lastLoginTime older than 4 weeks.

(pwdExpirationTime:1.3.6.1.4.1.26027.1.4.5:=5d) will match all entries that have pwdExpirationTime greater than the Current Time plus 5 days, i.e. all entries that will expire in more than 5 days.

The true benefit of those matching rules, is actually when expressing policies in the OpenDJ server, for example for granting or denying access based on some attribute with a generalizedTime syntax, such as last login time, pwdChangedTime, modifyTimeStamp …

For example, imagine an auxiliary objectClass representing a service, with some specific attributes including an expiration date : validUntil. Now, you want to allow these attributes to be read only if the expiration date is not passed.

aci: (targetattr="serviceAttr1 || serverAttr2")(targetfilter="(validUntil:1.3.6.1.4.1.26027.1.4.5:=0s)")
  (version 3.0; acl "Read Valid service attributes"; allow (read, search, compare)
  userdn="ldap:///all";)

As you can see, this is a good way to hide (deny access to) stale data in a directory server, and to simplify client applications that need to search for entries based on some generalizedTime attributes. For example, consider using these “relative time” matching rules for all your audit queries for expired or unused accounts.

Finally, remember that the OpenDJ directory server doesn’t allow unindexed searches by default. So you might also want to create an index for the “relative time” matching rules. That’s a 2 steps process :

Define the index

$ bin/dsconfig create-local-db-index --backend-name userRoot --set index-type:extensible \
 --set index-extensible-matching-rule:1.3.6.1.4.1.26027.1.4.5 \
 --set index-extensible-matching-rule:1.3.6.1.4.1.26027.1.4.6 \
 --index-name createTimestamp -h localhost -p 4444 \
 -D cn=Directory\ Manager -w secret12 -n -X

Rebuild the index

$ bin/rebuild-index -b dc=example,dc=com -i createTimestamp \
 -h localhost -p 4444 -D cn=directory\ manager -w secret12 -X

OpenDJ: Analyzing Search Filters and Indexes

LDAP directory services greatly rely on indexes to provide fast and accurate search results.

OpenDJ, the open source LDAP directory services for the Java platform, provides a number of tools to ensure indexes are efficiently used or to optimize them for even better performances.

To start with, OpenDJ rejects by default all unindexed searches, unless the authenticated user has the privilege to perform them. Unindexed searches are rejected because they result in scanning the whole database, which consumes lots of resources and time. There are legitimate uses of unindexed search though, and OpenDJ offers a way to control who can perform them through a privilege. To learn more about privileges, how to grant them, please check the Administration Guide or some of my previous posts.

When unindexed searches are completed, OpenDJ (starting with revision 7148 of the OpenDJ trunk, and therefore OpenDJ 2.5) does logs the “Unindexed” keyword as part of the Search Response access log message. But the access log file can also be used to identify search operations that are not making an optimal use of indexes. Simply check for those search responses that have been returned with an etime (execution time) greater than the average.

The access log example below contains both an unusually high etime (expressed in ms) and the Unindexed tag.

[27/Jul/2011:20:27:27 +0200] SEARCH RES conn=0 op=1 msgID=2 result=0 nentries=10001 Unindexed etime=1846

The verify-index command let you check that no index is corrupted (i.e. no data is missing from indexes).

The rebuild-index command let you build or rebuild an index that would be corrupted or had its configuration changed.

One of the tuning parameter of indexes is the index-entry-limit (which was known in Sun DSEE as the AllIDsThreshold), the maximum size of entries kept in an index record, before the server stop maintaining that record and consider it’s more efficient to scan the whole database. For more information on the index entry limit, check the Section 7.2.4 Changing Index Entry Limits of the Indexing chapter of the Administration Guide.

OpenDJ provides a static analyzer of indexes which can help to understand how well the attributes are indexed, as well as help to tune the index entry limit. This tool is a function of the dbtest utility and is simply used as follow:

$ bin/dbtest list-index-status -n userRoot -b "dc=example,dc=com"

Index Name Index Type JE Database Name Index Valid Record Count Undefined 95% 90% 85%

---------------------------------------------------------------------------------------------------------------------------------------
id2children                Index       dc_example_dc_com_id2children                true         2             0          0    0    0
id2subtree                 Index       dc_example_dc_com_id2subtree                 true         2             0          0    0    0
uid.equality               Index       dc_example_dc_com_uid.equality               true         2000          0          0    0    0
aci.presence               Index       dc_example_dc_com_aci.presence               true         0             0          0    0    0
ds-sync-conflict.equality  Index       dc_example_dc_com_ds-sync-conflict.equality  true         0             0          0    0    0
givenName.equality         Index       dc_example_dc_com_givenName.equality         true         2000          0          0    0    0
givenName.substring        Index       dc_example_dc_com_givenName.substring        true         5777          0          0    0    0
objectClass.equality       Index       dc_example_dc_com_objectClass.equality       true         6             0          0    0    0
member.equality            Index       dc_example_dc_com_member.equality            true         0             0          0    0    0
uniqueMember.equality      Index       dc_example_dc_com_uniqueMember.equality      true         0             0          0    0    0
cn.equality                Index       dc_example_dc_com_cn.equality                true         2000          0          0    0    0
cn.substring               Index       dc_example_dc_com_cn.substring               true         19407         0          0    0    0
sn.equality                Index       dc_example_dc_com_sn.equality                true         2000          0          0    0    0
sn.substring               Index       dc_example_dc_com_sn.substring               true         8147          0          0    0    0
telephoneNumber.equality   Index       dc_example_dc_com_telephoneNumber.equality   true         2000          0          0    0    0
telephoneNumber.substring  Index       dc_example_dc_com_telephoneNumber.substring  true         16506         0          0    0    0
ds-sync-hist.ordering      Index       dc_example_dc_com_ds-sync-hist.ordering      true         1             0          0    0    0
mail.equality              Index       dc_example_dc_com_mail.equality              true         2000          0          0    0    0
mail.substring             Index       dc_example_dc_com_mail.substring             true         7235          0          0    0    0
entryUUID.equality         Index       dc_example_dc_com_entryUUID.equality         true         2002          0          0    0    0

Total: 20

If an index contains a non zero value (N) in the undefined column, it means N index keys have reached the index entry limit and are no longer maintained. This can be normal, for example with the ObjectClass equality index, where the vast majority of entries will have the same objectclasses (top, Person, organizationalPerson, inetOrgPerson). But, for other attributes, such as cn, it may indicate that the index entry limit is too low.

Finally, OpenDJ has an option to do a live analysis of search filters and how they use indexes. To enable live index analysis, simply enable it for the database backend that contains the data :

dsconfig set-backend-prop --backend-name userRoot  --set index-filter-analyzer-enabled:true \
 --set max-entries:50 -h localhost -p 4444 -D cn=Directory\ Manager -w ****** -n -X

The max-entries parameter specifies how many filter items are being analyzed and kept in memory. Only the last max-entries will be kept. If there is a huge variety of requests against the directory service, you might want to increase the number. However, keep in mind that the analysis is kept in memory, and the higher the number the largest the impact on the overall performances of the server.

We do not recommend that you leave the index analysis enabled all the time, especially in production. The index analyzer should be used to gather statistics over a flow of requests for a short period of time, and should be disabled afterwards to free the resources.

The result of the index analyzer can be retrieved under the cn=monitor suffix, more specifically as part of the database environment of the backend.

$ bin/ldapsearch -p 1389 -D cn=directory\ manager -w secret12  \
-b "cn=userRoot Database Environment,cn=monitor" '(objectclass=*)' filter-use

dn: cn=userRoot Database Environment,cn=monitor
filter-use: (uid=user.*) hits:1 maxmatches:20 message:
filter-use: (tel=*) hits:1 maxmatches:-1 message:presence index type is disabled
  for the tel attribute
filter-use: (objectClass=groupOfURLs) hits:1 maxmatches:0 message:
filter-use: (objectClass=groupOfEntries) hits:1 maxmatches:0 message:
filter-use: (objectClass=person) hits:1 maxmatches:20 message:
filter-use: (objectClass=ds-virtual-static-group) hits:1 maxmatches:0 message:
filter-use: (aci=*) hits:1 maxmatches:0 message:
filter-use: (objectClass=groupOfNames) hits:1 maxmatches:0 message:
filter-use: (objectClass=groupOfUniqueNames) hits:1 maxmatches:0 message:
filter-use: (objectClass=ldapSubentry) hits:1 maxmatches:0 message:
filter-use: (objectClass=subentry) hits:1 maxmatches:0 message:

hits represents the number of time this filter was used. the maxmatches represents the maximum number of entries that were returned for that filter.

Index analysis and tuning is not a simple task, and I recommend to play with these tools  a lot on a test environment to understand how to get the best out of them. But, as you can see, OpenDJ provides you with all the tools you need to get the best performances out of your LDAP directory.

OpenDJ: Troubleshooting LDAP SSL connections

Troubleshooting Secure Socket Layer (SSL, also now standardized as TLS) issues is not trivial and there is no secret sauce specific to OpenDJ.

Should an LDAP SSL connection fails due to the server, you should find a descriptive error message in the server’s errors log (in logs/errors). But sometime the connection is aborted by the client with some obscure message. Often we see a message ending with ” javax.net.ssl.SSLHandshakeException: no cipher suites in common“.

Java has some debugging capabilities embedded and they are pretty easy to use with the OpenDJ LDAP directory server, which just need to be restarted with some additional arguments: -Djavax.net.debug=all or -Djavax.net.debug=ssl.

There are two ways to add extra arguments to the OpenDJ server startup command, using an environment variable, or using the java.properties file.

Using env variable

– you define the OPENDS_JAVA_ARGS environment variable. And you restart the server. If you do so, make sure you include all previous arguments.

OPENDS_JAVA_ARGS='-server -Xms1G -Xmx1G -Djavax.net.debug=ssl,handshake,trustmanager' bin/start-ds

Using the java.properties file

Edit the java.properties file in the config directory.
Since you probably only want to track the OpenDS directory server SSL access, you should append the -Djavax.net.debug=ssl,handshake,trustmanager args to the start-ds line (rather than applying it to all commands).

start-ds.java-args=-Xms1G -Xmx1G -server -Djavax.net.debug=ssl,handshake,trustmanager

Save the file and run the dsjavaproperties command:

bin/dsjavaproperties

Now restart the server, using the start-ds command

Where is the output ?

All SSL related logs are output in the logs/server.out file.
To test, you can use ldapsearch :

bin/ldapsearch -Z -X -p 1636 -b "" -s base '(objectclass=*)'

And if you look into the logs/server.out file, you will see something similar to this:

Using SSLEngineImpl.
 Allow unsafe renegotiation: false
 Allow legacy hello messages: true
 Is initial handshake: true
 Is secure renegotiation: false
 LDAP Request Handler 0 for connection handler LDAP Connection Handler 0.0.0.0 port 1636, READ: SSL v2, contentType = Handshake, translated length = 81
 *** ClientHello, TLSv1
 RandomCookie: GMT: 1287771875 bytes = { 68, 231, 5, 253, 105, 26, 137, 36, 38, 238, 12, 141, 110, 12, 59, 10, 192, 135, 113, 119, 108, 153, 10, 31, 127, 120, 110, 61 }
 Session ID: {}
 Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
 ...

This will help you to identify what part of the secure connection is failing and fix it.

Note that -Djavax.net.debug=ssl enables debug of the SSL connections, while -Djavax.net.debug=all enables full debugging including use of certificates, and more. You can also find more debug options by using -Djavax.net.debug=help.

 

OpenDJ 2.4.3 is now available

Another revision of OpenDJ has just been released. OpenDJ 2.4.3 is an update release of the OpenDJ project and resolves several issues found around the External Change Log and the bundled database version. The version is built out of revision 7007 of the b2.4 branch of the code repository.

The full details about the release have been posted in the OpenDJ 2.4.3 Release Notes.

As usual, you can find every thing on the OpenDJ Downloads page:

In addition, some draft documentation for OpenDJ, and more specifically the Administration Guide, are now published (and regularly updated) on the OpenDJ project site.

Feedback is important to us and you can participate on the IRC channel, the mailing lists or join our community.

Enjoy !

OpenDJ: Enabling the External Change Log on a single server

Yesterday, I described how easy it is to enable Multi-Master Replication between 2 instances of OpenDJ. One of the nice thing with OpenDJ replication, is that all changes are also publicly available (subject to access control) through LDAP under the cn=changelog suffix, also nick-named the External Change Log.

But the command to enable replication and thus the External Change Log requires 2 servers. So what if you want to enable the External Change Log on a single server ?

Note that this is not a fully supported procedure, but is handy for unit testing against the External Change Log. In production environment, you will have multiple servers for high availability and thus the External Change Log will be automatically configured.

Well you cannot use the dsreplication command, but you can configure the OpenDJ instance with the dsconfig utility.

$ bin/dsconfig create-replication-server -h ldap1.example.com -p 4444 \
  -D "cn=directory manager" -w secret12 -X -n \
  --provider-name "Multimaster Synchronization" --set replication-port:8989 \
  --set replication-server-id:2 --type generic
  
$ bin/dsconfig create-replication-domain -h ldap1.example.com -p 4444 \
  -D "cn=directory manager" -w secret12 -X -n \
  --provider-name "Multimaster Synchronization" --set base-dn:dc=example,dc=com \
  --set replication-server:ldap1.example.com:8989 --set server-id:3 \
  --type generic --domain-name example_com

If you want to be able to join this server in a replication topology, you should also create the global administrator’s entry. If you do so, then you will be able to use the dsreplication enable command as illustrated here.

$ bin/dsframework create-admin-user -X -h ldap1.example.com -p 4444 \
  -D "cn=Directory Manager" -w secret12 --userID admin --set password:password

Once enabled, you can read or search the changes with ldapsearch or other LDAP clients :

$ bin/ldapsearch -D cn=directory\ manager -w secret12 -h ldap1.example.com -p 1389 \
  -J "1.3.6.1.4.1.26027.1.5.4:false:;" -b "cn=changelog" '(objectclass=*)'
dn: cn=changelog
cn: changelog
objectClass: top
objectClass: container

# Public changelog exchange control(1.3.6.1.4.1.26027.1.5.4): dc=example,dc=com:0000012fd9bdf863000300000001;
dn: replicationCSN=0000012fd9bdf863000300000001,dc=example,dc=com,cn=changelog
targetDN: cn=a,ou=people,dc=example,dc=com
changeNumber: 0
changes:: b2JqZWN0Q2xhc3M6IHBlcnNvbgpvYmplY3RDbGFzczogdG9wCmNuOiBhCnNuOiBhCmVudH
 J5VVVJRDogNWQzMTNlY2UtYjY4Mi00MDFiLTg2NmYtM2NiZWNlMWNjNTJjCmNyZWF0ZVRpbWVzdGFtc
 DogMjAxMTA1MTAxMTQ5NTZaCmNyZWF0b3JzTmFtZTogY249RGlyZWN0b3J5IE1hbmFnZXIsY249Um9v
 dCBETnMsY249Y29uZmlnCg==
changeType: add
changeTime: 20110510114956Z
objectClass: top
objectClass: changeLogEntry

# Public changelog exchange control(1.3.6.1.4.1.26027.1.5.4): dc=example,dc=com:0000012fd9be46af000300000002;
dn: replicationCSN=0000012fd9be46af000300000002,dc=example,dc=com,cn=changelog
targetDN: cn=a,ou=people,dc=example,dc=com
changeNumber: 0
changes:: YWRkOiBkZXNjcmlwdGlvbgpkZXNjcmlwdGlvbjogTmV3IG9uZQotCnJlcGxhY2U6IG1vZG
 lmaWVyc05hbWUKbW9kaWZpZXJzTmFtZTogY249RGlyZWN0b3J5IE1hbmFnZXIsY249Um9vdCBETnMsY
 249Y29uZmlnCi0KcmVwbGFjZTogbW9kaWZ5VGltZXN0YW1wCm1vZGlmeVRpbWVzdGFtcDogMjAxMTA1
 MTAxMTUwMTZaCi0K
changeType: modify
changeTime: 20110510115016Z
objectClass: top
objectClass: changeLogEntry

Note: the search above uses the “Cookie Control” which is the optimized way to search the External Change Log. The value “;” means that the “cookie” is unknown, and therefore the search starts from the first change. If you want to continue from the last change received, provide the string value that is either in the ChangeLogCookie operational attribute (returned if asked for) or the comment before the change itself.