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