001/* 002 * Copyright 2010-2017 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2010-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.util.Arrays; 026import java.util.List; 027 028import com.unboundid.ldap.protocol.AddRequestProtocolOp; 029import com.unboundid.ldap.protocol.AddResponseProtocolOp; 030import com.unboundid.ldap.protocol.BindRequestProtocolOp; 031import com.unboundid.ldap.protocol.BindResponseProtocolOp; 032import com.unboundid.ldap.protocol.CompareRequestProtocolOp; 033import com.unboundid.ldap.protocol.CompareResponseProtocolOp; 034import com.unboundid.ldap.protocol.DeleteRequestProtocolOp; 035import com.unboundid.ldap.protocol.DeleteResponseProtocolOp; 036import com.unboundid.ldap.protocol.ExtendedRequestProtocolOp; 037import com.unboundid.ldap.protocol.ExtendedResponseProtocolOp; 038import com.unboundid.ldap.protocol.IntermediateResponseProtocolOp; 039import com.unboundid.ldap.protocol.LDAPMessage; 040import com.unboundid.ldap.protocol.ModifyRequestProtocolOp; 041import com.unboundid.ldap.protocol.ModifyResponseProtocolOp; 042import com.unboundid.ldap.protocol.ModifyDNRequestProtocolOp; 043import com.unboundid.ldap.protocol.ModifyDNResponseProtocolOp; 044import com.unboundid.ldap.protocol.SearchRequestProtocolOp; 045import com.unboundid.ldap.protocol.SearchResultDoneProtocolOp; 046import com.unboundid.ldap.sdk.AddRequest; 047import com.unboundid.ldap.sdk.BindRequest; 048import com.unboundid.ldap.sdk.CompareRequest; 049import com.unboundid.ldap.sdk.Control; 050import com.unboundid.ldap.sdk.DeleteRequest; 051import com.unboundid.ldap.sdk.ExtendedRequest; 052import com.unboundid.ldap.sdk.ExtendedResult; 053import com.unboundid.ldap.sdk.GenericSASLBindRequest; 054import com.unboundid.ldap.sdk.IntermediateResponse; 055import com.unboundid.ldap.sdk.IntermediateResponseListener; 056import com.unboundid.ldap.sdk.LDAPConnection; 057import com.unboundid.ldap.sdk.LDAPException; 058import com.unboundid.ldap.sdk.LDAPResult; 059import com.unboundid.ldap.sdk.ModifyRequest; 060import com.unboundid.ldap.sdk.ModifyDNRequest; 061import com.unboundid.ldap.sdk.SearchRequest; 062import com.unboundid.ldap.sdk.ServerSet; 063import com.unboundid.ldap.sdk.SimpleBindRequest; 064import com.unboundid.util.Debug; 065import com.unboundid.util.NotMutable; 066import com.unboundid.util.StaticUtils; 067import com.unboundid.util.ThreadSafety; 068import com.unboundid.util.ThreadSafetyLevel; 069import com.unboundid.util.Validator; 070 071import static com.unboundid.ldap.listener.ListenerMessages.*; 072 073 074 075/** 076 * This class provides an implementation of a simple LDAP listener request 077 * handler that may be used to forward the request to another LDAP directory 078 * server. 079 */ 080@NotMutable() 081@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 082public final class ProxyRequestHandler 083 extends LDAPListenerRequestHandler 084 implements IntermediateResponseListener 085{ 086 /** 087 * The serial version UID for this serializable class. 088 */ 089 private static final long serialVersionUID = -8714030276701707669L; 090 091 092 093 // The connection to the LDAP server to which requests will be forwarded. 094 private final LDAPConnection ldapConnection; 095 096 // The client connection that has been established. 097 private final LDAPListenerClientConnection listenerConnection; 098 099 // The server set that will be used to establish the connection. 100 private final ServerSet serverSet; 101 102 103 104 /** 105 * Creates a new instance of this proxy request handler that will use the 106 * provided {@link ServerSet} to connect to an LDAP server. 107 * 108 * @param serverSet The server that will be used to create LDAP connections 109 * to forward any requests received. It must not be 110 * {@code null}. 111 */ 112 public ProxyRequestHandler(final ServerSet serverSet) 113 { 114 Validator.ensureNotNull(serverSet); 115 116 this.serverSet = serverSet; 117 118 ldapConnection = null; 119 listenerConnection = null; 120 } 121 122 123 124 /** 125 * Creates a new instance of this proxy request handler with the provided 126 * information. 127 * 128 * @param serverSet The server that will be used to create LDAP 129 * connections to forward any requests received. 130 * It must not be {@code null}. 131 * @param ldapConnection The connection to the LDAP server to which 132 * requests will be forwarded. 133 * @param listenerConnection The client connection with which this request 134 * handler is associated. 135 */ 136 private ProxyRequestHandler(final ServerSet serverSet, 137 final LDAPConnection ldapConnection, 138 final LDAPListenerClientConnection listenerConnection) 139 { 140 this.serverSet = serverSet; 141 this.ldapConnection = ldapConnection; 142 this.listenerConnection = listenerConnection; 143 } 144 145 146 147 /** 148 * {@inheritDoc} 149 */ 150 @Override() 151 public ProxyRequestHandler newInstance( 152 final LDAPListenerClientConnection connection) 153 throws LDAPException 154 { 155 return new ProxyRequestHandler(serverSet, serverSet.getConnection(), 156 connection); 157 } 158 159 160 161 /** 162 * {@inheritDoc} 163 */ 164 @Override() 165 public void closeInstance() 166 { 167 ldapConnection.close(); 168 } 169 170 171 172 /** 173 * {@inheritDoc} 174 */ 175 @Override() 176 public LDAPMessage processAddRequest(final int messageID, 177 final AddRequestProtocolOp request, 178 final List<Control> controls) 179 { 180 final AddRequest addRequest = new AddRequest(request.getDN(), 181 request.getAttributes()); 182 if (! controls.isEmpty()) 183 { 184 addRequest.setControls(controls); 185 } 186 addRequest.setIntermediateResponseListener(this); 187 188 LDAPResult addResult; 189 try 190 { 191 addResult = ldapConnection.add(addRequest); 192 } 193 catch (final LDAPException le) 194 { 195 Debug.debugException(le); 196 addResult = le.toLDAPResult(); 197 } 198 199 final AddResponseProtocolOp addResponseProtocolOp = 200 new AddResponseProtocolOp(addResult.getResultCode().intValue(), 201 addResult.getMatchedDN(), addResult.getDiagnosticMessage(), 202 Arrays.asList(addResult.getReferralURLs())); 203 204 return new LDAPMessage(messageID, addResponseProtocolOp, 205 Arrays.asList(addResult.getResponseControls())); 206 } 207 208 209 210 /** 211 * {@inheritDoc} 212 */ 213 @Override() 214 public LDAPMessage processBindRequest(final int messageID, 215 final BindRequestProtocolOp request, 216 final List<Control> controls) 217 { 218 final Control[] controlArray; 219 if ((controls == null) || (controls.isEmpty())) 220 { 221 controlArray = StaticUtils.NO_CONTROLS; 222 } 223 else 224 { 225 controlArray = new Control[controls.size()]; 226 controls.toArray(controlArray); 227 } 228 229 final BindRequest bindRequest; 230 if (request.getCredentialsType() == BindRequestProtocolOp.CRED_TYPE_SIMPLE) 231 { 232 bindRequest = new SimpleBindRequest(request.getBindDN(), 233 request.getSimplePassword().getValue(), controlArray); 234 } 235 else 236 { 237 bindRequest = new GenericSASLBindRequest(request.getBindDN(), 238 request.getSASLMechanism(), request.getSASLCredentials(), 239 controlArray); 240 } 241 242 bindRequest.setIntermediateResponseListener(this); 243 244 LDAPResult bindResult; 245 try 246 { 247 bindResult = ldapConnection.bind(bindRequest); 248 } 249 catch (final LDAPException le) 250 { 251 Debug.debugException(le); 252 bindResult = le.toLDAPResult(); 253 } 254 255 final BindResponseProtocolOp bindResponseProtocolOp = 256 new BindResponseProtocolOp(bindResult.getResultCode().intValue(), 257 bindResult.getMatchedDN(), bindResult.getDiagnosticMessage(), 258 Arrays.asList(bindResult.getReferralURLs()), null); 259 260 return new LDAPMessage(messageID, bindResponseProtocolOp, 261 Arrays.asList(bindResult.getResponseControls())); 262 } 263 264 265 266 /** 267 * {@inheritDoc} 268 */ 269 @Override() 270 public LDAPMessage processCompareRequest(final int messageID, 271 final CompareRequestProtocolOp request, 272 final List<Control> controls) 273 { 274 final CompareRequest compareRequest = new CompareRequest(request.getDN(), 275 request.getAttributeName(), request.getAssertionValue().getValue()); 276 if (! controls.isEmpty()) 277 { 278 compareRequest.setControls(controls); 279 } 280 compareRequest.setIntermediateResponseListener(this); 281 282 LDAPResult compareResult; 283 try 284 { 285 compareResult = ldapConnection.compare(compareRequest); 286 } 287 catch (final LDAPException le) 288 { 289 Debug.debugException(le); 290 compareResult = le.toLDAPResult(); 291 } 292 293 final CompareResponseProtocolOp compareResponseProtocolOp = 294 new CompareResponseProtocolOp(compareResult.getResultCode().intValue(), 295 compareResult.getMatchedDN(), 296 compareResult.getDiagnosticMessage(), 297 Arrays.asList(compareResult.getReferralURLs())); 298 299 return new LDAPMessage(messageID, compareResponseProtocolOp, 300 Arrays.asList(compareResult.getResponseControls())); 301 } 302 303 304 305 /** 306 * {@inheritDoc} 307 */ 308 @Override() 309 public LDAPMessage processDeleteRequest(final int messageID, 310 final DeleteRequestProtocolOp request, 311 final List<Control> controls) 312 { 313 final DeleteRequest deleteRequest = new DeleteRequest(request.getDN()); 314 if (! controls.isEmpty()) 315 { 316 deleteRequest.setControls(controls); 317 } 318 deleteRequest.setIntermediateResponseListener(this); 319 320 LDAPResult deleteResult; 321 try 322 { 323 deleteResult = ldapConnection.delete(deleteRequest); 324 } 325 catch (final LDAPException le) 326 { 327 Debug.debugException(le); 328 deleteResult = le.toLDAPResult(); 329 } 330 331 final DeleteResponseProtocolOp deleteResponseProtocolOp = 332 new DeleteResponseProtocolOp(deleteResult.getResultCode().intValue(), 333 deleteResult.getMatchedDN(), deleteResult.getDiagnosticMessage(), 334 Arrays.asList(deleteResult.getReferralURLs())); 335 336 return new LDAPMessage(messageID, deleteResponseProtocolOp, 337 Arrays.asList(deleteResult.getResponseControls())); 338 } 339 340 341 342 /** 343 * {@inheritDoc} 344 */ 345 @Override() 346 public LDAPMessage processExtendedRequest(final int messageID, 347 final ExtendedRequestProtocolOp request, 348 final List<Control> controls) 349 { 350 final ExtendedRequest extendedRequest; 351 if (controls.isEmpty()) 352 { 353 extendedRequest = new ExtendedRequest(request.getOID(), 354 request.getValue()); 355 } 356 else 357 { 358 final Control[] controlArray = new Control[controls.size()]; 359 controls.toArray(controlArray); 360 extendedRequest = new ExtendedRequest(request.getOID(), 361 request.getValue(), controlArray); 362 } 363 extendedRequest.setIntermediateResponseListener(this); 364 365 try 366 { 367 final ExtendedResult extendedResult = 368 ldapConnection.processExtendedOperation(extendedRequest); 369 370 final ExtendedResponseProtocolOp extendedResponseProtocolOp = 371 new ExtendedResponseProtocolOp( 372 extendedResult.getResultCode().intValue(), 373 extendedResult.getMatchedDN(), 374 extendedResult.getDiagnosticMessage(), 375 Arrays.asList(extendedResult.getReferralURLs()), 376 extendedResult.getOID(), extendedResult.getValue()); 377 return new LDAPMessage(messageID, extendedResponseProtocolOp, 378 Arrays.asList(extendedResult.getResponseControls())); 379 } 380 catch (final LDAPException le) 381 { 382 Debug.debugException(le); 383 384 final ExtendedResponseProtocolOp extendedResponseProtocolOp = 385 new ExtendedResponseProtocolOp(le.getResultCode().intValue(), 386 le.getMatchedDN(), le.getMessage(), 387 Arrays.asList(le.getReferralURLs()), null, null); 388 return new LDAPMessage(messageID, extendedResponseProtocolOp, 389 Arrays.asList(le.getResponseControls())); 390 } 391 } 392 393 394 395 /** 396 * {@inheritDoc} 397 */ 398 @Override() 399 public LDAPMessage processModifyRequest(final int messageID, 400 final ModifyRequestProtocolOp request, 401 final List<Control> controls) 402 { 403 final ModifyRequest modifyRequest = new ModifyRequest(request.getDN(), 404 request.getModifications()); 405 if (! controls.isEmpty()) 406 { 407 modifyRequest.setControls(controls); 408 } 409 modifyRequest.setIntermediateResponseListener(this); 410 411 LDAPResult modifyResult; 412 try 413 { 414 modifyResult = ldapConnection.modify(modifyRequest); 415 } 416 catch (final LDAPException le) 417 { 418 Debug.debugException(le); 419 modifyResult = le.toLDAPResult(); 420 } 421 422 final ModifyResponseProtocolOp modifyResponseProtocolOp = 423 new ModifyResponseProtocolOp(modifyResult.getResultCode().intValue(), 424 modifyResult.getMatchedDN(), modifyResult.getDiagnosticMessage(), 425 Arrays.asList(modifyResult.getReferralURLs())); 426 427 return new LDAPMessage(messageID, modifyResponseProtocolOp, 428 Arrays.asList(modifyResult.getResponseControls())); 429 } 430 431 432 433 /** 434 * {@inheritDoc} 435 */ 436 @Override() 437 public LDAPMessage processModifyDNRequest(final int messageID, 438 final ModifyDNRequestProtocolOp request, 439 final List<Control> controls) 440 { 441 final ModifyDNRequest modifyDNRequest = new ModifyDNRequest(request.getDN(), 442 request.getNewRDN(), request.deleteOldRDN(), 443 request.getNewSuperiorDN()); 444 if (! controls.isEmpty()) 445 { 446 modifyDNRequest.setControls(controls); 447 } 448 modifyDNRequest.setIntermediateResponseListener(this); 449 450 LDAPResult modifyDNResult; 451 try 452 { 453 modifyDNResult = ldapConnection.modifyDN(modifyDNRequest); 454 } 455 catch (final LDAPException le) 456 { 457 Debug.debugException(le); 458 modifyDNResult = le.toLDAPResult(); 459 } 460 461 final ModifyDNResponseProtocolOp modifyDNResponseProtocolOp = 462 new ModifyDNResponseProtocolOp( 463 modifyDNResult.getResultCode().intValue(), 464 modifyDNResult.getMatchedDN(), 465 modifyDNResult.getDiagnosticMessage(), 466 Arrays.asList(modifyDNResult.getReferralURLs())); 467 468 return new LDAPMessage(messageID, modifyDNResponseProtocolOp, 469 Arrays.asList(modifyDNResult.getResponseControls())); 470 } 471 472 473 474 /** 475 * {@inheritDoc} 476 */ 477 @Override() 478 public LDAPMessage processSearchRequest(final int messageID, 479 final SearchRequestProtocolOp request, 480 final List<Control> controls) 481 { 482 final String[] attrs; 483 final List<String> attrList = request.getAttributes(); 484 if (attrList.isEmpty()) 485 { 486 attrs = StaticUtils.NO_STRINGS; 487 } 488 else 489 { 490 attrs = new String[attrList.size()]; 491 attrList.toArray(attrs); 492 } 493 494 final ProxySearchResultListener searchListener = 495 new ProxySearchResultListener(listenerConnection, messageID); 496 497 final SearchRequest searchRequest = new SearchRequest(searchListener, 498 request.getBaseDN(), request.getScope(), request.getDerefPolicy(), 499 request.getSizeLimit(), request.getTimeLimit(), request.typesOnly(), 500 request.getFilter(), attrs); 501 502 if (! controls.isEmpty()) 503 { 504 searchRequest.setControls(controls); 505 } 506 searchRequest.setIntermediateResponseListener(this); 507 508 LDAPResult searchResult; 509 try 510 { 511 searchResult = ldapConnection.search(searchRequest); 512 } 513 catch (final LDAPException le) 514 { 515 Debug.debugException(le); 516 searchResult = le.toLDAPResult(); 517 } 518 519 final SearchResultDoneProtocolOp searchResultDoneProtocolOp = 520 new SearchResultDoneProtocolOp(searchResult.getResultCode().intValue(), 521 searchResult.getMatchedDN(), searchResult.getDiagnosticMessage(), 522 Arrays.asList(searchResult.getReferralURLs())); 523 524 return new LDAPMessage(messageID, searchResultDoneProtocolOp, 525 Arrays.asList(searchResult.getResponseControls())); 526 } 527 528 529 530 /** 531 * {@inheritDoc} 532 */ 533 public void intermediateResponseReturned( 534 final IntermediateResponse intermediateResponse) 535 { 536 try 537 { 538 listenerConnection.sendIntermediateResponse( 539 intermediateResponse.getMessageID(), 540 new IntermediateResponseProtocolOp(intermediateResponse.getOID(), 541 intermediateResponse.getValue()), 542 intermediateResponse.getControls()); 543 } 544 catch (final LDAPException le) 545 { 546 Debug.debugException(le); 547 } 548 } 549}