001 /*
002 * Copyright 2011-2013 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2011-2013 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.listener;
022
023
024
025 import java.io.OutputStream;
026 import java.util.List;
027 import javax.net.ssl.SSLSocketFactory;
028
029 import com.unboundid.asn1.ASN1Buffer;
030 import com.unboundid.ldap.protocol.AbandonRequestProtocolOp;
031 import com.unboundid.ldap.protocol.AddRequestProtocolOp;
032 import com.unboundid.ldap.protocol.BindRequestProtocolOp;
033 import com.unboundid.ldap.protocol.CompareRequestProtocolOp;
034 import com.unboundid.ldap.protocol.DeleteRequestProtocolOp;
035 import com.unboundid.ldap.protocol.ExtendedRequestProtocolOp;
036 import com.unboundid.ldap.protocol.ExtendedResponseProtocolOp;
037 import com.unboundid.ldap.protocol.ModifyRequestProtocolOp;
038 import com.unboundid.ldap.protocol.ModifyDNRequestProtocolOp;
039 import com.unboundid.ldap.protocol.SearchRequestProtocolOp;
040 import com.unboundid.ldap.protocol.UnbindRequestProtocolOp;
041 import com.unboundid.ldap.protocol.LDAPMessage;
042 import com.unboundid.ldap.sdk.Control;
043 import com.unboundid.ldap.sdk.ExtendedRequest;
044 import com.unboundid.ldap.sdk.LDAPException;
045 import com.unboundid.ldap.sdk.ResultCode;
046 import com.unboundid.ldap.sdk.extensions.StartTLSExtendedRequest;
047 import com.unboundid.util.Debug;
048 import com.unboundid.util.StaticUtils;
049 import com.unboundid.util.ThreadSafety;
050 import com.unboundid.util.ThreadSafetyLevel;
051
052 import static com.unboundid.ldap.listener.ListenerMessages.*;
053
054
055
056 /**
057 * This class provides a request handler implementation that can be used to
058 * convert an existing connection to use TLS encryption. It will handle
059 * StartTLS extended operations directly, but will pass all other requests and
060 * responses through to another request handler.
061 */
062 @ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
063 public final class StartTLSRequestHandler
064 extends LDAPListenerRequestHandler
065 {
066 // The client connection with which this request handler is associated.
067 private final LDAPListenerClientConnection connection;
068
069 // The request handler that will be used to process all operations except the
070 // StartTLS extended operation.
071 private final LDAPListenerRequestHandler requestHandler;
072
073 // The SSL socket factory that will be used to SSL-enable the existing socket.
074 private final SSLSocketFactory sslSocketFactory;
075
076
077
078 /**
079 * Creates a new StartTLS request handler with the provided information.
080 *
081 * @param sslSocketFactory The SSL socket factory that will be used to
082 * convert the existing socket to use SSL
083 * encryption.
084 * @param requestHandler The request handler that will be used to process
085 * all operations except StartTLS extended
086 * operations.
087 */
088 public StartTLSRequestHandler(final SSLSocketFactory sslSocketFactory,
089 final LDAPListenerRequestHandler requestHandler)
090 {
091 this.sslSocketFactory = sslSocketFactory;
092 this.requestHandler = requestHandler;
093
094 connection = null;
095 }
096
097
098
099 /**
100 * Creates a new StartTLS request handler with the provided information.
101 *
102 * @param sslSocketFactory The SSL socket factory that will be used to
103 * convert the existing socket to use SSL
104 * encryption.
105 * @param requestHandler The request handler that will be used to process
106 * all operations except StartTLS extended
107 * operations.
108 * @param connection The connection to the associated client.
109 */
110 private StartTLSRequestHandler(final SSLSocketFactory sslSocketFactory,
111 final LDAPListenerRequestHandler requestHandler,
112 final LDAPListenerClientConnection connection)
113 {
114 this.sslSocketFactory = sslSocketFactory;
115 this.requestHandler = requestHandler;
116 this.connection = connection;
117 }
118
119
120
121 /**
122 * {@inheritDoc}
123 */
124 @Override()
125 public StartTLSRequestHandler
126 newInstance(final LDAPListenerClientConnection connection)
127 throws LDAPException
128 {
129 return new StartTLSRequestHandler(sslSocketFactory,
130 requestHandler.newInstance(connection), connection);
131 }
132
133
134
135 /**
136 * {@inheritDoc}
137 */
138 @Override()
139 public void closeInstance()
140 {
141 requestHandler.closeInstance();
142 }
143
144
145
146 /**
147 * {@inheritDoc}
148 */
149 @Override()
150 public void processAbandonRequest(final int messageID,
151 final AbandonRequestProtocolOp request,
152 final List<Control> controls)
153 {
154 requestHandler.processAbandonRequest(messageID, request, controls);
155 }
156
157
158
159 /**
160 * {@inheritDoc}
161 */
162 @Override()
163 public LDAPMessage processAddRequest(final int messageID,
164 final AddRequestProtocolOp request,
165 final List<Control> controls)
166 {
167 return requestHandler.processAddRequest(messageID, request, controls);
168 }
169
170
171
172 /**
173 * {@inheritDoc}
174 */
175 @Override()
176 public LDAPMessage processBindRequest(final int messageID,
177 final BindRequestProtocolOp request,
178 final List<Control> controls)
179 {
180 return requestHandler.processBindRequest(messageID, request, controls);
181 }
182
183
184
185 /**
186 * {@inheritDoc}
187 */
188 @Override()
189 public LDAPMessage processCompareRequest(final int messageID,
190 final CompareRequestProtocolOp request,
191 final List<Control> controls)
192 {
193 return requestHandler.processCompareRequest(messageID, request, controls);
194 }
195
196
197
198 /**
199 * {@inheritDoc}
200 */
201 @Override()
202 public LDAPMessage processDeleteRequest(final int messageID,
203 final DeleteRequestProtocolOp request,
204 final List<Control> controls)
205 {
206 return requestHandler.processDeleteRequest(messageID, request, controls);
207 }
208
209
210
211 /**
212 * {@inheritDoc}
213 */
214 @Override()
215 public LDAPMessage processExtendedRequest(final int messageID,
216 final ExtendedRequestProtocolOp request,
217 final List<Control> controls)
218 {
219 if (request.getOID().equals(StartTLSExtendedRequest.STARTTLS_REQUEST_OID))
220 {
221 try
222 {
223 // Make sure we can decode the request as a valid StartTLS request.
224 final StartTLSExtendedRequest startTLSRequest =
225 new StartTLSExtendedRequest(new ExtendedRequest(request.getOID(),
226 request.getValue()));
227
228 final OutputStream clearOutputStream =
229 connection.convertToTLS(sslSocketFactory);
230
231 final LDAPMessage responseMessage = new LDAPMessage(messageID,
232 new ExtendedResponseProtocolOp(ResultCode.SUCCESS_INT_VALUE, null,
233 null, null, null, null));
234 final ASN1Buffer buffer = new ASN1Buffer();
235 responseMessage.writeTo(buffer);
236
237 try
238 {
239 buffer.writeTo(clearOutputStream);
240 clearOutputStream.flush();
241 }
242 catch (final Exception e)
243 {
244 Debug.debugException(e);
245 final LDAPException le = new LDAPException(ResultCode.LOCAL_ERROR,
246 ERR_START_TLS_REQUEST_HANDLER_WRITE_RESPONSE_FAILURE.get(
247 StaticUtils.getExceptionMessage(e)),
248 e);
249 connection.close(le);
250 throw le;
251 }
252
253 return responseMessage;
254 }
255 catch (final LDAPException le)
256 {
257 Debug.debugException(le);
258
259 return new LDAPMessage(messageID,
260 new ExtendedResponseProtocolOp(le.getResultCode().intValue(),
261 le.getMatchedDN(), le.getDiagnosticMessage(),
262 StaticUtils.toList(le.getReferralURLs()), null, null),
263 le.getResponseControls());
264 }
265 }
266 else
267 {
268 return requestHandler.processExtendedRequest(messageID, request,
269 controls);
270 }
271 }
272
273
274
275 /**
276 * {@inheritDoc}
277 */
278 @Override()
279 public LDAPMessage processModifyRequest(final int messageID,
280 final ModifyRequestProtocolOp request,
281 final List<Control> controls)
282 {
283 return requestHandler.processModifyRequest(messageID, request, controls);
284 }
285
286
287
288 /**
289 * {@inheritDoc}
290 */
291 @Override()
292 public LDAPMessage processModifyDNRequest(final int messageID,
293 final ModifyDNRequestProtocolOp request,
294 final List<Control> controls)
295 {
296 return requestHandler.processModifyDNRequest(messageID, request, controls);
297 }
298
299
300
301 /**
302 * {@inheritDoc}
303 */
304 @Override()
305 public LDAPMessage processSearchRequest(final int messageID,
306 final SearchRequestProtocolOp request,
307 final List<Control> controls)
308 {
309 return requestHandler.processSearchRequest(messageID, request, controls);
310 }
311
312
313
314 /**
315 * {@inheritDoc}
316 */
317 @Override()
318 public void processUnbindRequest(final int messageID,
319 final UnbindRequestProtocolOp request,
320 final List<Control> controls)
321 {
322 requestHandler.processUnbindRequest(messageID, request, controls);
323 }
324 }