mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Matthew Swift
01.43.2012 46a7d32926385c97696f2b52605171139dc773e6
Fix OPENDJ-417: Minor improvements to server-side SSL support

* remove SSL settings from LDAPListenerOptions
* rename LDAPClientContext startSASL and startTLS methods
* allow multiple connection security layers to be added
* add SSL support to Server example

3 files deleted
1 files added
9 files modified
841 ■■■■■ changed files
opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Server.java 132 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/ConnectionSecurityLayerFilter.java 180 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPClientFilter.java 3 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPListenerImpl.java 17 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPServerFilter.java 49 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/SASLDecoderTransformer.java 102 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/SASLEncoderTransformer.java 102 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/SASLFilter.java 50 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ConnectionSecurityLayer.java 3 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPClientContext.java 20 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPListenerOptions.java 63 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPOptions.java 114 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java 6 ●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Server.java
@@ -40,6 +40,8 @@
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.net.ssl.SSLContext;
import org.forgerock.opendj.ldap.*;
import org.forgerock.opendj.ldap.requests.*;
import org.forgerock.opendj.ldap.responses.*;
@@ -68,13 +70,11 @@
      RequestHandler<RequestContext>
  {
    private final ConcurrentSkipListMap<DN, Entry> entries;
    private final ReentrantReadWriteLock entryLock =
        new ReentrantReadWriteLock();
    private final ReentrantReadWriteLock entryLock = new ReentrantReadWriteLock();
    private MemoryBackend(
        final ConcurrentSkipListMap<DN, Entry> entries)
    private MemoryBackend(final ConcurrentSkipListMap<DN, Entry> entries)
    {
      this.entries = entries;
    }
@@ -97,24 +97,22 @@
        DN dn = request.getName();
        if (entries.containsKey(dn))
        {
          resultHandler.handleErrorResult(ErrorResultException
              .newErrorResult(ResultCode.ENTRY_ALREADY_EXISTS,
                  "The entry " + dn.toString() + " already exists"));
          resultHandler.handleErrorResult(ErrorResultException.newErrorResult(
              ResultCode.ENTRY_ALREADY_EXISTS, "The entry " + dn.toString()
                  + " already exists"));
        }
        DN parent = dn.parent();
        if (!entries.containsKey(parent))
        {
          resultHandler.handleErrorResult(ErrorResultException
              .newErrorResult(ResultCode.NO_SUCH_OBJECT,
                  "The parent entry " + parent.toString()
                      + " does not exist"));
          resultHandler.handleErrorResult(ErrorResultException.newErrorResult(
              ResultCode.NO_SUCH_OBJECT,
              "The parent entry " + parent.toString() + " does not exist"));
        }
        else
        {
          entries.put(dn, request);
          resultHandler.handleResult(Responses
              .newResult(ResultCode.SUCCESS));
          resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS));
        }
      }
      finally
@@ -145,8 +143,7 @@
      else
      {
        // TODO: always succeed.
        resultHandler.handleResult(Responses
            .newBindResult(ResultCode.SUCCESS));
        resultHandler.handleResult(Responses.newBindResult(ResultCode.SUCCESS));
      }
    }
@@ -183,15 +180,14 @@
        DN dn = request.getName();
        if (!entries.containsKey(dn))
        {
          resultHandler.handleErrorResult(ErrorResultException
              .newErrorResult(ResultCode.NO_SUCH_OBJECT, "The entry "
                  + dn.toString() + " does not exist"));
          resultHandler.handleErrorResult(ErrorResultException.newErrorResult(
              ResultCode.NO_SUCH_OBJECT, "The entry " + dn.toString()
                  + " does not exist"));
        }
        else
        {
          entries.remove(dn);
          resultHandler.handleResult(Responses
              .newResult(ResultCode.SUCCESS));
          resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS));
        }
      }
      finally
@@ -207,14 +203,12 @@
     */
    @Override
    public <R extends ExtendedResult> void handleExtendedRequest(
        final RequestContext requestContext,
        final ExtendedRequest<R> request,
        final RequestContext requestContext, final ExtendedRequest<R> request,
        final IntermediateResponseHandler intermediateResponseHandler,
        final ResultHandler<? super R> resultHandler)
    {
      // TODO: not implemented.
      resultHandler.handleErrorResult(newErrorResult(
          ResultCode.PROTOCOL_ERROR,
      resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR,
          "Extended request operation not supported"));
    }
