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}