1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.ldap.client.api;
21
22
23 import static org.apache.directory.api.ldap.model.message.ResultCodeEnum.processResponse;
24
25 import java.io.File;
26 import java.io.FileWriter;
27 import java.io.IOException;
28 import java.net.InetSocketAddress;
29 import java.net.SocketAddress;
30 import java.nio.channels.UnresolvedAddressException;
31 import java.security.PrivilegedExceptionAction;
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.concurrent.ConcurrentHashMap;
38 import java.util.concurrent.ExecutionException;
39 import java.util.concurrent.TimeUnit;
40 import java.util.concurrent.TimeoutException;
41 import java.util.concurrent.atomic.AtomicBoolean;
42 import java.util.concurrent.locks.ReentrantLock;
43
44 import javax.net.ssl.SSLContext;
45 import javax.security.auth.Subject;
46 import javax.security.auth.login.Configuration;
47 import javax.security.auth.login.LoginContext;
48 import javax.security.sasl.Sasl;
49 import javax.security.sasl.SaslClient;
50
51 import org.apache.directory.api.asn1.DecoderException;
52 import org.apache.directory.api.asn1.util.Oid;
53 import org.apache.directory.api.ldap.codec.api.BinaryAttributeDetector;
54 import org.apache.directory.api.ldap.codec.api.DefaultConfigurableBinaryAttributeDetector;
55 import org.apache.directory.api.ldap.codec.api.ExtendedResponseDecorator;
56 import org.apache.directory.api.ldap.codec.api.LdapApiService;
57 import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
58 import org.apache.directory.api.ldap.codec.api.LdapDecoder;
59 import org.apache.directory.api.ldap.codec.api.LdapMessageContainer;
60 import org.apache.directory.api.ldap.codec.api.MessageDecorator;
61 import org.apache.directory.api.ldap.codec.api.MessageEncoderException;
62 import org.apache.directory.api.ldap.codec.api.SchemaBinaryAttributeDetector;
63 import org.apache.directory.api.ldap.extras.extended.startTls.StartTlsRequestImpl;
64 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
65 import org.apache.directory.api.ldap.model.cursor.Cursor;
66 import org.apache.directory.api.ldap.model.cursor.CursorException;
67 import org.apache.directory.api.ldap.model.cursor.EntryCursor;
68 import org.apache.directory.api.ldap.model.cursor.SearchCursor;
69 import org.apache.directory.api.ldap.model.entry.Attribute;
70 import org.apache.directory.api.ldap.model.entry.DefaultEntry;
71 import org.apache.directory.api.ldap.model.entry.Entry;
72 import org.apache.directory.api.ldap.model.entry.Modification;
73 import org.apache.directory.api.ldap.model.entry.ModificationOperation;
74 import org.apache.directory.api.ldap.model.entry.Value;
75 import org.apache.directory.api.ldap.model.exception.LdapAuthenticationException;
76 import org.apache.directory.api.ldap.model.exception.LdapException;
77 import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
78 import org.apache.directory.api.ldap.model.exception.LdapNoPermissionException;
79 import org.apache.directory.api.ldap.model.exception.LdapOperationException;
80 import org.apache.directory.api.ldap.model.exception.LdapOtherException;
81 import org.apache.directory.api.ldap.model.message.AbandonRequest;
82 import org.apache.directory.api.ldap.model.message.AbandonRequestImpl;
83 import org.apache.directory.api.ldap.model.message.AddRequest;
84 import org.apache.directory.api.ldap.model.message.AddRequestImpl;
85 import org.apache.directory.api.ldap.model.message.AddResponse;
86 import org.apache.directory.api.ldap.model.message.AliasDerefMode;
87 import org.apache.directory.api.ldap.model.message.BindRequest;
88 import org.apache.directory.api.ldap.model.message.BindRequestImpl;
89 import org.apache.directory.api.ldap.model.message.BindResponse;
90 import org.apache.directory.api.ldap.model.message.CompareRequest;
91 import org.apache.directory.api.ldap.model.message.CompareRequestImpl;
92 import org.apache.directory.api.ldap.model.message.CompareResponse;
93 import org.apache.directory.api.ldap.model.message.Control;
94 import org.apache.directory.api.ldap.model.message.DeleteRequest;
95 import org.apache.directory.api.ldap.model.message.DeleteRequestImpl;
96 import org.apache.directory.api.ldap.model.message.DeleteResponse;
97 import org.apache.directory.api.ldap.model.message.ExtendedRequest;
98 import org.apache.directory.api.ldap.model.message.ExtendedResponse;
99 import org.apache.directory.api.ldap.model.message.IntermediateResponse;
100 import org.apache.directory.api.ldap.model.message.IntermediateResponseImpl;
101 import org.apache.directory.api.ldap.model.message.LdapResult;
102 import org.apache.directory.api.ldap.model.message.Message;
103 import org.apache.directory.api.ldap.model.message.ModifyDnRequest;
104 import org.apache.directory.api.ldap.model.message.ModifyDnRequestImpl;
105 import org.apache.directory.api.ldap.model.message.ModifyDnResponse;
106 import org.apache.directory.api.ldap.model.message.ModifyRequest;
107 import org.apache.directory.api.ldap.model.message.ModifyRequestImpl;
108 import org.apache.directory.api.ldap.model.message.ModifyResponse;
109 import org.apache.directory.api.ldap.model.message.Request;
110 import org.apache.directory.api.ldap.model.message.Response;
111 import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
112 import org.apache.directory.api.ldap.model.message.SearchRequest;
113 import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
114 import org.apache.directory.api.ldap.model.message.SearchResultDone;
115 import org.apache.directory.api.ldap.model.message.SearchResultEntry;
116 import org.apache.directory.api.ldap.model.message.SearchResultReference;
117 import org.apache.directory.api.ldap.model.message.SearchScope;
118 import org.apache.directory.api.ldap.model.message.UnbindRequest;
119 import org.apache.directory.api.ldap.model.message.UnbindRequestImpl;
120 import org.apache.directory.api.ldap.model.message.controls.ManageDsaITImpl;
121 import org.apache.directory.api.ldap.model.message.controls.OpaqueControl;
122 import org.apache.directory.api.ldap.model.message.extended.AddNoDResponse;
123 import org.apache.directory.api.ldap.model.message.extended.BindNoDResponse;
124 import org.apache.directory.api.ldap.model.message.extended.CompareNoDResponse;
125 import org.apache.directory.api.ldap.model.message.extended.DeleteNoDResponse;
126 import org.apache.directory.api.ldap.model.message.extended.ExtendedNoDResponse;
127 import org.apache.directory.api.ldap.model.message.extended.ModifyDnNoDResponse;
128 import org.apache.directory.api.ldap.model.message.extended.ModifyNoDResponse;
129 import org.apache.directory.api.ldap.model.message.extended.NoticeOfDisconnect;
130 import org.apache.directory.api.ldap.model.message.extended.SearchNoDResponse;
131 import org.apache.directory.api.ldap.model.name.Dn;
132 import org.apache.directory.api.ldap.model.name.Rdn;
133 import org.apache.directory.api.ldap.model.schema.AttributeType;
134 import org.apache.directory.api.ldap.model.schema.ObjectClass;
135 import org.apache.directory.api.ldap.model.schema.SchemaManager;
136 import org.apache.directory.api.ldap.model.schema.parsers.OpenLdapSchemaParser;
137 import org.apache.directory.api.ldap.model.schema.registries.Registries;
138 import org.apache.directory.api.ldap.model.schema.registries.SchemaLoader;
139 import org.apache.directory.api.ldap.schemamanager.impl.DefaultSchemaManager;
140 import org.apache.directory.api.util.StringConstants;
141 import org.apache.directory.api.util.Strings;
142 import org.apache.directory.ldap.client.api.callback.SaslCallbackHandler;
143 import org.apache.directory.ldap.client.api.exception.InvalidConnectionException;
144 import org.apache.directory.ldap.client.api.future.AddFuture;
145 import org.apache.directory.ldap.client.api.future.BindFuture;
146 import org.apache.directory.ldap.client.api.future.CompareFuture;
147 import org.apache.directory.ldap.client.api.future.DeleteFuture;
148 import org.apache.directory.ldap.client.api.future.ExtendedFuture;
149 import org.apache.directory.ldap.client.api.future.ModifyDnFuture;
150 import org.apache.directory.ldap.client.api.future.ModifyFuture;
151 import org.apache.directory.ldap.client.api.future.ResponseFuture;
152 import org.apache.directory.ldap.client.api.future.SearchFuture;
153 import org.apache.mina.core.filterchain.IoFilter;
154 import org.apache.mina.core.future.CloseFuture;
155 import org.apache.mina.core.future.ConnectFuture;
156 import org.apache.mina.core.future.IoFuture;
157 import org.apache.mina.core.future.IoFutureListener;
158 import org.apache.mina.core.future.WriteFuture;
159 import org.apache.mina.core.service.IoConnector;
160 import org.apache.mina.core.session.IoSession;
161 import org.apache.mina.filter.codec.ProtocolCodecFilter;
162 import org.apache.mina.filter.codec.ProtocolEncoderException;
163 import org.apache.mina.filter.ssl.SslFilter;
164 import org.apache.mina.transport.socket.nio.NioSocketConnector;
165 import org.slf4j.Logger;
166 import org.slf4j.LoggerFactory;
167
168
169
170
171
172
173
174
175
176
177
178 public class LdapNetworkConnection extends AbstractLdapConnection implements LdapAsyncConnection
179 {
180
181 private static final Logger LOG = LoggerFactory.getLogger( LdapNetworkConnection.class );
182
183
184 private long timeout = LdapConnectionConfig.DEFAULT_TIMEOUT;
185
186
187 private LdapConnectionConfig config;
188
189
190 private IoConnector connector;
191
192
193 private ReentrantLock connectorMutex = new ReentrantLock();
194
195
196
197
198
199 private IoSession ldapSession;
200
201
202 private Map<Integer, ResponseFuture<? extends Response>> futureMap = new ConcurrentHashMap<Integer, ResponseFuture<? extends Response>>();
203
204
205 private List<String> supportedControls;
206
207
208 private Entry rootDse;
209
210
211 private AtomicBoolean authenticated = new AtomicBoolean( false );
212
213
214 private AtomicBoolean connected = new AtomicBoolean( false );
215
216
217
218
219 private List<ConnectionClosedEventListener> conCloseListeners;
220
221
222 private IoFilter ldapProtocolFilter = new ProtocolCodecFilter( codec.getProtocolCodecFactory() );
223
224
225 private static final String SSL_FILTER_KEY = "sslFilter";
226
227
228 private static final String EXCEPTION_KEY = "sessionException";
229
230
231
232 static final String TIME_OUT_ERROR = "TimeOut occurred";
233
234 static final String NO_RESPONSE_ERROR = "The response queue has been emptied, no response was found.";
235
236
237
238
239
240
241 public boolean isConnected()
242 {
243 return ( ldapSession != null ) && connected.get();
244 }
245
246
247
248
249
250 public boolean isAuthenticated()
251 {
252 return isConnected() && authenticated.get();
253 }
254
255
256
257
258
259
260
261
262 private void checkSession() throws InvalidConnectionException
263 {
264 if ( ldapSession == null )
265 {
266 throw new InvalidConnectionException( "Cannot connect on the server, the connection is null" );
267 }
268
269 if ( !connected.get() )
270 {
271 throw new InvalidConnectionException( "Cannot connect on the server, the connection is invalid" );
272 }
273 }
274
275
276 private void addToFutureMap( int messageId, ResponseFuture<? extends Response> future )
277 {
278 LOG.debug( "Adding <" + messageId + ", " + future.getClass().getName() + ">" );
279 futureMap.put( messageId, future );
280 }
281
282
283 private ResponseFuture<? extends Response> getFromFutureMap( int messageId )
284 {
285 ResponseFuture<? extends Response> future = futureMap.remove( messageId );
286
287 if ( future != null )
288 {
289 LOG.debug( "Removing <" + messageId + ", " + future.getClass().getName() + ">" );
290 }
291
292 return future;
293 }
294
295
296 private ResponseFuture<? extends Response> peekFromFutureMap( int messageId )
297 {
298 ResponseFuture<? extends Response> future = futureMap.get( messageId );
299
300
301 if ( future != null )
302 {
303 LOG.debug( "Getting <" + messageId + ", " + future.getClass().getName() + ">" );
304 }
305
306 return future;
307 }
308
309
310
311
312
313
314 static long getTimeout( long connectionTimoutInMS, int searchTimeLimitInSeconds )
315 {
316 if ( searchTimeLimitInSeconds < 0 )
317 {
318 return connectionTimoutInMS;
319 }
320 else if ( searchTimeLimitInSeconds == 0 )
321 {
322 return Long.MAX_VALUE;
323 }
324 else
325 {
326 long searchTimeLimitInMS = searchTimeLimitInSeconds * 1000L;
327 return Math.max( searchTimeLimitInMS, connectionTimoutInMS );
328 }
329 }
330
331
332
333
334
335
336
337 public LdapNetworkConnection()
338 {
339 this( null, -1, false );
340 }
341
342
343
344
345
346
347
348
349 public LdapNetworkConnection( LdapConnectionConfig config )
350 {
351 this( config, LdapApiServiceFactory.getSingleton() );
352 }
353
354
355 public LdapNetworkConnection( LdapConnectionConfig config, LdapApiService ldapApiService )
356 {
357 super( ldapApiService );
358 this.config = config;
359
360 if ( config.getBinaryAttributeDetector() == null )
361 {
362 config.setBinaryAttributeDetector( new DefaultConfigurableBinaryAttributeDetector() );
363 }
364 }
365
366
367
368
369
370
371
372
373 public LdapNetworkConnection( boolean useSsl )
374 {
375 this( null, -1, useSsl );
376 }
377
378
379 public LdapNetworkConnection( boolean useSsl, LdapApiService ldapApiService )
380 {
381 this( null, -1, useSsl, ldapApiService );
382 }
383
384
385
386
387
388
389
390
391
392 public LdapNetworkConnection( String server )
393 {
394 this( server, -1, false );
395 }
396
397
398 public LdapNetworkConnection( String server, LdapApiService ldapApiService )
399 {
400 this( server, -1, false, ldapApiService );
401 }
402
403
404
405
406
407
408
409
410
411
412
413 public LdapNetworkConnection( String server, boolean useSsl )
414 {
415 this( server, -1, useSsl );
416 }
417
418
419 public LdapNetworkConnection( String server, boolean useSsl, LdapApiService ldapApiService )
420 {
421 this( server, -1, useSsl, ldapApiService );
422 }
423
424
425
426
427
428
429
430
431
432 public LdapNetworkConnection( String server, int port )
433 {
434 this( server, port, false );
435 }
436
437
438 public LdapNetworkConnection( String server, int port, LdapApiService ldapApiService )
439 {
440 this( server, port, false, ldapApiService );
441 }
442
443
444
445
446
447
448
449
450
451
452
453
454 public LdapNetworkConnection( String server, int port, boolean useSsl )
455 {
456 this( buildConfig( server, port, useSsl ) );
457 }
458
459
460 public LdapNetworkConnection( String server, int port, boolean useSsl, LdapApiService ldapApiService )
461 {
462 this( buildConfig( server, port, useSsl ), ldapApiService );
463 }
464
465
466 private static LdapConnectionConfig buildConfig( String server, int port, boolean useSsl )
467 {
468 LdapConnectionConfig config = new LdapConnectionConfig();
469 config.setUseSsl( useSsl );
470
471 if ( port != -1 )
472 {
473 config.setLdapPort( port );
474 }
475 else
476 {
477 if ( useSsl )
478 {
479 config.setLdapPort( config.getDefaultLdapsPort() );
480 }
481 else
482 {
483 config.setLdapPort( config.getDefaultLdapPort() );
484 }
485 }
486
487
488 if ( Strings.isEmpty( server ) )
489 {
490 config.setLdapHost( "localhost" );
491 }
492 else
493 {
494 config.setLdapHost( server );
495 }
496
497 config.setBinaryAttributeDetector( new DefaultConfigurableBinaryAttributeDetector() );
498
499 return config;
500 }
501
502
503
504
505
506
507 public boolean connect() throws LdapException
508 {
509 if ( ( ldapSession != null ) && connected.get() )
510 {
511
512 return true;
513 }
514
515
516 if ( connector == null )
517 {
518
519 connector = new NioSocketConnector( 1 );
520
521
522 connector.getFilterChain().addLast( "ldapCodec", ldapProtocolFilter );
523
524
525 if ( config.isUseSsl() )
526 {
527 addSslFilter();
528 }
529
530
531 connector.setHandler( this );
532 }
533
534
535 SocketAddress address = new InetSocketAddress( config.getLdapHost(), config.getLdapPort() );
536
537
538 ConnectFuture connectionFuture = connector.connect( address );
539
540
541 try
542 {
543 connectionFuture.await( timeout );
544 }
545 catch ( InterruptedException e )
546 {
547 connector = null;
548 LOG.debug( "Interrupted while waiting for connection to establish with server {}:{}", config.getLdapHost(),
549 config.getLdapPort(), e );
550 throw new LdapOtherException( e.getMessage(), e );
551 }
552
553 boolean isConnected = connectionFuture.isConnected();
554
555 if ( !isConnected )
556 {
557
558 try
559 {
560 close();
561 }
562 catch ( IOException ioe )
563 {
564
565 }
566
567 Throwable e = connectionFuture.getException();
568
569 if ( e != null )
570 {
571 StringBuilder message = new StringBuilder( "Cannot connect on the server: " );
572
573
574
575 if ( ( e instanceof UnresolvedAddressException ) && ( e.getMessage() == null ) )
576 {
577 message.append( "Hostname '" );
578 message.append( config.getLdapHost() );
579 message.append( "' could not be resolved." );
580 throw new InvalidConnectionException( message.toString(), e );
581 }
582
583
584 message.append( e.getMessage() );
585 throw new InvalidConnectionException( message.toString(), e );
586 }
587
588 return false;
589 }
590
591
592 CloseFuture closeFuture = connectionFuture.getSession().getCloseFuture();
593
594
595 closeFuture.addListener( new IoFutureListener<IoFuture>()
596 {
597 public void operationComplete( IoFuture future )
598 {
599
600 LOG.debug( "received a NoD, closing everything" );
601
602 for ( int messageId : futureMap.keySet() )
603 {
604 ResponseFuture<?> responseFuture = futureMap.get( messageId );
605 LOG.debug( "closing {}", responseFuture );
606
607 responseFuture.cancel();
608
609 try
610 {
611 if ( responseFuture instanceof AddFuture )
612 {
613 ( ( AddFuture ) responseFuture ).set( AddNoDResponse.PROTOCOLERROR );
614 }
615 else if ( responseFuture instanceof BindFuture )
616 {
617 ( ( BindFuture ) responseFuture ).set( BindNoDResponse.PROTOCOLERROR );
618 }
619 else if ( responseFuture instanceof CompareFuture )
620 {
621 ( ( CompareFuture ) responseFuture ).set( CompareNoDResponse.PROTOCOLERROR );
622 }
623 else if ( responseFuture instanceof DeleteFuture )
624 {
625 ( ( DeleteFuture ) responseFuture ).set( DeleteNoDResponse.PROTOCOLERROR );
626 }
627 else if ( responseFuture instanceof ExtendedFuture )
628 {
629 ( ( ExtendedFuture ) responseFuture ).set( ExtendedNoDResponse.PROTOCOLERROR );
630 }
631 else if ( responseFuture instanceof ModifyFuture )
632 {
633 ( ( ModifyFuture ) responseFuture ).set( ModifyNoDResponse.PROTOCOLERROR );
634 }
635 else if ( responseFuture instanceof ModifyDnFuture )
636 {
637 ( ( ModifyDnFuture ) responseFuture ).set( ModifyDnNoDResponse.PROTOCOLERROR );
638 }
639 else if ( responseFuture instanceof SearchFuture )
640 {
641 ( ( SearchFuture ) responseFuture ).set( SearchNoDResponse.PROTOCOLERROR );
642 }
643 }
644 catch ( ExecutionException e )
645 {
646 LOG.error( "Error while processing the NoD for {}", responseFuture );
647 }
648 catch ( InterruptedException e )
649 {
650 LOG.error( "Error while processing the NoD for {}", responseFuture );
651 }
652
653 futureMap.remove( messageId );
654 }
655
656 futureMap.clear();
657 }
658 } );
659
660
661 ldapSession = connectionFuture.getSession();
662 connected.set( true );
663
664
665 @SuppressWarnings("unchecked")
666 LdapMessageContainer<MessageDecorator<? extends Message>> container =
667 ( LdapMessageContainer<MessageDecorator<? extends Message>> ) ldapSession
668 .getAttribute( LdapDecoder.MESSAGE_CONTAINER_ATTR );
669
670 if ( container != null )
671 {
672 if ( schemaManager != null )
673 {
674 if ( !( container.getBinaryAttributeDetector() instanceof SchemaBinaryAttributeDetector ) )
675 {
676 container.setBinaryAttributeDetector( new SchemaBinaryAttributeDetector( schemaManager ) );
677 }
678 }
679 }
680 else
681 {
682 BinaryAttributeDetector atDetector = new DefaultConfigurableBinaryAttributeDetector();
683
684 if ( schemaManager != null )
685 {
686 atDetector = new SchemaBinaryAttributeDetector( schemaManager );
687 }
688
689 ldapSession.setAttribute( LdapDecoder.MESSAGE_CONTAINER_ATTR,
690 new LdapMessageContainer<MessageDecorator<? extends Message>>( codec, atDetector ) );
691 }
692
693
694 messageId.set( 0 );
695
696
697 return true;
698 }
699
700
701
702
703
704 public void close() throws IOException
705 {
706
707 if ( ( ldapSession != null ) && connected.get() )
708 {
709 ldapSession.close( true );
710 connected.set( false );
711 }
712
713
714
715 connectorMutex.lock();
716
717 try
718 {
719 if ( connector != null )
720 {
721 connector.dispose();
722 connector = null;
723 }
724 }
725 finally
726 {
727 connectorMutex.unlock();
728 }
729
730
731 messageId.set( 0 );
732 }
733
734
735
736
737
738
739
740
741 public void add( Entry entry ) throws LdapException
742 {
743 if ( entry == null )
744 {
745 String msg = "Cannot add an empty entry";
746 LOG.debug( msg );
747 throw new IllegalArgumentException( msg );
748 }
749
750 AddRequest addRequest = new AddRequestImpl();
751 addRequest.setEntry( entry );
752
753 AddResponse addResponse = add( addRequest );
754
755 processResponse( addResponse );
756 }
757
758
759
760
761
762 public AddFuture addAsync( Entry entry ) throws LdapException
763 {
764 if ( entry == null )
765 {
766 String msg = "Cannot add null entry";
767 LOG.debug( msg );
768 throw new IllegalArgumentException( msg );
769 }
770
771 AddRequest addRequest = new AddRequestImpl();
772 addRequest.setEntry( entry );
773
774 return addAsync( addRequest );
775 }
776
777
778
779
780
781 public AddResponse add( AddRequest addRequest ) throws LdapException
782 {
783 if ( addRequest == null )
784 {
785 String msg = "Cannot process a null addRequest";
786 LOG.debug( msg );
787 throw new IllegalArgumentException( msg );
788 }
789
790 if ( addRequest.getEntry() == null )
791 {
792 String msg = "Cannot add a null entry";
793 LOG.debug( msg );
794 throw new IllegalArgumentException( msg );
795 }
796
797 AddFuture addFuture = addAsync( addRequest );
798
799
800 try
801 {
802
803
804 AddResponse addResponse = addFuture.get( timeout, TimeUnit.MILLISECONDS );
805
806 if ( addResponse == null )
807 {
808
809 LOG.error( "Add failed : timeout occurred" );
810 throw new LdapException( TIME_OUT_ERROR );
811 }
812
813 if ( addResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
814 {
815
816 LOG.debug( "Add successful : {}", addResponse );
817 }
818 else
819 {
820
821 LOG.debug( "Add failed : {}", addResponse );
822 }
823
824 return addResponse;
825 }
826 catch ( TimeoutException te )
827 {
828
829 if ( !addFuture.isCancelled() )
830 {
831 abandon( addRequest.getMessageId() );
832 }
833
834
835 LOG.error( "Add failed : timeout occurred" );
836 throw new LdapException( TIME_OUT_ERROR, te );
837 }
838 catch ( Exception ie )
839 {
840
841 LOG.error( NO_RESPONSE_ERROR, ie );
842
843
844 if ( !addFuture.isCancelled() )
845 {
846 abandon( addRequest.getMessageId() );
847 }
848
849 throw new LdapException( NO_RESPONSE_ERROR, ie );
850 }
851 }
852
853
854
855
856
857 public AddFuture addAsync( AddRequest addRequest ) throws LdapException
858 {
859 if ( addRequest == null )
860 {
861 String msg = "Cannot process a null addRequest";
862 LOG.debug( msg );
863 throw new IllegalArgumentException( msg );
864 }
865
866 if ( addRequest.getEntry() == null )
867 {
868 String msg = "Cannot add a null entry";
869 LOG.debug( msg );
870 throw new IllegalArgumentException( msg );
871 }
872
873 checkSession();
874
875 int newId = messageId.incrementAndGet();
876
877 addRequest.setMessageId( newId );
878 AddFuture addFuture = new AddFuture( this, newId );
879 addToFutureMap( newId, addFuture );
880
881
882 writeRequest( addRequest );
883
884
885 return addFuture;
886 }
887
888
889
890
891
892
893
894 public void abandon( int messageId )
895 {
896 if ( messageId < 0 )
897 {
898 String msg = "Cannot abandon a negative message ID";
899 LOG.debug( msg );
900 throw new IllegalArgumentException( msg );
901 }
902
903 AbandonRequest abandonRequest = new AbandonRequestImpl();
904 abandonRequest.setAbandoned( messageId );
905
906 abandonInternal( abandonRequest );
907 }
908
909
910
911
912
913 public void abandon( AbandonRequest abandonRequest )
914 {
915 if ( abandonRequest == null )
916 {
917 String msg = "Cannot process a null abandonRequest";
918 LOG.debug( msg );
919 throw new IllegalArgumentException( msg );
920 }
921
922 abandonInternal( abandonRequest );
923 }
924
925
926
927
928
929 private void abandonInternal( AbandonRequest abandonRequest )
930 {
931 LOG.debug( "Sending request \n{}", abandonRequest );
932
933 int newId = messageId.incrementAndGet();
934 abandonRequest.setMessageId( newId );
935
936
937 ldapSession.write( abandonRequest );
938
939
940 int abandonId = abandonRequest.getAbandoned();
941
942 ResponseFuture<? extends Response> rf = getFromFutureMap( abandonId );
943
944
945
946
947 if ( rf != null )
948 {
949 LOG.debug( "sending cancel signal to future" );
950 rf.cancel( true );
951 }
952 else
953 {
954
955 LOG
956 .error(
957 "There is no future associated with operation message ID {}, perhaps the operation would have been completed",
958 abandonId );
959 }
960 }
961
962
963
964
965
966 public void bind() throws LdapException
967 {
968 LOG.debug( "Bind request" );
969
970
971 BindRequest bindRequest = createBindRequest( config.getName(), Strings.getBytesUtf8( config.getCredentials() ) );
972
973 BindResponse bindResponse = bind( bindRequest );
974
975 processResponse( bindResponse );
976 }
977
978
979
980
981
982 public void anonymousBind() throws LdapException
983 {
984 LOG.debug( "Anonymous Bind request" );
985
986
987 BindRequest bindRequest = createBindRequest( StringConstants.EMPTY, StringConstants.EMPTY_BYTES );
988
989 BindResponse bindResponse = bind( bindRequest );
990
991 processResponse( bindResponse );
992 }
993
994
995
996
997
998 public BindFuture bindAsync() throws LdapException
999 {
1000 LOG.debug( "Asynchronous Bind request" );
1001
1002
1003 BindRequest bindRequest = createBindRequest( config.getName(), Strings.getBytesUtf8( config.getCredentials() ) );
1004
1005 return bindAsync( bindRequest );
1006 }
1007
1008
1009
1010
1011
1012 public BindFuture anonymousBindAsync() throws LdapException
1013 {
1014 LOG.debug( "Anonymous asynchronous Bind request" );
1015
1016
1017 BindRequest bindRequest = createBindRequest( StringConstants.EMPTY, StringConstants.EMPTY_BYTES );
1018
1019 return bindAsync( bindRequest );
1020 }
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031 public BindFuture bindAsync( String name ) throws LdapException
1032 {
1033 LOG.debug( "Bind request : {}", name );
1034
1035
1036 BindRequest bindRequest = createBindRequest( name, StringConstants.EMPTY_BYTES );
1037
1038 return bindAsync( bindRequest );
1039 }
1040
1041
1042
1043
1044
1045 public BindFuture bindAsync( String name, String credentials ) throws LdapException
1046 {
1047 LOG.debug( "Bind request : {}", name );
1048
1049
1050 if ( Strings.isEmpty( credentials ) && Strings.isNotEmpty( name ) )
1051 {
1052 LOG.debug( "The password is missing" );
1053 throw new LdapAuthenticationException( "The password is missing" );
1054 }
1055
1056
1057 BindRequest bindRequest = createBindRequest( name, Strings.getBytesUtf8( credentials ) );
1058
1059 return bindAsync( bindRequest );
1060 }
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071 public BindFuture bindAsync( Dn name ) throws LdapException
1072 {
1073 LOG.debug( "Bind request : {}", name );
1074
1075
1076 BindRequest bindRequest = createBindRequest( name, StringConstants.EMPTY_BYTES );
1077
1078 return bindAsync( bindRequest );
1079 }
1080
1081
1082
1083
1084
1085 public BindFuture bindAsync( Dn name, String credentials ) throws LdapException
1086 {
1087 LOG.debug( "Bind request : {}", name );
1088
1089
1090 if ( Strings.isEmpty( credentials ) && ( !Dn.EMPTY_DN.equals( name ) ) )
1091 {
1092 LOG.debug( "The password is missing" );
1093 throw new LdapAuthenticationException( "The password is missing" );
1094 }
1095
1096
1097 BindRequest bindRequest = createBindRequest( name, Strings.getBytesUtf8( credentials ) );
1098
1099 return bindAsync( bindRequest );
1100 }
1101
1102
1103
1104
1105
1106 public BindResponse bind( BindRequest bindRequest ) throws LdapException
1107 {
1108 if ( bindRequest == null )
1109 {
1110 String msg = "Cannot process a null bindRequest";
1111 LOG.debug( msg );
1112 throw new IllegalArgumentException( msg );
1113 }
1114
1115 BindFuture bindFuture = bindAsync( bindRequest );
1116
1117
1118 try
1119 {
1120
1121
1122 BindResponse bindResponse = bindFuture.get( timeout, TimeUnit.MILLISECONDS );
1123
1124 if ( bindResponse == null )
1125 {
1126
1127 LOG.error( "Bind failed : timeout occurred" );
1128 throw new LdapException( TIME_OUT_ERROR );
1129 }
1130
1131 if ( bindResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
1132 {
1133 authenticated.set( true );
1134
1135
1136 LOG.debug( "Bind successful : {}", bindResponse );
1137 }
1138 else
1139 {
1140
1141 LOG.debug( "Bind failed : {}", bindResponse );
1142 }
1143
1144 return bindResponse;
1145 }
1146 catch ( TimeoutException te )
1147 {
1148
1149 LOG.error( "Bind failed : timeout occurred" );
1150 throw new LdapException( TIME_OUT_ERROR, te );
1151 }
1152 catch ( Exception ie )
1153 {
1154
1155 LOG.error( NO_RESPONSE_ERROR, ie );
1156 throw new LdapException( NO_RESPONSE_ERROR, ie );
1157 }
1158 }
1159
1160
1161
1162
1163
1164 private BindRequest createBindRequest( String name, byte[] credentials ) throws LdapException
1165 {
1166 return createBindRequest( name, credentials, null, ( Control[] ) null );
1167 }
1168
1169
1170
1171
1172
1173 private BindRequest createBindRequest( Dn name, byte[] credentials ) throws LdapException
1174 {
1175 return createBindRequest( name.getName(), credentials, null, ( Control[] ) null );
1176 }
1177
1178
1179
1180
1181
1182 public BindFuture bindAsync( BindRequest bindRequest ) throws LdapException
1183 {
1184 if ( bindRequest == null )
1185 {
1186 String msg = "Cannot process a null bindRequest";
1187 LOG.debug( msg );
1188 throw new IllegalArgumentException( msg );
1189 }
1190
1191
1192 authenticated.set( false );
1193
1194
1195 connect();
1196
1197
1198 if ( config.isUseTls() && !config.isUseSsl() )
1199 {
1200 startTls();
1201 }
1202
1203
1204 checkSession();
1205
1206
1207 int newId = messageId.incrementAndGet();
1208 bindRequest.setMessageId( newId );
1209
1210 LOG.debug( "Sending request \n{}", bindRequest );
1211
1212
1213 BindFuture bindFuture = new BindFuture( this, newId );
1214
1215 addToFutureMap( newId, bindFuture );
1216
1217 writeRequest( bindRequest );
1218
1219
1220 return bindFuture;
1221 }
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232 public BindResponse bindSaslPlain( String authcid, String credentials ) throws LdapException
1233 {
1234 return bindSaslPlain( null, authcid, credentials );
1235 }
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247 public BindResponse bindSaslPlain( String authzid, String authcid, String credentials ) throws LdapException
1248 {
1249 LOG.debug( "SASL PLAIN Bind request" );
1250
1251
1252 SaslPlainRequest saslRequest = new SaslPlainRequest();
1253 saslRequest.setAuthorizationId( authzid );
1254 saslRequest.setUsername( authcid );
1255 saslRequest.setCredentials( credentials );
1256
1257 BindFuture bindFuture = bindAsync( saslRequest );
1258
1259
1260 try
1261 {
1262
1263
1264 BindResponse bindResponse = bindFuture.get( timeout, TimeUnit.MILLISECONDS );
1265
1266 if ( bindResponse == null )
1267 {
1268
1269 LOG.error( "Bind failed : timeout occurred" );
1270 throw new LdapException( TIME_OUT_ERROR );
1271 }
1272
1273 if ( bindResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
1274 {
1275 authenticated.set( true );
1276
1277
1278 LOG.debug( "Bind successful : {}", bindResponse );
1279 }
1280 else
1281 {
1282
1283 LOG.debug( "Bind failed : {}", bindResponse );
1284 }
1285
1286 return bindResponse;
1287 }
1288 catch ( TimeoutException te )
1289 {
1290
1291 LOG.error( "Bind failed : timeout occurred" );
1292 throw new LdapException( TIME_OUT_ERROR, te );
1293 }
1294 catch ( Exception ie )
1295 {
1296
1297 LOG.error( NO_RESPONSE_ERROR, ie );
1298
1299 throw new LdapException( NO_RESPONSE_ERROR, ie );
1300 }
1301 }
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311 public BindResponse bind( SaslCramMd5Request request ) throws LdapException
1312 {
1313 if ( request == null )
1314 {
1315 String msg = "Cannot process a null request";
1316 LOG.debug( msg );
1317 throw new IllegalArgumentException( msg );
1318 }
1319
1320 BindFuture bindFuture = bindAsync( request );
1321
1322
1323 try
1324 {
1325
1326
1327 BindResponse bindResponse = bindFuture.get( timeout, TimeUnit.MILLISECONDS );
1328
1329 if ( bindResponse == null )
1330 {
1331
1332 LOG.error( "Bind failed : timeout occurred" );
1333 throw new LdapException( TIME_OUT_ERROR );
1334 }
1335
1336 if ( bindResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
1337 {
1338 authenticated.set( true );
1339
1340
1341 LOG.debug( "Bind successful : {}", bindResponse );
1342 }
1343 else
1344 {
1345
1346 LOG.debug( "Bind failed : {}", bindResponse );
1347 }
1348
1349 return bindResponse;
1350 }
1351 catch ( TimeoutException te )
1352 {
1353
1354 LOG.error( "Bind failed : timeout occurred" );
1355 throw new LdapException( TIME_OUT_ERROR, te );
1356 }
1357 catch ( Exception ie )
1358 {
1359
1360 LOG.error( NO_RESPONSE_ERROR, ie );
1361
1362 throw new LdapException( NO_RESPONSE_ERROR, ie );
1363 }
1364 }
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374 public BindFuture bindAsync( SaslRequest request )
1375 throws LdapException
1376 {
1377 return bindSasl( request );
1378 }
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388 public BindResponse bind( SaslDigestMd5Request request ) throws LdapException
1389 {
1390 if ( request == null )
1391 {
1392 String msg = "Cannot process a null request";
1393 LOG.debug( msg );
1394 throw new IllegalArgumentException( msg );
1395 }
1396
1397 BindFuture bindFuture = bindAsync( request );
1398
1399
1400 try
1401 {
1402
1403
1404 BindResponse bindResponse = bindFuture.get( timeout, TimeUnit.MILLISECONDS );
1405
1406 if ( bindResponse == null )
1407 {
1408
1409 LOG.error( "Bind failed : timeout occurred" );
1410 throw new LdapException( TIME_OUT_ERROR );
1411 }
1412
1413 if ( bindResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
1414 {
1415 authenticated.set( true );
1416
1417
1418 LOG.debug( "Bind successful : {}", bindResponse );
1419 }
1420 else
1421 {
1422
1423 LOG.debug( "Bind failed : {}", bindResponse );
1424 }
1425
1426 return bindResponse;
1427 }
1428 catch ( TimeoutException te )
1429 {
1430
1431 LOG.error( "Bind failed : timeout occurred" );
1432 throw new LdapException( TIME_OUT_ERROR, te );
1433 }
1434 catch ( Exception ie )
1435 {
1436
1437 LOG.error( NO_RESPONSE_ERROR, ie );
1438
1439 throw new LdapException( NO_RESPONSE_ERROR, ie );
1440 }
1441 }
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451 public BindResponse bind( SaslGssApiRequest request ) throws LdapException
1452 {
1453 if ( request == null )
1454 {
1455 String msg = "Cannot process a null request";
1456 LOG.debug( msg );
1457 throw new IllegalArgumentException( msg );
1458 }
1459
1460 BindFuture bindFuture = bindAsync( request );
1461
1462
1463 try
1464 {
1465
1466
1467 BindResponse bindResponse = bindFuture.get( timeout, TimeUnit.MILLISECONDS );
1468
1469 if ( bindResponse == null )
1470 {
1471
1472 LOG.error( "Bind failed : timeout occurred" );
1473 throw new LdapException( TIME_OUT_ERROR );
1474 }
1475
1476 if ( bindResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
1477 {
1478 authenticated.set( true );
1479
1480
1481 LOG.debug( "Bind successful : {}", bindResponse );
1482 }
1483 else
1484 {
1485
1486 LOG.debug( "Bind failed : {}", bindResponse );
1487 }
1488
1489 return bindResponse;
1490 }
1491 catch ( TimeoutException te )
1492 {
1493
1494 LOG.error( "Bind failed : timeout occurred" );
1495 throw new LdapException( TIME_OUT_ERROR, te );
1496 }
1497 catch ( Exception ie )
1498 {
1499
1500 LOG.error( NO_RESPONSE_ERROR, ie );
1501
1502 throw new LdapException( NO_RESPONSE_ERROR, ie );
1503 }
1504 }
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514 public BindFuture bindAsync( SaslGssApiRequest request )
1515 throws LdapException
1516 {
1517
1518 if ( request.getKrb5ConfFilePath() != null )
1519 {
1520
1521 System.setProperty( "java.security.krb5.conf", request.getKrb5ConfFilePath() );
1522 }
1523 else if ( ( request.getRealmName() != null ) && ( request.getKdcHost() != null )
1524 && ( request.getKdcPort() != 0 ) )
1525 {
1526 try
1527 {
1528
1529 String krb5ConfPath = createKrb5ConfFile( request.getRealmName(), request.getKdcHost(),
1530 request.getKdcPort() );
1531 System.setProperty( "java.security.krb5.conf", krb5ConfPath );
1532 }
1533 catch ( IOException ioe )
1534 {
1535 throw new LdapException( ioe );
1536 }
1537 }
1538 else
1539 {
1540
1541 System.clearProperty( "java.security.krb5.conf" );
1542 }
1543
1544
1545 if ( request.getLoginModuleConfiguration() != null )
1546 {
1547
1548 Configuration.setConfiguration( request.getLoginModuleConfiguration() );
1549 }
1550 else
1551 {
1552
1553 Configuration.setConfiguration( new Krb5LoginConfiguration() );
1554 }
1555
1556 try
1557 {
1558 System.setProperty( "javax.security.auth.useSubjectCredsOnly", "true" );
1559 LoginContext loginContext = new LoginContext( request.getLoginContextName(),
1560 new SaslCallbackHandler( request ) );
1561 loginContext.login();
1562
1563 final SaslGssApiRequest requetFinal = request;
1564 return ( BindFuture ) Subject.doAs( loginContext.getSubject(), new PrivilegedExceptionAction<Object>()
1565 {
1566 public Object run() throws Exception
1567 {
1568 return bindSasl( requetFinal );
1569 }
1570 } );
1571 }
1572 catch ( Exception e )
1573 {
1574 throw new LdapException( e );
1575 }
1576 }
1577
1578
1579
1580
1581
1582 public EntryCursor search( Dn baseDn, String filter, SearchScope scope, String... attributes )
1583 throws LdapException
1584 {
1585 if ( baseDn == null )
1586 {
1587 LOG.debug( "received a null dn for a search" );
1588 throw new IllegalArgumentException( "The base Dn cannot be null" );
1589 }
1590
1591
1592 SearchRequest searchRequest = new SearchRequestImpl();
1593
1594 searchRequest.setBase( baseDn );
1595 searchRequest.setFilter( filter );
1596 searchRequest.setScope( scope );
1597 searchRequest.addAttributes( attributes );
1598 searchRequest.setDerefAliases( AliasDerefMode.DEREF_ALWAYS );
1599
1600
1601 return new EntryCursorImpl( search( searchRequest ) );
1602 }
1603
1604
1605
1606
1607
1608 public EntryCursor search( String baseDn, String filter, SearchScope scope, String... attributes )
1609 throws LdapException
1610 {
1611 return search( new Dn( baseDn ), filter, scope, attributes );
1612 }
1613
1614
1615
1616
1617
1618 public SearchFuture searchAsync( Dn baseDn, String filter, SearchScope scope, String... attributes )
1619 throws LdapException
1620 {
1621
1622 SearchRequest searchRequest = new SearchRequestImpl();
1623
1624 searchRequest.setBase( baseDn );
1625 searchRequest.setFilter( filter );
1626 searchRequest.setScope( scope );
1627 searchRequest.addAttributes( attributes );
1628 searchRequest.setDerefAliases( AliasDerefMode.DEREF_ALWAYS );
1629
1630
1631 return searchAsync( searchRequest );
1632 }
1633
1634
1635
1636
1637
1638 public SearchFuture searchAsync( String baseDn, String filter, SearchScope scope, String... attributes )
1639 throws LdapException
1640 {
1641 return searchAsync( new Dn( baseDn ), filter, scope, attributes );
1642 }
1643
1644
1645
1646
1647
1648 public SearchFuture searchAsync( SearchRequest searchRequest ) throws LdapException
1649 {
1650 if ( searchRequest == null )
1651 {
1652 String msg = "Cannot process a null searchRequest";
1653 LOG.debug( msg );
1654 throw new IllegalArgumentException( msg );
1655 }
1656
1657 if ( searchRequest.getBase() == null )
1658 {
1659 String msg = "Cannot process a searchRequest which base DN is null";
1660 LOG.debug( msg );
1661 throw new IllegalArgumentException( msg );
1662 }
1663
1664
1665 checkSession();
1666
1667 int newId = messageId.incrementAndGet();
1668 searchRequest.setMessageId( newId );
1669
1670 if ( searchRequest.isIgnoreReferrals() )
1671 {
1672
1673 searchRequest.addControl( new ManageDsaITImpl() );
1674 }
1675
1676 LOG.debug( "Sending request \n{}", searchRequest );
1677
1678 SearchFuture searchFuture = new SearchFuture( this, searchRequest.getMessageId() );
1679 addToFutureMap( searchRequest.getMessageId(), searchFuture );
1680
1681
1682 writeRequest( searchRequest );
1683
1684
1685 if ( searchFuture.isCancelled() )
1686 {
1687
1688 throw new LdapException( searchFuture.getCause() );
1689 }
1690
1691
1692 return searchFuture;
1693 }
1694
1695
1696
1697
1698
1699 public SearchCursor search( SearchRequest searchRequest ) throws LdapException
1700 {
1701 if ( searchRequest == null )
1702 {
1703 String msg = "Cannot process a null searchRequest";
1704 LOG.debug( msg );
1705 throw new IllegalArgumentException( msg );
1706 }
1707
1708 SearchFuture searchFuture = searchAsync( searchRequest );
1709
1710 long timeout = getTimeout( this.timeout, searchRequest.getTimeLimit() );
1711
1712 return new SearchCursorImpl( searchFuture, timeout, TimeUnit.MILLISECONDS );
1713 }
1714
1715
1716
1717
1718
1719
1720
1721
1722 public void unBind() throws LdapException
1723 {
1724
1725 checkSession();
1726
1727
1728
1729 int newId = messageId.incrementAndGet();
1730
1731
1732 UnbindRequest unbindRequest = new UnbindRequestImpl();
1733 unbindRequest.setMessageId( newId );
1734
1735 LOG.debug( "Sending Unbind request \n{}", unbindRequest );
1736
1737
1738
1739 ldapSession.write( unbindRequest );
1740
1741
1742
1743
1744
1745 authenticated.set( false );
1746
1747
1748 clearMaps();
1749
1750
1751 if ( ldapSession != null )
1752 {
1753 CloseFuture closeFuture = ldapSession.close( true );
1754
1755 LOG.debug( "waiting for closeFuture" );
1756 closeFuture.awaitUninterruptibly();
1757 LOG.debug( "closeFuture done" );
1758 connected.set( false );
1759 }
1760
1761
1762 messageId.set( 0 );
1763
1764
1765 LOG.debug( "Unbind successful" );
1766 }
1767
1768
1769
1770
1771
1772
1773
1774 public void setConnector( IoConnector connector )
1775 {
1776 this.connector = connector;
1777 }
1778
1779
1780
1781
1782
1783 public void setTimeOut( long timeout )
1784 {
1785 if ( timeout <= 0 )
1786 {
1787 this.timeout = Long.MAX_VALUE;
1788 }
1789 else
1790 {
1791 this.timeout = timeout;
1792 }
1793 }
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803 @Override
1804 public void exceptionCaught( IoSession session, Throwable cause ) throws Exception
1805 {
1806 LOG.warn( cause.getMessage(), cause );
1807 session.setAttribute( EXCEPTION_KEY, cause );
1808
1809 if ( cause instanceof ProtocolEncoderException )
1810 {
1811 Throwable realCause = ( ( ProtocolEncoderException ) cause ).getCause();
1812
1813 if ( realCause instanceof MessageEncoderException )
1814 {
1815 int messageId = ( ( MessageEncoderException ) realCause ).getMessageId();
1816
1817 ResponseFuture<?> response = futureMap.get( messageId );
1818 response.cancel( true );
1819 response.setCause( realCause );
1820 }
1821 }
1822
1823 session.close( true );
1824 }
1825
1826
1827
1828
1829
1830 private boolean isNoticeOfDisconnect( Message message )
1831 {
1832 if ( message instanceof ExtendedResponse )
1833 {
1834 ExtendedResponse response = ( ExtendedResponse ) message;
1835
1836 if ( response.getResponseName().equals( NoticeOfDisconnect.EXTENSION_OID ) )
1837 {
1838 return true;
1839 }
1840 }
1841
1842 return false;
1843 }
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854 @Override
1855 public void messageReceived( IoSession session, Object message ) throws Exception
1856 {
1857
1858 Message response = ( Message ) message;
1859 LOG.debug( "-------> {} Message received <-------", response );
1860 int messageId = response.getMessageId();
1861
1862
1863
1864 ResponseFuture<? extends Response> responseFuture = peekFromFutureMap( messageId );
1865
1866 boolean isNoD = isNoticeOfDisconnect( response );
1867
1868 if ( ( responseFuture == null ) && !isNoD )
1869 {
1870 LOG.info( "There is no future associated with the messageId {}, ignoring the message", messageId );
1871 return;
1872 }
1873
1874 if ( isNoD )
1875 {
1876
1877 session.close( true );
1878
1879 return;
1880 }
1881
1882 switch ( response.getType() )
1883 {
1884 case ADD_RESPONSE:
1885
1886 AddResponse addResponse = ( AddResponse ) response;
1887
1888 AddFuture addFuture = ( AddFuture ) responseFuture;
1889
1890
1891 if ( LOG.isDebugEnabled() )
1892 {
1893 if ( addResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
1894 {
1895
1896 LOG.debug( "Add successful : {}", addResponse );
1897 }
1898 else
1899 {
1900
1901 LOG.debug( "Add failed : {}", addResponse );
1902 }
1903 }
1904
1905
1906 addFuture.set( addResponse );
1907
1908
1909 removeFromFutureMaps( messageId );
1910
1911 break;
1912
1913 case BIND_RESPONSE:
1914
1915 BindResponse bindResponse = ( BindResponse ) response;
1916
1917 BindFuture bindFuture = ( BindFuture ) responseFuture;
1918
1919
1920 if ( bindResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
1921 {
1922 authenticated.set( true );
1923
1924
1925 LOG.debug( "Bind successful : {}", bindResponse );
1926 }
1927 else
1928 {
1929
1930 LOG.debug( "Bind failed : {}", bindResponse );
1931 }
1932
1933
1934 bindFuture.set( bindResponse );
1935
1936
1937 removeFromFutureMaps( messageId );
1938
1939 break;
1940
1941 case COMPARE_RESPONSE:
1942
1943 CompareResponse compareResponse = ( CompareResponse ) response;
1944
1945 CompareFuture compareFuture = ( CompareFuture ) responseFuture;
1946
1947
1948 if ( LOG.isDebugEnabled() )
1949 {
1950 if ( compareResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
1951 {
1952
1953 LOG.debug( "Compare successful : {}", compareResponse );
1954 }
1955 else
1956 {
1957
1958 LOG.debug( "Compare failed : {}", compareResponse );
1959 }
1960 }
1961
1962
1963 compareFuture.set( compareResponse );
1964
1965
1966 removeFromFutureMaps( messageId );
1967
1968 break;
1969
1970 case DEL_RESPONSE:
1971
1972 DeleteResponse deleteResponse = ( DeleteResponse ) response;
1973
1974 DeleteFuture deleteFuture = ( DeleteFuture ) responseFuture;
1975
1976 if ( LOG.isDebugEnabled() )
1977 {
1978 if ( deleteResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
1979 {
1980
1981 LOG.debug( "Delete successful : {}", deleteResponse );
1982 }
1983 else
1984 {
1985
1986 LOG.debug( "Delete failed : {}", deleteResponse );
1987 }
1988 }
1989
1990
1991 deleteFuture.set( deleteResponse );
1992
1993
1994 removeFromFutureMaps( messageId );
1995
1996 break;
1997
1998 case EXTENDED_RESPONSE:
1999
2000 ExtendedResponse extendedResponse = ( ExtendedResponse ) response;
2001
2002 ExtendedFuture extendedFuture = ( ExtendedFuture ) responseFuture;
2003
2004
2005 if ( LOG.isDebugEnabled() )
2006 {
2007 if ( extendedResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
2008 {
2009
2010 LOG.debug( "Extended successful : {}", extendedResponse );
2011 }
2012 else
2013 {
2014
2015 LOG.debug( "Extended failed : {}", extendedResponse );
2016 }
2017 }
2018
2019
2020 extendedFuture.set( extendedResponse );
2021
2022
2023 removeFromFutureMaps( messageId );
2024
2025 break;
2026
2027 case INTERMEDIATE_RESPONSE:
2028 IntermediateResponse intermediateResponse = null;
2029
2030 if ( responseFuture instanceof SearchFuture )
2031 {
2032 intermediateResponse = new IntermediateResponseImpl( messageId );
2033 addControls( intermediateResponse, response );
2034 ( ( SearchFuture ) responseFuture ).set( intermediateResponse );
2035 }
2036 else if ( responseFuture instanceof ExtendedFuture )
2037 {
2038 intermediateResponse = new IntermediateResponseImpl( messageId );
2039 addControls( intermediateResponse, response );
2040 ( ( ExtendedFuture ) responseFuture ).set( intermediateResponse );
2041 }
2042 else
2043 {
2044
2045 throw new UnsupportedOperationException( "Unknown ResponseFuture type "
2046 + responseFuture.getClass().getName() );
2047 }
2048
2049 intermediateResponse.setResponseName( ( ( IntermediateResponse ) response ).getResponseName() );
2050 intermediateResponse.setResponseValue( ( ( IntermediateResponse ) response ).getResponseValue() );
2051
2052 break;
2053
2054 case MODIFY_RESPONSE:
2055
2056 ModifyResponse modifyResponse = ( ModifyResponse ) response;
2057
2058 ModifyFuture modifyFuture = ( ModifyFuture ) responseFuture;
2059
2060 if ( LOG.isDebugEnabled() )
2061 {
2062 if ( modifyResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
2063 {
2064
2065 LOG.debug( "ModifyFuture successful : {}", modifyResponse );
2066 }
2067 else
2068 {
2069
2070 LOG.debug( "ModifyFuture failed : {}", modifyResponse );
2071 }
2072 }
2073
2074
2075 modifyFuture.set( modifyResponse );
2076
2077
2078 removeFromFutureMaps( messageId );
2079
2080 break;
2081
2082 case MODIFYDN_RESPONSE:
2083
2084 ModifyDnResponse modifyDnResponse = ( ModifyDnResponse ) response;
2085
2086 ModifyDnFuture modifyDnFuture = ( ModifyDnFuture ) responseFuture;
2087
2088 if ( LOG.isDebugEnabled() )
2089 {
2090 if ( modifyDnResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
2091 {
2092
2093 LOG.debug( "ModifyDN successful : {}", modifyDnResponse );
2094 }
2095 else
2096 {
2097
2098 LOG.debug( "ModifyDN failed : {}", modifyDnResponse );
2099 }
2100 }
2101
2102
2103 modifyDnFuture.set( modifyDnResponse );
2104
2105
2106 removeFromFutureMaps( messageId );
2107
2108 break;
2109
2110 case SEARCH_RESULT_DONE:
2111
2112 SearchResultDone searchResultDone = ( SearchResultDone ) response;
2113
2114 SearchFuture searchFuture = ( SearchFuture ) responseFuture;
2115
2116 if ( LOG.isDebugEnabled() )
2117 {
2118 if ( searchResultDone.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
2119 {
2120
2121 LOG.debug( "Search successful : {}", searchResultDone );
2122 }
2123 else
2124 {
2125
2126 LOG.debug( "Search failed : {}", searchResultDone );
2127 }
2128 }
2129
2130
2131 searchFuture.set( searchResultDone );
2132
2133
2134 removeFromFutureMaps( messageId );
2135
2136 break;
2137
2138 case SEARCH_RESULT_ENTRY:
2139
2140 SearchResultEntry searchResultEntry = ( SearchResultEntry ) response;
2141
2142 if ( schemaManager != null )
2143 {
2144 searchResultEntry.setEntry( new DefaultEntry( schemaManager, searchResultEntry.getEntry() ) );
2145 }
2146
2147 searchFuture = ( SearchFuture ) responseFuture;
2148
2149 if ( LOG.isDebugEnabled() )
2150 {
2151 LOG.debug( "Search entry found : {}", searchResultEntry );
2152 }
2153
2154
2155 searchFuture.set( searchResultEntry );
2156
2157 break;
2158
2159 case SEARCH_RESULT_REFERENCE:
2160
2161 SearchResultReference searchResultReference = ( SearchResultReference ) response;
2162
2163 searchFuture = ( SearchFuture ) responseFuture;
2164
2165 if ( LOG.isDebugEnabled() )
2166 {
2167 LOG.debug( "Search reference found : {}", searchResultReference );
2168 }
2169
2170
2171 searchFuture.set( searchResultReference );
2172
2173 break;
2174
2175 default:
2176 throw new IllegalStateException( "Unexpected response type " + response.getType() );
2177 }
2178 }
2179
2180
2181
2182
2183
2184 public void modify( Entry entry, ModificationOperation modOp ) throws LdapException
2185 {
2186 if ( entry == null )
2187 {
2188 LOG.debug( "received a null entry for modification" );
2189 throw new IllegalArgumentException( "Entry to be modified cannot be null" );
2190 }
2191
2192 ModifyRequest modReq = new ModifyRequestImpl();
2193 modReq.setName( entry.getDn() );
2194
2195 Iterator<Attribute> itr = entry.iterator();
2196
2197 while ( itr.hasNext() )
2198 {
2199 modReq.addModification( itr.next(), modOp );
2200 }
2201
2202 ModifyResponse modifyResponse = modify( modReq );
2203
2204 processResponse( modifyResponse );
2205 }
2206
2207
2208
2209
2210
2211 public void modify( Dn dn, Modification... modifications ) throws LdapException
2212 {
2213 if ( dn == null )
2214 {
2215 LOG.debug( "received a null dn for modification" );
2216 throw new IllegalArgumentException( "The Dn to be modified cannot be null" );
2217 }
2218
2219 if ( ( modifications == null ) || ( modifications.length == 0 ) )
2220 {
2221 String msg = "Cannot process a ModifyRequest without any modification";
2222 LOG.debug( msg );
2223 throw new IllegalArgumentException( msg );
2224 }
2225
2226 ModifyRequest modReq = new ModifyRequestImpl();
2227 modReq.setName( dn );
2228
2229 for ( Modification modification : modifications )
2230 {
2231 modReq.addModification( modification );
2232 }
2233
2234 ModifyResponse modifyResponse = modify( modReq );
2235
2236 processResponse( modifyResponse );
2237 }
2238
2239
2240
2241
2242
2243 public void modify( String dn, Modification... modifications ) throws LdapException
2244 {
2245 modify( new Dn( dn ), modifications );
2246 }
2247
2248
2249
2250
2251
2252 public ModifyResponse modify( ModifyRequest modRequest ) throws LdapException
2253 {
2254 if ( modRequest == null )
2255 {
2256 String msg = "Cannot process a null modifyRequest";
2257 LOG.debug( msg );
2258 throw new IllegalArgumentException( msg );
2259 }
2260
2261 ModifyFuture modifyFuture = modifyAsync( modRequest );
2262
2263
2264 try
2265 {
2266
2267
2268 ModifyResponse modifyResponse = modifyFuture.get( timeout, TimeUnit.MILLISECONDS );
2269
2270 if ( modifyResponse == null )
2271 {
2272
2273 LOG.error( "Modify failed : timeout occurred" );
2274 throw new LdapException( TIME_OUT_ERROR );
2275 }
2276
2277 if ( modifyResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
2278 {
2279
2280 LOG.debug( "Modify successful : {}", modifyResponse );
2281 }
2282 else
2283 {
2284 if ( modifyResponse instanceof ModifyNoDResponse )
2285 {
2286
2287 throw new LdapException( modifyResponse.getLdapResult().getDiagnosticMessage() );
2288 }
2289
2290
2291 LOG.debug( "Modify failed : {}", modifyResponse );
2292 }
2293
2294 return modifyResponse;
2295 }
2296 catch ( TimeoutException te )
2297 {
2298
2299 if ( !modifyFuture.isCancelled() )
2300 {
2301 abandon( modRequest.getMessageId() );
2302 }
2303
2304
2305 LOG.error( "Modify failed : timeout occurred" );
2306 throw new LdapException( TIME_OUT_ERROR, te );
2307 }
2308 catch ( Exception ie )
2309 {
2310
2311 LOG.error( NO_RESPONSE_ERROR, ie );
2312
2313
2314 if ( !modifyFuture.isCancelled() )
2315 {
2316 abandon( modRequest.getMessageId() );
2317 }
2318
2319 throw new LdapException( ie.getMessage(), ie );
2320 }
2321 }
2322
2323
2324
2325
2326
2327 public ModifyFuture modifyAsync( ModifyRequest modRequest ) throws LdapException
2328 {
2329 if ( modRequest == null )
2330 {
2331 String msg = "Cannot process a null modifyRequest";
2332 LOG.debug( msg );
2333 throw new IllegalArgumentException( msg );
2334 }
2335
2336 if ( modRequest.getName() == null )
2337 {
2338 String msg = "Cannot process a modifyRequest which DN is null";
2339 LOG.debug( msg );
2340 throw new IllegalArgumentException( msg );
2341 }
2342
2343 checkSession();
2344
2345 int newId = messageId.incrementAndGet();
2346 modRequest.setMessageId( newId );
2347
2348 ModifyFuture modifyFuture = new ModifyFuture( this, newId );
2349 addToFutureMap( newId, modifyFuture );
2350
2351
2352 writeRequest( modRequest );
2353
2354
2355 return modifyFuture;
2356 }
2357
2358
2359
2360
2361
2362 public void rename( String entryDn, String newRdn ) throws LdapException
2363 {
2364 rename( entryDn, newRdn, true );
2365 }
2366
2367
2368
2369
2370
2371 public void rename( Dn entryDn, Rdn newRdn ) throws LdapException
2372 {
2373 rename( entryDn, newRdn, true );
2374 }
2375
2376
2377
2378
2379
2380 public void rename( String entryDn, String newRdn, boolean deleteOldRdn ) throws LdapException
2381 {
2382 if ( entryDn == null )
2383 {
2384 String msg = "Cannot process a rename of a null Dn";
2385 LOG.debug( msg );
2386 throw new IllegalArgumentException( msg );
2387 }
2388
2389 if ( newRdn == null )
2390 {
2391 String msg = "Cannot process a rename with a null Rdn";
2392 LOG.debug( msg );
2393 throw new IllegalArgumentException( msg );
2394 }
2395
2396 try
2397 {
2398 rename( new Dn( entryDn ), new Rdn( newRdn ), deleteOldRdn );
2399 }
2400 catch ( LdapInvalidDnException e )
2401 {
2402 LOG.error( e.getMessage(), e );
2403 throw new LdapException( e.getMessage(), e );
2404 }
2405 }
2406
2407
2408
2409
2410
2411 public void rename( Dn entryDn, Rdn newRdn, boolean deleteOldRdn ) throws LdapException
2412 {
2413 if ( entryDn == null )
2414 {
2415 String msg = "Cannot process a rename of a null Dn";
2416 LOG.debug( msg );
2417 throw new IllegalArgumentException( msg );
2418 }
2419
2420 if ( newRdn == null )
2421 {
2422 String msg = "Cannot process a rename with a null Rdn";
2423 LOG.debug( msg );
2424 throw new IllegalArgumentException( msg );
2425 }
2426
2427 ModifyDnRequest modDnRequest = new ModifyDnRequestImpl();
2428 modDnRequest.setName( entryDn );
2429 modDnRequest.setNewRdn( newRdn );
2430 modDnRequest.setDeleteOldRdn( deleteOldRdn );
2431
2432 ModifyDnResponse modifyDnResponse = modifyDn( modDnRequest );
2433
2434 processResponse( modifyDnResponse );
2435 }
2436
2437
2438
2439
2440
2441 public void move( String entryDn, String newSuperiorDn ) throws LdapException
2442 {
2443 if ( entryDn == null )
2444 {
2445 String msg = "Cannot process a move of a null Dn";
2446 LOG.debug( msg );
2447 throw new IllegalArgumentException( msg );
2448 }
2449
2450 if ( newSuperiorDn == null )
2451 {
2452 String msg = "Cannot process a move to a null newSuperior";
2453 LOG.debug( msg );
2454 throw new IllegalArgumentException( msg );
2455 }
2456
2457 try
2458 {
2459 move( new Dn( entryDn ), new Dn( newSuperiorDn ) );
2460 }
2461 catch ( LdapInvalidDnException e )
2462 {
2463 LOG.error( e.getMessage(), e );
2464 throw new LdapException( e.getMessage(), e );
2465 }
2466 }
2467
2468
2469
2470
2471
2472 public void move( Dn entryDn, Dn newSuperiorDn ) throws LdapException
2473 {
2474 if ( entryDn == null )
2475 {
2476 String msg = "Cannot process a move of a null Dn";
2477 LOG.debug( msg );
2478 throw new IllegalArgumentException( msg );
2479 }
2480
2481 if ( newSuperiorDn == null )
2482 {
2483 String msg = "Cannot process a move to a null newSuperior";
2484 LOG.debug( msg );
2485 throw new IllegalArgumentException( msg );
2486 }
2487
2488 ModifyDnRequest modDnRequest = new ModifyDnRequestImpl();
2489 modDnRequest.setName( entryDn );
2490 modDnRequest.setNewSuperior( newSuperiorDn );
2491
2492
2493 modDnRequest.setNewRdn( entryDn.getRdn() );
2494
2495 ModifyDnResponse modifyDnResponse = modifyDn( modDnRequest );
2496
2497 processResponse( modifyDnResponse );
2498 }
2499
2500
2501
2502
2503
2504 public void moveAndRename( Dn entryDn, Dn newDn ) throws LdapException
2505 {
2506 moveAndRename( entryDn, newDn, true );
2507 }
2508
2509
2510
2511
2512
2513 public void moveAndRename( String entryDn, String newDn ) throws LdapException
2514 {
2515 moveAndRename( new Dn( entryDn ), new Dn( newDn ), true );
2516 }
2517
2518
2519
2520
2521
2522 public void moveAndRename( Dn entryDn, Dn newDn, boolean deleteOldRdn ) throws LdapException
2523 {
2524
2525 if ( entryDn == null )
2526 {
2527 throw new IllegalArgumentException( "The entry Dn must not be null" );
2528 }
2529
2530 if ( entryDn.isRootDse() )
2531 {
2532 throw new IllegalArgumentException( "The RootDSE cannot be moved" );
2533 }
2534
2535 if ( newDn == null )
2536 {
2537 throw new IllegalArgumentException( "The new Dn must not be null" );
2538 }
2539
2540 if ( newDn.isRootDse() )
2541 {
2542 throw new IllegalArgumentException( "The RootDSE cannot be the target" );
2543 }
2544
2545
2546 ModifyDnRequest modDnRequest = new ModifyDnRequestImpl();
2547 modDnRequest.setName( entryDn );
2548 modDnRequest.setNewRdn( newDn.getRdn() );
2549 modDnRequest.setNewSuperior( newDn.getParent() );
2550 modDnRequest.setDeleteOldRdn( deleteOldRdn );
2551
2552 ModifyDnResponse modifyDnResponse = modifyDn( modDnRequest );
2553
2554 processResponse( modifyDnResponse );
2555 }
2556
2557
2558
2559
2560
2561 public void moveAndRename( String entryDn, String newDn, boolean deleteOldRdn ) throws LdapException
2562 {
2563 moveAndRename( new Dn( entryDn ), new Dn( newDn ), true );
2564 }
2565
2566
2567
2568
2569
2570 public ModifyDnResponse modifyDn( ModifyDnRequest modDnRequest ) throws LdapException
2571 {
2572 if ( modDnRequest == null )
2573 {
2574 String msg = "Cannot process a null modDnRequest";
2575 LOG.debug( msg );
2576 throw new IllegalArgumentException( msg );
2577 }
2578
2579 ModifyDnFuture modifyDnFuture = modifyDnAsync( modDnRequest );
2580
2581
2582 try
2583 {
2584
2585
2586 ModifyDnResponse modifyDnResponse = modifyDnFuture.get( timeout, TimeUnit.MILLISECONDS );
2587
2588 if ( modifyDnResponse == null )
2589 {
2590
2591 LOG.error( "ModifyDN failed : timeout occurred" );
2592 throw new LdapException( TIME_OUT_ERROR );
2593 }
2594
2595 if ( modifyDnResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
2596 {
2597
2598 LOG.debug( "ModifyDN successful : {}", modifyDnResponse );
2599 }
2600 else
2601 {
2602
2603 LOG.debug( "Modify failed : {}", modifyDnResponse );
2604 }
2605
2606 return modifyDnResponse;
2607 }
2608 catch ( TimeoutException te )
2609 {
2610
2611 if ( !modifyDnFuture.isCancelled() )
2612 {
2613 abandon( modDnRequest.getMessageId() );
2614 }
2615
2616
2617 LOG.error( "Modify failed : timeout occurred" );
2618 throw new LdapException( TIME_OUT_ERROR, te );
2619 }
2620 catch ( Exception ie )
2621 {
2622
2623 LOG.error( NO_RESPONSE_ERROR, ie );
2624
2625
2626 if ( !modifyDnFuture.isCancelled() )
2627 {
2628 abandon( modDnRequest.getMessageId() );
2629 }
2630
2631 throw new LdapException( NO_RESPONSE_ERROR, ie );
2632 }
2633 }
2634
2635
2636
2637
2638
2639 public ModifyDnFuture modifyDnAsync( ModifyDnRequest modDnRequest ) throws LdapException
2640 {
2641 if ( modDnRequest == null )
2642 {
2643 String msg = "Cannot process a null modDnRequest";
2644 LOG.debug( msg );
2645 throw new IllegalArgumentException( msg );
2646 }
2647
2648 if ( modDnRequest.getName() == null )
2649 {
2650 String msg = "Cannot process a modifyRequest which DN is null";
2651 LOG.debug( msg );
2652 throw new IllegalArgumentException( msg );
2653 }
2654
2655 if ( ( modDnRequest.getNewSuperior() == null ) && ( modDnRequest.getNewRdn() == null ) )
2656 {
2657 String msg = "Cannot process a modifyRequest which new superior and new Rdn are null";
2658 LOG.debug( msg );
2659 throw new IllegalArgumentException( msg );
2660 }
2661
2662 checkSession();
2663
2664 int newId = messageId.incrementAndGet();
2665 modDnRequest.setMessageId( newId );
2666
2667 ModifyDnFuture modifyDnFuture = new ModifyDnFuture( this, newId );
2668 addToFutureMap( newId, modifyDnFuture );
2669
2670
2671 writeRequest( modDnRequest );
2672
2673
2674 return modifyDnFuture;
2675 }
2676
2677
2678
2679
2680
2681 public void delete( String dn ) throws LdapException
2682 {
2683 delete( new Dn( dn ) );
2684 }
2685
2686
2687
2688
2689
2690 public void delete( Dn dn ) throws LdapException
2691 {
2692 DeleteRequest deleteRequest = new DeleteRequestImpl();
2693 deleteRequest.setName( dn );
2694
2695 DeleteResponse deleteResponse = delete( deleteRequest );
2696
2697 processResponse( deleteResponse );
2698 }
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708 public void deleteTree( Dn dn ) throws LdapException
2709 {
2710 String treeDeleteOid = "1.2.840.113556.1.4.805";
2711
2712 if ( isControlSupported( treeDeleteOid ) )
2713 {
2714 DeleteRequest deleteRequest = new DeleteRequestImpl();
2715 deleteRequest.setName( dn );
2716 deleteRequest.addControl( new OpaqueControl( treeDeleteOid ) );
2717 DeleteResponse deleteResponse = delete( deleteRequest );
2718
2719 processResponse( deleteResponse );
2720 }
2721 else
2722 {
2723 String msg = "The subtreeDelete control (1.2.840.113556.1.4.805) is not supported by the server\n"
2724 + " The deletion has been aborted";
2725 LOG.error( msg );
2726 throw new LdapException( msg );
2727 }
2728 }
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738 public void deleteTree( String dn ) throws LdapException
2739 {
2740 try
2741 {
2742 String treeDeleteOid = "1.2.840.113556.1.4.805";
2743 Dn newDn = new Dn( dn );
2744
2745 if ( isControlSupported( treeDeleteOid ) )
2746 {
2747 DeleteRequest deleteRequest = new DeleteRequestImpl();
2748 deleteRequest.setName( newDn );
2749 deleteRequest.addControl( new OpaqueControl( treeDeleteOid ) );
2750 DeleteResponse deleteResponse = delete( deleteRequest );
2751
2752 processResponse( deleteResponse );
2753 }
2754 else
2755 {
2756 String msg = "The subtreeDelete control (1.2.840.113556.1.4.805) is not supported by the server\n"
2757 + " The deletion has been aborted";
2758 LOG.error( msg );
2759 throw new LdapException( msg );
2760 }
2761 }
2762 catch ( LdapInvalidDnException e )
2763 {
2764 LOG.error( e.getMessage(), e );
2765 throw new LdapException( e.getMessage(), e );
2766 }
2767 }
2768
2769
2770
2771
2772
2773 public DeleteResponse delete( DeleteRequest deleteRequest ) throws LdapException
2774 {
2775 if ( deleteRequest == null )
2776 {
2777 String msg = "Cannot process a null deleteRequest";
2778 LOG.debug( msg );
2779 throw new IllegalArgumentException( msg );
2780 }
2781
2782 DeleteFuture deleteFuture = deleteAsync( deleteRequest );
2783
2784
2785 try
2786 {
2787
2788
2789 DeleteResponse delResponse = deleteFuture.get( timeout, TimeUnit.MILLISECONDS );
2790
2791 if ( delResponse == null )
2792 {
2793
2794 LOG.error( "Delete failed : timeout occurred" );
2795 throw new LdapException( TIME_OUT_ERROR );
2796 }
2797
2798 if ( delResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
2799 {
2800
2801 LOG.debug( "Delete successful : {}", delResponse );
2802 }
2803 else
2804 {
2805
2806 LOG.debug( "Delete failed : {}", delResponse );
2807 }
2808
2809 return delResponse;
2810 }
2811 catch ( TimeoutException te )
2812 {
2813
2814 if ( !deleteFuture.isCancelled() )
2815 {
2816 abandon( deleteRequest.getMessageId() );
2817 }
2818
2819
2820 LOG.error( "Del failed : timeout occurred" );
2821 throw new LdapException( TIME_OUT_ERROR, te );
2822 }
2823 catch ( Exception ie )
2824 {
2825
2826 LOG.error( NO_RESPONSE_ERROR, ie );
2827
2828
2829 if ( !deleteFuture.isCancelled() )
2830 {
2831 abandon( deleteRequest.getMessageId() );
2832 }
2833
2834 throw new LdapException( NO_RESPONSE_ERROR, ie );
2835 }
2836 }
2837
2838
2839
2840
2841
2842 public DeleteFuture deleteAsync( DeleteRequest deleteRequest ) throws LdapException
2843 {
2844 if ( deleteRequest == null )
2845 {
2846 String msg = "Cannot process a null deleteRequest";
2847 LOG.debug( msg );
2848 throw new IllegalArgumentException( msg );
2849 }
2850
2851 if ( deleteRequest.getName() == null )
2852 {
2853 String msg = "Cannot process a deleteRequest which DN is null";
2854 LOG.debug( msg );
2855 throw new IllegalArgumentException( msg );
2856 }
2857
2858 checkSession();
2859
2860 int newId = messageId.incrementAndGet();
2861
2862 deleteRequest.setMessageId( newId );
2863
2864 DeleteFuture deleteFuture = new DeleteFuture( this, newId );
2865 addToFutureMap( newId, deleteFuture );
2866
2867
2868 writeRequest( deleteRequest );
2869
2870
2871 return deleteFuture;
2872 }
2873
2874
2875
2876
2877
2878 public boolean compare( String dn, String attributeName, String value ) throws LdapException
2879 {
2880 return compare( new Dn( dn ), attributeName, value );
2881 }
2882
2883
2884
2885
2886
2887 public boolean compare( String dn, String attributeName, byte[] value ) throws LdapException
2888 {
2889 return compare( new Dn( dn ), attributeName, value );
2890 }
2891
2892
2893
2894
2895
2896 public boolean compare( String dn, String attributeName, Value<?> value ) throws LdapException
2897 {
2898 return compare( new Dn( dn ), attributeName, value );
2899 }
2900
2901
2902
2903
2904
2905 public boolean compare( Dn dn, String attributeName, String value ) throws LdapException
2906 {
2907 CompareRequest compareRequest = new CompareRequestImpl();
2908 compareRequest.setName( dn );
2909 compareRequest.setAttributeId( attributeName );
2910 compareRequest.setAssertionValue( value );
2911
2912 CompareResponse compareResponse = compare( compareRequest );
2913
2914 return processResponse( compareResponse );
2915 }
2916
2917
2918
2919
2920
2921 public boolean compare( Dn dn, String attributeName, byte[] value ) throws LdapException
2922 {
2923 CompareRequest compareRequest = new CompareRequestImpl();
2924 compareRequest.setName( dn );
2925 compareRequest.setAttributeId( attributeName );
2926 compareRequest.setAssertionValue( value );
2927
2928 CompareResponse compareResponse = compare( compareRequest );
2929
2930 return processResponse( compareResponse );
2931 }
2932
2933
2934
2935
2936
2937 public boolean compare( Dn dn, String attributeName, Value<?> value ) throws LdapException
2938 {
2939 CompareRequest compareRequest = new CompareRequestImpl();
2940 compareRequest.setName( dn );
2941 compareRequest.setAttributeId( attributeName );
2942
2943 if ( value.isHumanReadable() )
2944 {
2945 compareRequest.setAssertionValue( value.getString() );
2946 }
2947 else
2948 {
2949 compareRequest.setAssertionValue( value.getBytes() );
2950 }
2951
2952 CompareResponse compareResponse = compare( compareRequest );
2953
2954 return processResponse( compareResponse );
2955 }
2956
2957
2958
2959
2960
2961 public CompareResponse compare( CompareRequest compareRequest ) throws LdapException
2962 {
2963 if ( compareRequest == null )
2964 {
2965 String msg = "Cannot process a null compareRequest";
2966 LOG.debug( msg );
2967 throw new IllegalArgumentException( msg );
2968 }
2969
2970 CompareFuture compareFuture = compareAsync( compareRequest );
2971
2972
2973 try
2974 {
2975
2976
2977 CompareResponse compareResponse = compareFuture.get( timeout, TimeUnit.MILLISECONDS );
2978
2979 if ( compareResponse == null )
2980 {
2981
2982 LOG.error( "Compare failed : timeout occurred" );
2983 throw new LdapException( TIME_OUT_ERROR );
2984 }
2985
2986 if ( compareResponse.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
2987 {
2988
2989 LOG.debug( "Compare successful : {}", compareResponse );
2990 }
2991 else
2992 {
2993
2994 LOG.debug( "Compare failed : {}", compareResponse );
2995 }
2996
2997 return compareResponse;
2998 }
2999 catch ( TimeoutException te )
3000 {
3001
3002 if ( !compareFuture.isCancelled() )
3003 {
3004 abandon( compareRequest.getMessageId() );
3005 }
3006
3007
3008 LOG.error( "Compare failed : timeout occurred" );
3009 throw new LdapException( TIME_OUT_ERROR, te );
3010 }
3011 catch ( Exception ie )
3012 {
3013
3014 LOG.error( NO_RESPONSE_ERROR, ie );
3015
3016
3017 if ( !compareFuture.isCancelled() )
3018 {
3019 abandon( compareRequest.getMessageId() );
3020 }
3021
3022 throw new LdapException( NO_RESPONSE_ERROR, ie );
3023 }
3024 }
3025
3026
3027
3028
3029
3030 public CompareFuture compareAsync( CompareRequest compareRequest ) throws LdapException
3031 {
3032 if ( compareRequest == null )
3033 {
3034 String msg = "Cannot process a null compareRequest";
3035 LOG.debug( msg );
3036 throw new IllegalArgumentException( msg );
3037 }
3038
3039 if ( compareRequest.getName() == null )
3040 {
3041 String msg = "Cannot process a compareRequest which DN is null";
3042 LOG.debug( msg );
3043 throw new IllegalArgumentException( msg );
3044 }
3045
3046 checkSession();
3047
3048 int newId = messageId.incrementAndGet();
3049
3050 compareRequest.setMessageId( newId );
3051
3052 CompareFuture compareFuture = new CompareFuture( this, newId );
3053 addToFutureMap( newId, compareFuture );
3054
3055
3056 writeRequest( compareRequest );
3057
3058
3059 return compareFuture;
3060 }
3061
3062
3063
3064
3065
3066 public ExtendedResponse extended( String oid ) throws LdapException
3067 {
3068 return extended( oid, null );
3069 }
3070
3071
3072
3073
3074
3075 public ExtendedResponse extended( String oid, byte[] value ) throws LdapException
3076 {
3077 try
3078 {
3079 return extended( new Oid( oid ), value );
3080 }
3081 catch ( DecoderException e )
3082 {
3083 String msg = "Failed to decode the OID " + oid;
3084 LOG.error( msg );
3085 throw new LdapException( msg, e );
3086 }
3087 }
3088
3089
3090
3091
3092
3093 public ExtendedResponse extended( Oid oid ) throws LdapException
3094 {
3095 return extended( oid, null );
3096 }
3097
3098
3099
3100
3101
3102 public ExtendedResponse extended( Oid oid, byte[] value ) throws LdapException
3103 {
3104 ExtendedRequest extendedRequest =
3105 LdapApiServiceFactory.getSingleton().newExtendedRequest( oid.toString(), value );
3106 return extended( extendedRequest );
3107 }
3108
3109
3110
3111
3112
3113 public ExtendedResponse extended( ExtendedRequest extendedRequest ) throws LdapException
3114 {
3115 if ( extendedRequest == null )
3116 {
3117 String msg = "Cannot process a null extendedRequest";
3118 LOG.debug( msg );
3119 throw new IllegalArgumentException( msg );
3120 }
3121
3122 ExtendedFuture extendedFuture = extendedAsync( extendedRequest );
3123
3124
3125 try
3126 {
3127
3128
3129 ExtendedResponse response = ( ExtendedResponse ) extendedFuture
3130 .get( timeout, TimeUnit.MILLISECONDS );
3131
3132 if ( response == null )
3133 {
3134
3135 LOG.error( "Extended failed : timeout occurred" );
3136 throw new LdapException( TIME_OUT_ERROR );
3137 }
3138
3139 if ( response.getLdapResult().getResultCode() == ResultCodeEnum.SUCCESS )
3140 {
3141
3142 LOG.debug( "Extended successful : {}", response );
3143 }
3144 else
3145 {
3146
3147 LOG.debug( "Extended failed : {}", response );
3148 }
3149
3150
3151 if ( Strings.isEmpty( response.getResponseName() ) )
3152 {
3153 response.setResponseName( extendedRequest.getRequestName() );
3154 }
3155
3156
3157 ExtendedResponseDecorator<?> decoratedResponse = codec.decorate( response );
3158
3159 return decoratedResponse;
3160 }
3161 catch ( TimeoutException te )
3162 {
3163
3164 if ( !extendedFuture.isCancelled() )
3165 {
3166 abandon( extendedRequest.getMessageId() );
3167 }
3168
3169
3170 LOG.error( "Extended failed : timeout occurred" );
3171 throw new LdapException( TIME_OUT_ERROR, te );
3172 }
3173 catch ( Exception ie )
3174 {
3175
3176 LOG.error( NO_RESPONSE_ERROR, ie );
3177
3178
3179 if ( !extendedFuture.isCancelled() )
3180 {
3181 abandon( extendedRequest.getMessageId() );
3182 }
3183
3184 throw new LdapException( NO_RESPONSE_ERROR, ie );
3185 }
3186 }
3187
3188
3189
3190
3191
3192 public ExtendedFuture extendedAsync( ExtendedRequest extendedRequest ) throws LdapException
3193 {
3194 if ( extendedRequest == null )
3195 {
3196 String msg = "Cannot process a null extendedRequest";
3197 LOG.debug( msg );
3198 throw new IllegalArgumentException( msg );
3199 }
3200
3201 checkSession();
3202
3203 int newId = messageId.incrementAndGet();
3204
3205 extendedRequest.setMessageId( newId );
3206 ExtendedFuture extendedFuture = new ExtendedFuture( this, newId );
3207 addToFutureMap( newId, extendedFuture );
3208
3209
3210 writeRequest( extendedRequest );
3211
3212
3213 return extendedFuture;
3214 }
3215
3216
3217
3218
3219
3220 public boolean exists( String dn ) throws LdapException
3221 {
3222 return exists( new Dn( dn ) );
3223 }
3224
3225
3226
3227
3228
3229 public boolean exists( Dn dn ) throws LdapException
3230 {
3231 try
3232 {
3233 Entry entry = lookup( dn, SchemaConstants.NO_ATTRIBUTE_ARRAY );
3234
3235 return entry != null;
3236 }
3237 catch ( LdapNoPermissionException lnpe )
3238 {
3239
3240 return false;
3241 }
3242 catch ( LdapException le )
3243 {
3244 throw le;
3245 }
3246 }
3247
3248
3249
3250
3251
3252 public Entry getRootDse() throws LdapException
3253 {
3254 return lookup( Dn.ROOT_DSE, SchemaConstants.ALL_USER_ATTRIBUTES_ARRAY );
3255 }
3256
3257
3258
3259
3260
3261 public Entry getRootDse( String... attributes ) throws LdapException
3262 {
3263 return lookup( Dn.ROOT_DSE, attributes );
3264 }
3265
3266
3267
3268
3269
3270 public Entry lookup( Dn dn ) throws LdapException
3271 {
3272 return lookup( dn, SchemaConstants.ALL_USER_ATTRIBUTES_ARRAY );
3273 }
3274
3275
3276
3277
3278
3279 public Entry lookup( String dn ) throws LdapException
3280 {
3281 return lookup( dn, SchemaConstants.ALL_USER_ATTRIBUTES_ARRAY );
3282 }
3283
3284
3285
3286
3287
3288 public Entry lookup( Dn dn, String... attributes ) throws LdapException
3289 {
3290 return lookup( dn, null, attributes );
3291 }
3292
3293
3294
3295
3296
3297 public Entry lookup( Dn dn, Control[] controls, String... attributes ) throws LdapException
3298 {
3299 Entry entry = null;
3300
3301 try
3302 {
3303 SearchRequest searchRequest = new SearchRequestImpl();
3304
3305 searchRequest.setBase( dn );
3306 searchRequest.setFilter( "(objectClass=*)" );
3307 searchRequest.setScope( SearchScope.OBJECT );
3308 searchRequest.addAttributes( attributes );
3309 searchRequest.setDerefAliases( AliasDerefMode.DEREF_ALWAYS );
3310
3311 if ( ( controls != null ) && ( controls.length > 0 ) )
3312 {
3313 searchRequest.addAllControls( controls );
3314 }
3315
3316 Cursor<Response> cursor = search( searchRequest );
3317
3318
3319 if ( cursor.next() )
3320 {
3321
3322 entry = ( ( SearchResultEntry ) cursor.get() ).getEntry();
3323 }
3324
3325
3326
3327 cursor.next();
3328
3329
3330 cursor.close();
3331 }
3332 catch ( CursorException e )
3333 {
3334 throw new LdapException( e );
3335 }
3336
3337 return entry;
3338 }
3339
3340
3341
3342
3343
3344 public Entry lookup( String dn, String... attributes ) throws LdapException
3345 {
3346 return lookup( new Dn( dn ), null, attributes );
3347 }
3348
3349
3350
3351
3352
3353 public Entry lookup( String dn, Control[] controls, String... attributes ) throws LdapException
3354 {
3355 return lookup( new Dn( dn ), controls, attributes );
3356 }
3357
3358
3359
3360
3361
3362 public boolean isControlSupported( String controlOID ) throws LdapException
3363 {
3364 return getSupportedControls().contains( controlOID );
3365 }
3366
3367
3368
3369
3370
3371 public List<String> getSupportedControls() throws LdapException
3372 {
3373 if ( supportedControls != null )
3374 {
3375 return supportedControls;
3376 }
3377
3378 if ( rootDse == null )
3379 {
3380 fetchRootDSE();
3381 }
3382
3383 supportedControls = new ArrayList<String>();
3384
3385 Attribute attr = rootDse.get( SchemaConstants.SUPPORTED_CONTROL_AT );
3386
3387 for ( Value<?> value : attr )
3388 {
3389 supportedControls.add( value.getString() );
3390 }
3391
3392 return supportedControls;
3393 }
3394
3395
3396
3397
3398
3399 public void loadSchema() throws LdapException
3400 {
3401 loadSchema( new DefaultSchemaLoader( this ) );
3402 }
3403
3404
3405
3406
3407
3408
3409
3410
3411 public void loadSchema( SchemaLoader loader ) throws LdapException
3412 {
3413 try
3414 {
3415 SchemaManager tmp = new DefaultSchemaManager( loader );
3416
3417 tmp.loadAllEnabled();
3418
3419 if ( !tmp.getErrors().isEmpty() )
3420 {
3421 String msg = "there are errors while loading the schema";
3422 LOG.error( msg + " {}", tmp.getErrors() );
3423 throw new LdapException( msg );
3424 }
3425
3426 schemaManager = tmp;
3427
3428
3429 ldapSession.setAttribute( LdapDecoder.MESSAGE_CONTAINER_ATTR,
3430 new LdapMessageContainer<MessageDecorator<? extends Message>>( codec,
3431 new SchemaBinaryAttributeDetector( schemaManager ) ) );
3432
3433 }
3434 catch ( LdapException le )
3435 {
3436 throw le;
3437 }
3438 catch ( Exception e )
3439 {
3440 LOG.error( "failed to load the schema", e );
3441 throw new LdapException( e );
3442 }
3443 }
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453 public void addSchema( File schemaFile ) throws LdapException
3454 {
3455 try
3456 {
3457 if ( schemaManager == null )
3458 {
3459 loadSchema();
3460 }
3461
3462 OpenLdapSchemaParser olsp = new OpenLdapSchemaParser();
3463 olsp.setQuirksMode( true );
3464 olsp.parse( schemaFile );
3465
3466 Registries registries = schemaManager.getRegistries();
3467 List<Throwable> errors = new ArrayList<Throwable>();
3468
3469 for ( AttributeType atType : olsp.getAttributeTypes() )
3470 {
3471 registries.buildReference( errors, atType );
3472 registries.getAttributeTypeRegistry().register(atType);
3473 }
3474
3475 for ( ObjectClass oc : olsp.getObjectClassTypes() )
3476 {
3477 registries.buildReference(errors, oc);
3478 registries.getObjectClassRegistry().register( oc );
3479 }
3480
3481 LOG.info( "successfully loaded the schema from file {}", schemaFile.getAbsolutePath() );
3482 }
3483 catch ( Exception e )
3484 {
3485 LOG.error( "failed to load the schema from file {}", schemaFile.getAbsolutePath() );
3486 throw new LdapException( e );
3487 }
3488 }
3489
3490
3491
3492
3493
3494 public void addSchema( String schemaFileName ) throws LdapException
3495 {
3496 addSchema( new File( schemaFileName ) );
3497 }
3498
3499
3500
3501
3502
3503 public LdapApiService getCodecService()
3504 {
3505 return codec;
3506 }
3507
3508
3509
3510
3511
3512 public SchemaManager getSchemaManager()
3513 {
3514 return schemaManager;
3515 }
3516
3517
3518
3519
3520
3521
3522 private void fetchRootDSE() throws LdapException
3523 {
3524 EntryCursor cursor = null;
3525
3526 try
3527 {
3528 cursor = search( "", "(objectClass=*)", SearchScope.OBJECT, "*", "+" );
3529 cursor.next();
3530 rootDse = cursor.get();
3531 }
3532 catch ( Exception e )
3533 {
3534 String msg = "Failed to fetch the RootDSE";
3535 LOG.error( msg );
3536 throw new LdapException( msg, e );
3537 }
3538 finally
3539 {
3540 if ( cursor != null )
3541 {
3542 try
3543 {
3544 cursor.close();
3545 }
3546 catch ( Exception e )
3547 {
3548 LOG.error( "Failed to close open cursor", e );
3549 }
3550 }
3551 }
3552 }
3553
3554
3555
3556
3557
3558
3559
3560 public LdapConnectionConfig getConfig()
3561 {
3562 return config;
3563 }
3564
3565
3566 private void addControls( Message codec, Message message )
3567 {
3568 Map<String, Control> controls = codec.getControls();
3569
3570 if ( controls != null )
3571 {
3572 for ( Control cc : controls.values() )
3573 {
3574 if ( cc == null )
3575 {
3576 continue;
3577 }
3578
3579 message.addControl( cc );
3580 }
3581 }
3582 }
3583
3584
3585
3586
3587
3588
3589
3590
3591 private void removeFromFutureMaps( int msgId )
3592 {
3593 getFromFutureMap( msgId );
3594 }
3595
3596
3597
3598
3599
3600 private void clearMaps()
3601 {
3602 futureMap.clear();
3603 }
3604
3605
3606
3607
3608
3609 public boolean doesFutureExistFor( int messageId )
3610 {
3611 ResponseFuture<?> responseFuture = futureMap.get( messageId );
3612 return responseFuture != null;
3613 }
3614
3615
3616
3617
3618
3619
3620
3621 public void addConnectionClosedEventListener( ConnectionClosedEventListener ccListener )
3622 {
3623 if ( conCloseListeners == null )
3624 {
3625 conCloseListeners = new ArrayList<ConnectionClosedEventListener>();
3626 }
3627
3628 conCloseListeners.add( ccListener );
3629 }
3630
3631
3632
3633
3634
3635
3636
3637
3638 public void sessionCreated( IoSession session ) throws Exception
3639 {
3640
3641 LdapMessageContainer<? extends MessageDecorator<Message>> ldapMessageContainer =
3642 new LdapMessageContainer<MessageDecorator<Message>>(
3643 codec, config.getBinaryAttributeDetector() );
3644
3645 session.setAttribute( LdapDecoder.MESSAGE_CONTAINER_ATTR, ldapMessageContainer );
3646 }
3647
3648
3649
3650
3651
3652 @Override
3653 public void sessionClosed( IoSession session ) throws Exception
3654 {
3655
3656 if ( !connected.get() )
3657 {
3658 return;
3659 }
3660
3661 ldapSession.close( true );
3662 connected.set( false );
3663
3664 messageId.set( 0 );
3665
3666 connectorMutex.lock();
3667
3668 try
3669 {
3670 if ( connector != null )
3671 {
3672 connector.dispose();
3673 connector = null;
3674 }
3675 }
3676 finally
3677 {
3678 connectorMutex.unlock();
3679 }
3680
3681 clearMaps();
3682
3683 if ( conCloseListeners != null )
3684 {
3685 LOG.debug( "notifying the registered ConnectionClosedEventListeners.." );
3686
3687 for ( ConnectionClosedEventListener listener : conCloseListeners )
3688 {
3689 listener.connectionClosed();
3690 }
3691 }
3692 }
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702 public void startTls() throws LdapException
3703 {
3704 try
3705 {
3706 if ( config.isUseSsl() )
3707 {
3708 throw new LdapException( "Cannot use TLS when the useSsl flag is set true in the configuration" );
3709 }
3710
3711 checkSession();
3712
3713 IoFilter sslFilter = ldapSession.getFilterChain().get( SSL_FILTER_KEY );
3714 if ( sslFilter != null )
3715 {
3716 LOG.debug( "LDAP session already using startTLS" );
3717 return;
3718 }
3719
3720 ExtendedResponse resp = extended( new StartTlsRequestImpl() );
3721 LdapResult result = resp.getLdapResult();
3722
3723 if ( result.getResultCode() == ResultCodeEnum.SUCCESS )
3724 {
3725 addSslFilter();
3726 }
3727 else
3728 {
3729 throw new LdapOperationException( result.getResultCode(), result.getDiagnosticMessage() );
3730 }
3731 }
3732 catch ( LdapException e )
3733 {
3734 throw e;
3735 }
3736 catch ( Exception e )
3737 {
3738 throw new LdapException( e );
3739 }
3740 }
3741
3742
3743
3744
3745
3746 private void addSslFilter() throws LdapException
3747 {
3748 try
3749 {
3750 SSLContext sslContext = SSLContext.getInstance( config.getSslProtocol() );
3751 sslContext.init( config.getKeyManagers(), config.getTrustManagers(), config.getSecureRandom() );
3752
3753 SslFilter sslFilter = new SslFilter( sslContext, true );
3754 sslFilter.setUseClientMode( true );
3755 sslFilter.setEnabledCipherSuites( config.getEnabledCipherSuites() );
3756
3757
3758 if ( ldapSession == null )
3759 {
3760 connector.getFilterChain().addFirst( SSL_FILTER_KEY, sslFilter );
3761 }
3762 else
3763
3764 {
3765 ldapSession.getFilterChain().addFirst( SSL_FILTER_KEY, sslFilter );
3766 }
3767 }
3768 catch ( Exception e )
3769 {
3770 String msg = "Failed to initialize the SSL context";
3771 LOG.error( msg, e );
3772 throw new LdapException( msg, e );
3773 }
3774 }
3775
3776
3777
3778
3779
3780
3781
3782 private BindFuture bindSasl( SaslRequest saslRequest ) throws LdapException
3783 {
3784
3785 authenticated.set( false );
3786
3787
3788 connect();
3789
3790
3791 checkSession();
3792
3793 BindRequest bindRequest = createBindRequest( ( String ) null, null,
3794 saslRequest.getSaslMechanism(), saslRequest
3795 .getControls() );
3796
3797
3798 int newId = messageId.incrementAndGet();
3799 bindRequest.setMessageId( newId );
3800
3801 LOG.debug( "Sending request \n{}", bindRequest );
3802
3803
3804 BindFuture bindFuture = new BindFuture( this, newId );
3805
3806
3807 addToFutureMap( newId, bindFuture );
3808
3809 try
3810 {
3811 BindResponse bindResponse = null;
3812 byte[] response = null;
3813 ResultCodeEnum result = null;
3814
3815
3816 Map<String, Object> properties = new HashMap<String, Object>();
3817
3818
3819 if ( saslRequest.getQualityOfProtection() != null )
3820 {
3821 properties.put( Sasl.QOP, saslRequest.getQualityOfProtection().getValue() );
3822 }
3823
3824
3825 if ( saslRequest.getSecurityStrength() != null )
3826 {
3827 properties.put( Sasl.STRENGTH, saslRequest.getSecurityStrength().getValue() );
3828 }
3829
3830
3831 if ( saslRequest.isMutualAuthentication() )
3832 {
3833 properties.put( Sasl.SERVER_AUTH, "true" );
3834 }
3835
3836
3837 SaslClient sc = Sasl.createSaslClient(
3838 new String[]
3839 { bindRequest.getSaslMechanism() },
3840 saslRequest.getAuthorizationId(),
3841 "ldap",
3842 config.getLdapHost(),
3843 properties,
3844 new SaslCallbackHandler( saslRequest ) );
3845
3846
3847
3848 if ( sc == null )
3849 {
3850 String message = "Cannot find a SASL factory for the " + bindRequest.getSaslMechanism() + " mechanism";
3851 LOG.error( message );
3852 throw new LdapException( message );
3853 }
3854
3855
3856
3857 if ( sc.hasInitialResponse() )
3858 {
3859 byte[] challengeResponse = sc.evaluateChallenge( new byte[0] );
3860
3861
3862 bindRequest.setCredentials( challengeResponse );
3863 writeRequest( bindRequest );
3864
3865
3866 bindResponse = bindFuture.get( timeout, TimeUnit.MILLISECONDS );
3867
3868 if ( bindResponse == null )
3869 {
3870
3871 LOG.error( "bind failed : timeout occurred" );
3872 throw new LdapException( TIME_OUT_ERROR );
3873 }
3874
3875 result = bindResponse.getLdapResult().getResultCode();
3876 }
3877 else
3878 {
3879
3880 BindRequest bindRequestCopy = new BindRequestImpl();
3881 bindRequestCopy.setMessageId( newId );
3882
3883 bindRequestCopy.setName( bindRequest.getName() );
3884 bindRequestCopy.setSaslMechanism( bindRequest.getSaslMechanism() );
3885 bindRequestCopy.setSimple( bindRequest.isSimple() );
3886 bindRequestCopy.setVersion3( bindRequest.getVersion3() );
3887 bindRequestCopy.addAllControls( bindRequest.getControls().values().toArray( new Control[0] ) );
3888
3889 writeRequest( bindRequestCopy );
3890
3891 bindResponse = bindFuture.get( timeout, TimeUnit.MILLISECONDS );
3892
3893 if ( bindResponse == null )
3894 {
3895
3896 LOG.error( "bind failed : timeout occurred" );
3897 throw new LdapException( TIME_OUT_ERROR );
3898 }
3899
3900 result = bindResponse.getLdapResult().getResultCode();
3901 }
3902
3903 while ( !sc.isComplete()
3904 && ( ( result == ResultCodeEnum.SASL_BIND_IN_PROGRESS ) || ( result == ResultCodeEnum.SUCCESS ) ) )
3905 {
3906 response = sc.evaluateChallenge( bindResponse.getServerSaslCreds() );
3907
3908 if ( result == ResultCodeEnum.SUCCESS )
3909 {
3910 if ( response != null )
3911 {
3912 throw new LdapException( "protocol error" );
3913 }
3914 }
3915 else
3916 {
3917 newId = messageId.incrementAndGet();
3918 bindRequest.setMessageId( newId );
3919 bindRequest.setCredentials( response );
3920
3921 addToFutureMap( newId, bindFuture );
3922
3923 writeRequest( bindRequest );
3924
3925 bindResponse = bindFuture.get( timeout, TimeUnit.MILLISECONDS );
3926
3927 if ( bindResponse == null )
3928 {
3929
3930 LOG.error( "bind failed : timeout occurred" );
3931 throw new LdapException( TIME_OUT_ERROR );
3932 }
3933
3934 result = bindResponse.getLdapResult().getResultCode();
3935 }
3936 }
3937
3938 bindFuture.set( bindResponse );
3939
3940 return bindFuture;
3941 }
3942 catch ( LdapException e )
3943 {
3944 throw e;
3945 }
3946 catch ( Exception e )
3947 {
3948 e.printStackTrace();
3949 throw new LdapException( e );
3950 }
3951 }
3952
3953
3954
3955
3956
3957 private void writeRequest( Request request ) throws LdapException
3958 {
3959
3960 WriteFuture writeFuture = ldapSession.write( request );
3961
3962 long localTimeout = timeout;
3963
3964 while ( localTimeout > 0 )
3965 {
3966
3967 boolean done = writeFuture.awaitUninterruptibly( 100 );
3968
3969 if ( done )
3970 {
3971 return;
3972 }
3973
3974
3975 if ( !ldapSession.isConnected() )
3976 {
3977
3978 LOG.error( "Message failed : something wrong has occurred" );
3979
3980 Exception exception = ( Exception ) ldapSession.removeAttribute( EXCEPTION_KEY );
3981
3982 if ( exception != null )
3983 {
3984 if ( exception instanceof LdapException )
3985 {
3986 throw ( LdapException ) exception;
3987 }
3988 else
3989 {
3990 throw new InvalidConnectionException( exception.getMessage() );
3991 }
3992 }
3993
3994 throw new InvalidConnectionException( "Error while sending some message : the session has been closed" );
3995 }
3996
3997 localTimeout -= 100;
3998 }
3999
4000 LOG.error( "TimeOut has occurred" );
4001 throw new LdapException( TIME_OUT_ERROR );
4002 }
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026 private String createKrb5ConfFile( String realmName, String kdcHost, int kdcPort ) throws IOException
4027 {
4028 StringBuilder sb = new StringBuilder();
4029
4030 sb.append( "[libdefaults]" )
4031 .append( "\n\t" );
4032 sb.append( "default_realm = " )
4033 .append( realmName )
4034 .append( "\n" );
4035
4036 sb.append( "[realms]" )
4037 .append( "\n\t" );
4038
4039 sb.append( realmName )
4040 .append( " = {" )
4041 .append( "\n\t\t" );
4042 sb.append( "kdc = " )
4043 .append( kdcHost )
4044 .append( ":" )
4045 .append( kdcPort )
4046 .append( "\n\t}\n" );
4047
4048 File krb5Conf = File.createTempFile( "client-api-krb5", ".conf" );
4049 krb5Conf.deleteOnExit();
4050 FileWriter fw = new FileWriter( krb5Conf );
4051 fw.write( sb.toString() );
4052 fw.close();
4053
4054 String krb5ConfPath = krb5Conf.getAbsolutePath();
4055
4056 LOG.debug( "krb 5 config file created at {}", krb5ConfPath );
4057
4058 return krb5ConfPath;
4059 }
4060
4061
4062
4063
4064
4065 public BinaryAttributeDetector getBinaryAttributeDetector()
4066 {
4067 if ( config != null )
4068 {
4069 return config.getBinaryAttributeDetector();
4070 }
4071 else
4072 {
4073 return null;
4074 }
4075 }
4076
4077
4078
4079
4080
4081 public void setBinaryAttributeDetector( BinaryAttributeDetector binaryAttributeDetector )
4082 {
4083 if ( config != null )
4084 {
4085 config.setBinaryAttributeDetector( binaryAttributeDetector );
4086 }
4087 }
4088
4089
4090
4091
4092
4093 @Override
4094 public void setSchemaManager( SchemaManager schemaManager )
4095 {
4096 this.schemaManager = schemaManager;
4097 }
4098 }