# LDAP secondary group memberships with OpenDJ and Ubuntu 12.04

As a follow-up to this post, let’s now configure OpenDJ and Ubuntu to use LDAP for assigning secondary groups to user accounts.

This is a quick guide intended for testing only, and we are assuming the setup here has been followed. One change is that we are using Ubuntu 12.04 x86 as the client system.

First, let’s create a new test group in OpenDJ. We assign it the structural object class namedObject, and the auxiliary object class posixGroup. The group GID number is 130, and we add a memberUid entry, with the UID of an existing LDAP account:

Now, on our test Ubuntu 12.04 x86 client, we modify /etc/ldap.conf, adding the following entry:

nss_schema rfc2307bis


This enables rfc2307bis LDAP schema support for PAM (OpenDJ uses the rfc2307bis schema by default).

Next, again in /etc/ldap.conf we uncomment the nss_base_group setting in the section headed with the comment “RFC2307bis naming contexts”, and give it the value as shown:

nss_base_group ou=Groups,dc=example,dc=co,dc=nz


Obviously you would modify the domain components to suit.

We now restart the nscd service, and verify that the secondary group information can be retrieved for an LDAP user:

itadmin@turrican2:/etc$sudo /etc/init.d/nscd restart * Restarting Name Service Cache Daemon nscd [ OK ] itadmin@turrican2:/etc$
itadmin@turrican2:/etc$id davek uid=1004(davek) gid=50(staff) groups=130(testgroup),50(staff)  We can see that the secondary group testgroup with the GID number of 130 is successfully retrieved from LDAP for this user. Advertisements # LDAPCon 2011 presentation on OpenDJ Great video here presented by Ludovic Poitou of ForgeRock, on the OpenDJ directory server project and its origins as OpenDS at Sun Microsystems: One thing I found of particular interest (and also because I can’t resist yet another dig at Oracle – but only because they make it so very easy) comes right at the end of the presentation (here), which not only indicates that code commits to the OpenDS project which Oracle inherited are practically dead (i.e. death by neglect), but that in June 2011 they actually created a proprietary fork of it (gee, imagine that!), called “Oracle Unified Directory”. It’s great to see that out of the two forks of OpenDS at least that I am aware of (the other is here), OpenDJ remains truly open, from the code to the documentation. No need to “contact sales” nor have to deal with a crummy “evaluation license”. And if you need professional support, ForgeRock offer that too. # OpenDS forked, becomes OpenDJ Between Oracle alternately shutting down Sun Microsystems’ open source projects (OpenSolaris, Project Wonderland et al), and those same communities forking left right and centre (think OpenIndiana, LibreOffice et al) comes the rather low-profile news that OpenDS has been forked by ForgeRock into OpenDJ: http://www.forgerock.com/opendj-faq.html Be checking this one out for sure. # Use OpenDS for Thunderbird LDAP Address Book data Trey Drake at Sun Microsystems has a quick little post for trying this with Apple Address Book: http://blogs.sun.com/treydrake/entry/mac_address_book_and_opends “Works like a charm” indeed, and doing the same with Thunderbird proves to be just as easy 🙂 Using the OpenDS setup instructions outlined in my Apache Roller post, and using Thunderbird 3.0 on OpenSolaris snv_134 x64, one simply configures an LDAP address book like so: By default OpenDS enables anonymous read/search access to the directory, so we don’t need to authenticate. Additionally, I’ve set up my OpenDS server to run automatically as a service using SMF – the guide which I followed to achieve this is here: https://docs.opends.org/2.2/page/ManagingTheDirectoryServerAsAnSMFServiceOpenSolarisOnly The only problem I encountered after configuring the above was getting the ldap user to access the OpenDS control panel GUI without X server security errors. One has to use the xhost command to grant access to the X server for the ldap user: $ xhost
access control enabled, only authorized clients can connect
SI:localuser:gdm
SI:localuser:root

$pfexec xhost +SI:localuser:ldap localuser:ldap being added to access control list$ xhost
access control enabled, only authorized clients can connect
SI:localuser:ldap
SI:localuser:gdm
SI:localuser:root


After which I could launch the OpenDS control-panel application as the ldap user fine – although I haven’t determined yet how to make this persistent across reboots or desktop logins.

# Using Apache Roller with OpenDS for LDAP authentication

This is a basic guide and is more a set of self-help notes while I learn about LDAP. Even so, at the end of this you’ll have an idea about how to securely authenticate to Roller with user account information held in an OpenDS LDAP directory.

