LDAPClientConnection.java revision c569c7bf70ff07adb776a1cb58d2aa2f341281b4
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Portions Copyright 2006-2007 Sun Microsystems, Inc.
*/
/**
* This class defines an LDAP client connection, which is a type of client
* connection that will be accepted by an instance of the LDAP connection
* handler and have its requests decoded by an LDAP request handler.
*/
public class LDAPClientConnection
extends ClientConnection
implements TLSCapableConnection
{
// The next operation ID that should be used for this connection.
private AtomicLong nextOperationID;
// Indicates whether the Directory Server believes this connection to be
// valid and available for communication.
private boolean connectionValid;
// Indicates whether this connection is about to be closed. This will be used
// to prevent accepting new requests while a disconnect is in progress.
private boolean disconnectRequested;
// Indicates whether the connection should keep statistics regarding the
// operations that it is performing.
private boolean keepStats;
// The BER type for the ASN.1 element that is in the process of being read.
private byte elementType;
// The encoded value for the ASN.1 element that is in the process of being
// read.
private byte[] elementValue;
// The set of all operations currently in progress on this connection.
// The connection security provider that was in use for the client connection
// before switching to a TLS-based provider.
// The connection security provider for this client connection.
// The port on the client from which this connection originated.
private int clientPort;
// The number of bytes contained in the value for the ASN.1 element that is in
// the process of being read.
private int elementLength;
// The number of bytes in the multi-byte length that are still needed to fully
// decode the length of the ASN.1 element in process.
private int elementLengthBytesNeeded;
// The current state for the data read for the ASN.1 element in progress.
private int elementReadState;
// The number of bytes that have already been read for the ASN.1 element
// value in progress.
private int elementValueBytesRead;
// The number of bytes that are still needed to fully decode the value of the
// ASN.1 element in progress.
private int elementValueBytesNeeded;
// The LDAP version that the client is using to communicate with the server.
private int ldapVersion;
// The port on the server to which this client has connected.
private int serverPort;
// The reference to the connection handler that accepted this connection.
private LDAPConnectionHandler connectionHandler;
// The reference to the request handler with which this connection is
// associated.
private LDAPRequestHandler requestHandler;
// The statistics tracker associated with this client connection.
private LDAPStatistics statTracker;
// The connection ID assigned to this connection.
private long connectionID;
// The lock used to provide threadsafe access to the set of operations in
// progress.
private ReentrantLock opsInProgressLock;
// The lock used to provide threadsafe access when sending data to the client.
private ReentrantLock transmitLock;
// The socket channel with which this client connection is associated.
private SocketChannel clientChannel;
// The string representation of the address of the client.
private String clientAddress;
// The name of the protocol that the client is using to communicate with the
// server.
// The string representation of the address of the server to which the client
// has connected.
private String serverAddress;
// The TLS connection security provider that may be used for this connection
// if StartTLS is requested.
/**
* Creates a new LDAP client connection with the provided information.
*
* @param connectionHandler The connection handler that accepted this
* connection.
* @param clientChannel The socket channel that may be used to
* communicate with the client.
*/
{
super();
this.connectionHandler = connectionHandler;
this.clientChannel = clientChannel;
this.securityProvider = null;
this.clearSecurityProvider = null;
opsInProgressLock = new ReentrantLock();
transmitLock = new ReentrantLock();
elementType = 0x00;
elementLength = 0;
elementValue = null;
ldapVersion = 3;
connectionValid = true;
disconnectRequested = false;
protocol = "LDAP";
" for " + toString();
if (keepStats)
{
}
if (connectionID < 0)
{
}
}
/**
* Retrieves the connection ID assigned to this connection.
*
* @return The connection ID assigned to this connection.
*/
public long getConnectionID()
{
return connectionID;
}
/**
* Retrieves the connection handler that accepted this client connection.
*
* @return The connection handler that accepted this client connection.
*/
public ConnectionHandler getConnectionHandler()
{
return connectionHandler;
}
/**
* Retrieves the request handler that will read requests for this client
* connection.
*
* @return The request handler that will read requests for this client
* connection, or <CODE>null</CODE> if none has been assigned yet.
*/
public LDAPRequestHandler getRequestHandler()
{
return requestHandler;
}
/**
* Specifies the request handler that will read requests for this client
* connection.
*
* @param requestHandler The request handler that will read requests for
* this client connection.
*/
{
this.requestHandler = requestHandler;
}
/**
* Retrieves the socket channel that can be used to communicate with the
* client.
*
* @return The socket channel that can be used to communicate with the
* client.
*/
public SocketChannel getSocketChannel()
{
return clientChannel;
}
/**
* Retrieves the protocol that the client is using to communicate with the
* Directory Server.
*
* @return The protocol that the client is using to communicate with the
* Directory Server.
*/
public String getProtocol()
{
return protocol;
}
/**
* Retrieves a string representation of the address of the client.
*
* @return A string representation of the address of the client.
*/
public String getClientAddress()
{
return clientAddress;
}
/**
* Retrieves the port number for this connection on the client system.
*
* @return The port number for this connection on the client system.
*/
public int getClientPort()
{
return clientPort;
}
/**
* Retrieves the address and port of the client system, separated by a colon.
*
* @return The address and port of the client system, separated by a colon.
*/
public String getClientHostPort()
{
}
/**
* Retrieves a string representation of the address on the server to which the
* client connected.
*
* @return A string representation of the address on the server to which the
* client connected.
*/
public String getServerAddress()
{
return serverAddress;
}
/**
* Retrieves the port number for this connection on the server system.
*
* @return The port number for this connection on the server system.
*/
public int getServerPort()
{
return serverPort;
}
/**
* Retrieves the address and port of the server system, separated by a colon.
*
* @return The address and port of the server system, separated by a colon.
*/
public String getServerHostPort()
{
}
/**
* Retrieves the <CODE>java.net.InetAddress</CODE> associated with the remote
* client system.
*
* @return The <CODE>java.net.InetAddress</CODE> associated with the remote
* client system. It may be <CODE>null</CODE> if the client is not
* connected over an IP-based connection.
*/
public InetAddress getRemoteAddress()
{
}
/**
* Retrieves the <CODE>java.net.InetAddress</CODE> for the Directory Server
* system to which the client has established the connection.
*
* @return The <CODE>java.net.InetAddress</CODE> for the Directory Server
* system to which the client has established the connection. It may
* be <CODE>null</CODE> if the client is not connected over an
* IP-based connection.
*/
public InetAddress getLocalAddress()
{
}
/**
* Indicates whether this client connection is currently using a secure
* mechanism to communicate with the server. Note that this may change over
* time based on operations performed by the client or server (e.g., it may go
* from <CODE>false</CODE> to <CODE>true</CODE> if the client uses the
* StartTLS extended operation).
*
* @return <CODE>true</CODE> if the client connection is currently using a
* secure mechanism to communicate with the server, or
* <CODE>false</CODE> if not.
*/
public boolean isSecure()
{
return securityProvider.isSecure();
}
/**
* Retrieves the connection security provider for this client connection.
*
* @return The connection security provider for this client connection.
*/
{
return securityProvider;
}
/**
* Specifies the connection security provider for this client connection.
*
* @param securityProvider The connection security provider to use for
* communication on this client connection.
*/
{
this.securityProvider = securityProvider;
if (securityProvider.isSecure())
{
}
else
{
protocol = "LDAP";
}
}
/**
* Retrieves the human-readable name of the security mechanism that is used to
* protect communication with this client.
*
* @return The human-readable name of the security mechanism that is used to
* protect communication with this client, or <CODE>null</CODE> if no
* security is in place.
*/
public String getSecurityMechanism()
{
return securityProvider.getSecurityMechanismName();
}
/**
* Retrieves the next operation ID that should be used for this connection.
*
* @return The next operation ID that should be used for this connection.
*/
public long nextOperationID()
{
return nextOperationID.getAndIncrement();
}
/**
* Sends a response to the client based on the information in the provided
* operation.
*
* @param operation The operation for which to send the response.
*/
{
{
}
}
/**
* Retrieves an LDAPMessage containing a response generated from the provided
* operation.
*
* @param operation The operation to use to generate the response
* LDAPMessage.
*
* @return An LDAPMessage containing a response generated from the provided
* operation.
*/
{
if (resultCode == null)
{
// This must mean that the operation has either not yet completed or that
// it completed without a result for some reason. In any case, log a
// message and set the response to "operations error".
}
// Referrals are not allowed for LDAPv2 clients.
if (ldapVersion == 2)
{
referralURLs = null;
{
}
{
{
}
}
}
else
{
}
switch (operation.getOperationType())
{
case ADD:
break;
case BIND:
break;
case COMPARE:
break;
case DELETE:
break;
case EXTENDED:
// If this an LDAPv2 client, then we can't send this.
if (ldapVersion == 2)
{
return null;
}
break;
case MODIFY:
break;
case MODIFY_DN:
break;
case SEARCH:
break;
default:
// This must be a type of operation that doesn't have a response. This
// shouldn't happen, so log a message and return.
return null;
}
// Controls are not allowed for LDAPv2 clients.
if (ldapVersion == 2)
{
}
else
{
{
}
else
{
for (Control c : responseControls)
{
}
}
}
}
/**
* Sends the provided search result entry to the client.
*
* @param searchOperation The search operation with which the entry is
* associated.
* @param searchEntry The search result entry to be sent to the client.
*/
{
{
}
else
{
for (Control c : entryControls)
{
}
}
controls));
}
/**
* Sends the provided search result reference to the client.
*
* @param searchOperation The search operation with which the reference is
* associated.
* @param searchReference The search result reference to be sent to the
* client.
*
* @return <CODE>true</CODE> if the client is able to accept referrals, or
* <CODE>false</CODE> if the client cannot handle referrals and no
* more attempts should be made to send them for the associated
* search operation.
*/
{
// Make sure this is not an LDAPv2 client. If it is, then they can't see
// referrals so we'll not send anything. Also, throw an exception so that
// the core server will know not to try sending any more referrals to this
// client for the rest of the operation.
if (ldapVersion == 2)
{
return false;
}
{
}
else
{
for (Control c : referenceControls)
{
}
}
controls));
return true;
}
/**
* Sends the provided intermediate response message to the client.
*
* @param intermediateResponse The intermediate response message to be sent.
*
* @return <CODE>true</CODE> if processing on the associated operation should
* continue, or <CODE>false</CODE> if not.
*/
protected boolean sendIntermediateResponseMessage(
{
{
}
// The only reason we shouldn't continue processing is if the connection is
// closed.
return connectionValid;
}
/**
* Sends the provided LDAP message to the client.
*
* @param securityProvider The connection security provider to use to
* handle any necessary security translation.
* @param message The LDAP message to send to the client.
*/
{
// Make sure that we can only send one message at a time. This locking will
// not have any impact on the ability to read requests from the client.
transmitLock.lock();
try
{
try
{
{
return;
}
if (debugEnabled())
{
}
if (keepStats)
{
}
}
catch (@Deprecated Exception e)
{
if (debugEnabled())
{
}
// We were unable to send the message due to some other internal
// problem. Disconnect from the client and return.
getBacktrace(e));
return;
}
}
catch (Exception e)
{
if (debugEnabled())
{
}
// FIXME -- Log a message or something
getBacktrace(e));
return;
}
finally
{
}
}
/**
* Closes the connection to the client, optionally sending it a message
* indicating the reason for the closure. Note that the ability to send a
* notice of disconnection may not be available for all protocols or under all
* circumstances.
*
* @param disconnectReason The disconnect reason that provides the generic
* cause for the disconnect.
* @param sendNotification Indicates whether to try to provide notification
* to the client that the connection will be closed.
* @param message The message to include in the disconnect
* notification response. It may be
* <CODE>null</CODE> if no message is to be sent.
* @param messageID The unique identifier associated with the message
* to send to the client. It may be -1 if no
* notification is to be sent.
*/
int messageID)
{
// If we are already in the middle of a disconnect, then don't do anything.
if (disconnectRequested)
{
return;
}
if (keepStats)
{
}
if (connectionID >= 0)
{
DirectoryServer.connectionClosed(this);
}
// Indicate that this connection is no longer valid.
connectionValid = false;
// Set a flag indicating that the connection is being terminated so that no
// new requests will be accepted. Also cancel all operations in progress.
try
{
disconnectRequested = true;
}
catch (Exception e)
{
if (debugEnabled())
{
}
}
finally
{
}
// See if we should send a notification to the client. If so, then
// construct and send a notice of disconnection unsolicited response.
// Note that we cannot send this notification to an LDAPv2 client.
{
try
{
int resultCode;
switch (disconnectReason)
{
case PROTOCOL_ERROR:
break;
case SERVER_SHUTDOWN:
break;
case SERVER_ERROR:
break;
case ADMIN_LIMIT_EXCEEDED:
case IDLE_TIME_LIMIT_EXCEEDED:
case IO_TIMEOUT:
break;
case CONNECTION_REJECTED:
break;
default:
break;
}
{
errMsg =
}
else
{
}
byte[] messageBytes =
try
{
} catch (Exception e) {}
}
catch (Exception e)
{
// NYI -- Log a message indicating that we couldn't send the notice of
// disconnection.
}
}
// Close the connection to the client.
try
{
}
catch (Exception e)
{
// In general, we don't care about any exception that might be thrown
// here.
if (debugEnabled())
{
}
}
try
{
}
catch (Exception e)
{
// In general, we don't care about any exception that might be thrown
// here.
if (debugEnabled())
{
}
}
// NYI -- Deregister the client connection from any server components that
// might know about it.
// Log a disconnect message.
if(messageID == -1)
{
} else
{
}
try
{
}
catch (Exception e)
{
if (debugEnabled())
{
}
}
}
/**
* Retrieves the set of operations in progress for this client connection.
* This list must not be altered by any caller.
*
* @return The set of operations in progress for this client connection.
*/
{
return operationsInProgress.values();
}
/**
* Retrieves the operation in progress with the specified message ID.
*
* @param messageID The message ID for the operation to retrieve.
*
* @return The operation in progress with the specified message ID, or
* <CODE>null</CODE> if no such operation could be found.
*/
{
}
/**
* Adds the provided operation to the set of operations in progress for this
* client connection.
*
* @param operation The operation to add to the set of operations in
* progress for this client connection.
*
* @throws DirectoryException If the operation is not added for some reason
* (e.g., the client already has reached the
* maximum allowed concurrent requests).
*/
throws DirectoryException
{
// We need to grab a lock to ensure that no one else can add operations to
// the queue while we are performing some preliminary checks.
try
{
// If we're already in the process of disconnecting the client, then
// reject the operation.
if (disconnectRequested)
{
msgID);
}
// See if there is already an operation in progress with the same message
// ID. If so, then we can't allow it.
{
}
// Add the operation to the list of operations in progress for this
// connection.
// Try to add the operation to the work queue.
}
catch (DirectoryException de)
{
if (debugEnabled())
{
}
throw de;
}
catch (Exception e)
{
if (debugEnabled())
{
}
}
finally
{
}
}
/**
* Removes the provided operation from the set of operations in progress for
* this client connection. Note that this does not make any attempt to
* cancel any processing that may already be in progress for the operation.
*
* @param messageID The message ID of the operation to remove from the set
* of operations in progress.
*
* @return <CODE>true</CODE> if the operation was found and removed from the
* set of operations in progress, or <CODE>false</CODE> if not.
*/
public boolean removeOperationInProgress(int messageID)
{
}
/**
* Attempts to cancel the specified operation.
*
* @param messageID The message ID of the operation to cancel.
* @param cancelRequest An object providing additional information about how
* the cancel should be processed.
*
* @return A cancel result that either indicates that the cancel was
* successful or provides a reason that it was not.
*/
{
{
// See if the operation is in the list of persistent searches.
{
{
{
}
return cancelResult;
}
}
return CancelResult.NO_SUCH_OPERATION;
}
else
{
{
}
}
}
/**
* Attempts to cancel all operations in progress on this connection.
*
* @param cancelRequest An object providing additional information about how
* the cancel should be processed.
*/
{
// Make sure that no one can add any new operations.
try
{
{
try
{
{
}
}
catch (Exception e)
{
if (debugEnabled())
{
}
}
}
{
}
}
catch (Exception e)
{
if (debugEnabled())
{
}
}
finally
{
}
}
/**
* Attempts to cancel all operations in progress on this connection except the
* operation with the specified message ID.
*
* @param cancelRequest An object providing additional information about how
* the cancel should be processed.
* @param messageID The message ID of the operation that should not be
* canceled.
*/
int messageID)
{
// Make sure that no one can add any new operations.
try
{
{
{
continue;
}
if (o != null)
{
try
{
{
}
}
catch (Exception e)
{
if (debugEnabled())
{
}
}
}
}
{
}
}
catch (Exception e)
{
if (debugEnabled())
{
}
}
finally
{
}
}
/**
* Process the information contained in the provided byte buffer as an ASN.1
* element. It may take several calls to this method in order to get all the
* information necessary to decode a single ASN.1 element, but it may also be
* possible that there are multiple elements (or at least fragments of
* multiple elements) in a single buffer. This will fully process whatever
* the client provided and set up the appropriate state information to make it
* possible to pick up in the right place the next time around.
*
* @param buffer The buffer containing the data to be processed. It must be
* ready for reading (i.e., it should have been flipped by the
* caller), and the data provided must be unencrypted (e.g.,
* if the client is communicating over SSL, then the
* decryption should happen before calling this method).
*
* @return <CODE>true</CODE> if all the data in the provided buffer was
* processed and the client connection can remain established, or
* <CODE>false</CODE> if a decoding error occurred and requests from
* this client should no longer be processed. Note that if this
* method does return <CODE>false</CODE>, then it must have already
* disconnected the client, and upon returning the request handler
* should remove it from the associated selector.
*/
{
if (debugEnabled())
{
}
if (keepStats)
{
}
while (bytesAvailable > 0)
{
switch (elementReadState)
{
// Read just the type and then loop again to see if there is more.
continue;
// Get the first length byte and see if it is a single-byte or
// multi-byte length.
{
// If the length is zero, then it cannot be a valid LDAP message.
if (elementLength == 0)
{
return false;
}
// Make sure that the element is not larger than the maximum allowed
// message size.
{
return false;
}
elementValue = new byte[elementLength];
continue;
}
else
{
if (elementLengthBytesNeeded > 4)
{
// We cannot handle multi-byte lengths in which more than four
// bytes are used to encode the length.
return false;
}
elementLength = 0x00;
{
// We can read the entire length, so do it.
while (elementLengthBytesNeeded > 0)
{
}
// If the length is zero, then it cannot be a valid LDAP message.
if (elementLength == 0)
{
return false;
}
// Make sure that the element is not larger than the maximum
// allowed message size.
{
return false;
}
elementValue = new byte[elementLength];
continue;
}
else
{
// We can't read the entire length, so just read what is
// available.
while (bytesAvailable > 0)
{
}
return true;
}
}
{
// We have enough data available to be able to read the entire
// length. Do so.
while (elementLengthBytesNeeded > 0)
{
}
// If the length is zero, then it cannot be a valid LDAP message.
if (elementLength == 0)
{
return false;
}
// Make sure that the element is not larger than the maximum allowed
// message size.
{
return false;
}
elementValue = new byte[elementLength];
continue;
}
else
{
// We still don't have enough data to complete the length, so just
// read as much as possible.
while (bytesAvailable > 0)
{
}
return true;
}
{
// We have enough data available to fully read the value. Finish
// reading the information and convert it to an ASN.1 element. Then
// decode that as an LDAP message.
try
{
}
catch (Exception e)
{
if (debugEnabled())
{
}
return false;
}
try
{
}
catch (Exception e)
{
if (debugEnabled())
{
}
return false;
}
{
continue;
}
else
{
return false;
}
}
else
{
// We can't read all the value, so just read as much as we have
// available and pick it up again the next time around.
return true;
}
default:
// This should never happen. There is an invalid internal read state.
// The only recourse that we have is to log a message and disconnect
// the client.
return false;
}
}
// If we've gotten here, then all of the data must have been processed
// properly so we can return true.
return true;
}
/**
* Processes the provided LDAP message read from the client and takes
* whatever action is appropriate. For most requests, this will include
* placing the operation in the work queue. Certain requests (in particular,
* abandons and unbinds) will be processed directly.
*
* @param message The LDAP message to process.
*
* @return <CODE>true</CODE> if the appropriate action was taken for the
* request, or <CODE>false</CODE> if there was a fatal error and
* the client has been disconnected as a result, or if the client
* unbound from the server.
*/
{
if (keepStats)
{
}
{
opControls = null;
}
else
{
for (LDAPControl c : ldapControls)
{
}
}
// FIXME -- See if there is a bind in progress. If so, then deny most
// kinds of operations.
// Figure out what type of operation we're dealing with based on the LDAP
// message. Abandon and unbind requests will be processed here. All other
// types of requests will be encapsulated into operations and put into the
// work queue to be picked up by a worker thread. Any other kinds of
// LDAP messages (e.g., response messages) are illegal and will result in
// the connection being terminated.
try
{
switch (message.getProtocolOpType())
{
case OP_TYPE_ABANDON_REQUEST:
case OP_TYPE_ADD_REQUEST:
case OP_TYPE_BIND_REQUEST:
case OP_TYPE_COMPARE_REQUEST:
case OP_TYPE_DELETE_REQUEST:
case OP_TYPE_EXTENDED_REQUEST:
case OP_TYPE_MODIFY_REQUEST:
case OP_TYPE_SEARCH_REQUEST:
case OP_TYPE_UNBIND_REQUEST:
default:
message.getMessageID());
return false;
}
}
catch (Exception e)
{
if (debugEnabled())
{
}
return false;
}
}
/**
* Processes the provided LDAP message as an abandon request.
*
* @param message The LDAP message containing the abandon request to
* process.
* @param controls The set of pre-decoded request controls contained in the
* message.
*
* @return <CODE>true</CODE> if the request was processed successfully, or
* <CODE>false</CODE> if not and the connection has been closed as a
* result (it is the responsibility of this method to close the
* connection).
*/
{
{
}
return connectionValid;
}
/**
* Processes the provided LDAP message as an add request.
*
* @param message The LDAP message containing the add request to process.
* @param controls The set of pre-decoded request controls contained in the
* message.
*
* @return <CODE>true</CODE> if the request was processed successfully, or
* <CODE>false</CODE> if not and the connection has been closed as a
* result (it is the responsibility of this method to close the
* connection).
*/
{
// Create the add operation and add it into the work queue.
try
{
}
catch (DirectoryException de)
{
if (debugEnabled())
{
}
de.getReferralURLs());
}
return connectionValid;
}
/**
* Processes the provided LDAP message as a bind request.
*
* @param message The LDAP message containing the bind request to process.
* @param controls The set of pre-decoded request controls contained in the
* message.
*
* @return <CODE>true</CODE> if the request was processed successfully, or
* <CODE>false</CODE> if not and the connection has been closed as a
* result (it is the responsibility of this method to close the
* connection).
*/
{
// See if this is an LDAPv2 bind request, and if so whether that should be
// allowed.
{
return false;
}
switch (protocolOp.getAuthenticationType())
{
case SIMPLE:
break;
case SASL:
break;
default:
// This is an invalid authentication type, and therefore a protocol
// error. As per RFC 2251, a protocol error in a bind request must
// result in terminating the connection.
return false;
}
// Add the operation into the work queue.
try
{
}
catch (DirectoryException de)
{
if (debugEnabled())
{
}
de.getReferralURLs());
// If it was a protocol error, then terminate the connection.
{
de.getErrorMessage());
}
}
return connectionValid;
}
/**
* Processes the provided LDAP message as a compare request.
*
* @param message The LDAP message containing the compare request to
* process.
* @param controls The set of pre-decoded request controls contained in the
* message.
*
* @return <CODE>true</CODE> if the request was processed successfully, or
* <CODE>false</CODE> if not and the connection has been closed as a
* result (it is the responsibility of this method to close the
* connection).
*/
{
// Add the operation into the work queue.
try
{
}
catch (DirectoryException de)
{
if (debugEnabled())
{
}
de.getMatchedDN(),
de.getReferralURLs());
}
return connectionValid;
}
/**
* Processes the provided LDAP message as a delete request.
*
* @param message The LDAP message containing the delete request to
* process.
* @param controls The set of pre-decoded request controls contained in the
* message.
*
* @return <CODE>true</CODE> if the request was processed successfully, or
* <CODE>false</CODE> if not and the connection has been closed as a
* result (it is the responsibility of this method to close the
* connection).
*/
{
protocolOp.getDN());
// Add the operation into the work queue.
try
{
}
catch (DirectoryException de)
{
if (debugEnabled())
{
}
de.getReferralURLs());
}
return connectionValid;
}
/**
* Processes the provided LDAP message as an extended request.
*
* @param message The LDAP message containing the extended request to
* process.
* @param controls The set of pre-decoded request controls contained in the
* message.
*
* @return <CODE>true</CODE> if the request was processed successfully, or
* <CODE>false</CODE> if not and the connection has been closed as a
* result (it is the responsibility of this method to close the
* connection).
*/
{
// See if this is an LDAPv2 client. If it is, then they should not be
// issuing extended requests. We can't send a response that we can be sure
// they can understand, so we have no choice but to close the connection.
if (ldapVersion == 2)
{
return false;
}
// FIXME -- Do we need to handle certain types of request here?
// -- StartTLS requests
// -- Cancel requests
// Add the operation into the work queue.
try
{
}
catch (DirectoryException de)
{
if (debugEnabled())
{
}
de.getMatchedDN(),
de.getReferralURLs());
}
return connectionValid;
}
/**
* Processes the provided LDAP message as a modify request.
*
* @param message The LDAP message containing the modify request to
* process.
* @param controls The set of pre-decoded request controls contained in the
* message.
*
* @return <CODE>true</CODE> if the request was processed successfully, or
* <CODE>false</CODE> if not and the connection has been closed as a
* result (it is the responsibility of this method to close the
* connection).
*/
{
// Add the operation into the work queue.
try
{
}
catch (DirectoryException de)
{
if (debugEnabled())
{
}
de.getReferralURLs());
}
return connectionValid;
}
/**
* Processes the provided LDAP message as a modify DN request.
*
* @param message The LDAP message containing the modify DN request to
* process.
* @param controls The set of pre-decoded request controls contained in the
* message.
*
* @return <CODE>true</CODE> if the request was processed successfully, or
* <CODE>false</CODE> if not and the connection has been closed as a
* result (it is the responsibility of this method to close the
* connection).
*/
{
// Add the operation into the work queue.
try
{
}
catch (DirectoryException de)
{
if (debugEnabled())
{
}
de.getMatchedDN(),
de.getReferralURLs());
}
return connectionValid;
}
/**
* Processes the provided LDAP message as a search request.
*
* @param message The LDAP message containing the search request to
* process.
* @param controls The set of pre-decoded request controls contained in the
* message.
*
* @return <CODE>true</CODE> if the request was processed successfully, or
* <CODE>false</CODE> if not and the connection has been closed as a
* result (it is the responsibility of this method to close the
* connection).
*/
{
// Add the operation into the work queue.
try
{
}
catch (DirectoryException de)
{
if (debugEnabled())
{
}
de.getMatchedDN(),
de.getReferralURLs());
}
return connectionValid;
}
/**
* Processes the provided LDAP message as an unbind request.
*
* @param message The LDAP message containing the unbind request to
* process.
* @param controls The set of pre-decoded request controls contained in the
* message.
*
* @return <CODE>true</CODE> if the request was processed successfully, or
* <CODE>false</CODE> if not and the connection has been closed as a
* result (it is the responsibility of this method to close the
* connection).
*/
{
// The client connection will never be valid after an unbind.
return false;
}
/**
* {@inheritDoc}
*/
public String getMonitorSummary()
{
{
}
if (securityProvider.isSecure())
{
}
else
{
}
}
/**
* Appends a string representation of this client connection to the provided
* buffer.
*
* @param buffer The buffer to which the information should be appended.
*/
{
}
/**
* Indicates whether TLS protection is actually available for the underlying
* client connection. If there is any reason that TLS protection cannot be
* enabled on this client connection, then it should be appended to the
* provided buffer.
*
* @param unavailableReason The buffer used to hold the reason that TLS is
* not available on the underlying client
* connection.
*
* @return <CODE>true</CODE> if TLS is available on the underlying client
* connection, or <CODE>false</CODE> if it is not.
*/
{
// Make sure that this client connection does not already have some other
// security provider enabled.
if (! (securityProvider instanceof NullConnectionSecurityProvider))
{
return false;
}
// Make sure that the connection handler allows the use of the StartTLS
// operation.
if (! connectionHandler.allowStartTLS())
{
return false;
}
// Make sure that the TLS security provider is available.
if (tlsSecurityProvider == null)
{
try
{
}
catch (Exception e)
{
if (debugEnabled())
{
}
return false;
}
}
// If we've gotten here, then everything looks OK.
return true;
}
/**
* Installs the TLS connection security provider on this client connection.
* If an error occurs in the process, then the underlying client connection
* must be terminated and an exception must be thrown to indicate the
* underlying cause.
*
* @throws DirectoryException If the TLS connection security provider could
* not be enabled and the underlying connection
* has been closed.
*/
public void enableTLSConnectionSecurityProvider()
throws DirectoryException
{
if (tlsSecurityProvider == null)
{
int msgID = MSGID_LDAP_TLS_NO_PROVIDER;
}
}
/**
* Disables the TLS connection security provider on this client connection.
* This must also eliminate any authentication that had been performed on the
* client connection so that it is in an anonymous state. If a problem occurs
* while attempting to revert the connection to a non-TLS-protected state,
* then an exception must be thrown and the client connection must be
* terminated.
*
* @throws DirectoryException If TLS protection cannot be reverted and the
* underlying client connection has been closed.
*/
public void disableTLSConnectionSecurityProvider()
throws DirectoryException
{
}
/**
* Sends a response to the client in the clear rather than through the
* encrypted channel. This should only be used when processing the StartTLS
* extended operation to send the response in the clear after the TLS
* negotiation has already been initiated.
*
* @param operation The operation for which to send the response in the
* clear.
*
*
* @throws DirectoryException If a problem occurs while sending the response
* in the clear.
*/
throws DirectoryException
{
if (clearSecurityProvider == null)
{
}
}
/**
* {@inheritDoc}
*/
public DN getKeyManagerProviderDN()
{
return connectionHandler.getKeyManagerProviderDN();
}
/**
* {@inheritDoc}
*/
public DN getTrustManagerProviderDN()
{
return connectionHandler.getTrustManagerProviderDN();
}
/**
* Retrieves the alias of the server certificate that should be used
* for operations requiring a server certificate. The default
* implementation returns {@code null} to indicate that any alias is
* acceptable.
*
* @return The alias of the server certificate that should be used
* for operations requring a server certificate, or
* {@code null} if any alias is acceptable.
*/
public String getCertificateAlias()
{
return connectionHandler.getSSLServerCertNickname();
}
}