001/*
002 * Copyright 2010-2018 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2010-2018 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}