Commit 9701ddf5 authored by Matt Tucker's avatar Matt Tucker Committed by matt

Work on LDAP.


git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@348 b35dd754-fafc-0310-a699-88a17e54d16e
parent dac64a1e
......@@ -81,11 +81,8 @@ Open the Messenger configuration file <tt>MESSENGER_HOME/config/jive-messenger.x
editor and add or change the following settings:
</p>
<ul>
<li>UserProvider.id.className - com.jivesoftware.xmpp.ldap.LdapUserIDProvider</li>
<li>UserProvider.properties.className</li>
<li>UserProvider.info.className</li>
<li>UserProvider.account.className</li>
<li>UserProvider.roster.className</li>
<li>ldap.host - LDAP server host; e.g. localhost or machine.example.com, etc.</li>
<li>ldap.port - LDAP server port number</li>
<li>ldap.usernameField - The field name that the username lookups will be performed on.</li>
......@@ -103,7 +100,6 @@ editor and add or change the following settings:
<li>ldap.sslEnabled - Enable SSL connections to your LDAP server. If you enable SSL connections, the LDAP server port
number most likely should be changed to 636.
</li>
<li>ldap.mode - "0" for all LDAP mode, "1" for mixed LDAP/Jive DB mode</li>
</ul>
<p>
Below is a sample set up.
......@@ -112,18 +108,12 @@ Below is a sample set up.
&lt;jive&gt;
...
&lt;UserProvider&gt;
&lt;id&gt;
&lt;className&gt;org.jivesoftware.messenger.ldap.LdapUserIDProvider&lt;/className&gt;
&lt;/id&gt;
&lt;properties&gt;
&lt;className&gt;org.jivesoftware.messenger.ldap.LdapUserPropertiesProvider&lt;/className&gt;
&lt;/properties&gt;
&lt;info&gt;
&lt;className&gt;org.jivesoftware.messenger.ldap.LdapUserInfoProvider&lt;/className&gt;
&lt;/info&gt;
&lt;account&gt;
&lt;className&gt;org.jivesoftware.messenger.ldap.LdapUserAccountProvider&lt;/className&gt;
&lt;/account&gt;
&lt;UserProvider&gt;
&lt;ldap&gt;
&lt;host&gt;myhost.com&lt;/host&gt;
......@@ -136,81 +126,8 @@ Below is a sample set up.
&lt;adminPassword&gt;adm1npwd&lt;/adminPassword&gt;
&lt;debugEnabled&gt;false&lt;/debugEnabled&gt;
&lt;sslEnabled&gt;false&lt;/sslEnabled&gt;
&lt;mode&gt;1&lt;/mode&gt;
&lt;/ldap&gt;
...
&lt;/jive&gt;
</code></pre>
<h2>Configure the LDAP Server (optional)</h2>
<p>
<b>Note:</b> If you use the "mixed mode" of the Jive Messenger LDAP module, no changes to your LDAP directory are
necessary. However, if you use the "pure mode", you'll need to make changes to your directory as detailed below.
Several custom LDAP attributes are used to store things such as the numeric Jive Messenger user ID,
the date the account was created, privacy flags, etc. The first step is to define these attributes in your LDAP
directory.
</p>
<table>
<tr>
<th>Name</th>
<th>Type</th>
<th>OID</th>
<th>Multi-valued</th>
<th>Description</th>
</tr>
<tr>
<td>jiveUserID</td>
<td>Integer </td>
<td>1.3.6.1.4.1.10985.389.2 </td>
<td>No </td>
<td>A numeric ID that Jive Messenger uses to identify a user.</td>
</tr>
<tr>
<td>jiveNameVisible </td>
<td>String </td>
<td>1.3.6.1.4.1.10985.389.3 </td>
<td>No </td>
<td>The value is "true" if a user wishes to show their name publicly; "false" otherwise.</td>
</tr>
<tr>
<td>jiveEmailVisible </td>
<td>String </td>
<td>1.3.6.1.4.1.2.10985.389.4 </td>
<td>No </td>
<td>The value is "true" if a user wishes to show their email address publicly; "false" otherwise.</td>
</tr>
<tr>
<td>jiveCDate </td>
<td>String </td>
<td>1.3.6.1.4.1.10985.389.6 </td>
<td>No </td>
<td>The date the user became a Jive Messenger user.</td>
</tr>
<tr>
<td>jiveMDate </td>
<td>String </td>
<td>1.3.6.1.4.1.10985.389.7 </td>
<td>No </td>
<td>The date the user information was last updated.</td>
</tr>
<tr>
<td>jiveProps </td>
<td>String </td>
<td>1.3.6.1.4.1.10985.389.8 </td>
<td>Yes </td>
<td>A collection of extended properties for the user.</td>
</tr>
</table>
<p>Next, you can optionally create a new object class that uses the specified attributes
(or modify an existing object to add the attributes). The Jive Messenger LDAP module does not actually pay attention to
object types, but only looks for the correct attributes. If you do create a new object, the object name should be
"jivePerson" with an OID of 1.3.6.1.4.1.2.10985.389.1.
</p>
<p>
Each of the attributes listed above must be added as an optional attribute since the attributes will not be
created until the user logs into Jive Messenger for the first time.
</p>
<p>
Also, you may wish to create an index on the "jiveUserID" attribute so that lookups on that field are fast.
</p>
</body>
......@@ -28,21 +28,14 @@
<baseDN></baseDN>
<adminDN></adminDN>
<adminPassword></adminPassword>
<mode>1</mode>
</ldap>
<UserProvider>
<id>
<className>org.jivesoftware.messenger.ldap.LdapUserIDProvider</className>
</id>
<properties>
<className>org.jivesoftware.messenger.ldap.LdapUserPropertiesProvider</className>
</properties>
<info>
<className>org.jivesoftware.messenger.ldap.LdapUserInfoProvider</className>
</info>
<account>
<className>org.jivesoftware.messenger.ldap.LdapUserAccountProvider</className>
</account>
</UserProvider>
<AuthProvider>
<className>org.jivesoftware.messenger.ldap.LdapAuthProvider</className>
......
......@@ -18,7 +18,7 @@ import org.jivesoftware.messenger.auth.UnauthorizedException;
* Implementation of auth provider interface for LDAP
* authentication service plug-in.
*
* @author Jim Berrettini
* @author Matt Tucker
*/
public class LdapAuthProvider implements AuthProvider {
private LdapManager manager;
......@@ -27,34 +27,14 @@ public class LdapAuthProvider implements AuthProvider {
manager = LdapManager.getInstance();
}
/**
* <p>Determines if the authentication system supports the use of
* plain-text passwords.</p>
*
* @return true - plain text passwords are supported.
*/
public boolean isPlainSupported() {
return true;
}
/**
* <p>Determines if the authentication system supports the use
* of digest authentication.</p>
*
* @return false - digest authentication is not currently supported.
*/
public boolean isDigestSupported() {
return false;
}
/**
* <p>Validates username and password against data in LDAP store. Returns if the username and password are valid otherwise the method throws an
* UnauthorizedException.<p>
*
* @param username
* @param password
* @throws UnauthorizedException
*/
public void authenticate(String username, String password) throws UnauthorizedException {
if (username == null || password == null) {
throw new UnauthorizedException();
......@@ -83,29 +63,11 @@ public class LdapAuthProvider implements AuthProvider {
}
}
/**
* <p>Validates username, unique session token, and digest generated from the
* password and token according to the Jabber digest auth protocol against data in LDAP store.
* Since Digest authentication is not currently supported, throws UnsupportedOperationsException.</p>
*
* @param username
* @param token
* @param digest
* @throws UnsupportedOperationException
*/
public void authenticate(String username, String token, String digest) throws UnsupportedOperationException {
throw new UnsupportedOperationException("Digest authentication not currently supported.");
}
/**
* <p>Updates username and password. Throws UnsupportedOperationException, as LDAP store is accessed in read-only
* mode.</p>
*
* @param username
* @param password
* @throws UnsupportedOperationException
*/
public void updatePassword(String username, String password) throws UnsupportedOperationException {
throw new UnsupportedOperationException("Cannot update password in LDAP");
}
}
}
\ No newline at end of file
......@@ -22,44 +22,23 @@ import javax.naming.directory.*;
/**
* Centralized administration of LDAP connections. The getInstance() method
* should be used to get an instace. The following Jive properties correspond
* to the properties of this manager: <ul>
* should be used to get an instace. The following configure this manager:<ul>
* <li> ldap.host
* <li> ldap.port
* <li> ldap.usernameField
* <li> ldap.baseDN
* <li> ldap.adminDN
* <li> ldap.adminPassword
* <li> ldap.mode
* <li> ldap.ldapDebugEnabled
* <li> ldap.sslEnabled
* <li> ldap.initialContextFactory -- if this value is not specified,
* "com.sun.jndi.ldap.LdapCtxFactory" will be used instead.
* </ul><p>
*
* The LDAP module operates in one of two modes:<ul>
* <li> ALL_LDAP_MODE -- all user data is stored in LDAP, including Jive-specific data such
* as the number of reward points, etc. This option requires making modifications to
* the schema of the directory.
* <li> LDAP_DB_MODE -- only critical user data is stored in LDAP (username, name, and email).
* All Jive-specific data is stored in the normal jiveUser and userProperty database
* tables. This mode requires no changes to the LDAP directory.</ul>
* </ul>
*
* @author Matt Tucker
*/
public class LdapManager {
/**
* The mode for storing all user data in LDAP, including Jive-specific data.
*/
public static final int ALL_LDAP_MODE = 0;
/**
* The mode for storing only critical user data in LDAP (username, name, and email) and all
* other Jive-specific user data in the normal database tables.
*/
public static final int LDAP_DB_MODE = 1;
private String host;
private int port = 389;
private String usernameField = "uid";
......@@ -69,7 +48,6 @@ public class LdapManager {
private String alternateBaseDN = null;
private String adminDN;
private String adminPassword;
private int mode = 0;
private boolean ldapDebugEnabled = false;
private boolean sslEnabled = false;
private String initialContextFactory;
......@@ -87,7 +65,7 @@ public class LdapManager {
}
/**
* Creates a new LdapManager instance. This class is a singleton so the
* Constructs a new LdapManager instance. This class is a singleton so the
* constructor is private.
*/
private LdapManager() {
......@@ -122,13 +100,6 @@ public class LdapManager {
this.adminPassword = JiveGlobals.getXMLProperty("ldap.adminPassword");
this.ldapDebugEnabled = "true".equals(JiveGlobals.getXMLProperty("ldap.ldapDebugEnabled"));
this.sslEnabled = "true".equals(JiveGlobals.getXMLProperty("ldap.sslEnabled"));
String modeStr = JiveGlobals.getXMLProperty("ldap.mode");
if (modeStr != null) {
try {
this.mode = Integer.parseInt(modeStr);
}
catch (NumberFormatException nfe) { }
}
this.initialContextFactory = JiveGlobals.getXMLProperty("ldap.initialContextFactory");
if (initialContextFactory != null) {
try {
......@@ -158,7 +129,6 @@ public class LdapManager {
Log.debug("\t adminPassword: " + adminPassword);
Log.debug("\t ldapDebugEnabled: " + ldapDebugEnabled);
Log.debug("\t sslEnabled: " + sslEnabled);
Log.debug("\t mode: " + mode);
Log.debug("\t initialContextFactory: " + initialContextFactory);
Log.debug("\t connectionPoolEnabled: " + connectionPoolEnabled);
}
......@@ -717,29 +687,4 @@ public class LdapManager {
this.adminPassword = adminPassword;
JiveGlobals.setXMLProperty("ldap.adminPassword", adminPassword);
}
/**
* Returns the LDAP mode that is being used. Valid values are LdapManager.ALL_LDAP_MODE and
* LdapManager.LDAP_DB_MODE. The mode dictates what user data will be stored and what data
* (if any) will be stored in the database. Authentication is always performed using
* LDAP regardless of the mode.
*
* @return the current mode.
*/
public int getMode() {
return mode;
}
/**
* Sets the LDAP mode that should be used. Valid values are LdapManager.ALL_LDAP_MODE and
* LdapManager.LDAP_DB_MODE. The mode dictates what user data will be stored and what data
* (if any) will be stored in the database. Authentication is always performed using
* LDAP regardless of the mode.
*
* @param mode the mode to use.
*/
public void setMode(int mode) {
this.mode = mode;
JiveGlobals.setXMLProperty("ldap.mode", ""+mode);
}
}
\ No newline at end of file
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.ldap;
import org.jivesoftware.util.Log;
import org.jivesoftware.util.LongList;
import javax.naming.*;
import javax.naming.directory.*;
/**
* LDAP implementation of the UserIDProvider interface.
*
* @author Matt Tucker
*/
public class LdapUserIDProvider {
private LdapManager manager;
public LdapUserIDProvider() {
manager = LdapManager.getInstance();
}
public int getUserCount() {
int count = 0;
// Note: the performance of this check may suffer badly for very large
// numbers of users since we manually iterate through results to get
// a count.
DirContext ctx = null;
try {
ctx = manager.getContext();
// Search for the dn based on the username.
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
constraints.setReturningAttributes(new String[]{manager.getUsernameField()});
String filter = "(" + manager.getUsernameField() + " + =*)";
NamingEnumeration answer = ctx.search("", filter, constraints);
while (answer.hasMoreElements()) {
count++;
answer.nextElement();
}
}
catch (Exception e) {
Log.error(e);
}
finally {
try { if (ctx != null) { ctx.close(); } }
catch (Exception e) { Log.error(e); }
}
return count;
}
public LongList getUserIDs() {
LongList users = new LongList(500);
// Otherwise, in LDAP-only mode.
DirContext ctx = null;
try {
ctx = manager.getContext();
// Search for the dn based on the username.
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
constraints.setReturningAttributes(new String[]{manager.getUsernameField()});
String filter = "(" + manager.getUsernameField() + " + =*)";
NamingEnumeration answer = ctx.search("", filter, constraints);
while (answer.hasMoreElements()) {
// Get the next userID.
users.add(Long.parseLong((String)(((SearchResult)answer.next()).getAttributes().get("jiveUserID")).get()));
}
}
catch (Exception e) {
Log.error(e);
}
finally {
try { if (ctx != null) { ctx.close(); } }
catch (Exception e) { Log.error(e); }
}
return users;
}
public LongList getUserIDs(int startIndex, int numResults) {
LongList users = new LongList();
DirContext ctx = null;
try {
ctx = manager.getContext();
// Search for the dn based on the username.
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
constraints.setReturningAttributes(new String[]{manager.getUsernameField()});
String filter = "(" + manager.getUsernameField() + " + =*)";
NamingEnumeration answer = ctx.search("", filter, constraints);
for (int i = 0; i < startIndex; i++) {
answer.next();
}
// Now read in desired number of results (or stop if we run out of results).
for (int i = 0; i < numResults; i++) {
if (answer.hasMoreElements()) {
// Get the next userID.
users.add(Long.parseLong((String)(((SearchResult)answer.next()).getAttributes().get("jiveUserID")).get()));
}
else {
break;
}
}
}
catch (Exception e) {
Log.error(e);
}
finally {
try { if (ctx != null) { ctx.close(); } }
catch (Exception e) { Log.error(e); }
}
return users;
}
/**
* Helper function to retrieve username from userDN.
*
* @param userDN
* @return username
* @throws NamingException
*/
private String getUsernameFromUserDN(String userDN) throws NamingException {
DirContext ctx = null;
try {
ctx = manager.getContext();
// Load record.
String[] attributes = new String[]{manager.getUsernameField()};
Attributes attrs = ctx.getAttributes(userDN, attributes);
return (String)attrs.get(manager.getUsernameField()).get();
}
finally {
try { if (ctx != null) { ctx.close(); } }
catch (Exception e) { Log.error(e); }
}
}
}
\ No newline at end of file
......@@ -99,11 +99,8 @@ public class LdapUserInfoProvider implements UserInfoProvider {
throw new UserNotFoundException(e);
}
finally {
try {
ctx.close();
}
catch (Exception e) {
}
try { ctx.close(); }
catch (Exception ignored) { }
}
return userInfo;
}
......
......@@ -22,94 +22,36 @@ import java.util.Map;
* @author Jim Berrettini
*/
public class LdapUserPropertiesProvider implements UserPropertiesProvider {
/**
* Delete Vcard property. Currently unimplemented.
*
* @param username
* @param name
* @throws UnsupportedOperationException
*/
public void deleteVcardProperty(String username, String name) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Delete user property. Currently unimplemented.
*
* @param username
* @param name
* @throws UnsupportedOperationException
*/
public void deleteUserProperty(String username, String name) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Insert new vCard property. Currently unimplemented.
*
* @param username
* @param name
* @param value
* @throws UnsupportedOperationException
*/
public void insertVcardProperty(String username, String name, String value) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Insert new user property. Currently unimplemented.
*
* @param username
* @param name
* @param value
* @throws UnsupportedOperationException
*/
public void insertUserProperty(String username, String name, String value) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Update vCard. Currently unimplemented.
*
* @param username
* @param name
* @param value
* @throws UnsupportedOperationException
*/
public void updateVcardProperty(String username, String name, String value) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Update user property. Currently unimplemented.
*
* @param username
* @param name
* @param value
* @throws UnsupportedOperationException
*/
public void updateUserProperty(String username, String name, String value) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* Get vCard properties. Unimplemented.
*
* @param username
* @return empty Map
*/
public Map getVcardProperties(String username) {
return Collections.EMPTY_MAP;
}
/**
* Get user properties. Unimplemented.
*
* @param username
* @return empty Map.
*/
public Map getUserProperties(String username) {
return Collections.EMPTY_MAP;
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment