Products

UnboundID LDAP SDK for Java

Product Information
Getting Started with the LDAP SDK

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.");
}