001/* 002 * Copyright 2011-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2011-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.listener; 022 023 024 025import java.io.OutputStream; 026import java.util.List; 027import javax.net.ssl.SSLSocketFactory; 028 029import com.unboundid.asn1.ASN1Buffer; 030import com.unboundid.ldap.protocol.AbandonRequestProtocolOp; 031import com.unboundid.ldap.protocol.AddRequestProtocolOp; 032import com.unboundid.ldap.protocol.BindRequestProtocolOp; 033import com.unboundid.ldap.protocol.CompareRequestProtocolOp; 034import com.unboundid.ldap.protocol.DeleteRequestProtocolOp; 035import com.unboundid.ldap.protocol.ExtendedRequestProtocolOp; 036import com.unboundid.ldap.protocol.ExtendedResponseProtocolOp; 037import com.unboundid.ldap.protocol.ModifyRequestProtocolOp; 038import com.unboundid.ldap.protocol.ModifyDNRequestProtocolOp; 039import com.unboundid.ldap.protocol.SearchRequestProtocolOp; 040import com.unboundid.ldap.protocol.UnbindRequestProtocolOp; 041import com.unboundid.ldap.protocol.LDAPMessage; 042import com.unboundid.ldap.sdk.Control; 043import com.unboundid.ldap.sdk.ExtendedRequest; 044import com.unboundid.ldap.sdk.LDAPException; 045import com.unboundid.ldap.sdk.ResultCode; 046import com.unboundid.ldap.sdk.extensions.StartTLSExtendedRequest; 047import com.unboundid.util.Debug; 048import com.unboundid.util.StaticUtils; 049import com.unboundid.util.ThreadSafety; 050import com.unboundid.util.ThreadSafetyLevel; 051 052import 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) 063public 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}