001    /*
002     * Copyright 2010-2016 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2010-2016 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     */
021    package com.unboundid.ldap.listener;
022    
023    
024    
025    import java.util.Arrays;
026    import java.util.List;
027    
028    import com.unboundid.ldap.protocol.AddRequestProtocolOp;
029    import com.unboundid.ldap.protocol.AddResponseProtocolOp;
030    import com.unboundid.ldap.protocol.BindRequestProtocolOp;
031    import com.unboundid.ldap.protocol.BindResponseProtocolOp;
032    import com.unboundid.ldap.protocol.CompareRequestProtocolOp;
033    import com.unboundid.ldap.protocol.CompareResponseProtocolOp;
034    import com.unboundid.ldap.protocol.DeleteRequestProtocolOp;
035    import com.unboundid.ldap.protocol.DeleteResponseProtocolOp;
036    import com.unboundid.ldap.protocol.ExtendedRequestProtocolOp;
037    import com.unboundid.ldap.protocol.ExtendedResponseProtocolOp;
038    import com.unboundid.ldap.protocol.IntermediateResponseProtocolOp;
039    import com.unboundid.ldap.protocol.LDAPMessage;
040    import com.unboundid.ldap.protocol.ModifyRequestProtocolOp;
041    import com.unboundid.ldap.protocol.ModifyResponseProtocolOp;
042    import com.unboundid.ldap.protocol.ModifyDNRequestProtocolOp;
043    import com.unboundid.ldap.protocol.ModifyDNResponseProtocolOp;
044    import com.unboundid.ldap.protocol.SearchRequestProtocolOp;
045    import com.unboundid.ldap.protocol.SearchResultDoneProtocolOp;
046    import com.unboundid.ldap.sdk.AddRequest;
047    import com.unboundid.ldap.sdk.BindRequest;
048    import com.unboundid.ldap.sdk.CompareRequest;
049    import com.unboundid.ldap.sdk.Control;
050    import com.unboundid.ldap.sdk.DeleteRequest;
051    import com.unboundid.ldap.sdk.ExtendedRequest;
052    import com.unboundid.ldap.sdk.ExtendedResult;
053    import com.unboundid.ldap.sdk.GenericSASLBindRequest;
054    import com.unboundid.ldap.sdk.IntermediateResponse;
055    import com.unboundid.ldap.sdk.IntermediateResponseListener;
056    import com.unboundid.ldap.sdk.LDAPConnection;
057    import com.unboundid.ldap.sdk.LDAPException;
058    import com.unboundid.ldap.sdk.LDAPResult;
059    import com.unboundid.ldap.sdk.ModifyRequest;
060    import com.unboundid.ldap.sdk.ModifyDNRequest;
061    import com.unboundid.ldap.sdk.SearchRequest;
062    import com.unboundid.ldap.sdk.ServerSet;
063    import com.unboundid.ldap.sdk.SimpleBindRequest;
064    import com.unboundid.util.Debug;
065    import com.unboundid.util.NotMutable;
066    import com.unboundid.util.StaticUtils;
067    import com.unboundid.util.ThreadSafety;
068    import com.unboundid.util.ThreadSafetyLevel;
069    import com.unboundid.util.Validator;
070    
071    import 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)
082    public 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    }