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