1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.tools;
21
22
23 import java.io.File;
24 import java.io.IOException;
25 import java.net.InetSocketAddress;
26 import java.net.SocketAddress;
27 import java.net.UnknownHostException;
28 import java.nio.ByteBuffer;
29 import java.nio.channels.SocketChannel;
30
31 import javax.naming.InvalidNameException;
32 import javax.naming.NamingException;
33
34 import org.apache.commons.cli.CommandLine;
35 import org.apache.commons.cli.Option;
36 import org.apache.commons.cli.Options;
37 import org.apache.directory.daemon.AvailablePortFinder;
38 import org.apache.directory.shared.asn1.ber.Asn1Decoder;
39 import org.apache.directory.shared.asn1.ber.IAsn1Container;
40 import org.apache.directory.shared.asn1.ber.tlv.TLVStateEnum;
41 import org.apache.directory.shared.asn1.codec.DecoderException;
42 import org.apache.directory.shared.asn1.codec.EncoderException;
43 import org.apache.directory.shared.ldap.codec.LdapDecoder;
44 import org.apache.directory.shared.ldap.codec.LdapMessage;
45 import org.apache.directory.shared.ldap.codec.LdapMessageContainer;
46 import org.apache.directory.shared.ldap.codec.LdapResult;
47 import org.apache.directory.shared.ldap.codec.add.AddRequest;
48 import org.apache.directory.shared.ldap.codec.bind.BindRequest;
49 import org.apache.directory.shared.ldap.codec.bind.BindResponse;
50 import org.apache.directory.shared.ldap.codec.bind.LdapAuthentication;
51 import org.apache.directory.shared.ldap.codec.bind.SimpleAuthentication;
52 import org.apache.directory.shared.ldap.codec.del.DelRequest;
53 import org.apache.directory.shared.ldap.codec.extended.ExtendedResponse;
54 import org.apache.directory.shared.ldap.codec.modify.ModifyRequest;
55 import org.apache.directory.shared.ldap.codec.modifyDn.ModifyDNRequest;
56 import org.apache.directory.shared.ldap.codec.unbind.UnBindRequest;
57 import org.apache.directory.shared.ldap.entry.Entry;
58 import org.apache.directory.shared.ldap.entry.EntryAttribute;
59 import org.apache.directory.shared.ldap.entry.Modification;
60 import org.apache.directory.shared.ldap.entry.Value;
61 import org.apache.directory.shared.ldap.ldif.ChangeType;
62 import org.apache.directory.shared.ldap.ldif.LdifEntry;
63 import org.apache.directory.shared.ldap.ldif.LdifReader;
64 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
65 import org.apache.directory.shared.ldap.name.LdapDN;
66 import org.apache.directory.shared.ldap.name.Rdn;
67 import org.apache.directory.shared.ldap.util.StringTools;
68
69
70
71
72
73
74
75
76
77 public class ImportCommand extends ToolCommand
78 {
79 public static final String PORT_RANGE = "(" + AvailablePortFinder.MIN_PORT_NUMBER + ", "
80 + AvailablePortFinder.MAX_PORT_NUMBER + ")";
81
82 private int port = 10389;
83
84 private String host = "localhost";
85
86 private String password = "secret";
87
88 private String user = "uid=admin,ou=system";
89
90 private String auth = "simple";
91
92 private File ldifFile;
93
94 private String logs;
95
96 private boolean ignoreErrors = false;
97
98 private static final int IMPORT_ERROR = -1;
99 private static final int IMPORT_SUCCESS = 0;
100
101
102
103
104 private SocketChannel channel;
105
106 private SocketAddress serverAddress;
107
108 private IAsn1Container ldapMessageContainer = new LdapMessageContainer();
109
110 private Asn1Decoder ldapDecoder = new LdapDecoder();
111
112
113
114
115
116
117 protected ImportCommand()
118 {
119 super( "import" );
120 }
121
122
123
124
125
126
127
128
129
130
131
132
133 private void connect() throws UnknownHostException, IOException
134 {
135 serverAddress = new InetSocketAddress( host, port );
136 channel = SocketChannel.open( serverAddress );
137 channel.configureBlocking( true );
138 }
139
140
141 private void sendMessage( ByteBuffer bb ) throws IOException
142 {
143 channel.write( bb );
144 bb.clear();
145 }
146
147
148 private LdapMessage readResponse( ByteBuffer bb ) throws IOException, DecoderException, NamingException
149 {
150
151 LdapMessage messageResp = null;
152
153 while ( true )
154 {
155 int nbRead = channel.read( bb );
156
157 if ( nbRead == -1 )
158 {
159 break;
160 }
161 else
162 {
163 bb.flip();
164
165
166 ldapDecoder.decode( bb, ldapMessageContainer );
167
168 if ( ldapMessageContainer.getState() == TLVStateEnum.PDU_DECODED )
169 {
170 messageResp = ( ( LdapMessageContainer ) ldapMessageContainer ).getLdapMessage();
171
172 if ( messageResp instanceof BindResponse )
173 {
174 BindResponse resp = ( ( LdapMessageContainer ) ldapMessageContainer ).getLdapMessage()
175 .getBindResponse();
176
177 if ( resp.getLdapResult().getResultCode() != ResultCodeEnum.SUCCESS )
178 {
179 System.out.println( "Error : " + resp.getLdapResult().getErrorMessage() );
180 }
181 }
182 else if ( messageResp instanceof ExtendedResponse )
183 {
184 ExtendedResponse resp = ( ( LdapMessageContainer ) ldapMessageContainer ).getLdapMessage()
185 .getExtendedResponse();
186
187 if ( resp.getLdapResult().getResultCode() != ResultCodeEnum.SUCCESS )
188 {
189 System.out.println( "Error : " + resp.getLdapResult().getErrorMessage() );
190 }
191 }
192
193 ( ( LdapMessageContainer ) ldapMessageContainer ).clean();
194 break;
195 }
196 else
197 {
198 bb.flip();
199 }
200 }
201 }
202
203 return messageResp;
204
205 }
206
207
208
209
210
211
212
213
214
215
216
217 private int addEntry( LdifEntry ldifEntry, int messageId ) throws IOException, DecoderException, InvalidNameException,
218 NamingException, EncoderException
219 {
220 AddRequest addRequest = new AddRequest();
221
222 String dn = ldifEntry.getDn().getUpName();
223
224 if ( isDebugEnabled() )
225 {
226 System.out.println( "Adding entry " + dn );
227 }
228
229 Entry entry = ldifEntry.getEntry();
230
231 addRequest.setEntryDn( new LdapDN( dn ) );
232
233
234 for ( EntryAttribute attribute:entry )
235 {
236 addRequest.addAttributeType( attribute.getId() );
237
238 for ( Value<?> value: attribute )
239 {
240 addRequest.addAttributeValue( value );
241 }
242 }
243
244 LdapMessage message = new LdapMessage();
245
246 message.setProtocolOP( addRequest );
247 message.setMessageId( messageId );
248
249
250 ByteBuffer bb = message.encode( null );
251 bb.flip();
252
253 sendMessage( bb );
254
255 bb.clear();
256
257
258 LdapMessage response = readResponse( bb );
259
260 LdapResult result = response.getAddResponse().getLdapResult();
261
262 if ( result.getResultCode() == ResultCodeEnum.SUCCESS )
263 {
264 if ( isDebugEnabled() )
265 {
266 System.out.println( "Add of Entry " + entry.getDn() + " was successful" );
267 }
268
269 return IMPORT_SUCCESS;
270 }
271 else
272 {
273 System.err.println( "Add of entry " + entry.getDn()
274 + " failed for the following reasons provided by the server:\n" + result.getErrorMessage() );
275
276 return IMPORT_ERROR;
277 }
278 }
279
280
281
282
283
284
285
286
287
288
289
290 private int deleteEntry( LdifEntry entry, int messageId ) throws IOException, DecoderException,
291 InvalidNameException, NamingException, EncoderException
292 {
293 DelRequest delRequest = new DelRequest();
294
295 String dn = entry.getDn().getUpName();
296
297 if ( isDebugEnabled() )
298 {
299 System.out.println( "Deleting entry " + dn );
300 }
301
302 delRequest.setEntry( new LdapDN( dn ) );
303
304 LdapMessage message = new LdapMessage();
305
306 message.setProtocolOP( delRequest );
307 message.setMessageId( messageId );
308
309
310 ByteBuffer bb = message.encode( null );
311 bb.flip();
312
313 sendMessage( bb );
314
315 bb.clear();
316
317
318 LdapMessage response = readResponse( bb );
319
320 LdapResult result = response.getDelResponse().getLdapResult();
321
322 if ( result.getResultCode() == ResultCodeEnum.SUCCESS )
323 {
324 if ( isDebugEnabled() )
325 {
326 System.out.println( "Delete of Entry " + entry.getDn() + " was successful" );
327 }
328
329 return IMPORT_SUCCESS;
330 }
331 else
332 {
333 System.err.println( "Delete of entry " + entry.getDn()
334 + " failed for the following reasons provided by the server:\n" + result.getErrorMessage() );
335 return IMPORT_ERROR;
336 }
337 }
338
339
340
341
342
343
344
345
346
347
348
349 private int changeModRDNEntry( LdifEntry entry, int messageId ) throws IOException, DecoderException,
350 InvalidNameException, NamingException, EncoderException
351 {
352 ModifyDNRequest modifyDNRequest = new ModifyDNRequest();
353
354 String dn = entry.getDn().getUpName();
355
356 if ( isDebugEnabled() )
357 {
358 System.out.println( "Modify DN of entry " + dn );
359 }
360
361 modifyDNRequest.setEntry( new LdapDN( dn ) );
362 modifyDNRequest.setDeleteOldRDN( entry.isDeleteOldRdn() );
363 modifyDNRequest.setNewRDN( new Rdn( entry.getNewRdn() ) );
364
365 if ( StringTools.isEmpty( entry.getNewSuperior() ) == false )
366 {
367 modifyDNRequest.setNewSuperior( new LdapDN( entry.getNewSuperior() ) );
368 }
369
370 LdapMessage message = new LdapMessage();
371
372 message.setProtocolOP( modifyDNRequest );
373 message.setMessageId( messageId );
374
375
376 ByteBuffer bb = message.encode( null );
377 bb.flip();
378
379 sendMessage( bb );
380
381 bb.clear();
382
383
384 LdapMessage response = readResponse( bb );
385
386 LdapResult result = response.getModifyDNResponse().getLdapResult();
387
388 if ( result.getResultCode() == ResultCodeEnum.SUCCESS )
389 {
390 if ( isDebugEnabled() )
391 {
392 System.out.println( "ModifyDn of Entry " + entry.getDn() + " was successful" );
393 }
394
395 return IMPORT_SUCCESS;
396 }
397 else
398 {
399 System.err.println( "ModifyDn of entry " + entry.getDn()
400 + " failed for the following reasons provided by the server:\n" + result.getErrorMessage() );
401 return IMPORT_ERROR;
402 }
403 }
404
405
406
407
408
409
410
411
412
413 private int changeModifyEntry( LdifEntry entry, int messageId ) throws IOException, DecoderException,
414 InvalidNameException, NamingException, EncoderException
415 {
416 ModifyRequest modifyRequest = new ModifyRequest();
417
418 String dn = entry.getDn().getUpName();
419
420 if ( isDebugEnabled() )
421 {
422 System.out.println( "Modify of entry " + dn );
423 }
424
425 modifyRequest.setObject( new LdapDN( dn ) );
426 modifyRequest.initModifications();
427
428 for ( Modification modification: entry.getModificationItems() )
429 {
430 modifyRequest.setCurrentOperation( modification.getOperation() );
431 modifyRequest.addAttributeTypeAndValues( modification.getAttribute().getId() );
432
433 for ( Value<?> value:modification.getAttribute() )
434 {
435 modifyRequest.addAttributeValue( value );
436 }
437 }
438
439 LdapMessage message = new LdapMessage();
440
441 message.setProtocolOP( modifyRequest );
442 message.setMessageId( messageId );
443
444
445 ByteBuffer bb = message.encode( null );
446 bb.flip();
447
448 sendMessage( bb );
449
450 bb.clear();
451
452
453 LdapMessage response = readResponse( bb );
454
455 LdapResult result = response.getModifyResponse().getLdapResult();
456
457 if ( result.getResultCode() == ResultCodeEnum.SUCCESS )
458 {
459 if ( isDebugEnabled() )
460 {
461 System.out.println( "Modify of Entry " + entry.getDn() + " was successful" );
462 }
463
464 return IMPORT_SUCCESS;
465 }
466 else
467 {
468 System.err.println( "Modify of entry " + entry.getDn()
469 + " failed for the following reasons provided by the server:\n" + result.getErrorMessage() );
470 return IMPORT_ERROR;
471 }
472 }
473
474
475
476
477
478
479
480
481
482
483
484 private int changeEntry( LdifEntry entry, int messageId ) throws IOException, DecoderException,
485 InvalidNameException, NamingException, EncoderException
486 {
487 switch ( entry.getChangeType().getChangeType() )
488 {
489 case ChangeType.ADD_ORDINAL:
490
491 return addEntry( entry, messageId );
492
493 case ChangeType.DELETE_ORDINAL:
494 return deleteEntry( entry, messageId );
495
496 case ChangeType.MODIFY_ORDINAL:
497 return changeModifyEntry( entry, messageId );
498
499 case ChangeType.MODDN_ORDINAL:
500 case ChangeType.MODRDN_ORDINAL:
501 return changeModRDNEntry( entry, messageId );
502
503 default:
504 return IMPORT_ERROR;
505 }
506 }
507
508
509
510
511
512
513
514 private void bind( int messageId ) throws NamingException, EncoderException, DecoderException, IOException
515 {
516 BindRequest bindRequest = new BindRequest();
517 LdapMessage message = new LdapMessage();
518 LdapAuthentication authentication = null;
519
520 if ( "simple".equals( auth ) )
521 {
522 authentication = new SimpleAuthentication();
523 ( ( SimpleAuthentication ) authentication ).setSimple( StringTools.getBytesUtf8( password ) );
524 }
525
526 bindRequest.setAuthentication( authentication );
527 bindRequest.setName( new LdapDN( user ) );
528 bindRequest.setVersion( 3 );
529
530 message.setProtocolOP( bindRequest );
531 message.setMessageId( messageId );
532
533
534 ByteBuffer bb = message.encode( null );
535 bb.flip();
536
537 connect();
538 sendMessage( bb );
539
540 bb.clear();
541
542
543 LdapMessage response = readResponse( bb );
544
545 LdapResult result = response.getBindResponse().getLdapResult();
546
547 if ( result.getResultCode() == ResultCodeEnum.SUCCESS )
548 {
549 if ( isDebugEnabled() )
550 {
551 System.out.println( "Binding of user " + user + " was successful" );
552 }
553 }
554 else
555 {
556 System.err.println( "Binding of user " + user
557 + " failed for the following reasons provided by the server:\n" + result.getErrorMessage() );
558 System.exit( 1 );
559 }
560 }
561
562
563
564
565
566
567
568
569
570
571
572
573 private void unbind( int messageId ) throws InvalidNameException, EncoderException, DecoderException, IOException
574 {
575 UnBindRequest unbindRequest = new UnBindRequest();
576 LdapMessage message = new LdapMessage();
577
578 message.setProtocolOP( unbindRequest );
579 message.setMessageId( messageId );
580 ByteBuffer bb = message.encode( null );
581 bb.flip();
582
583 sendMessage( bb );
584
585 if ( isDebugEnabled() )
586 {
587 System.out.println( "Unbinding of user " + user + " was successful" );
588 }
589 }
590
591
592
593
594
595
596
597
598 public void execute( CommandLine cmd ) throws Exception
599 {
600 processOptions( cmd );
601
602 if ( isDebugEnabled() )
603 {
604 System.out.println( "Parameters for Ldif import request:" );
605 System.out.println( "port = " + port );
606 System.out.println( "host = " + host );
607 System.out.println( "user = " + user );
608 System.out.println( "auth type = " + auth );
609 System.out.println( "file = " + ldifFile );
610 System.out.println( "logs = " + logs );
611 }
612
613 int messageId = 0;
614
615
616 bind( messageId++ );
617
618 if ( isDebugEnabled() )
619 {
620 System.out.println( "Connection to the server established.\n" + "Importing data ... " );
621 }
622
623 LdifReader ldifReader = new LdifReader( ldifFile );
624
625 if ( ldifReader.containsEntries() )
626 {
627
628 long t0 = System.currentTimeMillis();
629 int nbAdd = 0;
630
631 for ( LdifEntry entry:ldifReader )
632 {
633
634 if ( ldifReader.hasError() )
635 {
636 System.err
637 .println( "Found an error while persing an entry : " + ldifReader.getError().getMessage() );
638
639 if ( ignoreErrors == false )
640 {
641 unbind( messageId );
642
643 System.err.println( "Import failed..." );
644 System.exit( 1 );
645 }
646 }
647
648 if ( ( addEntry( entry, messageId++ ) == IMPORT_ERROR ) && ( ignoreErrors == false ) )
649 {
650 unbind( messageId );
651
652 System.err.println( "Import failed..." );
653 System.exit( 1 );
654 }
655
656 nbAdd++;
657
658 if ( nbAdd % 10 == 0 )
659 {
660 System.out.print( '.' );
661 }
662
663 if ( nbAdd % 500 == 0 )
664 {
665 System.out.println( nbAdd );
666 }
667 }
668
669 long t1 = System.currentTimeMillis();
670
671 System.out.println( "Done!" );
672 System.out.println( nbAdd + " users added in " + ( ( t1 - t0 ) / 1000 ) + " seconds" );
673 }
674 else
675 {
676
677 long t0 = System.currentTimeMillis();
678 int nbMod = 0;
679
680 for ( LdifEntry entry:ldifReader )
681 {
682
683 if ( ldifReader.hasError() )
684 {
685 System.err
686 .println( "Found an error while persing an entry : " + ldifReader.getError().getMessage() );
687
688 if ( ignoreErrors == false )
689 {
690 unbind( messageId );
691
692 System.err.println( "Import failed..." );
693 System.exit( 1 );
694 }
695 }
696
697 if ( ( changeEntry( entry, messageId++ ) == IMPORT_ERROR ) && ( ignoreErrors == false ) )
698 {
699 unbind( messageId );
700
701 System.err.println( "Import failed..." );
702 System.exit( 1 );
703 }
704
705 nbMod++;
706
707 if ( nbMod % 10 == 0 )
708 {
709 System.out.print( '.' );
710 }
711
712 if ( nbMod % 500 == 0 )
713 {
714 System.out.println( nbMod );
715 }
716 }
717
718 long t1 = System.currentTimeMillis();
719
720 System.out.println( "Done!" );
721 System.out.println( nbMod + " users changed in " + ( ( t1 - t0 ) / 1000 ) + " seconds" );
722 }
723
724
725 unbind( messageId++ );
726
727 }
728
729
730
731
732
733
734
735
736
737
738 private void processOptions( CommandLine cmd )
739 {
740 if ( isDebugEnabled() )
741 {
742 System.out.println( "Processing options for launching diagnostic UI ..." );
743 }
744
745
746
747
748
749 if ( cmd.hasOption( 'h' ) )
750 {
751 host = cmd.getOptionValue( 'h' );
752
753 if ( isDebugEnabled() )
754 {
755 System.out.println( "ignore-errors overriden by -i option: true" );
756 }
757 }
758 else if ( isDebugEnabled() )
759 {
760 System.out.println( "ignore-errors set to default: false" );
761 }
762
763
764
765
766
767 if ( cmd.hasOption( 'p' ) )
768
769 {
770 String val = cmd.getOptionValue( 'p' );
771
772 try
773 {
774 port = Integer.parseInt( val );
775 }
776 catch ( NumberFormatException e )
777 {
778 System.err.println( "port value of '" + val + "' is not a number" );
779 System.exit( 1 );
780 }
781
782 if ( port > AvailablePortFinder.MAX_PORT_NUMBER )
783 {
784 System.err.println( "port value of '" + val + "' is larger than max port number: "
785 + AvailablePortFinder.MAX_PORT_NUMBER );
786 System.exit( 1 );
787 }
788 else if ( port < AvailablePortFinder.MIN_PORT_NUMBER )
789 {
790 System.err.println( "port value of '" + val + "' is smaller than the minimum port number: "
791 + AvailablePortFinder.MIN_PORT_NUMBER );
792 System.exit( 1 );
793 }
794
795 if ( isDebugEnabled() )
796 {
797 System.out.println( "port overriden by -p option: " + port );
798 }
799 }
800 else if ( getApacheDS() != null )
801 {
802 port = getApacheDS().getLdapService().getIpPort();
803
804 if ( isDebugEnabled() )
805 {
806 System.out.println( "port overriden by server.xml configuration: " + port );
807 }
808 }
809 else if ( isDebugEnabled() )
810 {
811 System.out.println( "port set to default: " + port );
812 }
813
814
815
816
817
818 if ( cmd.hasOption( 'u' ) )
819 {
820 user = cmd.getOptionValue( 'u' );
821
822 if ( isDebugEnabled() )
823 {
824 System.out.println( "user overriden by -u option: " + user );
825 }
826 }
827 else if ( isDebugEnabled() )
828 {
829 System.out.println( "user set to default: " + user );
830 }
831
832
833
834
835
836 if ( cmd.hasOption( 'w' ) )
837 {
838 password = cmd.getOptionValue( 'w' );
839
840 if ( isDebugEnabled() )
841 {
842 System.out.println( "password overriden by -w option: " + password );
843 }
844 }
845 else if ( isDebugEnabled() )
846 {
847 System.out.println( "password set to default: " + password );
848 }
849
850
851
852
853
854 if ( cmd.hasOption( 'a' ) )
855 {
856 auth = cmd.getOptionValue( 'a' );
857
858 if ( isDebugEnabled() )
859 {
860 System.out.println( "authentication type overriden by -a option: " + auth );
861 }
862 }
863 else if ( isDebugEnabled() )
864 {
865 System.out.println( "authentication type set to default: " + auth );
866 }
867
868
869
870
871
872 if ( cmd.hasOption( 'e' ) )
873 {
874 ignoreErrors = true;
875
876 if ( isDebugEnabled() )
877 {
878 System.out.println( "authentication type overriden by -a option: " + auth );
879 }
880 }
881 else if ( isDebugEnabled() )
882 {
883 System.out.println( "authentication type set to default: " + auth );
884 }
885
886
887
888
889
890 if ( cmd.hasOption( 'f' ) )
891 {
892 String ldifFileName = cmd.getOptionValue( 'f' );
893
894 ldifFile = new File( ldifFileName );
895
896 if ( ldifFile.exists() == false )
897 {
898 System.err.println( "ldif file '" + ldifFileName + "' does not exist" );
899 System.exit( 1 );
900 }
901
902 if ( ldifFile.canRead() == false )
903 {
904 System.err.println( "ldif file '" + ldifFileName + "' can't be read" );
905 System.exit( 1 );
906 }
907
908 if ( isDebugEnabled() )
909 {
910 try
911 {
912 System.out.println( "ldif file to import: " + ldifFile.getCanonicalPath() );
913 }
914 catch ( IOException ioe )
915 {
916 System.out.println( "ldif file to import: " + ldifFileName );
917 }
918 }
919 }
920 else
921 {
922 System.err.println( "ldif file name must be provided" );
923 System.exit( 1 );
924 }
925 }
926
927
928 public Options getOptions()
929 {
930 Options opts = new Options();
931 Option op = new Option( "h", "host", true, "server host: defaults to localhost" );
932 op.setRequired( false );
933 opts.addOption( op );
934 op = new Option( "p", "port", true, "server port: defaults to 10389 or server.xml specified port" );
935 op.setRequired( false );
936 opts.addOption( op );
937 op = new Option( "u", "user", true, "the user: default to uid=admin, ou=system" );
938 op.setRequired( false );
939 opts.addOption( op );
940 op = new Option( "w", "password", true, "the apacheds administrator's password: defaults to secret" );
941 op.setRequired( false );
942 opts.addOption( op );
943 op = new Option( "a", "auth", true, "the authentication mode: defaults to 'simple'" );
944 op.setRequired( false );
945 opts.addOption( op );
946 op = new Option( "f", "file", true, "the ldif file to import" );
947 op.setRequired( true );
948 opts.addOption( op );
949 op = new Option( "e", "ignore", false, "continue to process the file even if errors are encountered " );
950 op.setRequired( false );
951 opts.addOption( op );
952
953 return opts;
954 }
955 }