Using Standard Extended Operations
Extended operations allow directory servers to perform processing which isn't
defined as part of the core LDAP specification. They provide a means of allowing
directory servers to provide enhanced functionality.
The Cancel Extended Operation
The cancel extended operation is defined in RFC 3909, and it is similar to the
standard LDAP abandon operation in that it can be used to request that the server
stop processing another operation. However, whereas the abandon request does not
have a response, and an operation which gets abandoned may never receive a response
from the server, the cancel extended operation does have a response, which allows
it to receive the result of the cancel operation and also ensures that any
operation which is canceled will be sent a result indicating that it has been
canceled.
Whenever the server processes a cancel request, it should include one of the
following result codes in the response:
-
CANCELED -- Indicates that the operation was successfully canceled.
-
NO_SUCH_OPERATION -- Indicates that the server was not able to find the
target operation (e.g., because it had already completed).
-
TOO_LATE -- Indicates that the client request was received too late and
the server processing is past the point at which the request can be canceled.
-
CANNOT_CANCEL -- Indicates that the associated operation is one that
cannot be canceled. Abandon, bind, and unbind requests cannot be canceled, and
neither can cancel or StartTLS extended operations.
Note that cancel requests are only available for use with operations that are being
processed asynchronously. See the Processing
Asynchronous Operations page for more information.
The following example initiates an asynchronous modify operation and then
attempts to cancel it:
Modification mod = new Modification(ModificationType.REPLACE, "description",
"This is the new description.");
ModifyRequest modifyRequest =
new ModifyRequest("dc=example,dc=com", mod);
AsyncRequestID asyncRequestID =
connection.asyncModify(modifyRequest, myAsyncResultListener);
// Assume that we've waited a reasonable amount of time but the modify
// hasn't completed yet so we'll try to cancel it.
CancelExtendedRequest cancelRequest =
new CancelExtendedRequest(asyncRequestID);
// NOTE: The processExtendedOperation method will only throw an exception
// if a problem occurs while trying to send the request or read the
// response. It will not throw an exception because of a non-success
// response. That's good for us in this case because the cancel result
// should never be "SUCCESS".
ExtendedResult cancelResult =
connection.processExtendedOperation(cancelRequest);
switch (cancelResult.getResultCode())
{
case ResultCode.CANCELED:
System.out.println("The operation was successfully canceled.");
break;
case ResultCode.NO_SUCH_OPERATION:
System.out.println("The server didn't know anything about the " +
"operation. Maybe it's already completed.");
break;
case ResultCode.TOO_LATE:
System.out.println("It was too late in the operation processing " +
"to cancel the operation.");
break;
case ResultCode.CANNOT_CANCEL:
System.out.println("The target operation is not one that could be " +
"canceled.");
break;
default:
System.err.println("An error occurred while processing the cancel " +
"request.");
break;
}
The Password Modify Extended Operation
The password modify extended operation is defined in RFC 3062 and can be used to
change the password for a given user. It provides the ability to specify the
user's current password for validation purposes, and also provides the ability to
request (by not including a new password value) that the server generate a new
password on the user's behalf (in which case the new password will be made
available through the getGeneratedPassword,
getGeneratedPasswordBytes, and getRawGeneratedPassword methods of
the corresponding PasswordModifyExtendedResult object).
The password modify extended request also provides a mechanism to identify the user
for which to change the password. If this is not provided, then it will change the
password for the currently-authenticated user. If it is provided, then the
specification is a little unclear as to the format of the value (in particular,
it says that the userIdentity field may or may not be an LDAP DN), but server
implementations generally support specifying the target userIdentity value as a DN,
and many also support specifying it as an authorization ID.
The following example demonstrates the use of the password modify extended
operation to change the password for user
"uid=john.doe,ou=People,dc=example,dc=com" and have the server generate a new
password for that user.
PasswordModifyExtendedRequest passwordModifyRequest =
new PasswordModifyExtendedRequest(
"uid=john.doe,ou=People,dc=example,dc=com", null, null);
PasswordModifyExtendedResult passwordModifyResult =
(PasswordModifyExtendedResult)
connection.processExtendedOperation(passwordModifyRequest);
// NOTE: The processExtendedOperation method will only throw an exception
// if a problem occurs while trying to send the request or read the
// response. It will not throw an exception because of a non-success
// response.
if (passwordModifyResult.getResultCode() == ResultCode.SUCCESS)
{
System.out.println("The password change was successful.");
System.out.println("The new password for the user is " +
passwordModifyResult.getGeneratedPassword());
}
else
{
System.err.println("An error occurred while attempting to process " +
"the password modify extended request.");
}
The StartTLS Extended Operation
The StartTLS extended operation is defined in RFC 4511 and may be used to initiate
a secure communication channel over a previously unencrypted connection. That is,
it provides the option of allowing the server to perform both clear-text and secure
communication over a single port so that it is not necessary to expose separate
ports for clear-text and encrypted communication.
The requirements for communicating with a directory server using a
StartTLS-encrypted channel are essentially the same as those for establishing an
SSL-based connection as described in the Creating and
Using LDAP Connections section. You can either use the default SSL context
provided by the JVM or specify your own context. In most cases, you will want to
use the latter, as it provides greater flexibility and more options for determining
whether to trust the server certificate. And as with creating SSL-based
connections, the com.unboundid.util.TrustAllSSLSocketFactory can be used
to request that the client blindly trust whatever certificate the server presents.
The following code demonstrates the process for using the StartTLS extended
operation with an SSL context provided by the TrustAllSSLSocketFactory:
SSLContext sslContext = new TrustAllSSLSocketFactory().getSSLContext();
ExtendedResult extendedResult = connection.processExtendedOperation(
new StartTLSExtendedRequest(sslContext));
// NOTE: The processExtendedOperation method will only throw an exception
// if a problem occurs while trying to send the request or read the
// response. It will not throw an exception because of a non-success
// response.
if (extendedResult.getResultCode() == ResultCode.SUCCESS)
{
System.out.println("Communication with the server is now secure.");
}
else
{
System.out.println("An error occurred while attempting to perform " +
"StartTLS negotiation. The connection can no longer be used.");
connection.close();
}
The "Who Am I?" Extended Operation
The "Who Am I?" extended operation is defined in RFC 4532, and is similar to the
authorization identity controls in that it can be used to obtain the current
authorization identity for a client connection. The "Who Am I?" request, however,
can be used at any time whereas the authorization identity controls can only be
used in conjunction with a bind operation.
The following code illustrates the use of the "Who Am I?" extended operation:
WhoAmIExtendedResult whoAmIResult =
(WhoAmIExtendedResult)
connection.processExtendedOperation(new WhoAmIExtendedRequest());
// NOTE: The processExtendedOperation method will only throw an exception
// if a problem occurs while trying to send the request or read the
// response. It will not throw an exception because of a non-success
// response.
if (whoAmIResult.getResultCode() == ResultCode.SUCCESS)
{
String authzID = whoAmIResult.getAuthorizationID();
if (authzID.length() == 0)
{
System.out.println("Your current authorization ID is that of the " +
"anonymous user.");
}
else
{
System.out.println("Your current authorization ID is " +
whoAmIResult.getAuthorizationID());
}
}
else
{
System.err.println("An error occurred while processing the " +
"Who Am I? extended operation.");
}
|