@@ -239,9 +233,9 @@
        Entry entry = entries.get(dn);
        if (entry == null)
        {
          resultHandler.handleErrorResult(ErrorResultException
              .newErrorResult(ResultCode.NO_SUCH_OBJECT, "The entry "
                  + dn.toString() + " does not exist"));
          resultHandler.handleErrorResult(ErrorResultException.newErrorResult(
              ResultCode.NO_SUCH_OBJECT, "The entry " + dn.toString()
                  + " does not exist"));
        }
        Entry newEntry = new LinkedHashMapEntry(entry);
@@ -264,17 +258,15 @@
          }
          else
          {
            resultHandler
                .handleErrorResult(newErrorResult(
                  ResultCode.PROTOCOL_ERROR,
                  "Modify request contains an unsupported modification type"));
            resultHandler.handleErrorResult(newErrorResult(
                ResultCode.PROTOCOL_ERROR,
                "Modify request contains an unsupported modification type"));
            return;
          }
        }
        entries.put(dn, newEntry);
        resultHandler.handleResult(Responses
            .newResult(ResultCode.SUCCESS));
        resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS));
      }
      finally
      {
@@ -294,8 +286,7 @@
        final ResultHandler<? super Result> resultHandler)
    {
      // TODO: not implemented.
      resultHandler.handleErrorResult(newErrorResult(
          ResultCode.PROTOCOL_ERROR,
      resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR,
          "ModifyDN request operation not supported"));
    }
@@ -318,9 +309,9 @@
        Entry baseEntry = entries.get(dn);
        if (baseEntry == null)
        {
          resultHandler.handleErrorResult(ErrorResultException
              .newErrorResult(ResultCode.NO_SUCH_OBJECT, "The entry "
                  + dn.toString() + " does not exist"));
          resultHandler.handleErrorResult(ErrorResultException.newErrorResult(
              ResultCode.NO_SUCH_OBJECT, "The entry " + dn.toString()
                  + " does not exist"));
          return;
        }
@@ -337,8 +328,7 @@
        }
        else if (scope.equals(SearchScope.SINGLE_LEVEL))
        {
          NavigableMap<DN, Entry> subtree = entries
              .tailMap(dn, false);
          NavigableMap<DN, Entry> subtree = entries.tailMap(dn, false);
          for (Entry entry : subtree.values())
          {
            // Check for cancellation.
@@ -402,8 +392,7 @@
          return;
        }
        resultHandler.handleResult(Responses
            .newResult(ResultCode.SUCCESS));
        resultHandler.handleResult(Responses.newResult(ResultCode.SUCCESS));
      }
      catch (CancelledResultException e)
      {
@@ -421,8 +410,7 @@
        SearchResultHandler resultHandler, Entry entry)
    {
      // TODO: check filter, strip attributes.
      return resultHandler.handleEntry(Responses
          .newSearchResultEntry(entry));
      return resultHandler.handleEntry(Responses.newSearchResultEntry(entry));
    }
  }
