001 /*
002 * Copyright 2007-2016 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2016 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 */
021 package com.unboundid.ldap.sdk;
022
023
024
025 import javax.net.ssl.SSLContext;
026 import javax.net.ssl.SSLSocketFactory;
027
028 import com.unboundid.ldap.sdk.extensions.StartTLSExtendedRequest;
029 import com.unboundid.util.NotMutable;
030 import com.unboundid.util.ThreadSafety;
031 import com.unboundid.util.ThreadSafetyLevel;
032
033 import 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)
075 public 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 }