com.novell.ldap.LDAPConnection Maven / Gradle / Ivy
/* **************************************************************************
* $OpenLDAP: pkg/jldap/com/novell/ldap/LDAPConnection.java,v 1.154 2006/02/09 08:43:45 sunilk Exp $
*
* Copyright (C) 1999 - 2003 Novell, Inc. All Rights Reserved.
*
* THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
* TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
* TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS
* AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE"
* IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION
* OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP
* PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT
* THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
******************************************************************************/
package com.novell.ldap;
import java.io.UnsupportedEncodingException;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Map;
import java.util.StringTokenizer;
import com.novell.security.sasl.*;
import javax.security.auth.callback.CallbackHandler;
import com.novell.ldap.*;
import com.novell.ldap.asn1.*;
import com.novell.ldap.client.*;
import com.novell.ldap.client.BindProperties;
import com.novell.ldap.client.Debug;
import com.novell.ldap.client.ReferralInfo;
import com.novell.ldap.rfc2251.RfcBindRequest;
import com.novell.ldap.rfc2251.RfcBindResponse;
//import com.novell.ldap.message.*;
import com.novell.ldap.resources.ExceptionMessages;
/**
* The central class that encapsulates the connection
* to a directory server through the LDAP protocol.
* LDAPConnection objects are used to perform common LDAP
* operations such as search, modify and add.
*
* In addition, LDAPConnection objects allow you to bind to an
* LDAP server, set connection and search constraints, and perform
* several other tasks.
*
*
An LDAPConnection object is not connected on
* construction and can only be connected to one server at one
* port. Multiple threads may share this single connection, typically
* by cloning the connection object, one for each thread. An
* application may have more than one LDAPConnection object, connected
* to the same or different directory servers.
*
* Sample Code: Search.java
*
*/
public class LDAPConnection implements Cloneable
{
private LDAPSearchConstraints defSearchCons = new LDAPSearchConstraints();
private LDAPControl[] responseCtls = null;
// Synchronization Object used to synchronize access to responseCtls
private Object responseCtlSemaphore = new Object();
private Connection conn = null;
private static Object nameLock = new Object(); // protect agentNum
private static int lConnNum = 0; // Debug, LDAPConnection number
private String name; // String name for debug
/**
* Used with search to specify that the scope of entrys to search is to
* search only the base obect.
*
*SCOPE_BASE = 0
*/
public static final int SCOPE_BASE = 0;
/**
* Used with search to specify that the scope of entrys to search is to
* search only the immediate subordinates of the base obect.
*
*SCOPE_ONE = 1
*/
public static final int SCOPE_ONE = 1;
/**
* Used with search to specify that the scope of entrys to search is to
* search the base object and all entries within its subtree.
*
*SCOPE_ONE = 2
*/
public static final int SCOPE_SUB = 2;
/**
* Used with search to specify that the scope of entries to search is to
* search the subordinate subtree object and all entries within it.
*
*SCOPE_SUBORDINATESUBTREE = 4
*/
public static final int SCOPE_SUBORDINATESUBTREE = 4;
/**
* Used with search instead of an attribute list to indicate that no
* attributes are to be returned.
*
*NO_ATTRS = "1.1"
*/
public static final String NO_ATTRS = "1.1";
/**
* Used with search instead of an attribute list to indicate that all
* attributes are to be returned.
*
*ALL_USER_ATTRS = "*"
*/
public static final String ALL_USER_ATTRS = "*";
/**
* Specifies the LDAPv3 protocol version when performing a bind operation.
*
* Specifies LDAP version V3 of the protocol, and is specified
* when performing bind operations.
*
You can use this identifier in the version parameter
* of the bind method to specify an LDAPv3 bind.
* LDAP_V3 is the default protocol version
*
*LDAP_V3 = 3
*
* @see #bind(int, String, byte[])
* @see #bind(int, String, byte[], LDAPConstraints)
* @see #bind(int, String, byte[], LDAPResponseQueue)
* @see #bind(int, String, byte[], LDAPResponseQueue, LDAPConstraints)
*/
public static final int LDAP_V3 = 3;
/**
* The default port number for LDAP servers.
*
* You can use this identifier to specify the port when establishing
* a clear text connection to a server. This the default port.
*
*DEFAULT_PORT = 389
*
* @see #connect(String, int)
*/
public static final int DEFAULT_PORT = 389;
/**
* The default SSL port number for LDAP servers.
*
*DEFAULT_SSL_PORT = 636
*
* You can use this identifier to specify the port when establishing
* a an SSL connection to a server.
.
*/
public static final int DEFAULT_SSL_PORT = 636;
/**
* A string that can be passed in to the getProperty method.
*
*LDAP_PROPERTY_SDK = "version.sdk"
*
* You can use this string to request the version of the SDK
.
*/
public static final String LDAP_PROPERTY_SDK = "version.sdk";
/**
* A string that can be passed in to the getProperty method.
*
*LDAP_PROPERTY_PROTOCOL = "version.protocol"
*
* You can use this string to request the version of the
* LDAP protocol
.
*/
public static final String LDAP_PROPERTY_PROTOCOL = "version.protocol";
/**
* A string that can be passed in to the getProperty method.
*
*LDAP_PROPERTY_SECURITY = "version.security"
*
* You can use this string to request the type of security
* being used
.
*/
public static final String LDAP_PROPERTY_SECURITY = "version.security";
/**
* A string that corresponds to the server shutdown notification OID.
* This notification may be used by the server to advise the client that
* the server is about to close the connection due to an error
* condition.
*
*SERVER_SHUTDOWN_OID = "1.3.6.1.4.1.1466.20036"
*/
public static final String SERVER_SHUTDOWN_OID = "1.3.6.1.4.1.1466.20036";
/**
* The OID string that identifies a StartTLS request and response.
*/
private static final String START_TLS_OID = "1.3.6.1.4.1.1466.20037";
/*
* Constructors
*/
/**
* Constructs a new LDAPConnection object, which represents a connection
* to an LDAP server.
*
*
Calling the constructor does not actually establish the connection.
* To connect to the LDAP server, use the connect method.
*
* @see #connect(String, int)
*/
public LDAPConnection()
{
this( null);
return;
}
/**
* Constructs a new LDAPConnection object, which will use the supplied
* class factory to construct a socket connection during
* LDAPConnection.connect method.
*
* @param factory An object capable of producing a Socket.
*
* @see #connect(String, int)
* @see #getSocketFactory()
* @see #setSocketFactory( LDAPSocketFactory)
*/
public LDAPConnection(LDAPSocketFactory factory)
{
// Get a unique connection name for debug
if( Debug.LDAP_DEBUG) {
synchronized( nameLock) {
name = "LDAPConnection(" + ++lConnNum + "): ";
}
Debug.trace( Debug.apiRequests, name + "Created");
}
conn = new Connection( factory );
return;
}
/**
* Constructs a new LDAPConnection object, which will use the supplied
* timeout value to construct a socket connection during
* LDAPConnection.connect method with the specified socket
* connect timeout value.
*
* @param timeout An object capable of producing a Socket
* with the specified Socket Connect timeout value.
*
* @see #getSocketTimeOut()
* @see #setSocketTimeOut(int)
*/
public LDAPConnection(int timeout)
{
// Get a unique connection name for debug
if( Debug.LDAP_DEBUG) {
synchronized( nameLock) {
name = "LDAPConnection(" + ++lConnNum + "): ";
}
Debug.trace( Debug.apiRequests, name + "Created");
}
conn = new Connection( timeout );
return;
}
/*
* The following are methods that affect the operation of
* LDAPConnection, but are not LDAP requests.
*/
/**
* Returns a copy of the object with a private context, but sharing the
* network connection if there is one.
*
* The network connection remains open until all clones have
* disconnected or gone out of scope. Any connection opened after
* cloning is private to the object making the connection.
*
* The clone can issue requests and freely modify options and search
* constraints, and , without affecting the source object or other clones.
* If the clone disconnects or reconnects, it is completely dissociated
* from the source object and other clones. Reauthenticating in a clone,
* however, is a global operation which will affect the source object
* and all associated clones, because it applies to the single shared
* physical connection. Any request by an associated object after one
* has reauthenticated will carry the new identity.
*
* @return A of the object.
*/
public Object clone()
{
LDAPConnection newClone;
Object newObj;
try {
newObj = super.clone();
newClone = (LDAPConnection)newObj;
} catch( CloneNotSupportedException ce) {
throw new RuntimeException("Internal error, cannot create clone");
}
newClone.conn = conn; // same underlying connection
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"clone()");
}
//now just duplicate the defSearchCons and responseCtls
if (defSearchCons != null){
newClone.defSearchCons=(LDAPSearchConstraints)defSearchCons.clone();
}
else{
newClone.defSearchCons = null;
}
if (responseCtls != null){
newClone.responseCtls = new LDAPControl[responseCtls.length];
for(int i=0; i < responseCtls.length; i++){
newClone.responseCtls[i] = (LDAPControl)responseCtls[i].clone();
}
}
else {
newClone.responseCtls = null;
}
conn.incrCloneCount(); // Increment the count of clones
return newObj;
}
/**
* Closes the connection, if open, and releases any other resources held
* by the object.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*
* @see #disconnect
*/
protected void finalize()
throws LDAPException
{
// Disconnect did not come from user API call
disconnect(defSearchCons, false);
return;
}
/**
* Returns the protocol version uses to authenticate.
*
* 0 is returned if no authentication has been performed.
*
* @return The protol version used for authentication or 0
* not authenticated.
*
* @see #bind( int, String, String)
*/
public int getProtocolVersion()
{
BindProperties prop = conn.getBindProperties();
if( prop == null) {
return LDAP_V3;
}
return prop.getProtocolVersion();
}
/**
* Returns the distinguished name (DN) used for as the bind name during
* the last successful bind operation. null
is returned
* if no authentication has been performed or if the bind resulted in
* an aonymous connection.
*
* @return The distinguished name if authenticated; otherwise, null.
*
* @see #bind( String, String)
* @see #isBound()
*/
public String getAuthenticationDN()
{
BindProperties prop = conn.getBindProperties();
if( prop == null) {
return null;
}
if( prop.isAnonymous()) {
return null;
}
return prop.getAuthenticationDN();
}
/**
* Returns the method used to authenticate the connection. The return
* value is one of the following:
*
*
* - "none" indicates the connection is not authenticated.
*
*
* - "simple" indicates simple authentication was used or that a null
* or empty authentication DN was specified.
*
* - "sasl" indicates that a SASL mechanism was used to authenticate
*
*
* @return The method used to authenticate the connection.
*/
public String getAuthenticationMethod()
{
BindProperties prop = conn.getBindProperties();
if( prop == null) {
return "simple";
}
return conn.getBindProperties().getAuthenticationMethod();
}
/**
* Returns the properties if any specified on binding with a
* SASL mechanism.
*
* Null is returned if no authentication has been performed
* or no authentication Map is present.
*
* @return The bind properties Map Object used for SASL bind or null if
* the connection is not present or not authenticated.
*
* @see #bind( String, String, String[], Map, Object )
*/
public Map getSaslBindProperties()
{
BindProperties prop = conn.getBindProperties();
if( prop == null) {
return null;
}
return conn.getBindProperties().getSaslBindProperties();
}
/**
* Returns the call back handler if any specified on binding with a
* SASL mechanism.
*
* Null is returned if no authentication has been performed
* or no authentication call back handler is present.
*
* @return The call back handler used for SASL bind or null if the
* object is not present or not authenticated.
*
* @see #bind( String, String, String[], Map, Object )
*/
public Object /* javax.security.auth.callback.CallbackHandler */
getSaslBindCallbackHandler()
{
BindProperties prop = conn.getBindProperties();
if( prop == null) {
return null;
}
return conn.getBindProperties().getSaslCallbackHandler();
}
/**
* Returns a copy of the set of constraints associated with this
* connection. These constraints apply to all operations performed
* through this connection (unless a different set of constraints is
* specified when calling an operation method).
*
* @return The set of default contraints that apply to this connection.
*
* @see #setConstraints(LDAPConstraints)
*/
public LDAPConstraints getConstraints()
{
return (LDAPConstraints)(this.defSearchCons).clone();
}
/**
* Returns the host name of the LDAP server to which the object is or
* was last connected, in the format originally specified.
*
* @return The host name of the LDAP server to which the object last
* connected or null if the object has never connected.
*
* @see #connect( String, int)
*/
public String getHost()
{
return conn.getHost();
}
/**
* Returns the port number of the LDAP server to which the object is or
* was last connected.
*
* @return The port number of the LDAP server to which the object last
* connected or -1 if the object has never connected.
*
* @see #connect( String, int)
*/
public int getPort()
{
return conn.getPort();
}
/**
* Returns a property of a connection object.
*
* @param name Name of the property to be returned.
*
* The following read-only properties are available
* for any given connection:
*
* - LDAP_PROPERTY_SDK returns the version of this SDK,
* as a Float data type.
*
* - LDAP_PROPERTY_PROTOCOL returns the highest supported version of
* the LDAP protocol, as a Float data type.
*
* - LDAP_PROPERTY_SECURITY returns a comma-separated list of the
* types of authentication supported, as a
* string.
*
*
* A deep copy of the property is provided where applicable; a
* client does not need to clone the object received.
*
* @return The object associated with the requested property,
* or null if the property is not defined.
*
* @see LDAPConstraints#getProperty(String)
* @see LDAPConstraints#setProperty(String, Object)
*/
public Object getProperty(String name)
{
if (name.equalsIgnoreCase(LDAP_PROPERTY_SDK))
return conn.sdk;
else if (name.equalsIgnoreCase(LDAP_PROPERTY_PROTOCOL))
return conn.protocol;
else if (name.equalsIgnoreCase(LDAP_PROPERTY_SECURITY))
return conn.security;
else {
return null;
}
}
/**
* Returns a copy of the set of search constraints associated with this
* connection. These constraints apply to search operations performed
* through this connection (unless a different set of
* constraints is specified when calling the search operation method).
*
* @return The set of default search contraints that apply to
* this connection.
*
* @see #setConstraints
* @see #search( String, int, String, String[], boolean, LDAPSearchConstraints)
*/
public LDAPSearchConstraints getSearchConstraints()
{
return (LDAPSearchConstraints)this.defSearchCons.clone();
}
/**
* Returns the LDAPSocketFactory used to establish this server connection.
*
* @return The LDAPSocketFactory used to establish a connection.
*
* @see #LDAPConnection( LDAPSocketFactory)
* @see #setSocketFactory( LDAPSocketFactory)
*/
public LDAPSocketFactory getSocketFactory()
{
return conn.getSocketFactory();
}
/**
* Indicates whether the object has authenticated to the connected LDAP
* server.
*
* @return True if the object has authenticated; false if it has not
* authenticated.
*
* @see #bind( String, String)
*/
public boolean isBound()
{
return conn.isBound();
}
/**
* Indicates whether the connection represented by this object is open
* at this time.
*
* @return True if connection is open; false if the connection is closed.
*/
public boolean isConnected()
{
return conn.isConnected();
}
/**
* Checks whether the connection represented by this object is still
* alive or not.
*
* @return True if connection is alive; false if the connection is closed.
*/
public boolean isConnectionAlive()
{
return conn.isConnectionAlive();
}
/**
* Indicatates if the connection is protected by TLS.
*
* @return If startTLS has completed this method returns true.
* If stopTLS has completed or start tls failed, this method returns false.
*
* @return True if the connection is protected by TLS.
*
* @see #startTLS
* @see #stopTLS
*/
public boolean isTLS()
{
return conn.isTLS();
}
/**
* Returns the SocketTimeOut value set.
*
* @return Returns the SocketTimeOut value if set, else 0
*
*@see #setSocketTimeOut(int)
*/
public int getSocketTimeOut()
{
return conn.getSocketTimeOut();
}
/**
* Sets the SocketTimeOut value.
*
*@see #getSocketTimeOut()
*/
public void setSocketTimeOut(int timeout)
{
conn.setSocketTimeOut(timeout);
return;
}
/**
* Sets the constraints that apply to all operations performed through
* this connection (unless a different set of constraints is specified
* when calling an operation method). An LDAPSearchConstraints object
* which is passed to this method sets all constraints, while an
* LDAPConstraints object passed to this method sets only base constraints.
*
* @param cons An LDAPConstraints or LDAPSearchConstraints Object
* containing the contstraint values to set.
*
* @see #getConstraints()
* @see #getSearchConstraints()
*/
public void setConstraints(LDAPConstraints cons)
{
// Set all constraints, replace the object with a new one
if( cons instanceof LDAPSearchConstraints) {
defSearchCons = (LDAPSearchConstraints)cons.clone();
return;
}
// We set the constraints this way, so a thread doesn't get an
// conconsistant view of the referrals.
LDAPSearchConstraints newCons =
(LDAPSearchConstraints)defSearchCons.clone();
newCons.setHopLimit(cons.getHopLimit());
newCons.setTimeLimit(cons.getTimeLimit());
newCons.setReferralHandler(cons.getReferralHandler());
newCons.setReferralFollowing(cons.getReferralFollowing());
LDAPControl[] lsc = cons.getControls();
if( lsc != null) {
newCons.setControls( lsc);
}
Hashtable lp = newCons.getProperties();
if( lp != null) {
newCons.setProperties( lp);
}
defSearchCons = newCons;
return;
}
/**
* Establishes the default LDAPSocketFactory used when
* LDAPConnection objects are constructed unless an
* LDAPSocketFactory is specified in the LDAPConnection
* object constructor.
*
* This method sets the default LDAPSocketFactory used for
* all subsequent LDAPConnection objects constructed. If called
* after LDAPConnection objects are created, those already created are not
* affected even if they disconnect and establish a new connection.
* It affects LDAPConnection objects only as they are constructed.
*
*
* The following code snippet provides a typical usage example:
*
* if (usingTLS) {
* LDAPConnection.setSocketFactory(myTLSFactory);
* }
* ...
* LDAPConnection conn = new LDAPConnection();
* conn.connect(myHost, myPort);
*
*
* In this example, connections are constructed with the default
* LDAPSocketFactory. At application start-up time, the default may be
* set to use a particular provided TLS socket factory.
*
* @param factory A factory object which can construct socket
* connections for an LDAPConnection.
*
* @see #LDAPConnection( LDAPSocketFactory)
*/
public static void setSocketFactory( LDAPSocketFactory factory)
{
Connection.setSocketFactory( factory);
return;
}
/**
* Registers an object to be notified on arrival of an unsolicited
* message from a server.
*
* An unsolicited message has the ID 0. A new thread is created and
* the method "messageReceived" in each registered object is called in
* turn.
*
* @param listener An object to be notified on arrival of an
* unsolicited message from a server. This object must
* implement the LDAPUnsolicitedNotificationListener interface.
*
*/
public void addUnsolicitedNotificationListener(
LDAPUnsolicitedNotificationListener listener)
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"addUnsolicitedNOtificationListener()");
}
if (listener != null)
conn.addUnsolicitedNotificationListener(listener);
}
/**
* Deregisters an object so that it will no longer be notified on
* arrival of an unsolicited message from a server. If the object is
* null or was not previously registered for unsolicited notifications,
* the method does nothing.
*
*
* @param listener An object to no longer be notified on arrival of
* an unsolicited message from a server.
*
*/
public void removeUnsolicitedNotificationListener(
LDAPUnsolicitedNotificationListener listener)
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"removeUnsolicitedNOtificationListener()");
}
if (listener != null)
conn.removeUnsolicitedNotificationListener(listener);
}
/**
* Starts Transport Layer Security (TLS) protocol on this connection
* to enable session privacy.
*
* This affects the LDAPConnection object and all cloned objects. A
* socket factory that implements LDAPTLSSocketFactory must be set on the
* connection.
*
* @exception LDAPException Thrown if TLS cannot be started. If a
* SocketFactory has been specified that does not implement
* LDAPTLSSocketFactory an LDAPException is thrown.
*
* @see #isTLS
* @see #stopTLS
* @see #setSocketFactory
*/
public void startTLS() throws LDAPException
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name + "startTLS()");
}
LDAPMessage startTLS = makeExtendedOperation(
new LDAPExtendedOperation( this.START_TLS_OID, null ), null);
int tlsID = startTLS.getMessageID();
conn.acquireWriteSemaphore( tlsID );
try {
if (!conn.areMessagesComplete()){
throw new LDAPLocalException(
ExceptionMessages.OUTSTANDING_OPERATIONS,
LDAPException.OPERATIONS_ERROR );
}
// Stop reader when response to startTLS request received
conn.stopReaderOnReply( tlsID );
// send tls message
LDAPResponseQueue queue =
sendRequestToServer(
startTLS,
defSearchCons.getTimeLimit(), null, null );
LDAPExtendedResponse response =
(LDAPExtendedResponse) queue.getResponse();
response.chkResultCode();
conn.startTLS();
}
finally {
//Free this semaphore no matter what exceptions get thrown
conn.startReader();
conn.freeWriteSemaphore( tlsID ) ;
}
return;
}
/**
* Stops Transport Layer Security(TLS) on the LDAPConnection and reverts
* back to an anonymous state.
*
* @throws LDAPException This can occur for the following reasons:
* - StartTLS has not been called before stopTLS
*
- There exists outstanding messages that have not received all
* responses
*
- The sever was not able to support the operation
*
* Note: The Sun and IBM implementions of JSSE do not currently allow
* stopping TLS on an open Socket. In order to produce the same results
* this method currently disconnects the socket and reconnects, giving
* the application an anonymous connection to the server, as required
* by StopTLS.
*
* @see #startTLS
* @see #isTLS
*/
public void stopTLS() throws LDAPException {
if (!isTLS()){
throw new LDAPLocalException(ExceptionMessages.NO_STARTTLS,
LDAPException.OPERATIONS_ERROR );
}
int semaphoreID = conn.acquireWriteSemaphore();
try{
if (!conn.areMessagesComplete()) {
throw new LDAPLocalException(
ExceptionMessages.OUTSTANDING_OPERATIONS,
LDAPException.OPERATIONS_ERROR );
}
//stopTLS stops and starts the reader thread for us.
conn.stopTLS();
}
finally {
conn.freeWriteSemaphore(semaphoreID);
}
return;
}
//*************************************************************************
// Below are all of the LDAP protocol operation methods
//*************************************************************************
//*************************************************************************
// abandon methods
//*************************************************************************
/**
*
*
* Notifies the server not to send additional results associated with
* this LDAPSearchResults object, and discards any results already
* received.
*
* @param results An object returned from a search.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void abandon(LDAPSearchResults results)
throws LDAPException
{
abandon( results, defSearchCons );
return;
}
/**
*
*
* Notifies the server not to send additional results associated with
* this LDAPSearchResults object, and discards any results already
* received.
*
* @param results An object returned from a search.
*
* @param cons The contraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void abandon(LDAPSearchResults results, LDAPConstraints cons)
throws LDAPException
{
results.abandon();
return;
}
/**
*
* Abandons an asynchronous operation.
*
* @param id The ID of the asynchronous operation to abandon. The ID
* can be obtained from the response queue for the
* operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void abandon(int id)
throws LDAPException
{
abandon(id, defSearchCons);
return;
}
/**
* Abandons an asynchronous operation, using the specified
* constraints.
*
* @param id The ID of the asynchronous operation to abandon.
* The ID can be obtained from the search
* queue for the operation.
*
* @param cons The contraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void abandon(int id, LDAPConstraints cons)
throws LDAPException
{
// We need to inform the Message Agent which owns this messageID to
// remove it from the queue.
try {
MessageAgent agent = conn.getMessageAgent(id);
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"abandon(" + id + ")");
}
agent.abandon(id, cons);
return;
} catch( NoSuchFieldException ex) {
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"abandon(" + id + "), agent not found");
}
return; // Ignore error
}
}
/**
* Abandons all outstanding operations managed by the queue.
*
* All operations in progress, which are managed by the specified queue,
* are abandoned.
*
* @param queue The queue returned from an asynchronous request.
* All outstanding operations managed by the queue
* are abandoned, and the queue is emptied.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void abandon( LDAPMessageQueue queue)
throws LDAPException
{
abandon( queue, defSearchCons);
return;
}
/**
* Abandons all outstanding operations managed by the queue.
*
* All operations in progress, which are managed by the specified
* queue, are abandoned.
*
* @param queue The queue returned from an asynchronous request.
* All outstanding operations managed by the queue
* are abandoned, and the queue is emptied.
*
* @param cons The contraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void abandon( LDAPMessageQueue queue, LDAPConstraints cons)
throws LDAPException
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"abandon(queue)");
}
if(queue != null) {
MessageAgent agent;
if( queue instanceof LDAPSearchQueue) {
agent = queue.getMessageAgent();
} else {
agent = queue.getMessageAgent();
}
int[] msgIds = agent.getMessageIDs();
for(int i=0; i
* @param cons Constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void add(LDAPEntry entry,
LDAPConstraints cons)
throws LDAPException
{
LDAPResponseQueue queue = add(entry, null, cons);
// Get a handle to the add response
LDAPResponse addResponse = (LDAPResponse)(queue.getResponse());
// Set local copy of responseControls synchronously if there were any
synchronized (responseCtlSemaphore) {
responseCtls = addResponse.getControls();
}
chkResultCode( queue, cons, addResponse);
return;
}
/**
* Asynchronously adds an entry to the directory.
*
* @param entry LDAPEntry object specifying the distinguished
* name and attributes of the new entry.
*
* @param queue Handler for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPResponseQueue add(LDAPEntry entry, LDAPResponseQueue queue)
throws LDAPException
{
return add(entry, queue, defSearchCons);
}
/**
* Asynchronously adds an entry to the directory, using the specified
* constraints.
*
* @param entry LDAPEntry object specifying the distinguished
* name and attributes of the new entry.
*
* @param queue Handler for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @param cons Constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPResponseQueue add(LDAPEntry entry,
LDAPResponseQueue queue,
LDAPConstraints cons)
throws LDAPException
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"add()");
}
if(cons == null)
cons = defSearchCons;
// error check the parameters
if(entry == null ) {
throw new IllegalArgumentException("The LDAPEntry parameter" +
" cannot be null");
}
if( entry.getDN() == null) {
throw new IllegalArgumentException("The DN value must be present" +
" in the LDAPEntry object");
}
LDAPMessage msg = new LDAPAddRequest( entry, cons.getControls());
return sendRequestToServer(msg, cons.getTimeLimit(), queue, null);
}
//*************************************************************************
// bind methods
//*************************************************************************
/**
* Synchronously authenticates to the LDAP server (that the object is
* currently connected to) as an LDAPv3 bind, using the specified name and
* password.
*
* If the object has been disconnected from an LDAP server,
* this method attempts to reconnect to the server. If the object
* has already authenticated, the old authentication is discarded.
*
* @param dn If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name.
*
* @param passwd If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name and passwd as password.
*
* Note: the application should use care in the use
* of String password objects. These are long lived
* objects, and may expose a security risk, especially
* in objects that are serialized. The LDAPConnection
* keeps no long lived instances of these objects.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*
* @deprecated replaced by {@link #bind(int, String, byte[])}
*/
public void bind(String dn,
String passwd)
throws LDAPException
{
bind( LDAP_V3, dn, passwd, defSearchCons);
return;
}
/**
* Synchronously authenticates to the LDAP server (that the object is
* currently connected to) using the specified name, password,
* and LDAP version.
*
* If the object has been disconnected from an LDAP server,
* this method attempts to reconnect to the server. If the object
* has already authenticated, the old authentication is discarded.
*
* @param version The LDAP protocol version, use LDAP_V3.
* LDAP_V2 is not supported.
*
* @param dn If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name.
*
* @param passwd If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name and passwd as password.
*
* Note: the application should use care in the use
* of String password objects. These are long lived
* objects, and may expose a security risk, especially
* in objects that are serialized. The LDAPConnection
* keeps no long lived instances of these objects.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*
* @deprecated replaced by {@link #bind(int, String, byte[])}
*/
public void bind(int version,
String dn,
String passwd)
throws LDAPException
{
bind( version, dn, passwd, defSearchCons);
return;
}
/**
* Synchronously authenticates to the LDAP server (that the object is
* currently connected to) as an LDAPv3 bind, using the specified name,
* password, and constraints.
*
* If the object has been disconnected from an LDAP server,
* this method attempts to reconnect to the server. If the object
* has already authenticated, the old authentication is discarded.
*
* @param dn If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name.
*
* @param passwd If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name and passwd as password.
* Note: the application should use care in the use
* of String password objects. These are long lived
* objects, and may expose a security risk, especially
* in objects that are serialized. The LDAPConnection
* keeps no long lived instances of these objects.
*
* @param cons Constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*
* @deprecated replaced by {@link #bind(int, String, byte[], LDAPConstraints)}
*/
public void bind(String dn,
String passwd,
LDAPConstraints cons)
throws LDAPException
{
bind( LDAP_V3, dn, passwd, cons);
return;
}
/**
* Synchronously authenticates to the LDAP server (that the object is
* currently connected to) using the specified name, password, LDAP version,
* and constraints.
*
* If the object has been disconnected from an LDAP server,
* this method attempts to reconnect to the server. If the object
* has already authenticated, the old authentication is discarded.
*
* @param version The LDAP protocol version, use LDAP_V3.
* LDAP_V2 is not supported.
*
* @param dn If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name.
*
* @param passwd If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name and passwd as password.
*
* Note: the application should use care in the use
* of String password objects. These are long lived
* objects, and may expose a security risk, especially
* in objects that are serialized. The LDAPConnection
* keeps no long lived instances of these objects.
*
* @param cons The constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*
* @deprecated replaced by
* {@link #bind(int, String, byte[], LDAPConstraints)}
*/
public void bind(int version,
String dn,
String passwd,
LDAPConstraints cons)
throws LDAPException
{
byte[] pw = null;
if( passwd != null) {
try {
pw = passwd.getBytes("UTF8");
passwd = null; // Keep no reference to String object
} catch( UnsupportedEncodingException ex) {
passwd = null; // Keep no reference to String object
throw new RuntimeException( ex.toString());
}
}
bind(version, dn, pw, cons);
return;
}
/**
* Synchronously authenticates to the LDAP server (that the object is
* currently connected to) using the specified name, password,
* and LDAP version.
*
* If the object has been disconnected from an LDAP server,
* this method attempts to reconnect to the server. If the object
* has already authenticated, the old authentication is discarded.
*
* @param version The version of the LDAP protocol to use
* in the bind, use LDAP_V3. LDAP_V2 is not supported.
*
* @param dn If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name.
*
* @param passwd If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name and passwd as password.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void bind(int version,
String dn,
byte[] passwd)
throws LDAPException
{
bind(version, dn, passwd, defSearchCons);
return;
}
/**
*
* Synchronously authenticates to the LDAP server (that the object is
* currently connected to) using the specified name, password, LDAP version,
* and constraints.
*
* If the object has been disconnected from an LDAP server,
* this method attempts to reconnect to the server. If the object
* has already authenticated, the old authentication is discarded.
*
* @param version The LDAP protocol version, use LDAP_V3.
* LDAP_V2 is not supported.
*
* @param dn If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name.
*
* @param passwd If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name and passwd as password.
*
* @param cons The constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void bind(int version,
String dn,
byte[] passwd,
LDAPConstraints cons)
throws LDAPException
{
LDAPResponseQueue queue =
bind(version, dn, passwd, null, cons);
LDAPResponse res = (LDAPResponse)queue.getResponse();
if( res != null) {
// Set local copy of responseControls synchronously if any
synchronized (responseCtlSemaphore) {
responseCtls = res.getControls();
}
chkResultCode( queue, cons, res);
}
return;
}
/**
* Asynchronously authenticates to the LDAP server (that the object is
* currently connected to) using the specified name, password, LDAP
* version, and queue.
*
* If the object has been disconnected from an LDAP server,
* this method attempts to reconnect to the server. If the object
* has already authenticated, the old authentication is discarded.
*
*
* @param version The LDAP protocol version, use LDAP_V3.
* LDAP_V2 is not supported.
*
* @param dn If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name.
*
* @param passwd If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name and passwd as password.
*
* @param queue Handler for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPResponseQueue bind(int version,
String dn,
byte[] passwd,
LDAPResponseQueue queue)
throws LDAPException
{
return bind(version, dn, passwd, queue, defSearchCons);
}
/**
* Asynchronously authenticates to the LDAP server (that the object is
* currently connected to) using the specified name, password, LDAP
* version, queue, and constraints.
*
* If the object has been disconnected from an LDAP server,
* this method attempts to reconnect to the server. If the object
* had already authenticated, the old authentication is discarded.
*
* @param version The LDAP protocol version, use LDAP_V3.
* LDAP_V2 is not supported.
*
* @param dn If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name.
*
* @param passwd If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name and passwd as password.
*
* @param queue Handler for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @param cons Constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPResponseQueue bind(int version,
String dn,
byte[] passwd,
LDAPResponseQueue queue,
LDAPConstraints cons)
throws LDAPException
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"bind(\"" + dn + "\")");
}
int msgId;
BindProperties bindProps;
if(cons == null)
cons = defSearchCons;
if(dn == null) {
dn = "";
} else {
dn = dn.trim();
}
if(passwd == null)
passwd = new byte[] {};
boolean anonymous = false;
if( passwd.length == 0) {
anonymous = true; // anonymous, passwd length zero with simple bind
dn = ""; // set to null if anonymous
}
LDAPMessage msg = new LDAPBindRequest( version, dn, passwd, cons.getControls());
msgId = msg.getMessageID();
bindProps = new BindProperties( version, dn, "simple",
anonymous, null, null);
// For bind requests, if not connected, attempt to reconnect
if( ! conn.isConnected()) {
if( conn.getHost() != null) {
conn.connect( conn.getHost(), conn.getPort());
} else {
throw new LDAPException( ExceptionMessages.CONNECTION_IMPOSSIBLE,
LDAPException.CONNECT_ERROR, null);
}
}
// The semaphore is released when the bind response is queued.
conn.acquireWriteSemaphore( msgId);
return sendRequestToServer( msg,cons.getTimeLimit(), queue, bindProps);
}
//*************************************************************************
// SASL bind methods
//*************************************************************************
/**
* Synchronously authenticates to the LDAP server (that the object is
* currently connected to) using the specified name and the specified set of
* mechanisms.
*
* If none of the requested SASL mechanisms is available, an
* exception is thrown. If the object has been disconnected from an
* LDAP server, this method attempts to reconnect to the server. If the
* object has already authenticated, the old authentication is
* discarded. If mechanisms is null, or if the first version of the
* method is called, the LDAP server will be interrogated for its
* supportedSaslMechanisms attribute of its root DSE. See RFC 2251 for a
* discussion of the SASL classes.
*
*
* @param dn If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name.
*
* @param authzId If not null and not empty, specifies an LDAP authzId to
* pass to the SASL layer. If null or empty, the authzId
* will be treated as an empty string and processed
* as per RFC 2222.
*
* @param props The optional qualifiers for the authentication
* session.
*
* @param cbh A class which may be called by the SASL client
* implementation to obtain additional information
* required, such as additional credentials.
* If cbh is not of type
* javax.security.auth.callback.CallbackHandler, a
* RuntimeException will be thrown.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void bind(String dn,
String authzId,
Map props,
Object cbh)/*javax.security.auth.callback.CallbackHandler*/
throws LDAPException
{
bind( dn, authzId, props, cbh, defSearchCons);
return;
}
/**
* Synchronously authenticates to the LDAP server (that the object is
* currently connected to) using the specified name and the specified set of
* mechanisms.
*
* If none of the requested SASL mechanisms is available, an
* exception is thrown. If the object has been disconnected from an
* LDAP server, this method attempts to reconnect to the server. If the
* object has already authenticated, the old authentication is
* discarded. If mechanisms is null, or if the first version of the
* method is called, the LDAP server will be interrogated for its
* supportedSaslMechanisms attribute of its root DSE. See RFC 2251 for a
* discussion of the SASL classes.
*
*
* @param dn If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name.
*
* @param authzId If not null and not empty, specifies an LDAP authzId to
* pass to the SASL layer. If null or empty, the authzId
* will be treated as an empty string and processed
* as per RFC 2222.
*
* @param props The optional qualifiers for the authentication
* session.
*
* @param cbh A class which may be called by the SASL client
* implementation to obtain additional information
* required, such as additional credentials.
* If cbh is not of type
* javax.security.auth.callback.CallbackHandler, a
* RuntimeException will be thrown.
*
* @param cons Constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void bind(String dn,
String authzId,
Map props,
Object cbh,/*javax.security.auth.callback.CallbackHandler*/
LDAPConstraints cons)
throws LDAPException
{
//"LDAPConnection.bind(with mechanisms) is not Implemented."
throw new LDAPLocalException(ExceptionMessages.NOT_IMPLEMENTED,
new Object[] {"LDAPConnection.bind(with mechanisms)"},
LDAPException.LDAP_NOT_SUPPORTED);
}
/**
* Synchronously authenticates to the LDAP server (that the object is
* currently connected to) using the specified name and the specified set of
* mechanisms.
*
* If none of the requested SASL mechanisms is available, an
* exception is thrown. If the object has been disconnected from an
* LDAP server, this method attempts to reconnect to the server. If the
* object has already authenticated, the old authentication is
* discarded. If mechanisms is null, or if the first version of the
* method is called, the LDAP server will be interrogated for its
* supportedSaslMechanisms attribute of its root DSE. See RFC 2251 for a
* discussion of the SASL classes.
*
* @param dn If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name.
* @param authzId If not null and not empty, specifies an LDAP authzId to
* pass to the SASL layer. If null or empty, the authzId
* will be treated as an empty string and processed
* as per RFC 2222.
*
* @param mechanisms An array of IANA-registered SASL mechanisms which
* the client is willing to use for authentication.
*
* @param props The optional qualifiers for the authentication
* session.
*
* @param cbh A class which may be called by the SASL client
* implementation to obtain additional information
* required, such as additional credentials.
* If cbh is not of type
* javax.security.auth.callback.CallbackHandler, a
* RuntimeException will be thrown.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void bind(String dn,
String authzId,
String[] mechanisms,
Map props,
Object cbh)/*javax.security.auth.callback.CallbackHandler*/
throws LDAPException
{
bind( dn, authzId, mechanisms, props, cbh, defSearchCons);
return;
}
/**
* Synchronously authenticates to the LDAP server (that the object is
* currently connected to) using the specified name and the specified set of
* mechanisms.
*
* If none of the requested SASL mechanisms is available, an
* exception is thrown. If the object has been disconnected from an
* LDAP server, this method attempts to reconnect to the server. If the
* object has already authenticated, the old authentication is
* discarded. If mechanisms is null, or if the first version of the
* method is called, the LDAP server will be interrogated for its
* supportedSaslMechanisms attribute of its root DSE. See RFC 2251 for a
* discussion of the SASL classes.
*
* @param dn If non-null and non-empty, specifies that the
* connection and all operations through it should
* be authenticated with dn as the distinguished
* name.
* @param authzId If not null and not empty, specifies an LDAP authzId to
* pass to the SASL layer. If null or empty, the authzId
* will be treated as an empty string and processed
* as per RFC 2222.
*
* @param mechanisms An array of IANA-registered SASL mechanisms which
* the client is willing to use for authentication.
*
* @param props The optional qualifiers for the authentication
* session.
*
* @param cbh A class which may be called by the SASL client
* implementation to obtain additional information
* required, such as additional credentials.
* If cbh is not of type
* javax.security.auth.callback.CallbackHandler, a
* RuntimeException will be thrown.
*
* @param cons Constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void bind(String dn,
String authzId,
String[] mechanisms,
Map props,
Object cbh,/*javax.security.auth.callback.CallbackHandler*/
LDAPConstraints cons)
throws LDAPException
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"saslBind(" + dn + ")");
}
if(cons == null)
cons = defSearchCons;
if(dn == null)
dn = "";
if (authzId == null)
authzId = "";
try
{
SaslClient saslClient = Sasl.createSaslClient(mechanisms,
authzId,
"ldap",
this.getHost(),
props,
(CallbackHandler)cbh);
if (saslClient == null)
{
throw new LDAPException(
"Unsupported SASL mechanism(s) and/or properties",
LDAPException.AUTH_METHOD_NOT_SUPPORTED, null);
}
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.saslBind, name +
"saslClient created, mechanism " +
saslClient.getMechanismName());
}
byte[] clientResponse = null;
boolean anonymous = false;
BindProperties bindProps = new BindProperties(LDAP_V3,
null,
"sasl",
anonymous,
null,
null);
// Acquire the bind semaphore and communicate its value to
// the corresponding Connection class.
int id = conn.acquireWriteSemaphore();
conn.setBindSemId( id);
if (saslClient.hasInitialResponse())
{
clientResponse = saslClient.evaluateChallenge(new
byte[0]);
}
while(!saslClient.isComplete())
{
try
{
byte[] replyBuf = LDAPTransport(
clientResponse,
saslClient.getMechanismName(),
bindProps);
if(replyBuf!=null)
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.saslBind, name +
"saslClient response " + replyBuf.length +
" bytes");
}
clientResponse = saslClient.evaluateChallenge(
replyBuf);
}
else
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.saslBind, name +
"saslClient response empty");
}
clientResponse = saslClient.evaluateChallenge(
new byte[0]);
}
}
catch(SaslException e)
{
// This call will free any client resources.
saslClient.dispose();
throw new LDAPException("Unexpected SASL error.",
LDAPException.OTHER, null, e);
}
catch(LDAPException lde)
{
// This call will free any client resources.
saslClient.dispose();
throw lde;
}
}
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.saslBind, name + "saslBind Complete");
}
}
catch (SaslException eSasl)
{
throw new LDAPException("SASL Bind Error.",
LDAPException.OTHER,
null,
eSasl.getCause());
}
//LDAP Bind complete
return;
}
/**
* Implements a LDAP Transport method which recives requests from the
* saslClient and send Data to the LDAP server and returns the response
* back to the saslClient
*
* @param toWrite request received from saslClient in a byte array
* @param mechanism Name of the saslClient Mechanism
* @param bindProps Bindproperties
*
* @return Response reived from the LDAP server in a byte array
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
private byte[] LDAPTransport( byte[] toWrite,
String mechanism,
BindProperties bindProps)
throws LDAPException
{
LDAPMessage msg;
RfcBindResponse bindResponse;
LDAPConstraints cons;
ASN1OctetString serverCreds;
cons = defSearchCons;
msg = new LDAPMessage(LDAPMessage.BIND_REQUEST,
new RfcBindRequest(LDAP_V3,
"",
mechanism,
toWrite),
cons.getControls());
LDAPResponseQueue queue = sendRequestToServer(msg,
cons.getTimeLimit(),
null,
bindProps);
LDAPResponse ldapResponse = (LDAPResponse)queue.getResponse();
bindResponse = (RfcBindResponse)ldapResponse.getASN1Object().get(1);
serverCreds = bindResponse.getServerSaslCreds();
int resultCode = ldapResponse.getResultCode();
byte[] replyBuf = null;
if ((resultCode == LDAPException.SASL_BIND_IN_PROGRESS) ||
(resultCode == LDAPException.SUCCESS))
{
if (serverCreds != null)
{
replyBuf = serverCreds.byteValue();
}
}
else {
ldapResponse.chkResultCode();
throw new LDAPException("SASL Bind Error.",
resultCode,
null);
}
return replyBuf;
}
//*************************************************************************
// compare methods
//*************************************************************************
/**
*
* Synchronously checks to see if an entry contains an attribute
* with a specified value.
*
* @param dn The distinguished name of the entry to use in the
* comparison.
*
* @param attr The attribute to compare against the entry. The
* method checks to see if the entry has an
* attribute with the same name and value as this
* attribute.
*
* @return True if the entry has the value,
* and false if the entry does not
* have the value or the attribute.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public boolean compare(String dn,
LDAPAttribute attr)
throws LDAPException
{
return compare(dn, attr, defSearchCons);
}
/**
*
* Synchronously checks to see if an entry contains an attribute with a
* specified value, using the specified constraints.
*
* @param dn The distinguished name of the entry to use in the
* comparison.
*
* @param attr The attribute to compare against the entry. The
* method checks to see if the entry has an
* attribute with the same name and value as this
* attribute.
*
* @param cons Constraints specific to the operation.
*
* @return True if the entry has the value,
* and false if the entry does not
* have the value or the attribute.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public boolean compare(String dn,
LDAPAttribute attr,
LDAPConstraints cons)
throws LDAPException
{
boolean ret = false;
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"compare(" + dn + ") if value");
}
LDAPResponseQueue queue = compare(dn, attr, null, cons);
LDAPResponse res = (LDAPResponse)queue.getResponse();
// Set local copy of responseControls synchronously - if there were any
synchronized (responseCtlSemaphore) {
responseCtls = res.getControls();
}
if(res.getResultCode() == LDAPException.COMPARE_TRUE) {
ret = true;
} else
if(res.getResultCode() == LDAPException.COMPARE_FALSE) {
ret = false;
} else {
chkResultCode( queue, cons, res);
}
return ret;
}
/**
* Asynchronously compares an attribute value with one in the directory,
* using the specified queue.
*
* Please note that a successful completion of this command results in
* one of two status codes: LDAPException.COMPARE_TRUE if the entry
* has the value, and LDAPException.COMPARE_FALSE if the entry
* does not have the value or the attribute.
*
* @param dn The distinguished name of the entry containing an
* attribute to compare.
*
* @param attr An attribute to compare.
*
* @param queue The queue for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*
* @see LDAPException#COMPARE_TRUE
* @see LDAPException#COMPARE_FALSE
*/
public LDAPResponseQueue compare(String dn,
LDAPAttribute attr,
LDAPResponseQueue queue)
throws LDAPException
{
return compare(dn, attr, queue, defSearchCons);
}
/**
* Asynchronously compares an attribute value with one in the directory,
* using the specified queue and contraints.
*
* Please note that a successful completion of this command results in
* one of two status codes: LDAPException.COMPARE_TRUE if the entry
* has the value, and LDAPException.COMPARE_FALSE if the entry
* does not have the value or the attribute.
*
* @param dn The distinguished name of the entry containing an
* attribute to compare.
*
* @param attr An attribute to compare.
*
* @param queue Handler for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @param cons Constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*
* @see LDAPException#COMPARE_TRUE
* @see LDAPException#COMPARE_FALSE
*/
public LDAPResponseQueue compare(String dn,
LDAPAttribute attr,
LDAPResponseQueue queue,
LDAPConstraints cons)
throws LDAPException
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"compare(" + dn + ") compare value");
}
if( attr.size() != 1) {
throw new IllegalArgumentException("compare: Exactly one value " +
"must be present in the LDAPAttribute");
}
if(dn == null ) {
// Invalid parameter
throw new IllegalArgumentException("compare: DN cannot be null");
}
if(cons == null)
cons = defSearchCons;
LDAPMessage msg = new LDAPCompareRequest( dn,
attr.getName(),
attr.getByteValue(),
cons.getControls());
return sendRequestToServer(msg, cons.getTimeLimit(), queue, null);
}
//*************************************************************************
// connect methods
//*************************************************************************
/**
*
* Connects to the specified host and port.
*
*
If this LDAPConnection object represents an open connection, the
* connection is closed first before the new connection is opened.
* At this point, there is no authentication, and any operations are
* conducted as an anonymous client.
*
* When more than one host name is specified, each host is contacted
* in turn until a connection can be established.
*
* @param host A host name or a dotted string representing the IP address
* of a host running an LDAP server. It may also
* contain a list of host names, space-delimited. Each host
* name can include a trailing colon and port number.
*
* @param port The TCP or UDP port number to connect to or contact.
* The default LDAP port is 389. The port parameter is
* ignored for any host hame which includes a colon and
* port number.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*
*/
public void connect(String host, int port)
throws LDAPException
{
// connect doesn't affect other clones
// If not a clone, destroys old connection.
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"connect(" + host + ", " + port + ")");
}
// Step through the space-delimited list
StringTokenizer hostList = new StringTokenizer(host," ");
String address = null;
int specifiedPort;
int colonIndex; //after the colon is the port
while (hostList.hasMoreTokens()) {
try{
specifiedPort=port;
address = hostList.nextToken();
colonIndex = address.indexOf((int)':');
if (colonIndex != -1 && colonIndex+1 != address.length()){
//parse Port out of address
try{
specifiedPort = Integer.parseInt(
address.substring(colonIndex+1));
address = address.substring(0, colonIndex);
}catch (Exception e){
throw new IllegalArgumentException(
ExceptionMessages.INVALID_ADDRESS);
}
}
// This may return a different conn object
// Disassociate this clone with the underlying connection.
conn = conn.destroyClone( true);
conn.connect( address, specifiedPort);
break;
}catch (LDAPException LE){
if (!hostList.hasMoreTokens())
throw LE;
}
}
return;
}
//*************************************************************************
// delete methods
//*************************************************************************
/**
*
* Synchronously deletes the entry with the specified distinguished name
* from the directory.
*
* Note: A Delete operation will not remove an entry that contains
* subordinate entries, nor will it dereference alias entries.
*
* @param dn The distinguished name of the entry to delete.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void delete(String dn)
throws LDAPException
{
delete(dn, defSearchCons);
return;
}
/**
* Synchronously deletes the entry with the specified distinguished name
* from the directory, using the specified constraints.
*
* Note: A Delete operation will not remove an entry that contains
* subordinate entries, nor will it dereference alias entries.
*
* @param dn The distinguished name of the entry to delete.
*
* @param cons Constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void delete(String dn, LDAPConstraints cons)
throws LDAPException
{
LDAPResponseQueue queue =
delete(dn, null, cons);
// Get a handle to the delete response
LDAPResponse deleteResponse = (LDAPResponse)(queue.getResponse());
// Set local copy of responseControls synchronously - if there were any
synchronized (responseCtlSemaphore) {
responseCtls = deleteResponse.getControls();
}
chkResultCode( queue, cons, deleteResponse);
return;
}
/**
* Asynchronously deletes the entry with the specified distinguished name
* from the directory and returns the results to the specified queue.
*
* Note: A Delete operation will not remove an entry that contains
* subordinate entries, nor will it dereference alias entries.
*
* @param dn The distinguished name of the entry to modify.
*
* @param queue The queue for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*
*/
public LDAPResponseQueue delete(String dn, LDAPResponseQueue queue)
throws LDAPException
{
return delete(dn, queue, defSearchCons);
}
/**
* Asynchronously deletes the entry with the specified distinguished name
* from the directory, using the specified contraints and queue.
*
* Note: A Delete operation will not remove an entry that contains
* subordinate entries, nor will it dereference alias entries.
*
* @param dn The distinguished name of the entry to delete.
*
* @param queue The queue for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @param cons The constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*
*/
public LDAPResponseQueue delete(String dn,
LDAPResponseQueue queue,
LDAPConstraints cons)
throws LDAPException
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"delete(" + dn + ")");
}
if(dn == null) {
// Invalid DN parameter
throw new IllegalArgumentException(
ExceptionMessages.DN_PARAM_ERROR);
}
if(cons == null)
cons = defSearchCons;
LDAPMessage msg = new LDAPDeleteRequest( dn, cons.getControls());
return sendRequestToServer(msg, cons.getTimeLimit(), queue, null);
}
//*************************************************************************
// disconnect method
//*************************************************************************
/**
*
* Synchronously disconnects from the LDAP server.
*
* Before the object can perform LDAP operations again, it must
* reconnect to the server by calling connect.
*
* The disconnect method abandons any outstanding requests, issues an
* unbind request to the server, and then closes the socket.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*
*/
public void disconnect()
throws LDAPException
{
// disconnect from API call
disconnect( defSearchCons, true);
return;
}
/**
* Synchronously disconnects from the LDAP server.
*
* Before the object can perform LDAP operations again, it must
* reconnect to the server by calling connect.
*
* The disconnect method abandons any outstanding requests, issues an
* unbind request to the server, and then closes the socket.
*
* @param cons LDPConstraints to be set with the unbind request
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void disconnect( LDAPConstraints cons)
throws LDAPException
{
// disconnect from API call
disconnect(cons, true);
return;
}
/**
* Synchronously disconnect from the server
*
* @param how true if application call disconnect API, false if finalize.
*/
private void disconnect(LDAPConstraints cons, boolean how)
throws LDAPException
{
// disconnect doesn't affect other clones
// If not a clone, distroys connection
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
(how?"disconnect()":"finalize()"));
}
conn = conn.destroyClone(how);
return;
}
//*************************************************************************
// extendedOperation methods
//*************************************************************************
/**
* Provides a synchronous means to access extended, non-mandatory
* operations offered by a particular LDAPv3 compliant server.
*
* @param op The object which contains (1) an identifier of an extended
* operation which should be recognized by the particular LDAP
* server this client is connected to and (2)
* an operation-specific sequence of octet strings
* or BER-encoded values.
*
* @return An operation-specific object, containing an ID and either an octet
* string or BER-encoded values.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPExtendedResponse extendedOperation(LDAPExtendedOperation op)
throws LDAPException
{
return extendedOperation(op, defSearchCons);
}
/*
* Synchronous LDAP extended request with SearchConstraints
*/
/**
*
* Provides a synchronous means to access extended, non-mandatory
* operations offered by a particular LDAPv3 compliant server.
*
* @param op The object which contains (1) an identifier of an extended
* operation which should be recognized by the particular LDAP
* server this client is connected to and (2) an
* operation-specific sequence of octet strings
* or BER-encoded values.
*
* @param cons The constraints specific to the operation.
*
* @return An operation-specific object, containing an ID and either an
* octet string or BER-encoded values.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPExtendedResponse extendedOperation(LDAPExtendedOperation op,
LDAPConstraints cons)
throws LDAPException
{
// Call asynchronous API and get back handler to reponse queue
LDAPResponseQueue queue = extendedOperation(op, cons, null);
LDAPExtendedResponse response =
(LDAPExtendedResponse) queue.getResponse();
// Set local copy of responseControls synchronously - if there were any
synchronized (responseCtlSemaphore) {
responseCtls = response.getControls();
}
chkResultCode( queue, cons, response);
return response;
}
/*
* Asynchronous LDAP extended request
*/
/**
* Provides an asynchronous means to access extended, non-mandatory
* operations offered by a particular LDAPv3 compliant server.
*
* @param op The object which contains (1) an identifier of an extended
* operation which should be recognized by the particular LDAP
* server this client is connected to and (2) an
* operation-specific sequence of octet strings
* or BER-encoded values.
*
* @param queue The queue for messages returned from a server in
* response to this request. If it is null, a queue
* object is created internally.
*
* @return An operation-specific object, containing an ID and either an octet
* string or BER-encoded values.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPResponseQueue extendedOperation(LDAPExtendedOperation op,
LDAPResponseQueue queue)
throws LDAPException
{
return extendedOperation(op, defSearchCons, queue);
}
/*
* Asynchronous LDAP extended request with SearchConstraints
*/
/**
* Provides an asynchronous means to access extended, non-mandatory
* operations offered by a particular LDAPv3 compliant server.
*
* @param op The object which contains (1) an identifier of an extended
* operation which should be recognized by the particular LDAP
* server this client is connected to and (2) an operation-
* specific sequence of octet strings or BER-encoded values.
*
* @param queue The queue for messages returned from a server in
* response to this request. If it is null, a queue
* object is created internally.
*
* @param cons The constraints specific to this operation.
*
* @return An operation-specific object, containing an ID and either an
* octet string or BER-encoded values.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPResponseQueue extendedOperation(LDAPExtendedOperation op,
LDAPConstraints cons,
LDAPResponseQueue queue)
throws LDAPException
{
// Use default constraints if none-specified
if(cons == null)
cons = defSearchCons;
LDAPMessage msg = makeExtendedOperation(op, cons);
return sendRequestToServer(msg, cons.getTimeLimit(), queue, null);
}
/**
* Formulates the extended operation, constraints into an
* LDAPMessage and returns the LDAPMessage. This is used by
* extendedOperation and startTLS which needs the LDAPMessage to
* get the MessageID.
*/
protected LDAPMessage makeExtendedOperation(LDAPExtendedOperation op,
LDAPConstraints cons)
throws LDAPException
{
// Use default constraints if none-specified
if(cons == null)
cons = defSearchCons;
// error check the parameters
if (op.getID() == null) {
// Invalid extended operation parameter, no OID specified
throw new IllegalArgumentException(
ExceptionMessages.OP_PARAM_ERROR);
}
return new LDAPExtendedRequest(op, cons.getControls());
}
//*************************************************************************
// getResponseControls method
//*************************************************************************
/**
* Returns the Server Controls associated with the most recent response
* to a synchronous request on this connection object, or null
* if the latest response contained no Server Controls. The method
* always returns null for asynchronous requests. For asynchronous
* requests, the response controls are available in LDAPMessage.
*
* @return The server controls associated with the most recent response
* to a synchronous request or null if the response contains no server
* controls.
*
* @see LDAPMessage#getControls()
*/
public LDAPControl[] getResponseControls()
{
if( responseCtls == null) {
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"getResponseControls() returns null");
}
return null;
}
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"getResponseControls()");
}
// We have to clone the control just in case
// we have two client threads that end up retreiving the
// same control.
LDAPControl [] clonedControl = new LDAPControl [responseCtls.length];
// Also note we synchronize access to the local response
// control object just in case another message containing controls
// comes in from the server while we are busy duplicating
// this one.
synchronized (responseCtlSemaphore) {
for(int i = 0; i < responseCtls.length; i++) {
clonedControl[i] = (LDAPControl) (responseCtls[i]).clone();
}
}
// Return the cloned copy. Note we have still left the
// control in the local responseCtls variable just in case
// somebody requests it again.
return clonedControl;
}
//*************************************************************************
// modify methods
//*************************************************************************
/**
* Synchronously makes a single change to an existing entry in the
* directory.
*
* For example, this modify method changes the value of an attribute,
* adds a new attribute value, or removes an existing attribute value.
*
* The LDAPModification object specifies both the change to be made and
* the LDAPAttribute value to be changed.
*
* If the request fails with {@link LDAPException#CONNECT_ERROR},
* it is indeterminate whether or not the server made the modification.
*
* @param dn The distinguished name of the entry to modify.
*
* @param mod A single change to be made to the entry.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void modify( String dn,
LDAPModification mod)
throws LDAPException
{
modify(dn, mod, defSearchCons);
return;
}
/**
*
* Synchronously makes a single change to an existing entry in the
* directory, using the specified constraints.
*
* For example, this modify method changes the value of an attribute,
* adds a new attribute value, or removes an existing attribute value.
*
* The LDAPModification object specifies both the change to be
* made and the LDAPAttribute value to be changed.
*
* If the request fails with {@link LDAPException#CONNECT_ERROR},
* it is indeterminate whether or not the server made the modification.
*
* @param dn The distinguished name of the entry to modify.
*
* @param mod A single change to be made to the entry.
*
* @param cons The constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void modify( String dn,
LDAPModification mod,
LDAPConstraints cons)
throws LDAPException
{
LDAPModification[] mods = new LDAPModification[1];
mods[0] = mod;
modify(dn, mods, cons);
return;
}
/**
*
* Synchronously makes a set of changes to an existing entry in the
* directory.
*
* For example, this modify method changes attribute values, adds
* new attribute values, or removes existing attribute values.
*
* Because the server applies all changes in an LDAPModification array
* atomically, the application can expect that no changes
* have been performed if an error is returned.
* If the request fails with {@link LDAPException#CONNECT_ERROR},
* it is indeterminate whether or not the server made the modifications.
*
* @param dn Distinguished name of the entry to modify.
*
* @param mods The changes to be made to the entry.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void modify( String dn,
LDAPModification[] mods)
throws LDAPException
{
modify(dn, mods, defSearchCons);
return;
}
/**
* Synchronously makes a set of changes to an existing entry in the
* directory, using the specified constraints.
*
* For example, this modify method changes attribute values, adds new
* attribute values, or removes existing attribute values.
*
* Because the server applies all changes in an LDAPModification array
* atomically, the application can expect that no changes
* have been performed if an error is returned.
* If the request fails with {@link LDAPException#CONNECT_ERROR},
* it is indeterminate whether or not the server made the modifications.
*
* @param dn The distinguished name of the entry to modify.
*
* @param mods The changes to be made to the entry.
*
* @param cons The constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an
* error message and an LDAP error code.
*/
public void modify( String dn,
LDAPModification[] mods,
LDAPConstraints cons)
throws LDAPException
{
LDAPResponseQueue queue =
modify(dn, mods, null, cons);
// Get a handle to the modify response
LDAPResponse modifyResponse = (LDAPResponse)(queue.getResponse());
// Set local copy of responseControls synchronously - if there were any
synchronized (responseCtlSemaphore) {
responseCtls = modifyResponse.getControls();
}
chkResultCode( queue, cons, modifyResponse);
return;
}
/**
* Asynchronously makes a single change to an existing entry in the
* directory.
*
* For example, this modify method can change the value of an attribute,
* add a new attribute value, or remove an existing attribute value.
*
* The LDAPModification object specifies both the change to be made and
* the LDAPAttribute value to be changed.
*
* If the request fails with {@link LDAPException#CONNECT_ERROR},
* it is indeterminate whether or not the server made the modification.
*
* @param dn Distinguished name of the entry to modify.
*
* @param mod A single change to be made to the entry.
*
* @param queue Handler for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPResponseQueue modify(String dn,
LDAPModification mod,
LDAPResponseQueue queue)
throws LDAPException
{
return modify(dn, mod, queue, defSearchCons);
}
/**
* Asynchronously makes a single change to an existing entry in the
* directory, using the specified constraints and queue.
*
* For example, this modify method can change the value of an attribute,
* add a new attribute value, or remove an existing attribute value.
*
* The LDAPModification object specifies both the change to be made
* and the LDAPAttribute value to be changed.
*
* If the request fails with {@link LDAPException#CONNECT_ERROR},
* it is indeterminate whether or not the server made the modification.
*
* @param dn Distinguished name of the entry to modify.
*
* @param mod A single change to be made to the entry.
*
* @param queue Handler for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @param cons Constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPResponseQueue modify(String dn,
LDAPModification mod,
LDAPResponseQueue queue,
LDAPConstraints cons)
throws LDAPException
{
LDAPModification[] mods = new LDAPModification[1];
mods[0] = mod;
return modify(dn, mods, queue, cons);
}
/**
* Asynchronously makes a set of changes to an existing entry in the
* directory.
*
* For example, this modify method can change attribute values, add new
* attribute values, or remove existing attribute values.
*
* Because the server applies all changes in an LDAPModification array
* atomically, the application can expect that no changes
* have been performed if an error is returned.
* If the request fails with {@link LDAPException#CONNECT_ERROR},
* it is indeterminate whether or not the server made the modifications.
*
* @param dn The distinguished name of the entry to modify.
*
* @param mods The changes to be made to the entry.
*
* @param queue The queue for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPResponseQueue modify(String dn,
LDAPModification[] mods,
LDAPResponseQueue queue)
throws LDAPException
{
return modify(dn, mods, queue, defSearchCons);
}
/**
* Asynchronously makes a set of changes to an existing entry in the
* directory, using the specified constraints and queue.
*
* For example, this modify method can change attribute values, add new
* attribute values, or remove existing attribute values.
*
* Because the server applies all changes in an LDAPModification array
* atomically, the application can expect that no changes
* have been performed if an error is returned.
* If the request fails with {@link LDAPException#CONNECT_ERROR},
* it is indeterminate whether or not the server made the modifications.
*
* @param dn The distinguished name of the entry to modify.
*
* @param mods The changes to be made to the entry.
*
* @param queue The queue for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @param cons Constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPResponseQueue modify(String dn,
LDAPModification[] mods,
LDAPResponseQueue queue,
LDAPConstraints cons)
throws LDAPException
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"modify(" + dn + "), " + mods.length + " modifications");
}
if(dn == null) {
// Invalid DN parameter
throw new IllegalArgumentException(
ExceptionMessages.DN_PARAM_ERROR);
}
if(cons == null)
cons = defSearchCons;
LDAPMessage msg = new LDAPModifyRequest( dn, mods, cons.getControls());
return sendRequestToServer(msg, cons.getTimeLimit(), queue, null);
}
//*************************************************************************
// read methods
//*************************************************************************
/**
* Synchronously reads the entry for the specified distiguished name (DN)
* and retrieves all attributes for the entry.
*
* @param dn The distinguished name of the entry to retrieve.
*
* @return the LDAPEntry read from the server.
*
* @exception LDAPException if the object was not found
*/
public LDAPEntry read(String dn)
throws LDAPException
{
return read(dn, defSearchCons);
}
/**
*
* Synchronously reads the entry for the specified distiguished name (DN),
* using the specified constraints, and retrieves all attributes for the
* entry.
*
* @param dn The distinguished name of the entry to retrieve.
*
* @param cons The constraints specific to the operation.
*
* @return the LDAPEntry read from the server
*
* @exception LDAPException if the object was not found
*/
public LDAPEntry read(String dn,
LDAPSearchConstraints cons)
throws LDAPException
{
return read(dn, null, cons);
}
/**
*
* Synchronously reads the entry for the specified distinguished name (DN)
* and retrieves only the specified attributes from the entry.
*
* @param dn The distinguished name of the entry to retrieve.
*
* @param attrs The names of the attributes to retrieve.
*
* @return the LDAPEntry read from the server
*
* @exception LDAPException if the object was not found
*/
public LDAPEntry read(String dn,
String[] attrs)
throws LDAPException
{
return read(dn, attrs, defSearchCons);
}
/**
* Synchronously reads the entry for the specified distinguished name (DN),
* using the specified constraints, and retrieves only the specified
* attributes from the entry.
*
* @param dn The distinguished name of the entry to retrieve.
*
* @param attrs The names of the attributes to retrieve.
*
* @param cons The constraints specific to the operation.
*
* @return the LDAPEntry read from the server
*
* @exception LDAPException if the object was not found
*/
public LDAPEntry read(String dn,
String[] attrs,
LDAPSearchConstraints cons)
throws LDAPException
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"read(" + dn + ")");
}
LDAPSearchResults sr = search(dn, SCOPE_BASE,
null,
attrs, false, cons);
LDAPEntry ret = null;
if( sr.hasMore()) {
ret = sr.next();
if( sr.hasMore()) {
// "Read response is ambiguous, multiple entries returned"
throw new LDAPLocalException(ExceptionMessages.READ_MULTIPLE,
LDAPException.AMBIGUOUS_RESPONSE);
}
}
return ret;
}
/**
* Synchronously reads the entry specified by the LDAP URL.
*
* When this read method is called, a new connection is created
* automatically, using the host and port specified in the URL. After
* finding the entry, the method closes the connection (in other words,
* it disconnects from the LDAP server).
*
* If the URL specifies a filter and scope, they are not used. Of the
* information specified in the URL, this method only uses the LDAP host
* name and port number, the base distinguished name (DN), and the list
* of attributes to return.
*
* @param toGet LDAP URL specifying the entry to read.
*
* @return The entry specified by the base DN.
*
* @exception LDAPException if the object was not found
*/
public static LDAPEntry read(LDAPUrl toGet)
throws LDAPException
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, "read(" + toGet.toString() + ")");
}
LDAPConnection lconn = new LDAPConnection();
lconn.connect(toGet.getHost(),toGet.getPort());
LDAPEntry toReturn = lconn.read(toGet.getDN(),toGet.getAttributeArray());
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, "read: disconnect()");
}
lconn.disconnect();
return toReturn;
}
/**
* Synchronously reads the entry specified by the LDAP URL, using the
* specified constraints.
*
* When this method is called, a new connection is created
* automatically, using the host and port specified in the URL. After
* finding the entry, the method closes the connection (in other words,
* it disconnects from the LDAP server).
*
* If the URL specifies a filter and scope, they are not used. Of the
* information specified in the URL, this method only uses the LDAP host
* name and port number, the base distinguished name (DN), and the list
* of attributes to return.
*
* @return The entry specified by the base DN.
*
* @param toGet LDAP URL specifying the entry to read.
*
* @param cons Constraints specific to the operation.
*
* @exception LDAPException if the object was not found
*/
public static LDAPEntry read(LDAPUrl toGet,
LDAPSearchConstraints cons)
throws LDAPException
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, "read(" + toGet.toString() + ")");
}
LDAPConnection lconn = new LDAPConnection();
lconn.connect(toGet.getHost(),toGet.getPort());
LDAPEntry toReturn = lconn.read(toGet.getDN(),
toGet.getAttributeArray(), cons);
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, "read: disconnect()");
}
lconn.disconnect();
return toReturn;
}
//*************************************************************************
// rename methods
//*************************************************************************
/**
*
* Synchronously renames an existing entry in the directory.
*
* @param dn The current distinguished name of the entry.
*
* @param newRdn The new relative distinguished name for the entry.
*
* @param deleteOldRdn If true, the old name is not retained as an
* attribute value. If false, the old name is
* retained as an attribute value.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void rename(String dn,
String newRdn,
boolean deleteOldRdn)
throws LDAPException
{
rename(dn, newRdn, deleteOldRdn, defSearchCons);
return;
}
/**
*
* Synchronously renames an existing entry in the directory, using the
* specified constraints.
*
* @param dn The current distinguished name of the entry.
*
* @param newRdn The new relative distinguished name for the entry.
*
* @param deleteOldRdn If true, the old name is not retained as an
* attribute value. If false, the old name is
* retained as an attribute value.
*
* @param cons The constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void rename(String dn,
String newRdn,
boolean deleteOldRdn,
LDAPConstraints cons)
throws LDAPException
{
// null for newParentdn means that this is originating as an LDAPv2 call
rename(dn, newRdn, null, deleteOldRdn, cons);
return;
}
/**
* Synchronously renames an existing entry in the directory, possibly
* repositioning the entry in the directory tree.
*
* @param dn The current distinguished name of the entry.
*
* @param newRdn The new relative distinguished name for the entry.
*
* @param newParentdn The distinguished name of an existing entry which
* is to be the new parent of the entry.
*
* @param deleteOldRdn If true, the old name is not retained as an
* attribute value. If false, the old name is
* retained as an attribute value.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void rename(String dn,
String newRdn,
String newParentdn,
boolean deleteOldRdn)
throws LDAPException
{
rename(dn, newRdn, newParentdn, deleteOldRdn, defSearchCons);
return;
}
/**
*
* Synchronously renames an existing entry in the directory, using the
* specified constraints and possibly repositioning the entry in the
* directory tree.
*
* @param dn The current distinguished name of the entry.
*
* @param newRdn The new relative distinguished name for the entry.
*
* @param newParentdn The distinguished name of an existing entry which
* is to be the new parent of the entry.
*
* @param deleteOldRdn If true, the old name is not retained as an
* attribute value. If false, the old name is
* retained as an attribute value.
*
* @param cons The constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public void rename(String dn,
String newRdn,
String newParentdn,
boolean deleteOldRdn,
LDAPConstraints cons)
throws LDAPException
{
LDAPResponseQueue queue =
rename(dn, newRdn, newParentdn, deleteOldRdn, null, cons);
// Get a handle to the rename response
LDAPResponse renameResponse = (LDAPResponse)(queue.getResponse());
// Set local copy of responseControls synchronously - if there were any
synchronized (responseCtlSemaphore) {
responseCtls = renameResponse.getControls();
}
chkResultCode( queue, cons, renameResponse);
return;
}
/*
* rename
*/
/**
* Asynchronously renames an existing entry in the directory.
*
* @param dn The current distinguished name of the entry.
*
* @param newRdn The new relative distinguished name for the entry.
*
* @param deleteOldRdn If true, the old name is not retained as an
* attribute value. If false, the old name is
* retained as an attribute value.
*
* @param queue The queue for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPResponseQueue rename(String dn,
String newRdn,
boolean deleteOldRdn,
LDAPResponseQueue queue)
throws LDAPException
{
return rename(dn, newRdn, deleteOldRdn, queue, defSearchCons);
}
/**
* Asynchronously renames an existing entry in the directory, using the
* specified constraints.
*
* @param dn The current distinguished name of the entry.
*
* @param newRdn The new relative distinguished name for the entry.
*
* @param deleteOldRdn If true, the old name is not retained as an
* attribute value. If false, the old name is
* retained as an attribute value.
*
* @param queue The queue for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @param cons The constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPResponseQueue rename(String dn,
String newRdn,
boolean deleteOldRdn,
LDAPResponseQueue queue,
LDAPConstraints cons)
throws LDAPException
{
return rename(dn, newRdn, null, deleteOldRdn, queue, cons);
}
/**
* Asynchronously renames an existing entry in the directory, possibly
* repositioning the entry in the directory.
*
* @param dn The current distinguished name of the entry.
*
* @param newRdn The new relative distinguished name for the entry.
*
* @param newParentdn The distinguished name of an existing entry which
* is to be the new parent of the entry.
*
* @param deleteOldRdn If true, the old name is not retained as an
* attribute value. If false, the old name is
* retained as an attribute value.
*
* @param queue The queue for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPResponseQueue rename(String dn,
String newRdn,
String newParentdn,
boolean deleteOldRdn,
LDAPResponseQueue queue)
throws LDAPException
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"rename(" + dn + "," + newRdn + "," + newParentdn + ")");
}
return rename(dn, newRdn, newParentdn,
deleteOldRdn, queue, defSearchCons);
}
/**
* Asynchronously renames an existing entry in the directory, using the
* specified constraints and possibily repositioning the entry in the
* directory.
*
* @param dn The current distinguished name of the entry.
*
* @param newRdn The new relative distinguished name for the entry.
*
* @param newParentdn The distinguished name of an existing entry which
* is to be the new parent of the entry.
*
* @param deleteOldRdn If true, the old name is not retained as an
* attribute value. If false, the old name is
* retained as an attribute value.
*
* @param queue The queue for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @param cons The constraints specific to the operation.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPResponseQueue rename(String dn,
String newRdn,
String newParentdn,
boolean deleteOldRdn,
LDAPResponseQueue queue,
LDAPConstraints cons)
throws LDAPException
{
if(dn == null || newRdn == null) {
// Invalid DN or RDN parameter
throw new IllegalArgumentException(
ExceptionMessages.RDN_PARAM_ERROR);
}
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"rename(" + dn + "," + newRdn + "," + newParentdn + ")");
}
if(cons == null)
cons = defSearchCons;
LDAPMessage msg = new LDAPModifyDNRequest( dn, newRdn, newParentdn,
deleteOldRdn, cons.getControls());
return sendRequestToServer(msg, cons.getTimeLimit(), queue, null);
}
//*************************************************************************
// search methods
//*************************************************************************
/**
*
* Synchronously performs the search specified by the parameters.
*
* @param base The base distinguished name to search from.
*
* @param scope The scope of the entries to search. The following
* are the valid options:
*
* - SCOPE_BASE - searches only the base DN
*
*
- SCOPE_ONE - searches only entries under the base DN
*
*
- SCOPE_SUB - searches the base DN and all entries
* within its subtree
*
* @param filter Search filter specifying the search criteria.
*
* @param attrs Names of attributes to retrieve.
*
* @param typesOnly If true, returns the names but not the values of
* the attributes found. If false, returns the
* names and values for attributes found.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPSearchResults search(String base,
int scope,
String filter,
String[] attrs,
boolean typesOnly)
throws LDAPException
{
return search(base, scope, filter, attrs, typesOnly, defSearchCons);
}
/**
*
* Synchronously performs the search specified by the parameters,
* using the specified search constraints (such as the
* maximum number of entries to find or the maximum time to wait for
* search results).
*
* As part of the search constraints, the method allows specifying
* whether or not the results are to be delivered all at once or in
* smaller batches. If specified that the results are to be delivered in
* smaller batches, each iteration blocks only until the next batch of
* results is returned.
*
* @param base The base distinguished name to search from.
*
* @param scope The scope of the entries to search. The following
* are the valid options:
*
* - SCOPE_BASE - searches only the base DN
*
*
- SCOPE_ONE - searches only entries under the base DN
*
*
- SCOPE_SUB - searches the base DN and all entries
* within its subtree
*
* @param filter The search filter specifying the search criteria.
*
* @param attrs The names of attributes to retrieve.
*
* @param typesOnly If true, returns the names but not the values of
* the attributes found. If false, returns the
* names and values for attributes found.
*
* @param cons The constraints specific to the search.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPSearchResults search(String base,
int scope,
String filter,
String[] attrs,
boolean typesOnly,
LDAPSearchConstraints cons)
throws LDAPException
{
LDAPSearchQueue queue =
search(base, scope, filter, attrs, typesOnly, null, cons);
if( cons == null )
cons = defSearchCons;
return new LDAPSearchResults(this, queue, cons);
}
/**
* Asynchronously performs the search specified by the parameters.
*
* @param base The base distinguished name to search from.
*
* @param scope The scope of the entries to search. The following
* are the valid options:
*
* - SCOPE_BASE - searches only the base DN
*
*
- SCOPE_ONE - searches only entries under the base DN
*
*
- SCOPE_SUB - searches the base DN and all entries
* within its subtree
*
* @param filter Search filter specifying the search criteria.
*
* @param attrs Names of attributes to retrieve.
*
* @param typesOnly If true, returns the names but not the values of
* the attributes found. If false, returns the
* names and values for attributes found.
*
* @param queue Handler for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPSearchQueue search(String base,
int scope,
String filter,
String[] attrs,
boolean typesOnly,
LDAPSearchQueue queue)
throws LDAPException
{
return search(base, scope, filter, attrs, typesOnly,
queue, defSearchCons);
}
/**
* Asynchronously performs the search specified by the parameters,
* also allowing specification of constraints for the search (such
* as the maximum number of entries to find or the maximum time to
* wait for search results).
*
* @param base The base distinguished name to search from.
*
* @param scope The scope of the entries to search. The following
* are the valid options:
*
* - SCOPE_BASE - searches only the base DN
*
*
- SCOPE_ONE - searches only entries under the base DN
*
*
- SCOPE_SUB - searches the base DN and all entries
* within its subtree
*
* @param filter The search filter specifying the search criteria.
*
* @param attrs The names of attributes to retrieve.
*
* @param typesOnly If true, returns the names but not the values of
* the attributes found. If false, returns the
* names and values for attributes found.
*
* @param queue The queue for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
*
* @param cons The constraints specific to the search.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public LDAPSearchQueue search(String base,
int scope,
String filter,
String[] attrs,
boolean typesOnly,
LDAPSearchQueue queue,
LDAPSearchConstraints cons)
throws LDAPException
{
if( filter == null) {
filter = "objectclass=*";
}
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"search(\"" + base + "\"," + scope + ",\"" + filter + "\")");
}
if(cons == null)
cons = defSearchCons;
LDAPMessage msg = new LDAPSearchRequest( base, scope, filter,
attrs, cons.getDereference(),
cons.getMaxResults(),
cons.getServerTimeLimit(),
typesOnly, cons.getControls());
MessageAgent agent;
LDAPSearchQueue myqueue = queue;
if(myqueue == null) {
agent = new MessageAgent();
myqueue = new LDAPSearchQueue( agent );
} else {
agent = queue.getMessageAgent();
}
try {
agent.sendMessage( conn, msg, cons.getTimeLimit(), myqueue, null);
} catch(LDAPException lex) {
throw lex;
}
return myqueue;
}
/*
* LDAP URL search
*/
/**
* Synchronously performs the search specified by the LDAP URL, returning
* an enumerable LDAPSearchResults object.
*
* @param toGet The LDAP URL specifying the entry to read.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public static LDAPSearchResults search(LDAPUrl toGet)
throws LDAPException
{
// Get a clone of default search constraints, method alters batchSize
return search( toGet, null);
}
/*
* LDAP URL search
*/
/**
* Synchronously perfoms the search specified by the LDAP URL, using
* the specified search constraints (such as the maximum number of
* entries to find or the maximum time to wait for search results).
*
* When this method is called, a new connection is created
* automatically, using the host and port specified in the URL. After
* all search results have been received from the server, the method
* closes the connection (in other words, it disconnects from the LDAP
* server).
*
* As part of the search constraints, a choice can be made as to whether
* to have the results delivered all at once or in smaller batches. If
* the results are to be delivered in smaller batches, each iteration
* blocks only until the next batch of results is returned.
*
*
* @param toGet LDAP URL specifying the entry to read.
*
* @param cons The constraints specific to the search.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
public static LDAPSearchResults search(LDAPUrl toGet,
LDAPSearchConstraints cons)
throws LDAPException
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests,
"LDAPConnection.search(" + toGet.toString() + ")");
}
LDAPConnection lconn = new LDAPConnection();
lconn.connect(toGet.getHost(),toGet.getPort());
if( cons == null) {
// This is a clone, so we already have our own copy
cons = lconn.getSearchConstraints();
} else {
// get our own copy of user's constraints because we modify it
cons = (LDAPSearchConstraints)cons.clone();
}
cons.setBatchSize(0); // Must wait until all results arrive
LDAPSearchResults toReturn = lconn.search(toGet.getDN(),
toGet.getScope(), toGet.getFilter(), toGet.getAttributeArray(),
false, cons);
lconn.disconnect();
return toReturn;
}
/**
* Sends an LDAP request to a directory server.
*
* The specified the LDAP request is sent to the directory server
* associated with this connection using default constraints. An LDAP
* request object is a subclass {@link LDAPMessage} with the operation
* type set to one of the request types. You can build a request by using
* the request classes found in this package
*
* You should note that, since LDAP requests sent to the server
* using sendRequest are asynchronous, automatic referral following
* does not apply to these requests.
*
* @param request The LDAP request to send to the directory server.
* @param queue The queue for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*
* @see LDAPMessage#getType()
* @see LDAPMessage#isRequest()
*/
public LDAPMessageQueue sendRequest( LDAPMessage request,
LDAPMessageQueue queue)
throws LDAPException
{
return sendRequest( request, queue, null);
}
/**
* Sends an LDAP request to a directory server.
*
* The specified the LDAP request is sent to the directory server
* associated with this connection. An LDAP request object is an
* {@link LDAPMessage} with the operation type set to one of the request
* types. You can build a request by using the request classes found in this
* package
*
* You should note that, since LDAP requests sent to the server
* using sendRequest are asynchronous, automatic referral following
* does not apply to these requests.
*
* @param request The LDAP request to send to the directory server.
* @param queue The queue for messages returned from a server in
* response to this request. If it is null, a
* queue object is created internally.
* @param cons The constraints that apply to this request
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*
* @see LDAPMessage#getType()
* @see LDAPMessage#isRequest()
*/
public LDAPMessageQueue sendRequest( LDAPMessage request,
LDAPMessageQueue queue,
LDAPConstraints cons)
throws LDAPException
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.apiRequests, name +
"sendRequest(" + request.toString() + ")");
}
if( ! request.isRequest() ) {
throw new RuntimeException( "Object is not a request message");
}
if(cons == null) {
cons = defSearchCons;
}
// Get the correct queue for a search request
MessageAgent agent;
LDAPMessageQueue myqueue = queue;
if(myqueue == null) {
agent = new MessageAgent();
if( request.getType() == LDAPMessage.SEARCH_REQUEST) {
myqueue = new LDAPSearchQueue( agent );
} else {
myqueue = new LDAPResponseQueue( agent );
}
} else {
if( request.getType() == LDAPMessage.SEARCH_REQUEST) {
agent = queue.getMessageAgent();
} else {
agent = queue.getMessageAgent();
}
}
try {
agent.sendMessage( conn, request, cons.getTimeLimit(), myqueue, null);
} catch(LDAPException lex) {
throw lex;
}
return myqueue;
}
//*************************************************************************
// helper methods
//*************************************************************************
/**
* Locates the appropriate message agent and sends
* the LDAP request to a directory server.
*
* @param msg the message to send
*
* @param timeout the timeout value
*
* @param queue the response queue or null
*
* @return the LDAPResponseQueue for this request
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
private LDAPResponseQueue sendRequestToServer( LDAPMessage msg,
int timeout,
LDAPResponseQueue queue,
BindProperties bindProps)
throws LDAPException
{
MessageAgent agent;
if(queue == null) {
agent = new MessageAgent();
queue = new LDAPResponseQueue( agent);
} else {
agent = queue.getMessageAgent();
}
agent.sendMessage( conn, msg, timeout, queue, bindProps);
return queue;
}
/**
* Return the Connection object associated with this LDAPConnection
*
* @return the Connection object
*/
/* package */
Connection getConnection( )
{
return conn;
}
/**
* Return the Connection object name associated with this LDAPConnection
*
* @return the Connection object name
*/
/* package */
String getConnectionName( )
{
return name;
}
/**
* get an LDAPConnection object so that we can follow a referral.
* This function is never called if cons.getReferralFollowing() returns
* false.
*
* @param referrals the array of referral strings
*
*
* @return The referralInfo object
*
* @exception LDAPReferralException A general exception which includes
* an error message and an LDAP error code.
*/
private ReferralInfo getReferralConnection( String[] referrals)
throws LDAPReferralException
{
ReferralInfo refInfo = null;
Throwable ex = null;
LDAPConnection rconn = null;
LDAPReferralHandler rh = defSearchCons.getReferralHandler();
int i = 0;
// Check if we use LDAPRebind to get authentication credentials
if( (rh == null) || (rh instanceof LDAPAuthHandler)) {
for( i = 0; i < referrals.length; i++) {
// dn, pw are null in the default case (anonymous bind)
String dn = null;
byte[] pw = null;
try {
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.referrals, name +
"getReferralConnection: " +
"url=" + referrals[i]);
}
rconn = new LDAPConnection( conn.getSocketFactory());
rconn.setConstraints( defSearchCons);
LDAPUrl url = new LDAPUrl(referrals[i]);
rconn.connect(url.getHost(),url.getPort());
if( rh != null) {
if( rh instanceof LDAPAuthHandler) {
// Get application supplied dn and pw
LDAPAuthProvider ap =
((LDAPAuthHandler)rh).getAuthProvider(
url.getHost(),url.getPort());
dn = ap.getDN();
pw = ap.getPassword();
}
}
rconn.bind( LDAP_V3, dn, pw);
ex = null;
refInfo = new ReferralInfo(rconn, referrals, url);
// Indicate this connection created to follow referral
rconn.getConnection().setActiveReferral( refInfo);
break;
} catch( Throwable lex) {
if( rconn != null) {
try {
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.referrals, name +
"getReferralConnection, exception " +
"binding for referral" + lex.toString());
}
rconn.disconnect();
rconn = null;
ex = lex;
} catch( LDAPException e) {
; // ignore
}
}
}
}
}
// Check if application gets connection and does bind
else { // rh instanceof LDAPBind
try {
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.referrals, name +
"getReferralConnection: " +
"Call LDAPBind.bind()");
}
rconn = ((LDAPBindHandler)rh).bind( referrals, this);
if( rconn == null) {
LDAPReferralException rex = new LDAPReferralException(
ExceptionMessages.REFERRAL_ERROR);
rex.setReferrals( referrals);
throw rex;
}
// Figure out which Url belongs to the connection
for( int idx = 0; idx < referrals.length; idx++) {
try {
LDAPUrl url = new LDAPUrl( referrals[idx]);
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.referrals, name +
"getReferralConnection: " +
"Compare host port " +
url.getHost() + "-" + rconn.getHost() +
" & " +
url.getPort() + "-" + rconn.getPort());
}
if( url.getHost().equalsIgnoreCase(rconn.getHost()) &&
(url.getPort() == rconn.getPort())) {
refInfo = new ReferralInfo(rconn, referrals, url);
break;
}
} catch ( Exception e) {
; // ignore
}
}
if( refInfo == null) {
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.referrals, name +
"getReferralConnection: " +
"LDAPBind.bind(): " +
" could not match connection with URL" +
referrals.toString());
}
// Could not match LDAPBind.bind() connecction with URL list
ex = new LDAPLocalException(
ExceptionMessages.REFERRAL_BIND_MATCH,
LDAPException.CONNECT_ERROR);
}
} catch( Throwable lex) {
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.referrals, name +
"getReferralConnection: " +
"Exception from LDAPBind.bind(): " +
lex.toString());
}
rconn = null;
ex = lex;
}
}
if( ex != null) {
// Could not connect to any server, throw an exception
LDAPException ldapex;
if( ex instanceof LDAPReferralException) {
throw (LDAPReferralException)ex;
} else
if( ex instanceof LDAPException) {
ldapex = (LDAPException)ex;
} else {
ldapex = new LDAPLocalException(
ExceptionMessages.SERVER_CONNECT_ERROR,
new Object[] { conn.getHost() },
LDAPException.CONNECT_ERROR, ex);
}
// Error attempting to follow a referral
LDAPReferralException rex = new LDAPReferralException(
ExceptionMessages.REFERRAL_ERROR,
ldapex);
rex.setReferrals(referrals);
// Use last URL string for the failed referral
rex.setFailedReferral( referrals[referrals.length-1]);
throw rex;
}
// We now have an authenticated connection
// to be used to follow the referral.
return refInfo;
}
/**
* Check the result code and throw an exception if needed.
*
* If referral following is enabled, checks if we need to
* follow a referral
*
* @param queue - the message queue of the current response
*
* @param cons - the constraints that apply to the request
*
* @param response - the LDAPResponse to check
*/
private void chkResultCode( LDAPMessageQueue queue,
LDAPConstraints cons,
LDAPResponse response)
throws LDAPException
{
if( (response.getResultCode() == LDAPException.REFERRAL) &&
cons.getReferralFollowing()) {
// Perform referral following and return
ArrayList refConn = null;
try {
chaseReferral( queue, cons, response,
response.getReferrals(), 0, false, null );
} finally {
releaseReferralConnections( refConn);
}
} else {
// Throws exception for non success result
response.chkResultCode();
}
return;
}
/**
* Follow referrals if necessary referral following enabled.
* This function is called only by synchronous requests.
* Search responses come here only if referral following is
* enabled and if we are processing a SearchResultReference
* or a Response with a status of REFERRAL, i.e. we are
* going to follow a referral.
*
* This functions recursively follows a referral until a result
* is returned or until the hop limit is reached.
*
* @param queue The LDAPResponseQueue for this request
*
* @param cons The constraints that apply to the request
*
* @param msg The referral or search reference response message
*
* @param initialReferrals The referral array returned from the
* initial request.
*
* @param hopCount the number of hops already used while
* following this referral
*
* @param searchReference true if the message is a search reference
*
* @param connectionList An optional array list used to store
* the LDAPConnection objects used in following the referral.
*
* @return The array list used to store the all LDAPConnection objects
* used in following the referral. The list will be empty
* if there were none.
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
/* package */
ArrayList chaseReferral( LDAPMessageQueue queue,
LDAPConstraints cons,
LDAPMessage msg,
String[] initialReferrals,
int hopCount,
boolean searchReference,
ArrayList connectionList)
throws LDAPException
{
ArrayList connList = connectionList;
LDAPConnection rconn = null; // new conn for following referral
ReferralInfo rinfo = null; // referral info
LDAPMessage origMsg;
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.referrals, name +
"Check for referrals, reference = " + searchReference);
}
// Get a place to store new connections
if( connList == null) {
connList = new ArrayList( cons.getHopLimit());
}
// Following referrals or search reference
String [] refs; // referral list
if( initialReferrals != null) {
// Search continuation reference from a search request
refs = initialReferrals;
origMsg = msg.getRequestingMessage();
} else { // Not a search request
LDAPResponse resp = (LDAPResponse)queue.getResponse();
if( resp.getResultCode() != LDAPException.REFERRAL) {
// Not referral result,throw Exception if nonzero result
resp.chkResultCode();
return connList;
}
// We have a referral response
refs = resp.getReferrals();
origMsg = resp.getRequestingMessage();
}
LDAPUrl refUrl; // referral represented as URL
try {
// increment hop count, check max hops
if( hopCount++ > cons.getHopLimit()) {
throw new LDAPLocalException("Max hops exceeded",
LDAPException.REFERRAL_LIMIT_EXCEEDED);
}
// Get a connection to follow the referral
rinfo = getReferralConnection( refs);
rconn = rinfo.getReferralConnection();
refUrl = rinfo.getReferralUrl();
connList.add( rconn);
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.referrals, name +
(searchReference?"Following search reference URL " :
"Following referral URL ") + refUrl.toString());
}
// rebuild msg into new msg changing msgID,dn,scope,filter
LDAPMessage newMsg = rebuildRequest( origMsg,
refUrl, searchReference);
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.referrals, name +
"following referral for " + refUrl.toString());
Debug.trace( Debug.referrals, name +
"request " + newMsg.toString());
}
// Send new message on new connection
try {
MessageAgent agent;
if( queue instanceof LDAPResponseQueue) {
agent=queue.getMessageAgent();
} else {
agent=queue.getMessageAgent();
}
agent.sendMessage( rconn.getConnection(), newMsg,
defSearchCons.getTimeLimit(), queue, null);
} catch(InterThreadException ex) {
// Error ending request to referred server
LDAPReferralException rex = new LDAPReferralException(
ExceptionMessages.REFERRAL_SEND,
LDAPException.CONNECT_ERROR, null, ex);
rex.setReferrals( initialReferrals);
ReferralInfo ref=rconn.getConnection().getActiveReferral();
rex.setFailedReferral( ref.getReferralUrl().toString());
throw rex;
}
if( initialReferrals == null) {
// For operation results, when all responses are complete,
// the stack unwinds back to the original and returns
// to the application.
// An exception is thrown for an error
connList = chaseReferral( queue, cons, null, null,
hopCount, false, connList);
} else {
// For search, just return to LDAPSearchResults object
return connList;
}
} catch (Exception ex) {
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.referrals, name +
"Throw exception " + ex.toString());
}
if( ex instanceof LDAPReferralException) {
throw (LDAPReferralException)ex;
} else {
// Set referral list and failed referral
LDAPReferralException rex = new LDAPReferralException(
ExceptionMessages.REFERRAL_ERROR, ex);
rex.setReferrals( refs);
if( rinfo != null) {
rex.setFailedReferral( rinfo.getReferralUrl().toString());
} else {
rex.setFailedReferral( refs[refs.length - 1]);
}
throw rex;
}
}
return connList;
}
/**
* Builds a new request replacing dn, scope, and filter where approprate
*
* @param msg the original LDAPMessage to build the new request from
*
* @param url the referral url
*
* @return a new LDAPMessage with appropriate information replaced
*
* @exception LDAPException A general exception which includes an error
* message and an LDAP error code.
*/
private
LDAPMessage rebuildRequest( LDAPMessage msg, LDAPUrl url, boolean reference)
throws LDAPException
{
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.referrals, name +
"rebuildRequest: original request = " +
"message(" + msg.getMessageID() + "), request type " +
msg.getType());
}
String dn = url.getDN(); // new base
String filter = null;
switch( msg.getType()) {
case LDAPMessage.SEARCH_REQUEST:
if( reference) {
filter = url.getFilter();
}
break;
// We are allowed to get a referral for the following
case LDAPMessage.ADD_REQUEST:
case LDAPMessage.BIND_REQUEST:
case LDAPMessage.COMPARE_REQUEST:
case LDAPMessage.DEL_REQUEST:
case LDAPMessage.EXTENDED_REQUEST:
case LDAPMessage.MODIFY_RDN_REQUEST:
case LDAPMessage.MODIFY_REQUEST:
break;
// The following return no response
case LDAPMessage.ABANDON_REQUEST:
case LDAPMessage.UNBIND_REQUEST:
default:
throw new LDAPLocalException(
// "Referral doesn't make sense for command"
ExceptionMessages.IMPROPER_REFERRAL,
new Object[] {
new Integer( msg.getType())
},
LDAPException.LOCAL_ERROR);
}
return msg.clone( dn, filter, reference);
}
/*
* Release connections acquired by following referrals
*
* @param list the list of the connections
*/
/* package */
void releaseReferralConnections( ArrayList list)
{
if( list == null) {
return;
}
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.referrals, name +
"Release referal connections");
}
// Release referral connections
for( int i = list.size()-1; i >= 0; i--) {
LDAPConnection rconn = null;
try {
rconn = (LDAPConnection)list.remove(i);
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.referrals, "\t" + name +
"Disconnecting " +
rconn.getConnectionName());
}
rconn.disconnect();
} catch( ArrayIndexOutOfBoundsException ex) {
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.referrals, "\t" + name +
"Failed to get conn at index " + i);
}
continue;
} catch( LDAPException lex) {
if( Debug.LDAP_DEBUG) {
Debug.trace( Debug.referrals, "\t" + name +
"Disconnect failed for " + rconn.getConnectionName());
}
continue;
}
}
return;
}
//*************************************************************************
// Schema Related methods
//*************************************************************************
/**
* Retrieves the schema associated with a particular schema DN in the
* directory server.
* The schema DN for a particular entry is obtained by calling the
* getSchemaDN method of LDAPConnection
*
* @param schemaDN The schema DN used to fetch the schema.
*
* @return An LDAPSchema entry containing schema attributes. If the
* entry contains no schema attributes then the returned LDAPSchema object
* will be empty.
*
* @exception LDAPException This exception occurs if the schema entry
* cannot be retrieved with this connection.
* @see #getSchemaDN()
* @see #getSchemaDN(String)
*/
public LDAPSchema fetchSchema ( String schemaDN ) throws LDAPException {
/* Read the schema definitions. If no entry is found an
* Exception is thrown */
LDAPEntry ent = read(schemaDN, LDAPSchema.schemaTypeNames);
return new LDAPSchema(ent);
}
/**
* Retrieves the Distiguished Name (DN) for the schema advertised in the
* root DSE of the Directory Server.
*
* The DN can be used with the methods fetchSchema and modify to retreive
* and extend schema definitions. The schema entry is located by reading
* subschemaSubentry attribute of the root DSE. This is equivalent to
* calling {@link #getSchemaDN(String) } with the DN parameter as an empty
* string: getSchemaDN("")
.
*
*
* @return Distinguished Name of a schema entry in effect for the
* Directory.
* @exception LDAPException This exception occurs if the schema DN
* cannot be retrieved, or if the subschemaSubentry attribute associated
* with the root DSE contains multiple values.
*
* @see #fetchSchema
* @see #modify
*/
public String getSchemaDN() throws LDAPException {
return getSchemaDN("");
}
/**
* Retrieves the Distiguished Name (DN) of the schema associated with a
* entry in the Directory.
*
* The DN can be used with the methods fetchSchema and modify to retreive
* and extend schema definitions. Reads the subschemaSubentry of the entry
* specified.
*
* @param dn Distinguished Name of any entry. The subschemaSubentry
* attribute is queried from this entry.
*
* @return Distinguished Name of a schema entry in effect for the entry
* identified by dn
.
*
* @exception LDAPException This exception occurs if a null or empty
* value is passed as dn, if the subschemasubentry attribute cannot
* be retrieved, or the subschemasubentry contains multiple values.
*
* @see #fetchSchema
* @see #modify
*/
public String getSchemaDN( String dn )
throws LDAPException
{
String attrSubSchema[] = { "subschemaSubentry" };
/* Read the entries subschemaSubentry attribute. Throws an exception if
* no entries are returned. */
LDAPEntry ent = this.read( dn, attrSubSchema );
LDAPAttribute attr = ent.getAttribute( attrSubSchema[0] );
String values[] = attr.getStringValueArray();
if( values == null || values.length < 1 ) {
throw new LDAPLocalException(
ExceptionMessages.NO_SCHEMA,
new Object[] { dn },
LDAPException.NO_RESULTS_RETURNED);
}
else if( values.length > 1 ) {
throw new LDAPLocalException(
ExceptionMessages.MULTIPLE_SCHEMA,
new Object[] { dn },
LDAPException.CONSTRAINT_VIOLATION);
}
return values[0];
}
}