@@ -436,9 +424,10 @@
   */
  public static void main(final String[] args)
  {
    if (args.length != 3)
    if (args.length != 3 && args.length != 6)
    {
      System.err.println("Usage: listenAddress listenPort ldifFile");
      System.err.println("Usage: listenAddress listenPort ldifFile "
          + "[keyStoreFile keyStorePassword certNickname]");
      System.exit(1);
    }
@@ -446,6 +435,9 @@
    final String localAddress = args[0];
    final int localPort = Integer.parseInt(args[1]);
    final String ldifFileName = args[2];
    final String keyStoreFileName = (args.length == 6) ? args[3] : null;
    final String keyStorePassword = (args.length == 6) ? args[4] : null;
    final String certNickname = (args.length == 6) ? args[5] : null;
    // Create the memory backend.
    final ConcurrentSkipListMap<DN, Entry> entries =
@@ -453,24 +445,54 @@
    final MemoryBackend backend = new MemoryBackend(entries);
    // Create a server connection adapter.
    final ServerConnectionFactory<LDAPClientContext, Integer> connectionHandler
      = Connections.newServerConnectionFactory(backend);
    final ServerConnectionFactory<LDAPClientContext, Integer> connectionHandler =
        Connections.newServerConnectionFactory(backend);
    // Create listener.
    final LDAPListenerOptions options = new LDAPListenerOptions()
        .setBacklog(4096);
    LDAPListener listener = null;
    try
    {
      listener = new LDAPListener(localAddress, localPort,
          connectionHandler, options);
      final LDAPListenerOptions options = new LDAPListenerOptions()
          .setBacklog(4096);
      if (keyStoreFileName != null)
      {
        // Configure SSL/TLS and enable it when connections are accepted.
        final SSLContext sslContext = new SSLContextBuilder()
            .setKeyManager(
                KeyManagers.useSingleCertificate(certNickname, KeyManagers
                    .useKeyStoreFile(keyStoreFileName,
                        keyStorePassword.toCharArray(), null)))
            .setTrustManager(TrustManagers.trustAll()).getSSLContext();
        ServerConnectionFactory<LDAPClientContext, Integer> sslWrapper =
            new ServerConnectionFactory<LDAPClientContext, Integer>()
        {
          public ServerConnection<Integer> handleAccept(
              LDAPClientContext clientContext) throws ErrorResultException
          {
            clientContext.enableTLS(sslContext, null, null, false, false);
            return connectionHandler.handleAccept(clientContext);
          }
        };
        listener = new LDAPListener(localAddress, localPort, sslWrapper,
            options);
      }
      else
      {
        // No SSL.
        listener = new LDAPListener(localAddress, localPort, connectionHandler,
            options);
      }
      System.out.println("Press any key to stop the server...");
      System.in.read();
    }
    catch (final IOException e)
    catch (final Exception e)
    {
      System.out.println("Error listening on " + localAddress + ":"
          + localPort);
      System.out
          .println("Error listening on " + localAddress + ":" + localPort);
      e.printStackTrace();
    }
    finally
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/ConnectionSecurityLayerFilter.java
New file
@@ -0,0 +1,180 @@
/*
 * 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
 * trunk/opendj3/legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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/opendj3/legal-notices/CDDLv1_0.txt.  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
 *
 *
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 *      Portions copyright 2012 ForgeRock AS.
 */
package com.forgerock.opendj.ldap;
import org.forgerock.opendj.ldap.ConnectionSecurityLayer;
import org.forgerock.opendj.ldap.ErrorResultException;
import org.glassfish.grizzly.AbstractTransformer;
import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.TransformationResult;
import org.glassfish.grizzly.attributes.AttributeStorage;
import org.glassfish.grizzly.filterchain.AbstractCodecFilter;
import org.glassfish.grizzly.memory.Buffers;
import org.glassfish.grizzly.memory.MemoryManager;
/**
 * Connection security layer filter adapter.
 */
final class ConnectionSecurityLayerFilter extends
    AbstractCodecFilter<Buffer, Buffer>
{
  /**
   * <tt>Transformer</tt>, which decodes SASL encrypted data, contained in the
   * input Buffer, to the output Buffer.
   */
  private static final class Decoder extends
      AbstractTransformer<Buffer, Buffer>
  {
    private static final int BUFFER_SIZE = 4096;
    private final byte[] buffer = new byte[BUFFER_SIZE];
    private final ConnectionSecurityLayer layer;
    private final MemoryManager<?> memoryManager;
    public Decoder(final ConnectionSecurityLayer layer,
        final MemoryManager<?> memoryManager)
    {
      this.layer = layer;
      this.memoryManager = memoryManager;
    }
    public String getName()
    {
      return this.getClass().getName();
    }
    public boolean hasInputRemaining(final AttributeStorage storage,
        final Buffer input)
    {
      return input != null && input.hasRemaining();
    }
    @Override
    public TransformationResult<Buffer, Buffer> transformImpl(
        final AttributeStorage storage, final Buffer input)
    {
      final int len = Math.min(buffer.length, input.remaining());
      input.get(buffer, 0, len);
      try
      {
        final Buffer output = Buffers.wrap(memoryManager,
            layer.unwrap(buffer, 0, len));
        return TransformationResult.createCompletedResult(output, input);
      }
      catch (final ErrorResultException e)
      {
        return TransformationResult.createErrorResult(e.getResult()
            .getResultCode().intValue(), e.getMessage());
      }
    }
  }
  /**
   * <tt>Transformer</tt>, which encodes SASL encrypted data, contained in the
   * input Buffer, to the output Buffer.
   */
  private static final class Encoder extends
      AbstractTransformer<Buffer, Buffer>
  {
    private static final int BUFFER_SIZE = 4096;
    private final byte[] buffer = new byte[BUFFER_SIZE];
    private final ConnectionSecurityLayer layer;
    private final MemoryManager<?> memoryManager;
    private Encoder(final ConnectionSecurityLayer layer,
        final MemoryManager<?> memoryManager)
    {
      this.layer = layer;
      this.memoryManager = memoryManager;
    }
    public String getName()
    {
      return this.getClass().getName();
    }
    public boolean hasInputRemaining(final AttributeStorage storage,
        final Buffer input)
    {
      return input != null && input.hasRemaining();
    }
    @Override
    public TransformationResult<Buffer, Buffer> transformImpl(
        final AttributeStorage storage, final Buffer input)
    {
      final int len = Math.min(buffer.length, input.remaining());
      input.get(buffer, 0, len);
      try
      {
        final Buffer output = Buffers.wrap(memoryManager,
            layer.wrap(buffer, 0, len));
        return TransformationResult.createCompletedResult(output, input);
      }
      catch (final ErrorResultException e)
      {
        return TransformationResult.createErrorResult(e.getResult()
            .getResultCode().intValue(), e.getMessage());
      }
    }
  }
  ConnectionSecurityLayerFilter(final ConnectionSecurityLayer layer,
      final MemoryManager<?> memoryManager)
  {
    super(new Decoder(layer, memoryManager), new Encoder(layer, memoryManager));
  }
}
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPClientFilter.java
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2010 Sun Microsystems, Inc.
 *      Portions copyright 2012 ForgeRock AS.
 */
package com.forgerock.opendj.ldap;
@@ -170,7 +171,7 @@
              {
                // The connection needs to be secured by the SASL
                // mechanism.
                ldapConnection.installFilter(new SASLFilter(l, ctx
                ldapConnection.installFilter(new ConnectionSecurityLayerFilter(l, ctx
                    .getConnection().getTransport().getMemoryManager()));
              }
            }
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPListenerImpl.java
@@ -23,7 +23,7 @@
 *
 *
 *      Copyright 2010 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 *      Portions copyright 2011-2012 ForgeRock AS
 */
package com.forgerock.opendj.ldap;
@@ -35,8 +35,6 @@
import java.net.SocketAddress;
import java.util.logging.Level;
import javax.net.ssl.SSLContext;
import org.forgerock.opendj.ldap.DecodeOptions;
import org.forgerock.opendj.ldap.LDAPClientContext;
import org.forgerock.opendj.ldap.LDAPListenerOptions;
@@ -46,8 +44,6 @@
import org.glassfish.grizzly.filterchain.TransportFilter;
import org.glassfish.grizzly.nio.transport.TCPNIOServerConnection;
import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
import org.glassfish.grizzly.ssl.SSLEngineConfigurator;
import org.glassfish.grizzly.ssl.SSLFilter;
import com.forgerock.opendj.util.StaticUtils;
@@ -95,17 +91,6 @@
    this.connectionFactory = factory;
    this.defaultFilterChain = new DefaultFilterChain();
    this.defaultFilterChain.add(new TransportFilter());
    if (options.getSSLContext() != null)
    {
      final SSLContext sslContext = options.getSSLContext();
      SSLEngineConfigurator sslEngineConfigurator;
      sslEngineConfigurator = new SSLEngineConfigurator(sslContext, false,
          false, false);
      this.defaultFilterChain.add(new SSLFilter(sslEngineConfigurator, null));
    }
    this.defaultFilterChain.add(new LDAPServerFilter(this, new LDAPReader(
        new DecodeOptions(options.getDecodeOptions())), 0));
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/LDAPServerFilter.java
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2010 Sun Microsystems, Inc.
 *      Portions copyright 2012 ForgeRock AS.
 */
package com.forgerock.opendj.ldap;
@@ -48,6 +49,7 @@
import org.glassfish.grizzly.Grizzly;
import org.glassfish.grizzly.attributes.Attribute;
import org.glassfish.grizzly.filterchain.*;
import org.glassfish.grizzly.filterchain.Filter;
import org.glassfish.grizzly.ssl.SSLEngineConfigurator;
import org.glassfish.grizzly.ssl.SSLFilter;
import org.glassfish.grizzly.ssl.SSLUtils;
@@ -313,16 +315,17 @@
    @Override
    public void startSASL(final ConnectionSecurityLayer bindContext)
    public void enableConnectionSecurityLayer(
        final ConnectionSecurityLayer layer)
    {
      installFilter(connection, new SASLFilter(bindContext, connection
          .getTransport().getMemoryManager()));
      installFilter(connection, new ConnectionSecurityLayerFilter(layer,
          connection.getTransport().getMemoryManager()));
    }
    @Override
    public void startTLS(final SSLContext sslContext, final String[] protocols,
    public void enableTLS(final SSLContext sslContext, final String[] protocols,
        final String[] suites, final boolean wantClientAuth,
        final boolean needClientAuth)
    {
@@ -1123,39 +1126,43 @@
      final org.glassfish.grizzly.filterchain.Filter filter)
  {
    FilterChain filterChain = (FilterChain) connection.getProcessor();
    // Ensure that the SSL filter is not installed twice.
    if (filter instanceof SSLFilter)
    {
      if (filterChain.get(filterChain.size() - 1) instanceof SSLFilter
          || filterChain.get(filterChain.size() - 2) instanceof SSLFilter)
      for (Filter f : filterChain)
      {
        // SSLFilter already installed.
        throw new IllegalStateException(
            "SSLFilter already installed on connection");
      }
    }
    if (filter instanceof SASLFilter)
    {
      if (filterChain.get(filterChain.size() - 1) instanceof SASLFilter)
      {
        // SASLFilter already installed.
        throw new IllegalStateException(
            "SASLFilter already installed on connection");
        if (f instanceof SSLFilter)
        {
          // SSLFilter already installed.
          throw new IllegalStateException("SSL already installed on connection");
        }
      }
    }
    // Copy on update the default filter chain.
    if (listener.getDefaultFilterChain() == filterChain)
    {
      filterChain = new DefaultFilterChain(filterChain);
      connection.setProcessor(filterChain);
    }
    if (filter instanceof SSLFilter
        && filterChain.get(filterChain.size() - 1) instanceof SASLFilter)
    // Ensure that the SSL filter is beneath any connection security layer
    // filters.
    if (filter instanceof SSLFilter)
    {
      filterChain.add(filterChain.size() - 2, filter);
      for (int i = filterChain.size() - 1; i >= 0; i--)
      {
        if (!(filterChain.get(i) instanceof ConnectionSecurityLayerFilter))
        {
          filterChain.add(i, filter);
          break;
        }
      }
    }
    else
    {
      // Add connection security layers to the end of the chain.
      filterChain.add(filterChain.size() - 1, filter);
    }
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/SASLDecoderTransformer.java
File was deleted
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/SASLEncoderTransformer.java
File was deleted
opendj3/opendj-ldap-sdk/src/main/java/com/forgerock/opendj/ldap/SASLFilter.java
File was deleted
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/ConnectionSecurityLayer.java
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2010 Sun Microsystems, Inc.
 *      Portions copyright 2012 ForgeRock AS.
 */
package org.forgerock.opendj.ldap;
@@ -56,7 +57,7 @@
   * @param len
   *          The number of bytes from {@code incoming} to be unwrapped.
   * @return A non-{@code null} byte array containing the unwrapped bytes.
   * @throws org.forgerock.opendj.ldap.ErrorResultException
   * @throws ErrorResultException
   *           If {@code incoming} cannot be successfully unwrapped.
   */
  byte[] unwrap(byte[] incoming, int offset, int len)
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPClientContext.java
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2010 Sun Microsystems, Inc.
 *      Portions copyright 2012 ForgeRock AS.
 */
package org.forgerock.opendj.ldap;
@@ -137,19 +138,24 @@
  /**
   * Starts the SASL integrity and/or confidentiality protection layer on the
   * underlying connection if possible.
   * Installs the provided connection security layer to the underlying
   * connection. This may be used to add a SASL integrity and/or confidentiality
   * protection layer after SASL authentication has completed, but could also be
   * used to add other layers such as compression. Multiple layers may be
   * installed.
   *
   * @param bindContext
   * @param layer
   *          The negotiated bind context that can be used to encode and decode
   *          data on the connection.
   */
  void startSASL(ConnectionSecurityLayer bindContext);
  void enableConnectionSecurityLayer(ConnectionSecurityLayer layer);
  /**
   * Starts the TLS/SSL security layer on the underlying connection if possible.
   * Installs the TLS/SSL security layer on the underlying connection. The
   * TLS/SSL security layer will be installed beneath any existing connection
   * security layers and can only be installed at most once.
   *
   * @param sslContext
   *          The {@code SSLContext} which should be used to secure the
@@ -165,7 +171,9 @@
   * @param needClientAuth
   *          Set to {@code true} if client authentication is required, or
   *          {@code false} if no client authentication is desired.
   * @throws IllegalStateException
   *           If the TLS/SSL security layer has already been installed.
   */
  void startTLS(SSLContext sslContext, String[] protocols, String[] suites,
  void enableTLS(SSLContext sslContext, String[] protocols, String[] suites,
      boolean wantClientAuth, boolean needClientAuth);
}
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPListenerOptions.java
@@ -30,8 +30,6 @@
import javax.net.ssl.SSLContext;
import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
import com.forgerock.opendj.util.Validator;
@@ -44,12 +42,8 @@
public final class LDAPListenerOptions
{
  private SSLContext sslContext;
  private DecodeOptions decodeOptions;
  private int backlog;
  private TCPNIOTransport transport;
@@ -60,7 +54,6 @@
   */
  public LDAPListenerOptions()
  {
    this.sslContext = null;
    this.backlog = 0;
    this.decodeOptions = new DecodeOptions();
    this.transport = null;
@@ -77,7 +70,6 @@
   */
  public LDAPListenerOptions(final LDAPListenerOptions options)
  {
    this.sslContext = options.sslContext;
    this.backlog = options.backlog;
    this.decodeOptions = new DecodeOptions(options.decodeOptions);
    this.transport = options.transport;
@@ -115,32 +107,15 @@
  /**
   * Returns the SSL context which will be used when initiating connections with
   * the Directory Server. By default no SSL context will be used, indicating
   * that connections will not be secured. If a non-{@code null} SSL context is
   * returned then connections will be secured using either SSL or StartTLS.
   *
   * @return The SSL context which will be used when initiating secure
   *         connections with the Directory Server, which may be {@code null}
   *         indicating that connections will not be secured.
   */
  public final SSLContext getSSLContext()
  {
    return sslContext;
  }
  /**
   * Returns the Grizzly TCP transport which will be used when initiating
   * connections with the Directory Server. By default this method will return
   * {@code null} indicating that the default transport factory should be
   * used to obtain a TCP transport.
   * connections with the Directory Server.
   * <p>
   * By default this method will return {@code null} indicating that the default
   * transport factory should be used to obtain a TCP transport.
   *
   * @return The Grizzly TCP transport which will be used when initiating
   *         connections with the Directory Server, or {@code null} if the
   *         default transport factory should be used to obtain a TCP
   *         transport.
   *         default transport factory should be used to obtain a TCP transport.
   */
  public final TCPNIOTransport getTCPNIOTransport()
  {
@@ -189,30 +164,11 @@
  /**
   * Sets the SSL context which will be used when initiating connections with
   * the Directory Server. By default no SSL context will be used, indicating
   * that connections will not be secured. If a non-{@code null} SSL context is
   * returned then connections will be secured using either SSL or StartTLS.
   *
   * @param sslContext
   *          The SSL context which will be used when initiating secure
   *          connections with the Directory Server, which may be {@code null}
   *          indicating that connections will not be secured.
   * @return A reference to this LDAP listener options.
   */
  public final LDAPListenerOptions setSSLContext(final SSLContext sslContext)
  {
    this.sslContext = sslContext;
    return this;
  }
  /**
   * Sets the Grizzly TCP transport which will be used when initiating
   * connections with the Directory Server. By default this method will return
   * {@code null} indicating that the default transport factory should be
   * used to obtain a TCP transport.
   * connections with the Directory Server.
   * <p>
   * By default this method will return {@code null} indicating that the default
   * transport factory should be used to obtain a TCP transport.
   *
   * @param transport
   *          The Grizzly TCP transport which will be used when initiating
@@ -227,4 +183,5 @@
    this.transport = transport;
    return this;
  }
}
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/LDAPOptions.java
@@ -48,23 +48,11 @@
public final class LDAPOptions
{
  private SSLContext sslContext;
  private boolean useStartTLS;
  private long timeoutInMillis;
  private DecodeOptions decodeOptions;
  /**
   * The list of cipher suite
   */
  private List<String> enabledCipherSuites = new LinkedList<String>();
  /**
   * the list of protocols
   */
  private List<String> enabledProtocols = new LinkedList<String>();
  private TCPNIOTransport transport;
@@ -120,10 +108,12 @@
  /**
   * Returns the SSL context which will be used when initiating connections with
   * the Directory Server. By default no SSL context will be used, indicating
   * that connections will not be secured. If a non-{@code null} SSL context is
   * returned then connections will be secured using either SSL or StartTLS
   * depending on {@link #useStartTLS()}.
   * the Directory Server.
   * <p>
   * By default no SSL context will be used, indicating that connections will
   * not be secured. If a non-{@code null} SSL context is returned then
   * connections will be secured using either SSL or StartTLS depending on
   * {@link #useStartTLS()}.
   *
   * @return The SSL context which will be used when initiating secure
   *         connections with the Directory Server, which may be {@code null}
@@ -138,9 +128,10 @@
  /**
   * Returns the Grizzly TCP transport which will be used when initiating
   * connections with the Directory Server. By default this method will return
   * {@code null} indicating that the default transport factory should be used
   * to obtain a TCP transport.
   * connections with the Directory Server.
   * <p>
   * By default this method will return {@code null} indicating that the default
   * transport factory should be used to obtain a TCP transport.
   *
   * @return The Grizzly TCP transport which will be used when initiating
   *         connections with the Directory Server, or {@code null} if the
@@ -189,10 +180,12 @@
  /**
   * Sets the SSL context which will be used when initiating connections with
   * the Directory Server. By default no SSL context will be used, indicating
   * that connections will not be secured. If a non-{@code null} SSL context is
   * returned then connections will be secured using either SSL or StartTLS
   * depending on {@link #useStartTLS()}.
   * the Directory Server.
   * <p>
   * By default no SSL context will be used, indicating that connections will
   * not be secured. If a non-{@code null} SSL context is returned then
   * connections will be secured using either SSL or StartTLS depending on
   * {@link #useStartTLS()}.
   *
   * @param sslContext
   *          The SSL context which will be used when initiating secure
@@ -210,9 +203,10 @@
  /**
   * Sets the Grizzly TCP transport which will be used when initiating
   * connections with the Directory Server. By default this method will return
   * {@code null} indicating that the default transport factory will be used to
   * obtain a TCP transport.
   * connections with the Directory Server.
   * <p>
   * By default this method will return {@code null} indicating that the default
   * transport factory will be used to obtain a TCP transport.
   *
   * @param transport
   *          The Grizzly TCP transport which will be used when initiating
@@ -250,8 +244,9 @@
  /**
   * Specifies whether or not SSL or StartTLS should be used for securing
   * connections when an SSL context is specified. By default SSL will be used
   * in preference to StartTLS.
   * connections when an SSL context is specified.
   * <p>
   * By default SSL will be used in preference to StartTLS.
   *
   * @param useStartTLS
   *          {@code true} if StartTLS should be used for securing connections
@@ -269,8 +264,9 @@
  /**
   * Indicates whether or not SSL or StartTLS should be used for securing
   * connections when an SSL context is specified. By default SSL will be used
   * in preference to StartTLS.
   * connections when an SSL context is specified.
   * <p>
   * By default SSL will be used in preference to StartTLS.
   *
   * @return {@code true} if StartTLS should be used for securing connections
   *         when an SSL context is specified, otherwise {@code false}
@@ -281,70 +277,80 @@
    return useStartTLS;
  }
  /**
   * Adds the protocol versions enabled for secure connections with the
   * Directory Server.
   *
   * <p>
   * The protocols must be supported by the SSLContext specified in
   * {@link #setSSLContext(SSLContext)}. Following a successful call to
   * this method, only the protocols listed in the protocols parameter are
   * enabled for use.
   * {@link #setSSLContext(SSLContext)}. Following a successful call to this
   * method, only the protocols listed in the protocols parameter are enabled
   * for use.
   *
   * @param protocols Names of all the protocols to enable.
   * @param protocols
   *          Names of all the protocols to enable.
   * @return A reference to this LDAP connection options.
   */
  public final LDAPOptions addEnabledProtocol(String... protocols)
  {
    for (final String protocol : protocols)
    {
      this.enabledProtocols.add(Validator.ensureNotNull(protocol));
      enabledProtocols.add(Validator.ensureNotNull(protocol));
    }
    return this;
  }
  /**
   * Adds the cipher suites enabled for secure connections with the
   * Directory Server.
   *
   * Adds the cipher suites enabled for secure connections with the Directory
   * Server.
   * <p>
   * The suites must be supported by the SSLContext specified in
   * {@link #setSSLContext(SSLContext)}. Following a successful call to
   * this method, only the suites listed in the protocols parameter are
   * enabled for use.
   * {@link #setSSLContext(SSLContext)}. Following a successful call to this
   * method, only the suites listed in the protocols parameter are enabled for
   * use.
   *
   * @param suites Names of all the suites to enable.
   * @param suites
   *          Names of all the suites to enable.
   * @return A reference to this LDAP connection options.
   */
  public final LDAPOptions addEnabledCipherSuite(String... suites)
  {
    for (final String suite : suites)
    {
      this.enabledCipherSuites.add(Validator.ensureNotNull(suite));
      enabledCipherSuites.add(Validator.ensureNotNull(suite));
    }
    return this;
  }
  /**
   * Returns the names of the protocol versions which are currently enabled
   * for secure connections with the Directory Server.
   * Returns the names of the protocol versions which are currently enabled for
   * secure connections with the Directory Server.
   *
   * @return an array of protocols or empty set if the default protocols
   * are to be used.
   * @return An array of protocols or empty set if the default protocols are to
   *         be used.
   */
  public final List<String> getEnabledProtocols()
  {
    return this.enabledProtocols;
    return enabledProtocols;
  }
  /**
   * Returns the names of the protocol versions which are currently enabled
   * for secure connections with the Directory Server.
   * Returns the names of the protocol versions which are currently enabled for
   * secure connections with the Directory Server.
   *
   * @return an array of protocols or empty set if the default protocols
   * are to be used.
   * @return An array of protocols or empty set if the default protocols are to
   *         be used.
   */
  public final List<String> getEnabledCipherSuites()
  {
    return this.enabledCipherSuites;
    return enabledCipherSuites;
  }
}
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java
@@ -23,7 +23,7 @@
 *
 *
 *      Copyright 2010 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 *      Portions copyright 2011-2012 ForgeRock AS
 */
package org.forgerock.opendj.ldap;
@@ -371,7 +371,7 @@
                }
              };
              clientContext.startSASL(csl);
              clientContext.enableConnectionSecurityLayer(csl);
            }
          }
@@ -576,7 +576,7 @@
        final R result = request.getResultDecoder().newExtendedErrorResult(
            ResultCode.SUCCESS, "", "");
        resultHandler.handleResult(result);
        clientContext.startTLS(sslContext, null, sslContext.getSocketFactory()
        clientContext.enableTLS(sslContext, null, sslContext.getSocketFactory()
            .getSupportedCipherSuites(), false, false);
      }
    }