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