We are using OpenDS v2.2, and an OpenSolaris system running Apache Roller as described in detail in my post here. This how-to assumes you have a freshly installed instance of Roller as described in that link, and have created the initial Roller administrator account with a username of “admin”.

Install OpenDS v2.2

The OpenDS installer is a thing of beauty, and a model for how easy software download and installation could be. Matter of fact, with its built-in Java monitoring and administration control panels, the whole package is pretty darn cool.

Go to http://www.opends.org/ and click the “Get 2.2″ now!” link. (make sure you have a recent JRE installed and a decent internet connection).

You’ll be presented with the OpenDS QuickSetup Welcome screen. We want to install a new server instance:

Enter your installation path, and under “LDAP Secure Access”, click the “Configure…” button; in the following screen enable SSL access, and generate a self-signed certificate. All other settings are fine at their defaults:

We want a standalone server:

For our Directory Data, the default Directory Base DN of dc=example,dc=com is fine. We also only want to create the base entry for now:

Review the settings, and click “Finish” to complete. Once OpenDS has worked its magic, launch the OpenDS control panel, and select the local server instance to manage:

Create LDAP account information in OpenDS

We’ll now quickly populate our OpenDS directory with some very basic user information.

In the OpenDS Control Panel main view, click the “Directory Data” disclosure arrow on the left-hand of the window, and select “Manage Entries”. In the “Manage Entries” window that appears, select “Entries” on the menu bar, then select “New Organizational Unit”. Name the new OU “People”:

Select the newly created “People” OU, and from the “Entries” menu, select “New User…”. Enter the information as follows, noting that the value for “User ID” (UID) will be the same as the Roller account username (in this case, the initial Roller administrator account):

Create additional entries in the same way if you like:

Import the OpenDS SSL certificate into the system and Glassfish domain keystores

We are setting this up with secure connections all ’round, so Roller needs to trust OpenDS by using OpenDS’ certificate. When installing OpenDS, we generated a self-signed certificate – so we simply locate this and import it into the relevant keystores. We use the keytool command to do this.

I’ve installed OpenDS to /opt/OpenDS, so the OpenDS keystore is located at /opt/OpenDS/config/keystore.

The location of the keystores for the system, and for the Glassfish domain containing the instance of Roller are located respectively at:

/usr/java/jre/lib/security/cacerts
/var/appserver/domains/domain1/config/cacerts.jks

Let’s view the contents of the OpenDS keystore:

$pfexec keytool -list -v -keystore /opt/OpenDS/config/keystore Enter keystore password: Keystore type: JKS Keystore provider: SUN Your keystore contains 1 entry Alias name: server-cert Creation date: 3/05/2010 Entry type: PrivateKeyEntry Certificate chain length: 1 Certificate[1]: Owner: CN=afterburner, O=OpenDS Self-Signed Certificate Issuer: CN=afterburner, O=OpenDS Self-Signed Certificate Serial number: Valid from: Mon May 03 16:38:02 NZST 2010 until: Wed May 02 16:38:02 NZST 2012 Certificate fingerprints: MD5: SHA1: Signature algorithm name: SHA1withRSA Version: 3  Now, export the OpenDS certificate to a file: $ pfexec keytool -export -alias "server-cert" \
-keystore /opt/OpenDS/config/keystore -file /tmp/server-cert.cer
Enter keystore password:
Certificate stored in file /tmp/server-cert.cer


Then import the exported certificate into the Java system keystore:

$pfexec keytool -import -v -trustcacerts -alias "server-cert" \ -keystore /usr/java/jre/lib/security/cacerts -file /tmp/server\-cert.cer Enter keystore password: Owner: CN=afterburner, O=OpenDS Self-Signed Certificate Issuer: CN=afterburner, O=OpenDS Self-Signed Certificate Serial number: Valid from: Mon May 03 16:38:02 NZST 2010 until: Wed May 02 16:38:02 NZST 2012 Certificate fingerprints: MD5: SHA1: Signature algorithm name: SHA1withRSA Version: 3 Trust this certificate? [no]: yes Certificate was added to keystore [Storing /usr/java/jre/lib/security/cacerts]  And do the same for the Glassfish Roller domain keystore: $ pfexec keytool -import -v -trustcacerts -alias "server-cert" \
-keystore /var/appserver/domains/domain1/config/cacerts.jks \
-file /tmp/server\-cert.cer
Enter keystore password:
Certificate already exists in system-wide CA keystore under alias server-cert
Do you still want to add it to your own keystore? [no]:  yes
Certificate was added to keystore
[Storing /var/appserver/domains/domain1/config/cacerts.jks]


