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