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.core;
21
22
23 import org.apache.directory.server.constants.ServerDNConstants;
24 import org.apache.directory.server.core.authn.AuthenticationInterceptor;
25 import org.apache.directory.server.core.authn.LdapPrincipal;
26 import org.apache.directory.server.core.authz.AciAuthorizationInterceptor;
27 import org.apache.directory.server.core.authz.DefaultAuthorizationInterceptor;
28 import org.apache.directory.server.core.changelog.ChangeLog;
29 import org.apache.directory.server.core.changelog.ChangeLogEvent;
30 import org.apache.directory.server.core.changelog.ChangeLogInterceptor;
31 import org.apache.directory.server.core.changelog.DefaultChangeLog;
32 import org.apache.directory.server.core.changelog.Tag;
33 import org.apache.directory.server.core.collective.CollectiveAttributeInterceptor;
34 import org.apache.directory.server.core.cursor.Cursor;
35 import org.apache.directory.server.core.entry.DefaultServerEntry;
36 import org.apache.directory.server.core.entry.ServerEntry;
37 import org.apache.directory.server.core.event.EventInterceptor;
38 import org.apache.directory.server.core.event.EventService;
39 import org.apache.directory.server.core.exception.ExceptionInterceptor;
40 import org.apache.directory.server.core.interceptor.Interceptor;
41 import org.apache.directory.server.core.interceptor.InterceptorChain;
42 import org.apache.directory.server.core.interceptor.context.AddContextPartitionOperationContext;
43 import org.apache.directory.server.core.interceptor.context.AddOperationContext;
44 import org.apache.directory.server.core.interceptor.context.BindOperationContext;
45 import org.apache.directory.server.core.interceptor.context.EntryOperationContext;
46 import org.apache.directory.server.core.interceptor.context.LookupOperationContext;
47 import org.apache.directory.server.core.interceptor.context.RemoveContextPartitionOperationContext;
48 import org.apache.directory.server.core.normalization.NormalizationInterceptor;
49 import org.apache.directory.server.core.operational.OperationalAttributeInterceptor;
50 import org.apache.directory.server.core.partition.DefaultPartitionNexus;
51 import org.apache.directory.server.core.partition.Partition;
52 import org.apache.directory.server.core.partition.PartitionNexus;
53 import org.apache.directory.server.core.partition.impl.btree.BTreePartition;
54 import org.apache.directory.server.xdbm.Index;
55 import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmIndex;
56 import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmPartition;
57 import org.apache.directory.server.core.schema.PartitionSchemaLoader;
58 import org.apache.directory.server.core.schema.SchemaInterceptor;
59 import org.apache.directory.server.core.schema.SchemaOperationControl;
60 import org.apache.directory.server.core.schema.SchemaPartitionDao;
61 import org.apache.directory.server.core.schema.SchemaService;
62 import org.apache.directory.server.core.security.TlsKeyGenerator;
63 import org.apache.directory.server.core.subtree.SubentryInterceptor;
64 import org.apache.directory.server.core.trigger.TriggerInterceptor;
65 import org.apache.directory.server.schema.SerializableComparator;
66 import org.apache.directory.server.schema.bootstrap.ApacheSchema;
67 import org.apache.directory.server.schema.bootstrap.ApachemetaSchema;
68 import org.apache.directory.server.schema.bootstrap.BootstrapSchemaLoader;
69 import org.apache.directory.server.schema.bootstrap.CoreSchema;
70 import org.apache.directory.server.schema.bootstrap.Schema;
71 import org.apache.directory.server.schema.bootstrap.SystemSchema;
72 import org.apache.directory.server.schema.bootstrap.partition.DbFileListing;
73 import org.apache.directory.server.schema.bootstrap.partition.SchemaPartitionExtractor;
74 import org.apache.directory.server.schema.registries.DefaultOidRegistry;
75 import org.apache.directory.server.schema.registries.DefaultRegistries;
76 import org.apache.directory.server.schema.registries.OidRegistry;
77 import org.apache.directory.server.schema.registries.Registries;
78 import org.apache.directory.shared.ldap.NotImplementedException;
79 import org.apache.directory.shared.ldap.constants.AuthenticationLevel;
80 import org.apache.directory.shared.ldap.constants.SchemaConstants;
81 import org.apache.directory.shared.ldap.entry.Entry;
82 import org.apache.directory.shared.ldap.entry.EntryAttribute;
83 import org.apache.directory.shared.ldap.entry.Modification;
84 import org.apache.directory.shared.ldap.entry.client.DefaultClientEntry;
85 import org.apache.directory.shared.ldap.exception.LdapNamingException;
86 import org.apache.directory.shared.ldap.exception.LdapNoPermissionException;
87 import org.apache.directory.shared.ldap.ldif.ChangeType;
88 import org.apache.directory.shared.ldap.ldif.LdifEntry;
89 import org.apache.directory.shared.ldap.ldif.LdifReader;
90 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
91 import org.apache.directory.shared.ldap.name.LdapDN;
92 import org.apache.directory.shared.ldap.name.Rdn;
93 import org.apache.directory.shared.ldap.schema.OidNormalizer;
94 import org.apache.directory.shared.ldap.util.AttributeUtils;
95 import org.apache.directory.shared.ldap.util.DateUtils;
96 import org.apache.directory.shared.ldap.util.StringTools;
97 import org.slf4j.Logger;
98 import org.slf4j.LoggerFactory;
99
100 import javax.naming.NamingException;
101
102 import java.io.BufferedReader;
103 import java.io.File;
104 import java.io.IOException;
105 import java.io.StringReader;
106 import java.util.ArrayList;
107 import java.util.Arrays;
108 import java.util.HashSet;
109 import java.util.List;
110 import java.util.Map;
111 import java.util.Set;
112
113
114
115
116
117
118
119
120 public class DefaultDirectoryService implements DirectoryService
121 {
122
123 private static final Logger LOG = LoggerFactory.getLogger( DefaultDirectoryService.class );
124
125 private static final String ILLEGAL_STATE_MSG = "Something has got to be severely " +
126 "wrong with the core packaging\nor the build to have " +
127 "resulted in this exception.";
128
129 private SchemaService schemaService;
130
131
132 private Registries registries;
133
134
135 private DefaultPartitionNexus partitionNexus;
136
137
138 private boolean firstStart;
139
140
141 private InterceptorChain interceptorChain;
142
143
144 private boolean started;
145
146
147 private ChangeLog changeLog;
148
149
150
151
152
153 private OperationManager operationManager = new DefaultOperationManager( this );
154
155
156 private LdapDN adminDn;
157
158
159 private CoreSession adminSession;
160
161
162 private static final String PARTIAL_IMPL_WARNING =
163 "WARNING: the changelog is only partially operational and will revert\n" +
164 "state without consideration of who made the original change. All reverting " +
165 "changes are made by the admin user.\n Furthermore the used controls are not at " +
166 "all taken into account";
167
168
169
170
171
172
173
174
175
176 public DefaultDirectoryService()
177 {
178 setDefaultInterceptorConfigurations();
179 changeLog = new DefaultChangeLog();
180
181
182
183
184
185
186 BootstrapSchemaLoader loader = new BootstrapSchemaLoader();
187 OidRegistry oidRegistry = new DefaultOidRegistry();
188 registries = new DefaultRegistries( "bootstrap", loader, oidRegistry );
189
190
191 Set<Schema> bootstrapSchemas = new HashSet<Schema>();
192 bootstrapSchemas.add( new ApachemetaSchema() );
193 bootstrapSchemas.add( new ApacheSchema() );
194 bootstrapSchemas.add( new CoreSchema() );
195 bootstrapSchemas.add( new SystemSchema() );
196
197
198 try
199 {
200 loader.loadWithDependencies( bootstrapSchemas, registries );
201 }
202 catch ( Exception e )
203 {
204 throw new IllegalStateException( ILLEGAL_STATE_MSG, e );
205 }
206
207
208 List<Throwable> errors = registries.checkRefInteg();
209 if ( !errors.isEmpty() )
210 {
211 NamingException e = new NamingException();
212 e.setRootCause( errors.get( 0 ) );
213 throw new IllegalStateException( ILLEGAL_STATE_MSG, e );
214 }
215
216 SerializableComparator.setRegistry( registries.getComparatorRegistry() );
217 }
218
219
220
221
222
223
224
225 public static final int MAX_SIZE_LIMIT_DEFAULT = 100;
226 public static final int MAX_TIME_LIMIT_DEFAULT = 10000;
227
228 private String instanceId;
229 private File workingDirectory = new File( "server-work" );
230 private boolean exitVmOnShutdown = true;
231 private boolean shutdownHookEnabled = true;
232 private boolean allowAnonymousAccess = true;
233 private boolean accessControlEnabled;
234 private boolean denormalizeOpAttrsEnabled;
235 private int maxSizeLimit = MAX_SIZE_LIMIT_DEFAULT;
236 private int maxTimeLimit = MAX_TIME_LIMIT_DEFAULT;
237 private List<Interceptor> interceptors;
238 private Partition systemPartition;
239 private Set<Partition> partitions = new HashSet<Partition>();
240 private List<? extends LdifEntry> testEntries = new ArrayList<LdifEntry>();
241 private EventService eventService;
242
243
244
245 public void setInstanceId( String instanceId )
246 {
247 this.instanceId = instanceId;
248 }
249
250
251 public String getInstanceId()
252 {
253 return instanceId;
254 }
255
256
257
258
259
260
261
262
263 public Set<? extends Partition> getPartitions()
264 {
265 Set<Partition> cloned = new HashSet<Partition>();
266 cloned.addAll( partitions );
267 return cloned;
268 }
269
270
271
272
273
274
275
276
277 public void setPartitions( Set<? extends Partition> partitions )
278 {
279 Set<Partition> cloned = new HashSet<Partition>();
280 cloned.addAll( partitions );
281 Set<String> names = new HashSet<String>();
282 for ( Partition partition : cloned )
283 {
284 String id = partition.getId();
285 if ( names.contains( id ) )
286 {
287 LOG.warn( "Encountered duplicate partition {} identifier.", id );
288 }
289 names.add( id );
290 }
291
292 this.partitions = cloned;
293 }
294
295
296
297
298
299
300
301 public boolean isAccessControlEnabled()
302 {
303 return accessControlEnabled;
304 }
305
306
307
308
309
310
311
312 public void setAccessControlEnabled( boolean accessControlEnabled )
313 {
314 this.accessControlEnabled = accessControlEnabled;
315 }
316
317
318
319
320
321
322
323
324
325
326 public boolean isAllowAnonymousAccess()
327 {
328 return allowAnonymousAccess;
329 }
330
331
332
333
334
335
336
337
338
339 public void setAllowAnonymousAccess( boolean enableAnonymousAccess )
340 {
341 this.allowAnonymousAccess = enableAnonymousAccess;
342 }
343
344
345
346
347
348
349
350 public List<Interceptor> getInterceptors()
351 {
352 List<Interceptor> cloned = new ArrayList<Interceptor>();
353 cloned.addAll( interceptors );
354 return cloned;
355 }
356
357
358
359
360
361
362
363
364 public void setInterceptors( List<Interceptor> interceptors )
365 {
366 Set<String> names = new HashSet<String>();
367 for ( Interceptor interceptor : interceptors )
368 {
369 String name = interceptor.getName();
370 if ( names.contains( name ) )
371 {
372 LOG.warn( "Encountered duplicate definitions for {} interceptor", interceptor.getName() );
373 }
374 names.add( name );
375 }
376
377 this.interceptors = interceptors;
378 }
379
380
381
382
383
384
385
386
387
388 public List<LdifEntry> getTestEntries()
389 {
390 List<LdifEntry> cloned = new ArrayList<LdifEntry>();
391 cloned.addAll( testEntries );
392 return cloned;
393 }
394
395
396
397
398
399
400
401
402
403 public void setTestEntries( List<? extends LdifEntry> testEntries )
404 {
405
406 List<LdifEntry> cloned = new ArrayList<LdifEntry>();
407 cloned.addAll( testEntries );
408 this.testEntries = testEntries;
409 }
410
411
412
413
414
415
416
417
418 public File getWorkingDirectory()
419 {
420 return workingDirectory;
421 }
422
423
424
425
426
427
428
429
430 public void setWorkingDirectory( File workingDirectory )
431 {
432 this.workingDirectory = workingDirectory;
433 }
434
435
436 public void setShutdownHookEnabled( boolean shutdownHookEnabled )
437 {
438 this.shutdownHookEnabled = shutdownHookEnabled;
439 }
440
441
442 public boolean isShutdownHookEnabled()
443 {
444 return shutdownHookEnabled;
445 }
446
447
448 public void setExitVmOnShutdown( boolean exitVmOnShutdown )
449 {
450 this.exitVmOnShutdown = exitVmOnShutdown;
451 }
452
453
454 public boolean isExitVmOnShutdown()
455 {
456 return exitVmOnShutdown;
457 }
458
459
460 public void setMaxSizeLimit( int maxSizeLimit )
461 {
462 this.maxSizeLimit = maxSizeLimit;
463 }
464
465
466 public int getMaxSizeLimit()
467 {
468 return maxSizeLimit;
469 }
470
471
472 public void setMaxTimeLimit( int maxTimeLimit )
473 {
474 this.maxTimeLimit = maxTimeLimit;
475 }
476
477
478 public int getMaxTimeLimit()
479 {
480 return maxTimeLimit;
481 }
482
483 public void setSystemPartition( Partition systemPartition )
484 {
485 this.systemPartition = systemPartition;
486 }
487
488
489 public Partition getSystemPartition()
490 {
491 return systemPartition;
492 }
493
494
495 public boolean isDenormalizeOpAttrsEnabled()
496 {
497 return denormalizeOpAttrsEnabled;
498 }
499
500
501 public void setDenormalizeOpAttrsEnabled( boolean denormalizeOpAttrsEnabled )
502 {
503 this.denormalizeOpAttrsEnabled = denormalizeOpAttrsEnabled;
504 }
505
506
507 public ChangeLog getChangeLog()
508 {
509 return changeLog;
510 }
511
512
513 public void setChangeLog( ChangeLog changeLog )
514 {
515 this.changeLog = changeLog;
516 }
517
518
519 public void addPartition( Partition parition ) throws Exception
520 {
521 partitions.add( parition );
522
523 if ( ! started )
524 {
525 return;
526 }
527
528 AddContextPartitionOperationContext addPartitionCtx =
529 new AddContextPartitionOperationContext( adminSession, parition );
530 partitionNexus.addContextPartition( addPartitionCtx );
531 }
532
533
534 public void removePartition( Partition partition ) throws Exception
535 {
536 partitions.remove( partition );
537
538 if ( ! started )
539 {
540 return;
541 }
542
543 RemoveContextPartitionOperationContext removePartitionCtx =
544 new RemoveContextPartitionOperationContext( adminSession, partition.getSuffixDn() );
545 partitionNexus.removeContextPartition( removePartitionCtx );
546 }
547
548
549
550
551
552
553
554 private void setDefaultInterceptorConfigurations()
555 {
556
557 List<Interceptor> list = new ArrayList<Interceptor>();
558
559 list.add( new NormalizationInterceptor() );
560 list.add( new AuthenticationInterceptor() );
561 list.add( new AciAuthorizationInterceptor() );
562 list.add( new DefaultAuthorizationInterceptor() );
563 list.add( new ExceptionInterceptor() );
564 list.add( new ChangeLogInterceptor() );
565 list.add( new OperationalAttributeInterceptor() );
566 list.add( new SchemaInterceptor() );
567 list.add( new SubentryInterceptor() );
568 list.add( new CollectiveAttributeInterceptor() );
569 list.add( new EventInterceptor() );
570 list.add( new TriggerInterceptor() );
571
572 setInterceptors( list );
573 }
574
575
576 public CoreSession getAdminSession()
577 {
578 return adminSession;
579 }
580
581
582 public CoreSession getSession()
583 {
584 return new DefaultCoreSession( new LdapPrincipal(), this );
585 }
586
587
588 public CoreSession getSession( LdapPrincipal principal )
589 {
590 return new DefaultCoreSession( principal, this );
591 }
592
593
594 public CoreSession getSession( LdapDN principalDn, byte[] credentials )
595 throws Exception
596 {
597 if ( ! started )
598 {
599 throw new IllegalStateException( "Service has not started." );
600 }
601
602 BindOperationContext bindContext = new BindOperationContext( null );
603 bindContext.setCredentials( credentials );
604 bindContext.setDn( principalDn );
605 operationManager.bind( bindContext );
606
607 return bindContext.getSession();
608 }
609
610
611 public CoreSession getSession( LdapDN principalDn, byte[] credentials, String saslMechanism, String saslAuthId )
612 throws Exception
613 {
614 if ( ! started )
615 {
616 throw new IllegalStateException( "Service has not started." );
617 }
618
619 BindOperationContext bindContext = new BindOperationContext( null );
620 bindContext.setCredentials( credentials );
621 bindContext.setDn( principalDn );
622 bindContext.setSaslMechanism( saslMechanism );
623 operationManager.bind( bindContext );
624
625 return bindContext.getSession();
626 }
627
628
629 public long revert() throws Exception
630 {
631 if ( changeLog == null || ! changeLog.isEnabled() )
632 {
633 throw new IllegalStateException( "The change log must be enabled to revert to previous log revisions." );
634 }
635
636 Tag latest = changeLog.getLatest();
637
638 if ( null != latest )
639 {
640 if ( latest.getRevision() < changeLog.getCurrentRevision() )
641 {
642 return revert( latest.getRevision() );
643 }
644 else
645 {
646 LOG.info( "Ignoring request to revert without changes since the latest tag." );
647 return changeLog.getCurrentRevision();
648 }
649 }
650
651 throw new IllegalStateException( "There must be at least one tag to revert to the latest tag." );
652 }
653
654
655
656
657
658 private void moddn( LdapDN oldDn, LdapDN newDn, boolean delOldRdn ) throws Exception
659 {
660 if ( oldDn.size() == 0 )
661 {
662 throw new LdapNoPermissionException( "can't rename the rootDSE" );
663 }
664
665
666 LdapDN oldBase = ( LdapDN ) oldDn.clone();
667 oldBase.remove( oldDn.size() - 1 );
668 LdapDN newBase = ( LdapDN ) newDn.clone();
669 newBase.remove( newDn.size() - 1 );
670
671
672 Rdn newRdn = newDn.getRdn( newDn.size() - 1 );
673 Rdn oldRdn = oldDn.getRdn( oldDn.size() - 1 );
674
675
676
677
678
679
680
681
682
683 if ( ( oldDn.size() == newDn.size() ) && oldBase.equals( newBase ) )
684 {
685 adminSession.rename( oldDn, newRdn, delOldRdn );
686 }
687 else
688 {
689 LdapDN target = ( LdapDN ) newDn.clone();
690 target.remove( newDn.size() - 1 );
691
692 if ( newRdn.equals( oldRdn ) )
693 {
694 adminSession.move( oldDn, target );
695 }
696 else
697 {
698 adminSession.moveAndRename( oldDn, target, new Rdn( newRdn ), delOldRdn );
699 }
700 }
701 }
702
703
704 public long revert( long revision ) throws Exception
705 {
706 if ( changeLog == null || ! changeLog.isEnabled() )
707 {
708 throw new IllegalStateException( "The change log must be enabled to revert to previous log revisions." );
709 }
710
711 if ( revision < 0 )
712 {
713 throw new IllegalArgumentException( "revision must be greater than or equal to 0" );
714 }
715
716 if ( revision >= changeLog.getChangeLogStore().getCurrentRevision() )
717 {
718 throw new IllegalArgumentException( "revision must be less than the current revision" );
719 }
720
721 Cursor<ChangeLogEvent> cursor = changeLog.getChangeLogStore().findAfter( revision );
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738 try
739 {
740 LOG.warn( PARTIAL_IMPL_WARNING );
741 cursor.afterLast();
742
743 while ( cursor.previous() )
744 {
745 ChangeLogEvent event = cursor.get();
746 List<LdifEntry> reverses = event.getReverseLdifs();
747
748 for ( LdifEntry reverse:reverses )
749 {
750 switch( reverse.getChangeType().getChangeType() )
751 {
752 case( ChangeType.ADD_ORDINAL ):
753 adminSession.add(
754 new DefaultServerEntry( registries, reverse.getEntry() ) );
755 break;
756
757 case( ChangeType.DELETE_ORDINAL ):
758 adminSession.delete( reverse.getDn() );
759 break;
760
761 case( ChangeType.MODIFY_ORDINAL ):
762 List<Modification> mods = reverse.getModificationItems();
763
764 adminSession.modify( reverse.getDn(), mods );
765 break;
766
767 case( ChangeType.MODDN_ORDINAL ):
768
769
770 case( ChangeType.MODRDN_ORDINAL ):
771 LdapDN forwardDn = event.getForwardLdif().getDn();
772 LdapDN reverseDn = reverse.getDn();
773
774 moddn( reverseDn, forwardDn, reverse.isDeleteOldRdn() );
775
776 break;
777
778 default:
779 LOG.error( "ChangeType unknown" );
780 throw new NotImplementedException( "Reverts of change type " + reverse.getChangeType()
781 + " has not yet been implemented!");
782 }
783 }
784 }
785 }
786 catch ( IOException e )
787 {
788 String message = "Encountered a failure while trying to revert to a previous revision: "
789 + revision;
790 LOG.error( message );
791 throw new NamingException( message );
792 }
793
794 return changeLog.getCurrentRevision();
795 }
796
797
798 public OperationManager getOperationManager()
799 {
800 return operationManager;
801 }
802
803
804
805
806
807 public synchronized void startup() throws Exception
808 {
809 if ( started )
810 {
811 return;
812 }
813
814 if ( shutdownHookEnabled )
815 {
816 Runtime.getRuntime().addShutdownHook( new Thread( new Runnable()
817 {
818 public void run()
819 {
820 try
821 {
822 shutdown();
823 }
824 catch ( Exception e )
825 {
826 LOG.warn( "Failed to shut down the directory service: "
827 + DefaultDirectoryService.this.instanceId, e );
828 }
829 }
830 }, "ApacheDS Shutdown Hook (" + instanceId + ')' ) );
831
832 LOG.info( "ApacheDS shutdown hook has been registered with the runtime." );
833 }
834 else if ( LOG.isWarnEnabled() )
835 {
836 LOG.warn( "ApacheDS shutdown hook has NOT been registered with the runtime."
837 + " This default setting for standalone operation has been overriden." );
838 }
839
840 initialize();
841 showSecurityWarnings();
842 started = true;
843
844 if ( !testEntries.isEmpty() )
845 {
846 createTestEntries();
847 }
848 }
849
850
851 public synchronized void sync() throws Exception
852 {
853 if ( !started )
854 {
855 return;
856 }
857
858 this.changeLog.sync();
859 this.partitionNexus.sync();
860 }
861
862
863 public synchronized void shutdown() throws Exception
864 {
865 if ( !started )
866 {
867 return;
868 }
869
870 this.changeLog.sync();
871 this.changeLog.destroy();
872
873 this.partitionNexus.sync();
874 this.partitionNexus.destroy();
875 this.interceptorChain.destroy();
876 this.started = false;
877 setDefaultInterceptorConfigurations();
878 }
879
880
881 public Registries getRegistries()
882 {
883 return registries;
884 }
885
886
887 public void setRegistries( Registries registries )
888 {
889 this.registries = registries;
890 }
891
892
893 public SchemaService getSchemaService()
894 {
895 return schemaService;
896 }
897
898
899 public void setSchemaService( SchemaService schemaService )
900 {
901 this.schemaService = schemaService;
902 }
903
904
905 public PartitionNexus getPartitionNexus()
906 {
907 return partitionNexus;
908 }
909
910
911 public InterceptorChain getInterceptorChain()
912 {
913 return interceptorChain;
914 }
915
916
917 public boolean isFirstStart()
918 {
919 return firstStart;
920 }
921
922
923 public boolean isStarted()
924 {
925 return started;
926 }
927
928
929 public ServerEntry newEntry( LdapDN dn )
930 {
931 return new DefaultServerEntry( registries, dn );
932 }
933
934
935
936
937
938
939
940
941
942
943 private boolean createBootstrapEntries() throws Exception
944 {
945 boolean firstStart = false;
946
947
948
949
950
951
952
953
954 if ( !partitionNexus.hasEntry( new EntryOperationContext( adminSession, PartitionNexus.getAdminName() ) ) )
955 {
956 firstStart = true;
957
958 ServerEntry serverEntry = new DefaultServerEntry( registries, PartitionNexus.getAdminName() );
959
960 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT,
961 SchemaConstants.TOP_OC,
962 SchemaConstants.PERSON_OC,
963 SchemaConstants.ORGANIZATIONAL_PERSON_OC,
964 SchemaConstants.INET_ORG_PERSON_OC );
965
966 serverEntry.put( SchemaConstants.UID_AT, PartitionNexus.ADMIN_UID );
967 serverEntry.put( SchemaConstants.USER_PASSWORD_AT, PartitionNexus.ADMIN_PASSWORD_BYTES );
968 serverEntry.put( SchemaConstants.DISPLAY_NAME_AT, "Directory Superuser" );
969 serverEntry.put( SchemaConstants.CN_AT, "system administrator" );
970 serverEntry.put( SchemaConstants.SN_AT, "administrator" );
971 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
972 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
973 serverEntry.put( SchemaConstants.DISPLAY_NAME_AT, "Directory Superuser" );
974
975 TlsKeyGenerator.addKeyPair( serverEntry );
976 partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
977 }
978
979
980
981
982
983 Map<String,OidNormalizer> oidsMap = registries.getAttributeTypeRegistry().getNormalizerMapping();
984 LdapDN userDn = new LdapDN( ServerDNConstants.USERS_SYSTEM_DN );
985 userDn.normalize( oidsMap );
986
987 if ( !partitionNexus.hasEntry( new EntryOperationContext( adminSession, userDn ) ) )
988 {
989 firstStart = true;
990
991 ServerEntry serverEntry = new DefaultServerEntry( registries, userDn );
992
993 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT,
994 SchemaConstants.TOP_OC,
995 SchemaConstants.ORGANIZATIONAL_UNIT_OC );
996
997 serverEntry.put( SchemaConstants.OU_AT, "users" );
998 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
999 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1000
1001 partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
1002 }
1003
1004
1005
1006
1007
1008 LdapDN groupDn = new LdapDN( ServerDNConstants.GROUPS_SYSTEM_DN );
1009 groupDn.normalize( oidsMap );
1010
1011 if ( !partitionNexus.hasEntry( new EntryOperationContext( adminSession, groupDn ) ) )
1012 {
1013 firstStart = true;
1014
1015 ServerEntry serverEntry = new DefaultServerEntry( registries, groupDn );
1016
1017 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT,
1018 SchemaConstants.TOP_OC,
1019 SchemaConstants.ORGANIZATIONAL_UNIT_OC );
1020
1021 serverEntry.put( SchemaConstants.OU_AT, "groups" );
1022 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1023 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1024
1025 partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
1026 }
1027
1028
1029
1030
1031
1032 LdapDN name = new LdapDN( ServerDNConstants.ADMINISTRATORS_GROUP_DN );
1033 name.normalize( oidsMap );
1034
1035 if ( !partitionNexus.hasEntry( new EntryOperationContext( adminSession, name ) ) )
1036 {
1037 firstStart = true;
1038
1039 ServerEntry serverEntry = new DefaultServerEntry( registries, name );
1040
1041 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT,
1042 SchemaConstants.TOP_OC,
1043 SchemaConstants.GROUP_OF_UNIQUE_NAMES_OC );
1044
1045 serverEntry.put( SchemaConstants.CN_AT, "Administrators" );
1046 serverEntry.put( SchemaConstants.UNIQUE_MEMBER_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1047 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1048 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1049
1050 partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074 }
1075
1076
1077
1078
1079
1080 LdapDN configurationDn = new LdapDN( "ou=configuration,ou=system" );
1081 configurationDn.normalize( oidsMap );
1082
1083 if ( !partitionNexus.hasEntry( new EntryOperationContext( adminSession, configurationDn ) ) )
1084 {
1085 firstStart = true;
1086
1087 ServerEntry serverEntry = new DefaultServerEntry( registries, configurationDn );
1088 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, SchemaConstants.ORGANIZATIONAL_UNIT_OC );
1089
1090 serverEntry.put( SchemaConstants.OU_AT, "configuration" );
1091 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1092 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1093
1094 partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
1095 }
1096
1097
1098
1099
1100
1101 LdapDN partitionsDn = new LdapDN( "ou=partitions,ou=configuration,ou=system" );
1102 partitionsDn.normalize( oidsMap );
1103
1104 if ( !partitionNexus.hasEntry( new EntryOperationContext( adminSession, partitionsDn ) ) )
1105 {
1106 firstStart = true;
1107
1108 ServerEntry serverEntry = new DefaultServerEntry( registries, partitionsDn );
1109 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, SchemaConstants.ORGANIZATIONAL_UNIT_OC );
1110
1111 serverEntry.put( SchemaConstants.OU_AT, "partitions" );
1112 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1113 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1114
1115 partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
1116 }
1117
1118
1119
1120
1121
1122 LdapDN servicesDn = new LdapDN( "ou=services,ou=configuration,ou=system" );
1123 servicesDn.normalize( oidsMap );
1124
1125 if ( !partitionNexus.hasEntry( new EntryOperationContext( adminSession, servicesDn ) ) )
1126 {
1127 firstStart = true;
1128
1129 ServerEntry serverEntry = new DefaultServerEntry( registries, servicesDn );
1130 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, SchemaConstants.ORGANIZATIONAL_UNIT_OC );
1131
1132 serverEntry.put( SchemaConstants.OU_AT, "services" );
1133 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1134 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1135
1136 partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
1137 }
1138
1139
1140
1141
1142
1143 LdapDN interceptorsDn = new LdapDN( "ou=interceptors,ou=configuration,ou=system" );
1144 interceptorsDn.normalize( oidsMap );
1145
1146 if ( !partitionNexus.hasEntry( new EntryOperationContext( adminSession, interceptorsDn ) ) )
1147 {
1148 firstStart = true;
1149
1150 ServerEntry serverEntry = new DefaultServerEntry( registries, interceptorsDn );
1151 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, SchemaConstants.ORGANIZATIONAL_UNIT_OC );
1152
1153 serverEntry.put( SchemaConstants.OU_AT, "interceptors" );
1154 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1155 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1156
1157 partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
1158 }
1159
1160
1161
1162
1163
1164 LdapDN sysPrefRootDn = new LdapDN( ServerDNConstants.SYSPREFROOT_SYSTEM_DN );
1165 sysPrefRootDn.normalize( oidsMap );
1166
1167 if ( !partitionNexus.hasEntry( new EntryOperationContext( adminSession, sysPrefRootDn ) ) )
1168 {
1169 firstStart = true;
1170
1171 ServerEntry serverEntry = new DefaultServerEntry( registries, sysPrefRootDn );
1172 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT,
1173 SchemaConstants.TOP_OC,
1174 SchemaConstants.ORGANIZATIONAL_UNIT_OC,
1175 SchemaConstants.EXTENSIBLE_OBJECT_OC );
1176
1177 serverEntry.put( "prefNodeName", "sysPrefRoot" );
1178 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1179 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1180
1181 partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
1182 }
1183
1184 return firstStart;
1185 }
1186
1187
1188
1189
1190
1191
1192 private void showSecurityWarnings() throws Exception
1193 {
1194
1195 boolean needToChangeAdminPassword = false;
1196
1197 LdapDN adminDn = new LdapDN( ServerDNConstants.ADMIN_SYSTEM_DN );
1198 adminDn.normalize( registries.getAttributeTypeRegistry().getNormalizerMapping() );
1199
1200 ServerEntry adminEntry = partitionNexus.lookup( new LookupOperationContext( adminSession, adminDn ) );
1201 Object userPassword = adminEntry.get( SchemaConstants.USER_PASSWORD_AT ).get();
1202
1203 if ( userPassword instanceof byte[] )
1204 {
1205 needToChangeAdminPassword = Arrays.equals( PartitionNexus.ADMIN_PASSWORD_BYTES, ( byte[] ) userPassword );
1206 }
1207 else if ( userPassword.toString().equals( PartitionNexus.ADMIN_PASSWORD_STRING ) )
1208 {
1209 needToChangeAdminPassword = PartitionNexus.ADMIN_PASSWORD_STRING.equals( userPassword.toString() );
1210 }
1211
1212 if ( needToChangeAdminPassword )
1213 {
1214 LOG.warn( "You didn't change the admin password of directory service " + "instance '" + instanceId + "'. "
1215 + "Please update the admin password as soon as possible " + "to prevent a possible security breach." );
1216 }
1217 }
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227 private void createTestEntries() throws Exception
1228 {
1229 for ( LdifEntry testEntry : testEntries )
1230 {
1231 try
1232 {
1233 LdifEntry ldifEntry = testEntry.clone();
1234 Entry entry = ldifEntry.getEntry();
1235 String dn = ldifEntry.getDn().getUpName();
1236
1237 try
1238 {
1239 getAdminSession().add(
1240 new DefaultServerEntry( registries, entry ) );
1241 }
1242 catch ( Exception e )
1243 {
1244 LOG.warn( dn + " test entry already exists.", e );
1245 }
1246 }
1247 catch ( CloneNotSupportedException cnse )
1248 {
1249 LOG.warn( "Cannot clone the entry ", cnse );
1250 }
1251 }
1252 }
1253
1254
1255
1256
1257
1258
1259
1260 private void initialize() throws Exception
1261 {
1262 if ( LOG.isDebugEnabled() )
1263 {
1264 LOG.debug( "---> Initializing the DefaultDirectoryService " );
1265 }
1266
1267
1268
1269
1270
1271 File schemaDirectory = new File( workingDirectory, "schema" );
1272 SchemaPartitionExtractor extractor;
1273 if ( ! schemaDirectory.exists() )
1274 {
1275 try
1276 {
1277 extractor = new SchemaPartitionExtractor( workingDirectory );
1278 extractor.extract();
1279 }
1280 catch ( IOException e )
1281 {
1282 NamingException ne = new NamingException( "Failed to extract pre-loaded schema partition." );
1283 ne.setRootCause( e );
1284 throw ne;
1285 }
1286 }
1287
1288
1289
1290
1291
1292 JdbmPartition schemaPartition = new JdbmPartition();
1293 schemaPartition.setId( "schema" );
1294 schemaPartition.setCacheSize( 1000 );
1295
1296 DbFileListing listing;
1297
1298 try
1299 {
1300 listing = new DbFileListing();
1301 }
1302 catch( IOException e )
1303 {
1304 throw new LdapNamingException( "Got IOException while trying to read DBFileListing: " + e.getMessage(),
1305 ResultCodeEnum.OTHER );
1306 }
1307
1308 Set<Index<?,ServerEntry>> indexedAttributes = new HashSet<Index<?,ServerEntry>>();
1309
1310 for ( String attributeId : listing.getIndexedAttributes() )
1311 {
1312 indexedAttributes.add( new JdbmIndex<Object,ServerEntry>( attributeId ) );
1313 }
1314
1315 schemaPartition.setIndexedAttributes( indexedAttributes );
1316 schemaPartition.setSuffix( ServerDNConstants.OU_SCHEMA_DN );
1317 schemaPartition.init( this );
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330 SchemaPartitionDao dao = new SchemaPartitionDao( schemaPartition, registries );
1331 Map<String,Schema> schemaMap = dao.getSchemas();
1332 Set<Partition> partitions = new HashSet<Partition>();
1333 partitions.add( systemPartition );
1334 partitions.addAll( this.partitions );
1335
1336 for ( Partition partition : partitions )
1337 {
1338 if ( partition instanceof BTreePartition )
1339 {
1340 JdbmPartition btpconf = ( JdbmPartition ) partition;
1341 for ( Index<?,ServerEntry> index : btpconf.getIndexedAttributes() )
1342 {
1343 String schemaName = dao.findSchema( index.getAttributeId() );
1344 if ( schemaName == null )
1345 {
1346 throw new NamingException( "Index on unidentified attribute: " + index.toString() );
1347 }
1348
1349 Schema schema = schemaMap.get( schemaName );
1350 if ( schema.isDisabled() )
1351 {
1352 dao.enableSchema( schemaName );
1353 }
1354 }
1355 }
1356 }
1357
1358
1359
1360
1361
1362 PartitionSchemaLoader schemaLoader = new PartitionSchemaLoader( schemaPartition, registries );
1363 Registries globalRegistries = new DefaultRegistries( "global", schemaLoader, registries.getOidRegistry() );
1364 schemaLoader.loadEnabled( globalRegistries );
1365 registries = globalRegistries;
1366 SerializableComparator.setRegistry( globalRegistries.getComparatorRegistry() );
1367
1368 SchemaOperationControl schemaControl = new SchemaOperationControl( registries, schemaLoader,
1369 new SchemaPartitionDao( schemaPartition, registries ) );
1370
1371 schemaService = new SchemaService( registries, schemaPartition, schemaControl );
1372
1373 adminDn = new LdapDN( ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1374 adminDn.normalize( registries.getAttributeTypeRegistry().getNormalizerMapping() );
1375 adminSession = new DefaultCoreSession( new LdapPrincipal( adminDn, AuthenticationLevel.STRONG ), this );
1376
1377 partitionNexus = new DefaultPartitionNexus( new DefaultServerEntry( registries, LdapDN.EMPTY_LDAPDN ) );
1378 partitionNexus.init( this );
1379 partitionNexus.addContextPartition( new AddContextPartitionOperationContext( adminSession, schemaPartition ) );
1380
1381
1382 firstStart = createBootstrapEntries();
1383
1384 interceptorChain = new InterceptorChain();
1385 interceptorChain.init( this );
1386
1387 if ( changeLog.isEnabled() )
1388 {
1389 changeLog.init( this );
1390 }
1391
1392 if ( LOG.isDebugEnabled() )
1393 {
1394 LOG.debug( "<--- DefaultDirectoryService initialized" );
1395 }
1396 }
1397
1398
1399
1400
1401
1402
1403
1404
1405 private Entry readEntry( String text )
1406 {
1407 StringReader strIn = new StringReader( text );
1408 BufferedReader in = new BufferedReader( strIn );
1409
1410 String line = null;
1411 Entry entry = new DefaultClientEntry();
1412
1413 try
1414 {
1415 while ( ( line = in.readLine() ) != null )
1416 {
1417 if ( line.length() == 0 )
1418 {
1419 continue;
1420 }
1421
1422 String addedLine = line.trim();
1423
1424 if ( StringTools.isEmpty( addedLine ) )
1425 {
1426 continue;
1427 }
1428
1429 EntryAttribute attribute = AttributeUtils.toClientAttribute(
1430 LdifReader.parseAttributeValue( addedLine ) );
1431 EntryAttribute oldAttribute = entry.get( attribute.getId() );
1432
1433 if ( oldAttribute != null )
1434 {
1435 try
1436 {
1437 oldAttribute.add( attribute.get() );
1438 entry.put( oldAttribute );
1439 }
1440 catch ( NamingException ne )
1441 {
1442
1443 }
1444 }
1445 else
1446 {
1447 try
1448 {
1449 entry.put( attribute );
1450 }
1451 catch ( NamingException ne )
1452 {
1453
1454 }
1455 }
1456 }
1457 }
1458 catch (IOException ioe)
1459 {
1460
1461 }
1462
1463 return entry;
1464 }
1465
1466
1467
1468
1469
1470
1471
1472
1473 public ServerEntry newEntry( String ldif, String dn )
1474 {
1475 try
1476 {
1477 Entry entry = readEntry( ldif );
1478 LdapDN ldapDn = new LdapDN( dn );
1479
1480 entry.setDn( ldapDn );
1481
1482
1483 ServerEntry serverEntry = new DefaultServerEntry( registries, entry );
1484 return serverEntry;
1485 }
1486 catch ( Exception e )
1487 {
1488 LOG.error( "Cannot build an entry for '{}' and this DN :'{}'", ldif, dn );
1489
1490 return null;
1491 }
1492 }
1493
1494
1495 public EventService getEventService()
1496 {
1497 return eventService;
1498 }
1499
1500
1501 public void setEventService( EventService eventService )
1502 {
1503 this.eventService = eventService;
1504 }
1505 }