Configure Roller for LDAP authentication

This involves modifications to the Roller security.xml file to enable LDAP logins, as well as a small change to the roller-custom.properties file. The security.xml file is located (on my system) at /opt/Roller/webapp/roller/WEB-INF. Let’s modify this file first.

Under the AUTHENTICATION section of security.xml I’ve added /roller-ui/user.do*=register to the value list for the filterInvocationInterceptor bean. Then under the authenticationManager bean I’ve commented out daoAuthenticationProvider and uncommented ldapAuthProvider.

A copy of this section of my security.xml file follows; hover your mouse over the top-right of the box and select “view source” for the full view:


<!-- ======================== AUTHENTICATION ======================= -->

<bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="objectDefinitionSource">
<value>
PATTERN_TYPE_APACHE_ANT
/roller-ui/login-redirect**=admin,editor
/roller-ui/profile**=admin,editor
/roller-ui/createWeblog**=admin,editor
/roller-ui/menu**=admin,editor
/roller-ui/authoring/**=admin,editor
/roller-ui/admin/**=admin
/roller-ui/user.do*=register
/rewrite-status*=admin
</value>
<!-- Add this to above list for LDAP/SSO configuration -->
<!-- /roller-ui/user.do*=register -->
</property>
</bean>

<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<!-- <ref local="daoAuthenticationProvider"/> -->
<ref local="ldapAuthProvider"/>
<!-- Uncomment this for CAS/SSO configuration <ref local="casAuthenticationProvider"/> -->
<ref local="anonymousAuthenticationProvider"/>
<!-- rememberMeAuthenticationProvider added programmatically -->
</list>
</property>
</bean>


Next, proceed to the LDAP AUTHENTICATION section of security.xml, and uncomment the sample block of code visible there. Most of the code is fine as-is, but we set the constructor-arg value for the initialDirContextFactory bean to the URL/BaseDN of our LDAP server, and the values for managerDn and managerPassword to our OpenDS directory administrator username and password respectively.

A copy of this section of my security.xml file follows; hover your mouse over the top-right of the box and select “view source” for the full view:


<!-- ===================== LDAP AUTHENTICATION ==================== -->

<bean id="initialDirContextFactory" class="org.acegisecurity.ldap.DefaultInitialDirContextFactory">
<constructor-arg value="ldaps://localhost:1636/dc=example,dc=com"/>
<property name="managerDn" value="cn=Directory Manager"/>
<property name="managerPassword" value="somepassword"/>
</bean>

<bean id="ldapUserSearch" class="org.acegisecurity.ldap.search.FilterBasedLdapUserSearch">
<constructor-arg index="0" value=""/>
<constructor-arg index="1" value="uid={0}"/>
<constructor-arg index="2" ref="initialDirContextFactory"/>
<property name="searchSubtree" value="true"/>
</bean>

<bean id="ldapAuthProvider" class="org.acegisecurity.providers.ldap.LdapAuthenticationProvider">
<constructor-arg>
<bean class="org.acegisecurity.providers.ldap.authenticator.BindAuthenticator">
<constructor-arg ref="initialDirContextFactory"/>
<property name="userSearch" ref="ldapUserSearch"/>
</bean>
</constructor-arg>
<constructor-arg ref="jdbcAuthoritiesPopulator"/>
<property name="userCache" ref="userCache"/>
</bean>

<bean id="jdbcAuthoritiesPopulator" class="org.apache.roller.weblogger.ui.core.security.AuthoritiesPopulator">
<property name="defaultRole" value="register"/>
</bean>



Now, add the following entry to roller-custom.properties (which resides on my system at /var/appserver/domains/domain1/lib/classes):

users.sso.enabled=true

A shout out to Trey Drake from Sun Microsystems who originally blogged about this at http://blogs.sun.com/treydrake/entry/opends_roller_integration.

Log in to Roller using LDAP authentication

The caveat here is that Roller user accounts must already exist for successful LDAP authentication; LDAP+Roller will not provision them automatically, at least not with this simple setup.

Restart the Glassfish Roller domain (and possibly the Roller MySQL database as well for completeness) and you should now be able to log in to Roller with the username admin, using the LDAP password specified when you created the corresponding admin account in OpenDS.

Additional Roller user accounts you create as the Roller admin user (using the Roller admin BUI) can use LDAP for authentication, provided the username you specify for the Roller user account is the same as the UID (User ID) for the corresponding OpenDS entry.