LDAP/AD integration is one of the most frustrating and time-consuming areas to troubleshoot, both for customers and for the Jive Support team. The purpose of this document is to unveil some of the mysteries of proper LDAP configuration with Jive products, and introduce some key tools and tricks which can help us help you to find a resolution as quickly as possible.
After you run through the initial Jive setup process, the only way to edit your LDAP settings in the application is via the system properties page (System > Settings > System Properties). You'll want to look for any of the keys that start with "ldap.". Keep in mind that changes to system properties require a system restart to take effect.
Alternatively, you can always choose to run through the setup process again. To do this, find the file jive_startup.xml in your jiveHome directory, and set the <setup> parameter to false.
| Key | Example Value | Explanation of Field | |
|---|---|---|---|
| ldap.serverType.id* | 2 = AD, 3 = openLDAP, 4 = other | Code for the type of LDAP instance | |
| ldap.host* | ldap.jive.com | Hostname or IP address of LDAP Server | |
| ldap.port* | 389 (default) or 636 (SSL) | Port number of LDAP server | |
| ldap.usernameField* | uid | The LDAP field name used for looking up username values | |
| ldap.baseDN* | DC=support,DC=jive,DC=com | The Distinguished Name of the base of your ldap tree. | |
| ldap.alternateBaseDN | DC=ldap,DC=jive,DC=com | An alternate baseDN which will be searched after the baseDN. | |
| ldap.nameField^ | cn | The element key for the name attribute. | |
| ldap.firstNameField^ | givenName | First name element in LDAP. | |
| ldap.lastNameField^ | sn | Surname element in LDAP | |
| ldap.emailField* | Email element in LDAP. | ||
| ldap.connectionPoolEnabled | true | Determines if LDAP connection pooling is enabled (http://java.sun.com/products/jndi/tutorial/ldap/connect/config.html). | |
| ldap.followReferrals | true | Determines whether or not LDAP queries will follow referrals. Not applicable to Active Directory. | |
| ldap.adminDN* | CN=AdminMan,OU=Domain Users,DC=support,DC=jive,DC=com | The DN for the LDAP admin user. | |
| ldap.adminPassword* | a54313f2d3bc98fb5234566995246c7 | The encrypted Admin password. | |
| ldap.adminPassword.key* | jOK2yjeI8h53UFB5 | A key used to encrypt the Admin password. | |
| ldap.adminPassword.encrypted* | true | Determines whether or not the Admin password is encrypted. Should be 'true'. | |
| ldap.ldapDebugEnabled | false | Turn on LDAP debug logging (This is VERY verbose! Do not use in Production except when troubleshooting!) | |
| ldap.sslEnabled | false | Use an SSL connection to communicate with LDAP server. | |
| ldap.initialContextFactory | |||
| ldap.searchFilter | (sAMAccountName={0}) | The field that identifies this LDIF in terms of what user it describes. | |
| ldap.groupNameField | cn | The field that maps a group to its CN in LDAP. | |
| ldap.groupMemberField | member | The field that maps a group to its members. | |
| ldap.groupDescriptionField | description | Maps a description of a group. | |
| ldap.posixMode | false | Connect to LDAP in posix mode. | |
| ldap.posixEnabled | false | Connect to LDAP in posix mode. | |
| ldap.groupSearchFilter^ | (objectClass=group) | The field that describes what key/value pair to expect when looking for a LDIF to delineate it's a group LDIF. | |
| ldap.managerField | manager | Maps the DN of a person's manager. (Used when synching relationships) | |
| ldap.photoField | photo | Maps a photo to a user's profile. | |
| ldap.lastUpdatedField | creationdate | Used to check if an LDAP record has been updated since the most recent sync. | |
| ldap.userGroupMember^ | memberOf | The field that maps a user to a group. (Should see on the user LDIF). | |
| ldap.userDN^ | ou=People | A RDN (relative to the baseDN) which contains users to sync to SBS. | |
| jive.sync.user.ldap | true | Determines whether or not user synchronizations are enabled. | |
| jive.sync.relationships.ldap | false | Determines whether or not user relationships are synchronized from LDAP. | |
| jive.sync.profile.ldap.photo | false | Determines whether or not profile photos are synchronized from LDAP. | |
| jive.sync.profile.ldap.login | false | Determines whether or not profiles are synchronized at login. | |
| jive.sync.auto.disable | true | Specifies whether Jive should disable user accounts which cannot be found in the LDAP directory. | |
| jive.sync.auto.disable.att.name | userAccountControl | The name of the attribute which indicates whether or not an account is disabled in LDAP. | |
| jive.sync.auto.disable.att.value | 514 (see link) | In Active Directory, use the following guide: http://support.microsoft.com/kb/305144 | |
| GroupManager.className | com.jivesoftware.base.ldap.LdapGroupManager for LDAP groups; com.jivesoftware.base.database.DbGroupManager to use default group manager | Controls whether or not permission groups are synched from LDAP. |
* Default/Required fields
^ Recommended fields
com.jivesoftware.base.ldap.LdapGroupManager
LDAP debugging might be the single most useful tool for troubleshooting an LDAP issue. Turn on the system property "ldap.ldapDebugEnabled=true" and restart your system. The LDAP output will be logged to whichever log file captures system output (i.e. catalina.out), NOT to clearspace.log. The application logs are also useful, so be sure to send that one along with catalina.out.
Be aware that LDAP debugging is VERY verbose. After you've gathered the required information and resolved your problem, you'll want to shut it off as soon as possible. As an alternative, you can also use a tool such as Wireshark to capture a TCP dump of LDAP traffic.
The account you associate with the ldap.adminDN attribute should be an LDAP administrator with full read access to the branch from which you will be synchronizing data with Clearspace. This account should not be associated with a Clearspace user or administrator. It is used to bind an LDAP connection from the Clearspace server.
All LDAP directories can read and write to a file format called LDIF. An LDIF can tell a Jive support engineer just about all we'll need to know about how you need to configure your settings to properly extract user and group records from LDAP. Here's an example:
dn: CN=Cyr \, Karl,OU=Jive_Users,DC=support,DC=jive,DC=com
changetype: add
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: Cyr , Karl
sn: Cyr
physicalDeliveryOfficeName: Awesome
givenName: Karl
initials: KC
distinguishedName: CN=Cyr \, Karl,OU=Jive_Users,DC=support,DC=jive,DC=com
instanceType: 4
whenCreated: 20081119215504.0Z
whenChanged: 20090202220617.0Z
displayName: Cyr , Karl
uSNCreated: 4391224
memberOf: CN=FilterGroup,OU=Jive_Users,DC=support,DC=jive,DC=com
uSNChanged: 4399897
department: Awesome
name: Cyr , Karl
objectGUID:: 2tnXRo7VxE6zc72YqLtOTw==
userAccountControl: 66048
badPwdCount: 1
codePage: 0
countryCode: 0
badPasswordTime: 128769530029375000
lastLogoff: 0
lastLogon: 128742007081093750
pwdLastSet: 128716053043750000
primaryGroupID: 513
objectSid:: AQUAAAAAAAUVAAAAF8sUcR3r8QcekDXQw9wAAA==
accountExpires: 9223372036854775807
logonCount: 0
sAMAccountName: karl
sAMAccountType: 805306368
userPrincipalName: karl@support.jive.com
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=support,DC=jive,DC=com
dSCorePropagationData: 20081119220919.0Z
dSCorePropagationData: 20081119220919.0Z
dSCorePropagationData: 20081119220919.0Z
dSCorePropagationData: 16010108151056.0Z
mail: karl@fake.com
Any LDAP directory browser provides the ability to export to and import from an LDIF file. If you're using Active Directory, check out the ldifde command line tool. Here's an example of the ldifde command which will yield an LDIF output like above:
Another excellent tool is JXplorer, which helps you to validate your LDAP mappings and provides an easy-to-use LDIF export.
User profile information is sychronized with LDAP whenever a user logs in. Alternatively, an administrator can launch a system-wide profile synchronization manually via the admin console (People > Settings > Profiles)
LDAP Groups can be pulled into the application for the purposes of managing permissions and access control. These are separate entities from Social Groups and are not visible to end-users. It is important to note that LDAP groups are lazy-loaded, which means that you will not see a group added to Clearspace until a member of of that group has authenticated to the system for the first time.
Using the lazy-loading technique for synchronizing group memberships is a big performance boost for the application. However, when you are setting up your communities for the first time, you may find it necessary to synchronize all group membership at once. To do this, use the following technique:
You can kick off the syncronization of LDAP groups to Clearspace by adding the attached spring.xml file to your jiveHome/etc directory, making a small change to it, and restarting your Clearspace instance.
Edit the following line:
<entry key="ldapGroupManagerImpl.syncTaskCronExpression" value="0 m h * * ?"></entry>
Where m and h are the minute and hour at which you would like the task to run. An optimal choice would be five minutes after your restart.
After you have verified that your groups have successfully synchronized you may want to remove the XML file and restart your server. By default, Clearspace "lazy-loads" LDAP groups, and this trick overrides that process to instead sync based on the cron task you've scheduled. Lazy-loading group memberships leads to better overall application performance.
In some directories, groups identify their members by the full distinguished name (DN) of their members. Other groups store their member associations by the common name (CN). The latter type is a POSIX group. For example:
member= CN=Cyr \, Karl,OU=Jive_Users,DC=support,DC=jive,DC=com -> "normal" group identification
memberuid=karlcyr -> "POSIX" group
If your group type is POSIX, you'll need to enable POSIX mode (see above).
If your DNs have elements which contain spaces, they may need to be escaped in order for Jive to communicate with AD:
CN=AdminMan,OU=Domain Users,DC=support,DC=jive,DC=com
CN=Admin\20Man,OU=Domain\20Users,DC=support,DC=jive,DC=com
08 Jun 2009 00:08:21,104 [Task Engine Worker 0] FATAL
control.AbstractRequestControlDirContextProcessor - No matching
response control found for paged results - looking for 'class
javax.naming.ldap.PagedResultsResponseControl
08 Jun 2009 00:08:21,105 [Task Engine Worker 0] WARN sync.LdapUserDataSynchronizer - Failed to retrieve all remote users
org.springframework.ldap.OperationNotSupportedException:
[LDAP: error code 12 - Unavailable Critical Extension]; nested
exception is javax.naming.OperationNotSupportedException: [LDAP: error
code 12 - Unavailable Critical Extension]; remaining name ''
at org.springframework.ldap.support.LdapUtils.convertLdapException(LdapUtils.java:199)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:319)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:259)
at
com.jivesoftware.community.user.sync.LdapUserDataSynchronizer.populateUsersUsingPaging(LdapUserDataSynchronizer.java:344)
at com.jivesoftware.community.user.sync.LdapUserDataSynchronizer.getAllRemoteUsers(LdapUserDataSynchronizer.java:314)
at com.jivesoftware.community.user.sync.LdapUserDataSynchronizer.doRun(LdapUserDataSynchronizer.java:188)
at com.jivesoftware.util.task.AbstractPollableRunnable.run(AbstractPollableRunnable.java:108)
at com.jivesoftware.util.cron.CronTask$TaskWrapper.run(CronTask.java:147)
at com.jivesoftware.util.task.TaskEngine$TaskEngineWorker.run(TaskEngine.java:392)
Caused
by: javax.naming.OperationNotSupportedException: [LDAP: error code 12 -
Unavailable Critical Extension]; remaining name ''
at com.sun.jndi.ldap.LdapCtx.mapErrorCode(LdapCtx.java:3065)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2951)
at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2758)
at com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1812)
at com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1735)
at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search(ComponentDirContext.java:368)
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:338)
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:321)
at javax.naming.directory.InitialDirContext.search(InitialDirContext.java:248)
at org.springframework.ldap.core.LdapTemplate$4.executeSearch(LdapTemplate.java:253)
at org.springframework.ldap.core.LdapTemplate.search(LdapTemplate.java:293)
... 7 more
08 Jun 2009 00:08:21,106 [Task Engine Worker 0] WARN sync.LdapUserDataSynchronizer - Failed to sychronize users
java.lang.NullPointerException
at
com.jivesoftware.community.user.sync.LdapUserDataSynchronizer.populateUsersUsingPaging(LdapUserDataSynchronizer.java:353)
at com.jivesoftware.community.user.sync.LdapUserDataSynchronizer.getAllRemoteUsers(LdapUserDataSynchronizer.java:314)
at com.jivesoftware.community.user.sync.LdapUserDataSynchronizer.doRun(LdapUserDataSynchronizer.java:188)
at com.jivesoftware.util.task.AbstractPollableRunnable.run(AbstractPollableRunnable.java:108)
at com.jivesoftware.util.cron.CronTask$TaskWrapper.run(CronTask.java:147)
at com.jivesoftware.util.task.TaskEngine$TaskEngineWorker.run(TaskEngine.java:392)
This error is occuring because your LDAP server does not support paged results and the application is trying to utilize them. You will need to disable this, which you can do with the following changes:
For 3.0.x:
Add the following sytem property and restart the server:
name: spring.ldapConfiguration.autoSetVersion
value: false
For 2.5.x:
Place the attached file (spring-ldap.xml) in your jiveHome/etc directory and restart the server.
Thanks Long- let me know if I missed anything! (Aside from the table of system properties I haven't started yet
).
Awesome doc, Karl! Unreachable LDAP referrals are a common source of woe. Would be good to get a section in here about that, but this is a great start that explains most of the common questions.
Very helpful. One thing I haven't been able to track down is how to back out of an LDAP config if you decide LDAP is not what you want to use. Is there a simple way to do that? Is it as simple as removing all of the values mentioned above from the config?
If you are a on the command line you can also use "ldapsearch". Handy in cases the connected ldap is not reachable from your own machines network.
I don't think it would be that simple. I haven't investigated making such a move, but I would imagine that it would take a little bit of manual effort. For one thing, the users in the Clearspace/SBS jiveuser table would all need to have the "Federated" bit changed to 0 so that the application knows that they should be authenticated against the database. For another, the passwords that are stored in the database for federated users are garbage, and would need to be reset. If you are interested in finding out more, please open a Support case and we can take a deeper look into it. Or, if anyone has already been through it, please feel free to chime in!
Awesome stuff Karl with a K!
LDAP browsers are also useful for verifying your settings/filters, they can help determine whether an issue lies in Clearspace or LDAP configuration.
Jxplorer is a good and free one: http://www.jxplorer.org