001/*
002 * Copyright 2007-2017 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2017 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.ldap.sdk;
022
023
024
025import javax.net.ssl.SSLContext;
026import javax.net.ssl.SSLSocketFactory;
027
028import com.unboundid.ldap.sdk.extensions.StartTLSExtendedRequest;
029import com.unboundid.util.NotMutable;
030import com.unboundid.util.ThreadSafety;
031import com.unboundid.util.ThreadSafetyLevel;
032
033import static com.unboundid.util.Validator.*;
034
035
036
037/**
038 * This class provides an implementation of a post-connect processor that can
039 * be used to perform StartTLS negotiation on an LDAP connection that is
040 * intended to be used in a connection pool.
041 * <BR><BR>
042 * <H2>Example</H2>
043 * The following example demonstrates the use of the StartTLS post-connect
044 * processor to create an LDAP connection pool whose connections are secured
045 * using StartTLS:
046 * <PRE>
047 * // Configure an SSLUtil instance and use it to obtain an SSLContext.
048 * SSLUtil sslUtil = new SSLUtil(new TrustStoreTrustManager(trustStorePath));
049 * SSLContext sslContext = sslUtil.createSSLContext();
050 *
051 * // Establish an insecure connection to the directory server.
052 * LDAPConnection connection = new LDAPConnection(serverAddress, nonSSLPort);
053 *
054 * // Use the StartTLS extended operation to secure the connection.
055 * ExtendedResult startTLSResult = connection.processExtendedOperation(
056 *      new StartTLSExtendedRequest(sslContext));
057 *
058 * // Create a connection pool that will secure its connections with StartTLS.
059 * BindResult bindResult = connection.bind(
060 *      "uid=john.doe,ou=People,dc=example,dc=com", "password");
061 * StartTLSPostConnectProcessor startTLSProcessor =
062 *      new StartTLSPostConnectProcessor(sslContext);
063 * LDAPConnectionPool pool =
064 *      new LDAPConnectionPool(connection, 1, 10, startTLSProcessor);
065 *
066 * // Verify that we can use the pool to communicate with the directory server.
067 * RootDSE rootDSE = pool.getRootDSE();
068 *
069 * // Close the connection pool.
070 * pool.close();
071 * </PRE>
072 */
073@NotMutable()
074@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
075public final class StartTLSPostConnectProcessor
076       implements PostConnectProcessor
077{
078  // The SSL context to use to perform the negotiation.
079  private final SSLContext sslContext;
080
081  // The SSL socket factory to create the secure connection.
082  private final SSLSocketFactory sslSocketFactory;
083
084
085
086  /**
087   * Creates a new instance of this StartTLS post-connect processor that will
088   * use the provided SSL context.
089   *
090   * @param  sslContext  The SSL context to use to perform the StartTLS
091   *                     negotiation.  It must not be {@code null}.
092   */
093  public StartTLSPostConnectProcessor(final SSLContext sslContext)
094  {
095    ensureNotNull(sslContext);
096
097    this.sslContext = sslContext;
098    sslSocketFactory = null;
099  }
100
101
102
103  /**
104   * Creates a new instance of this StartTLS post-connect processor that will
105   * use the provided SSL context.
106   *
107   * @param  sslSocketFactory  The SSL socket factory to use to create the
108   *                           TLS-secured socket.  It must not be {@code null}.
109   */
110  public StartTLSPostConnectProcessor(final SSLSocketFactory sslSocketFactory)
111  {
112    ensureNotNull(sslSocketFactory);
113
114    this.sslSocketFactory = sslSocketFactory;
115    sslContext = null;
116  }
117
118
119
120  /**
121   * {@inheritDoc}
122   */
123  public void processPreAuthenticatedConnection(final LDAPConnection connection)
124         throws LDAPException
125  {
126    final StartTLSExtendedRequest startTLSRequest;
127    if (sslContext == null)
128    {
129      startTLSRequest = new StartTLSExtendedRequest(sslSocketFactory);
130    }
131    else
132    {
133      startTLSRequest = new StartTLSExtendedRequest(sslContext);
134    }
135
136    // Since the StartTLS processing will occur during the course of
137    // establishing the connection for use in the pool, set the connect timeout
138    // for the operation to be equal to the connect timeout from the connection
139    // options.
140    final LDAPConnectionOptions opts = connection.getConnectionOptions();
141    startTLSRequest.setResponseTimeoutMillis(opts.getConnectTimeoutMillis());
142
143    final ExtendedResult r =
144         connection.processExtendedOperation(startTLSRequest);
145    if (! r.getResultCode().equals(ResultCode.SUCCESS))
146    {
147      throw new LDAPExtendedOperationException(r);
148    }
149  }
150
151
152
153  /**
154   * {@inheritDoc}
155   */
156  public void processPostAuthenticatedConnection(
157                   final LDAPConnection connection)
158         throws LDAPException
159  {
160    // No implementation is required for this post-connect processor.
161  }
162}