001 /*
002 * Copyright 2010-2013 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2010-2013 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 }