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 java.io.BufferedReader;
24 import java.io.File;
25 import java.io.FileNotFoundException;
26 import java.io.IOException;
27 import java.io.RandomAccessFile;
28 import java.io.StringReader;
29 import java.lang.reflect.Method;
30 import java.nio.channels.FileLock;
31 import java.nio.channels.OverlappingFileLockException;
32 import java.security.MessageDigest;
33 import java.util.ArrayList;
34 import java.util.HashSet;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Set;
38 import java.util.UUID;
39 import java.util.concurrent.ConcurrentHashMap;
40 import java.util.concurrent.locks.Lock;
41 import java.util.concurrent.locks.ReadWriteLock;
42 import java.util.concurrent.locks.ReentrantReadWriteLock;
43
44 import org.apache.directory.api.ldap.codec.api.LdapApiService;
45 import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
46 import org.apache.directory.api.ldap.model.constants.AuthenticationLevel;
47 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
48 import org.apache.directory.api.ldap.model.csn.Csn;
49 import org.apache.directory.api.ldap.model.csn.CsnFactory;
50 import org.apache.directory.api.ldap.model.cursor.Cursor;
51 import org.apache.directory.api.ldap.model.entry.Attribute;
52 import org.apache.directory.api.ldap.model.entry.DefaultEntry;
53 import org.apache.directory.api.ldap.model.entry.Entry;
54 import org.apache.directory.api.ldap.model.entry.Modification;
55 import org.apache.directory.api.ldap.model.entry.Value;
56 import org.apache.directory.api.ldap.model.exception.LdapException;
57 import org.apache.directory.api.ldap.model.exception.LdapNoPermissionException;
58 import org.apache.directory.api.ldap.model.exception.LdapOperationException;
59 import org.apache.directory.api.ldap.model.exception.LdapOtherException;
60 import org.apache.directory.api.ldap.model.ldif.ChangeType;
61 import org.apache.directory.api.ldap.model.ldif.LdifEntry;
62 import org.apache.directory.api.ldap.model.ldif.LdifReader;
63 import org.apache.directory.api.ldap.model.name.Dn;
64 import org.apache.directory.api.ldap.model.name.DnUtils;
65 import org.apache.directory.api.ldap.model.name.Rdn;
66 import org.apache.directory.api.ldap.model.schema.SchemaManager;
67 import org.apache.directory.api.ldap.util.tree.DnNode;
68 import org.apache.directory.api.util.TimeProvider;
69 import org.apache.directory.api.util.DateUtils;
70 import org.apache.directory.api.util.Strings;
71 import org.apache.directory.api.util.exception.NotImplementedException;
72 import org.apache.directory.server.constants.ApacheSchemaConstants;
73 import org.apache.directory.server.constants.ServerDNConstants;
74 import org.apache.directory.server.core.admin.AdministrativePointInterceptor;
75 import org.apache.directory.server.core.api.AttributeTypeProvider;
76 import org.apache.directory.server.core.api.CoreSession;
77 import org.apache.directory.server.core.api.DirectoryService;
78 import org.apache.directory.server.core.api.DnFactory;
79 import org.apache.directory.server.core.api.InstanceLayout;
80 import org.apache.directory.server.core.api.InterceptorEnum;
81 import org.apache.directory.server.core.api.LdapPrincipal;
82 import org.apache.directory.server.core.api.ObjectClassProvider;
83 import org.apache.directory.server.core.api.OperationEnum;
84 import org.apache.directory.server.core.api.OperationManager;
85 import org.apache.directory.server.core.api.ReferralManager;
86 import org.apache.directory.server.core.api.administrative.AccessControlAdministrativePoint;
87 import org.apache.directory.server.core.api.administrative.CollectiveAttributeAdministrativePoint;
88 import org.apache.directory.server.core.api.administrative.SubschemaAdministrativePoint;
89 import org.apache.directory.server.core.api.administrative.TriggerExecutionAdministrativePoint;
90 import org.apache.directory.server.core.api.changelog.ChangeLog;
91 import org.apache.directory.server.core.api.changelog.ChangeLogEvent;
92 import org.apache.directory.server.core.api.changelog.Tag;
93 import org.apache.directory.server.core.api.changelog.TaggableSearchableChangeLogStore;
94 import org.apache.directory.server.core.api.event.EventService;
95 import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
96 import org.apache.directory.server.core.api.interceptor.Interceptor;
97 import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
98 import org.apache.directory.server.core.api.interceptor.context.BindOperationContext;
99 import org.apache.directory.server.core.api.interceptor.context.HasEntryOperationContext;
100 import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext;
101 import org.apache.directory.server.core.api.interceptor.context.OperationContext;
102 import org.apache.directory.server.core.api.journal.Journal;
103 import org.apache.directory.server.core.api.partition.Partition;
104 import org.apache.directory.server.core.api.partition.PartitionNexus;
105 import org.apache.directory.server.core.api.partition.PartitionTxn;
106 import org.apache.directory.server.core.api.schema.SchemaPartition;
107 import org.apache.directory.server.core.api.subtree.SubentryCache;
108 import org.apache.directory.server.core.api.subtree.SubtreeEvaluator;
109 import org.apache.directory.server.core.authn.AuthenticationInterceptor;
110 import org.apache.directory.server.core.authn.ppolicy.PpolicyConfigContainer;
111 import org.apache.directory.server.core.authz.AciAuthorizationInterceptor;
112 import org.apache.directory.server.core.authz.DefaultAuthorizationInterceptor;
113 import org.apache.directory.server.core.changelog.ChangeLogInterceptor;
114 import org.apache.directory.server.core.changelog.DefaultChangeLog;
115 import org.apache.directory.server.core.collective.CollectiveAttributeInterceptor;
116 import org.apache.directory.server.core.event.EventInterceptor;
117 import org.apache.directory.server.core.exception.ExceptionInterceptor;
118 import org.apache.directory.server.core.journal.DefaultJournal;
119 import org.apache.directory.server.core.journal.JournalInterceptor;
120 import org.apache.directory.server.core.normalization.NormalizationInterceptor;
121 import org.apache.directory.server.core.operational.OperationalAttributeInterceptor;
122 import org.apache.directory.server.core.referral.ReferralInterceptor;
123 import org.apache.directory.server.core.schema.SchemaInterceptor;
124 import org.apache.directory.server.core.shared.DefaultCoreSession;
125 import org.apache.directory.server.core.shared.DefaultDnFactory;
126 import org.apache.directory.server.core.shared.partition.DefaultPartitionNexus;
127 import org.apache.directory.server.core.subtree.SubentryInterceptor;
128 import org.apache.directory.server.core.trigger.TriggerInterceptor;
129 import org.apache.directory.server.i18n.I18n;
130 import org.slf4j.Logger;
131 import org.slf4j.LoggerFactory;
132
133
134
135
136
137
138
139 public class DefaultDirectoryService implements DirectoryService
140 {
141
142 private static final Logger LOG = LoggerFactory.getLogger( DefaultDirectoryService.class );
143
144 private SchemaPartition schemaPartition;
145
146
147 private SchemaManager schemaManager;
148
149
150 private LdapApiService ldapCodecService = LdapApiServiceFactory.getSingleton();
151
152
153 private DefaultPartitionNexus partitionNexus;
154
155
156 private boolean firstStart;
157
158
159 private boolean started;
160
161
162 private ChangeLog changeLog;
163
164
165 private Journal journal;
166
167
168
169
170
171 private OperationManager operationManager = new DefaultOperationManager( this );
172
173
174 private Dn adminDn;
175
176
177 private CoreSession adminSession;
178
179
180 private ReferralManager referralManager;
181
182
183 private boolean passwordHidden = false;
184
185
186 private CsnFactory csnFactory;
187
188
189 private int replicaId;
190
191
192 private static final String PARTIAL_IMPL_WARNING =
193 "WARNING: the changelog is only partially operational and will revert\n"
194 + "state without consideration of who made the original change. All reverting "
195 + "changes are made by the admin user.\n Furthermore the used controls are not at "
196 + "all taken into account";
197
198
199 private long syncPeriodMillis;
200
201
202 private static final long DEFAULT_SYNC_PERIOD = 15000;
203
204
205 public static final int MAX_SIZE_LIMIT_DEFAULT = 100;
206
207
208 public static final int MAX_TIME_LIMIT_DEFAULT = 10000;
209
210
211 private String instanceId;
212
213
214 private InstanceLayout instanceLayout;
215
216
217
218
219
220
221 private boolean exitVmOnShutdown = true;
222
223
224 private boolean shutdownHookEnabled = true;
225
226
227 private boolean allowAnonymousAccess = false;
228
229
230 private boolean accessControlEnabled;
231
232
233 private boolean denormalizeOpAttrsEnabled;
234
235
236 private List<Interceptor> interceptors;
237 private Map<String, Interceptor> interceptorNames;
238
239
240 private ReadWriteLock interceptorsLock = new ReentrantReadWriteLock();
241
242
243 private Lock readLock = interceptorsLock.readLock();
244 private Lock writeLock = interceptorsLock.writeLock();
245
246
247 private Map<OperationEnum, List<String>> operationInterceptors;
248
249
250 private Partition systemPartition;
251
252
253 private Set<Partition> partitions = new HashSet<>();
254
255
256 private List<? extends LdifEntry> testEntries = new ArrayList<>();
257
258
259 private EventService eventService;
260
261
262 private int maxPDUSize = Integer.MAX_VALUE;
263
264
265 private RandomAccessFile lockFile = null;
266
267 private static final String LOCK_FILE_NAME = ".dirservice.lock";
268
269
270 private DnNode<AccessControlAdministrativePoint> accessControlAPCache;
271
272
273 private DnNode<CollectiveAttributeAdministrativePoint> collectiveAttributeAPCache;
274
275
276 private DnNode<SubschemaAdministrativePoint> subschemaAPCache;
277
278
279 private DnNode<TriggerExecutionAdministrativePoint> triggerExecutionAPCache;
280
281
282 private DnFactory dnFactory;
283
284
285 SubentryCachebtree/SubentryCache.html#SubentryCache">SubentryCache subentryCache = new SubentryCache();
286
287
288 private SubtreeEvaluator evaluator;
289
290
291 private AttributeTypeProvider atProvider;
292
293
294 private ObjectClassProvider ocProvider;
295
296 private TimeProvider timeProvider;
297
298
299
300
301
302
303
304
305
306
307
308 public DefaultDirectoryService() throws LdapException
309 {
310 changeLog = new DefaultChangeLog();
311 journal = new DefaultJournal();
312 syncPeriodMillis = DEFAULT_SYNC_PERIOD;
313 csnFactory = new CsnFactory( replicaId );
314 evaluator = new SubtreeEvaluator( schemaManager );
315 setDefaultInterceptorConfigurations();
316 timeProvider = TimeProvider.DEFAULT;
317 }
318
319
320
321
322
323
324 public void setInstanceId( String instanceId )
325 {
326 this.instanceId = instanceId;
327 }
328
329
330 public String getInstanceId()
331 {
332 return instanceId;
333 }
334
335
336
337
338
339
340
341 public Set<? extends Partition> getPartitions()
342 {
343 Set<Partition> cloned = new HashSet<>();
344 cloned.addAll( partitions );
345 return cloned;
346 }
347
348
349
350
351
352
353
354 public void setPartitions( Set<? extends Partition> partitions )
355 {
356 Set<Partition> cloned = new HashSet<>();
357 cloned.addAll( partitions );
358 Set<String> names = new HashSet<>();
359
360 for ( Partition partition : cloned )
361 {
362 String id = partition.getId();
363
364 if ( names.contains( id ) )
365 {
366 LOG.warn( "Encountered duplicate partition {} identifier.", id );
367 }
368
369 names.add( id );
370 }
371
372 this.partitions = cloned;
373 }
374
375
376
377
378
379
380
381 public boolean isAccessControlEnabled()
382 {
383 return accessControlEnabled;
384 }
385
386
387
388
389
390
391
392 public void setAccessControlEnabled( boolean accessControlEnabled )
393 {
394 this.accessControlEnabled = accessControlEnabled;
395 }
396
397
398
399
400
401
402
403
404
405
406 public boolean isAllowAnonymousAccess()
407 {
408 return allowAnonymousAccess;
409 }
410
411
412
413
414
415
416
417
418
419 public void setAllowAnonymousAccess( boolean enableAnonymousAccess )
420 {
421 this.allowAnonymousAccess = enableAnonymousAccess;
422 }
423
424
425
426
427
428
429
430 public List<Interceptor> getInterceptors()
431 {
432 List<Interceptor> cloned = new ArrayList<>();
433
434 readLock.lock();
435
436 try
437 {
438 cloned.addAll( interceptors );
439
440 return cloned;
441 }
442 finally
443 {
444 readLock.unlock();
445 }
446 }
447
448
449
450
451
452
453
454 public List<String> getInterceptors( OperationEnum operation )
455 {
456 List<String> cloned = new ArrayList<>();
457
458 readLock.lock();
459
460 try
461 {
462 cloned.addAll( operationInterceptors.get( operation ) );
463
464 return cloned;
465 }
466 finally
467 {
468 readLock.unlock();
469 }
470
471 }
472
473
474
475
476
477 private void initOperationsList()
478 {
479 writeLock.lock();
480
481 try
482 {
483 operationInterceptors = new ConcurrentHashMap<>();
484
485 for ( OperationEnum operation : OperationEnum.getOperations() )
486 {
487 List<String> operationList = new ArrayList<>();
488
489 for ( Interceptor interceptor : interceptors )
490 {
491 gatherInterceptors( interceptor, interceptor.getClass(), operation, operationList );
492 }
493
494 operationInterceptors.put( operation, operationList );
495 }
496 }
497 finally
498 {
499 writeLock.unlock();
500 }
501 }
502
503
504
505
506
507
508
509
510
511
512
513 private void gatherInterceptors( Interceptor interceptor, Class<?> interceptorClz, OperationEnum operation,
514 List<String> selectedInterceptorList )
515 {
516
517 if ( ( interceptorClz == null ) || ( interceptorClz == BaseInterceptor.class ) )
518 {
519 return;
520 }
521
522
523
524 Method[] methods = interceptorClz.getDeclaredMethods();
525
526 for ( Method method : methods )
527 {
528 Class<?>[] param = method.getParameterTypes();
529
530
531 if ( ( param != null ) && ( param.length == 1 )
532 && OperationContext.class.isAssignableFrom( param[0] ) && method.getName().equals( operation.getMethodName() ) )
533 {
534 if ( !selectedInterceptorList.contains( interceptor.getName() ) )
535 {
536 selectedInterceptorList.add( interceptor.getName() );
537 }
538
539 break;
540 }
541 }
542
543
544 gatherInterceptors( interceptor, interceptorClz.getSuperclass(), operation, selectedInterceptorList );
545 }
546
547
548
549
550
551
552 private void addInterceptor( Interceptor interceptor, int position ) throws LdapException
553 {
554
555 interceptor.init( this );
556
557 writeLock.lock();
558
559 try
560 {
561 for ( OperationEnum operation : OperationEnum.getOperations() )
562 {
563 List<String> operationList = operationInterceptors.get( operation );
564
565 Method[] methods = interceptor.getClass().getDeclaredMethods();
566
567 for ( Method method : methods )
568 {
569 if ( method.getName().equals( operation.getMethodName() ) )
570 {
571 if ( position == -1 )
572 {
573 operationList.add( interceptor.getName() );
574 }
575 else
576 {
577 operationList.add( position, interceptor.getName() );
578 }
579
580 break;
581 }
582 }
583 }
584
585 interceptorNames.put( interceptor.getName(), interceptor );
586
587 if ( position == -1 )
588 {
589 interceptors.add( interceptor );
590 }
591 else
592 {
593 interceptors.add( position, interceptor );
594 }
595 }
596 finally
597 {
598 writeLock.unlock();
599 }
600 }
601
602
603
604
605
606 private void removeOperationsList( String interceptorName )
607 {
608 Interceptor interceptor = interceptorNames.get( interceptorName );
609
610 writeLock.lock();
611
612 try
613 {
614 for ( OperationEnum operation : OperationEnum.getOperations() )
615 {
616 List<String> operationList = operationInterceptors.get( operation );
617
618 Method[] methods = interceptor.getClass().getDeclaredMethods();
619
620 for ( Method method : methods )
621 {
622 if ( method.getName().equals( operation.getMethodName() ) )
623 {
624 operationList.remove( interceptor.getName() );
625
626 break;
627 }
628 }
629 }
630
631 interceptorNames.remove( interceptorName );
632 interceptors.remove( interceptor );
633 }
634 finally
635 {
636 writeLock.unlock();
637 }
638 }
639
640
641
642
643
644
645
646 public void setInterceptors( List<Interceptor> interceptors )
647 {
648 Map<String, Interceptor> interceptorNames = new ConcurrentHashMap<>();
649
650
651 for ( Interceptor interceptor : interceptors )
652 {
653 if ( interceptorNames.containsKey( interceptor.getName() ) )
654 {
655 LOG.warn( "Encountered duplicate definitions for {} interceptor", interceptor.getName() );
656 continue;
657 }
658
659 interceptorNames.put( interceptor.getName(), interceptor );
660 }
661
662 this.interceptors = interceptors;
663 this.interceptorNames = interceptorNames;
664
665
666 initOperationsList();
667 }
668
669
670
671
672
673 private void initInterceptors() throws LdapException
674 {
675 for ( Interceptor interceptor : interceptors )
676 {
677 interceptor.init( this );
678 }
679 }
680
681
682
683
684
685
686
687
688 public List<LdifEntry> getTestEntries()
689 {
690 List<LdifEntry> cloned = new ArrayList<>();
691 cloned.addAll( testEntries );
692
693 return cloned;
694 }
695
696
697
698
699
700
701
702 public void setTestEntries( List<? extends LdifEntry> testEntries )
703 {
704
705 List<LdifEntry> cloned = new ArrayList<>();
706 cloned.addAll( testEntries );
707 this.testEntries = testEntries;
708 }
709
710
711
712
713
714 public InstanceLayout getInstanceLayout()
715 {
716 return instanceLayout;
717 }
718
719
720
721
722
723 public void setInstanceLayout( InstanceLayout instanceLayout ) throws IOException
724 {
725 this.instanceLayout = instanceLayout;
726
727
728 if ( !instanceLayout.getInstanceDirectory().exists() && !instanceLayout.getInstanceDirectory().mkdirs() )
729 {
730 throw new IOException( I18n.err( I18n.ERR_112_COULD_NOT_CREATE_DIRECTORY,
731 instanceLayout.getInstanceDirectory() ) );
732 }
733
734 if ( !instanceLayout.getLogDirectory().exists() && !instanceLayout.getLogDirectory().mkdirs() )
735 {
736 throw new IOException( I18n.err( I18n.ERR_112_COULD_NOT_CREATE_DIRECTORY,
737 instanceLayout.getLogDirectory() ) );
738 }
739
740 if ( !instanceLayout.getRunDirectory().exists() && !instanceLayout.getRunDirectory().mkdirs() )
741 {
742 throw new IOException( I18n.err( I18n.ERR_112_COULD_NOT_CREATE_DIRECTORY,
743 instanceLayout.getRunDirectory() ) );
744 }
745
746 if ( !instanceLayout.getPartitionsDirectory().exists() && !instanceLayout.getPartitionsDirectory().mkdirs() )
747 {
748 throw new IOException( I18n.err( I18n.ERR_112_COULD_NOT_CREATE_DIRECTORY,
749 instanceLayout.getPartitionsDirectory() ) );
750 }
751
752 if ( !instanceLayout.getConfDirectory().exists() && !instanceLayout.getConfDirectory().mkdirs() )
753 {
754 throw new IOException( I18n.err( I18n.ERR_112_COULD_NOT_CREATE_DIRECTORY,
755 instanceLayout.getConfDirectory() ) );
756 }
757 }
758
759
760 public void setShutdownHookEnabled( boolean shutdownHookEnabled )
761 {
762 this.shutdownHookEnabled = shutdownHookEnabled;
763 }
764
765
766 public boolean isShutdownHookEnabled()
767 {
768 return shutdownHookEnabled;
769 }
770
771
772 public void setExitVmOnShutdown( boolean exitVmOnShutdown )
773 {
774 this.exitVmOnShutdown = exitVmOnShutdown;
775 }
776
777
778 public boolean isExitVmOnShutdown()
779 {
780 return exitVmOnShutdown;
781 }
782
783
784 public void setSystemPartition( Partition systemPartition )
785 {
786 this.systemPartition = systemPartition;
787 }
788
789
790 public Partition getSystemPartition()
791 {
792 return systemPartition;
793 }
794
795
796
797
798
799 public boolean isDenormalizeOpAttrsEnabled()
800 {
801 return denormalizeOpAttrsEnabled;
802 }
803
804
805
806
807
808
809 public void setDenormalizeOpAttrsEnabled( boolean denormalizeOpAttrsEnabled )
810 {
811 this.denormalizeOpAttrsEnabled = denormalizeOpAttrsEnabled;
812 }
813
814
815
816
817
818 public ChangeLog getChangeLog()
819 {
820 return changeLog;
821 }
822
823
824
825
826
827 public Journal getJournal()
828 {
829 return journal;
830 }
831
832
833
834
835
836 public void setChangeLog( ChangeLog changeLog )
837 {
838 this.changeLog = changeLog;
839 }
840
841
842
843
844
845 public void setJournal( Journal journal )
846 {
847 this.journal = journal;
848 }
849
850
851
852
853
854 public void addPartition( Partition partition ) throws LdapException
855 {
856 partition.setSchemaManager( schemaManager );
857
858
859 if ( partitionNexus != null )
860 {
861 partitionNexus.addContextPartition( partition );
862 }
863
864
865 partitions.add( partition );
866 }
867
868
869
870
871
872 public void removePartition( Partition partition ) throws LdapException
873 {
874
875
876 if ( partitionNexus != null )
877 {
878 partitionNexus.removeContextPartition( partition.getSuffixDn().getNormName() );
879 }
880
881
882 partitions.remove( partition );
883 }
884
885
886
887
888
889
890
891
892
893 private void setDefaultInterceptorConfigurations()
894 {
895
896 List<Interceptor> list = new ArrayList<>();
897
898 list.add( new NormalizationInterceptor() );
899 list.add( new AuthenticationInterceptor() );
900 list.add( new ReferralInterceptor() );
901 list.add( new AciAuthorizationInterceptor() );
902 list.add( new DefaultAuthorizationInterceptor() );
903 list.add( new AdministrativePointInterceptor() );
904 list.add( new ExceptionInterceptor() );
905 list.add( new SchemaInterceptor() );
906 list.add( new OperationalAttributeInterceptor() );
907 list.add( new CollectiveAttributeInterceptor() );
908 list.add( new SubentryInterceptor() );
909 list.add( new EventInterceptor() );
910 list.add( new TriggerInterceptor() );
911 list.add( new ChangeLogInterceptor() );
912 list.add( new JournalInterceptor() );
913
914 setInterceptors( list );
915 }
916
917
918 public CoreSession getAdminSession()
919 {
920 return adminSession;
921 }
922
923
924
925
926
927 public CoreSession getSession()
928 {
929 return new DefaultCoreSession( new LdapPrincipal( schemaManager ), this );
930 }
931
932
933
934
935
936 public CoreSession getSession( LdapPrincipal principal )
937 {
938 return new DefaultCoreSession( principal, this );
939 }
940
941
942
943
944
945 public CoreSession getSession( Dn principalDn, byte[] credentials ) throws LdapException
946 {
947 synchronized ( this )
948 {
949 if ( !started )
950 {
951 throw new IllegalStateException( "Service has not started." );
952 }
953 }
954
955 BindOperationContextptor/context/BindOperationContext.html#BindOperationContext">BindOperationContext bindContext = new BindOperationContext( null );
956 bindContext.setCredentials( credentials );
957
958 if ( principalDn.isSchemaAware() )
959 {
960 bindContext.setDn( principalDn );
961 }
962 else
963 {
964 bindContext.setDn( new Dn( schemaManager, principalDn ) );
965 }
966
967 bindContext.setInterceptors( getInterceptors( OperationEnum.BIND ) );
968
969 operationManager.bind( bindContext );
970
971 return bindContext.getSession();
972 }
973
974
975
976
977
978 public CoreSession getSession( Dn principalDn, byte[] credentials, String saslMechanism, String saslAuthId )
979 throws LdapException
980 {
981 synchronized ( this )
982 {
983 if ( !started )
984 {
985 throw new IllegalStateException( "Service has not started." );
986
987 }
988 }
989
990 BindOperationContextptor/context/BindOperationContext.html#BindOperationContext">BindOperationContext bindContext = new BindOperationContext( null );
991 bindContext.setTransaction( partitionNexus.beginReadTransaction() );
992 bindContext.setCredentials( credentials );
993
994 if ( principalDn.isSchemaAware() )
995 {
996 bindContext.setDn( principalDn );
997 }
998 else
999 {
1000 bindContext.setDn( new Dn( schemaManager, principalDn ) );
1001 }
1002
1003 bindContext.setSaslMechanism( saslMechanism );
1004 bindContext.setInterceptors( getInterceptors( OperationEnum.BIND ) );
1005
1006 operationManager.bind( bindContext );
1007
1008 return bindContext.getSession();
1009 }
1010
1011
1012 public long revert() throws LdapException
1013 {
1014 if ( changeLog == null || !changeLog.isEnabled() )
1015 {
1016 throw new IllegalStateException( I18n.err( I18n.ERR_310 ) );
1017 }
1018
1019 Tag latest = changeLog.getLatest();
1020
1021 if ( null != latest )
1022 {
1023 if ( latest.getRevision() < changeLog.getCurrentRevision() )
1024 {
1025 return revert( latest.getRevision() );
1026 }
1027 else
1028 {
1029 LOG.info( "Ignoring request to revert without changes since the latest tag." );
1030 return changeLog.getCurrentRevision();
1031 }
1032 }
1033
1034 throw new IllegalStateException( I18n.err( I18n.ERR_311 ) );
1035 }
1036
1037
1038
1039
1040
1041 private void moddn( Dn oldDn, Dn newDn, boolean delOldRdn ) throws LdapException
1042 {
1043 if ( oldDn.size() == 0 )
1044 {
1045 throw new LdapNoPermissionException( I18n.err( I18n.ERR_312 ) );
1046 }
1047
1048
1049 Dn oldBase = oldDn.getParent();
1050 Dn newBase = newDn.getParent();
1051
1052
1053 Rdn newRdn = newDn.getRdn();
1054 Rdn oldRdn = oldDn.getRdn();
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064 if ( ( oldDn.size() == newDn.size() ) && oldBase.equals( newBase ) )
1065 {
1066 adminSession.rename( oldDn, newRdn, delOldRdn );
1067 }
1068 else
1069 {
1070 Dn target = newDn.getParent();
1071
1072 if ( newRdn.equals( oldRdn ) )
1073 {
1074 adminSession.move( oldDn, target );
1075 }
1076 else
1077 {
1078 adminSession.moveAndRename( oldDn, target, newRdn, delOldRdn );
1079 }
1080 }
1081 }
1082
1083
1084 public long revert( long revision ) throws LdapException
1085 {
1086 if ( changeLog == null || !changeLog.isEnabled() )
1087 {
1088 throw new IllegalStateException( I18n.err( I18n.ERR_310 ) );
1089 }
1090
1091 if ( revision < 0 )
1092 {
1093 throw new IllegalArgumentException( I18n.err( I18n.ERR_239 ) );
1094 }
1095
1096 if ( revision >= changeLog.getChangeLogStore().getCurrentRevision() )
1097 {
1098 throw new IllegalArgumentException( I18n.err( I18n.ERR_314 ) );
1099 }
1100
1101 Cursor<ChangeLogEvent> cursor = changeLog.getChangeLogStore().findAfter( revision );
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117 PartitionTxn transaction = systemPartition.beginWriteTransaction();
1118
1119 adminSession.addTransaction( systemPartition, transaction );
1120 adminSession.beginSessionTransaction();
1121
1122 try
1123 {
1124 LOG.warn( PARTIAL_IMPL_WARNING );
1125 cursor.afterLast();
1126
1127 while ( cursor.previous() )
1128 {
1129 ChangeLogEvent event = cursor.get();
1130 List<LdifEntry> reverses = event.getReverseLdifs();
1131
1132 for ( LdifEntry reverse : reverses )
1133 {
1134 switch ( reverse.getChangeType().getChangeType() )
1135 {
1136 case ChangeType.ADD_ORDINAL:
1137 adminSession.add(
1138 new DefaultEntry( schemaManager, reverse.getEntry() ), true );
1139 break;
1140
1141 case ChangeType.DELETE_ORDINAL:
1142 adminSession.delete( reverse.getDn(), true );
1143 break;
1144
1145 case ChangeType.MODIFY_ORDINAL:
1146 List<Modification> mods = reverse.getModifications();
1147
1148 adminSession.modify( reverse.getDn(), mods, true );
1149 break;
1150
1151 case ChangeType.MODDN_ORDINAL:
1152
1153
1154 case ChangeType.MODRDN_ORDINAL:
1155 Dn forwardDn = event.getForwardLdif().getDn();
1156 Dn reverseDn = reverse.getDn();
1157
1158 moddn( reverseDn, forwardDn, reverse.isDeleteOldRdn() );
1159
1160 break;
1161
1162 default:
1163 LOG.error( I18n.err( I18n.ERR_75 ) );
1164 throw new NotImplementedException( I18n.err( I18n.ERR_76, reverse.getChangeType() ) );
1165 }
1166 }
1167
1168 adminSession.endSessionTransaction( true );
1169 }
1170 }
1171 catch ( Exception e )
1172 {
1173 try
1174 {
1175 adminSession.endSessionTransaction( false );
1176 }
1177 catch ( IOException ioe )
1178 {
1179 throw new LdapOperationException( ioe.getMessage(), ioe );
1180 }
1181
1182 throw new LdapOperationException( e.getMessage(), e );
1183 }
1184 finally
1185 {
1186 try
1187 {
1188 cursor.close();
1189 }
1190 catch ( Exception e )
1191 {
1192 throw new LdapOperationException( e.getMessage(), e );
1193 }
1194 }
1195
1196 return changeLog.getCurrentRevision();
1197 }
1198
1199
1200 public OperationManager getOperationManager()
1201 {
1202 return operationManager;
1203 }
1204
1205
1206
1207
1208
1209 public synchronized void startup() throws LdapException
1210 {
1211 if ( started )
1212 {
1213 return;
1214 }
1215
1216 lockWorkDir();
1217
1218 if ( shutdownHookEnabled )
1219 {
1220 Runtime.getRuntime().addShutdownHook( new Thread( new Runnable()
1221 {
1222 public void run()
1223 {
1224 try
1225 {
1226 shutdown();
1227 }
1228 catch ( Exception e )
1229 {
1230 LOG.warn( "Failed to shut down the directory service: "
1231 + DefaultDirectoryService.this.instanceId, e );
1232 }
1233 }
1234 }, "ApacheDS Shutdown Hook (" + instanceId + ')' ) );
1235
1236 LOG.info( "ApacheDS shutdown hook has been registered with the runtime." );
1237 }
1238 else if ( LOG.isWarnEnabled() )
1239 {
1240 LOG.warn( "ApacheDS shutdown hook has NOT been registered with the runtime."
1241 + " This default setting for standalone operation has been overriden." );
1242 }
1243
1244 initialize();
1245 showSecurityWarnings();
1246
1247 started = true;
1248
1249 if ( !testEntries.isEmpty() )
1250 {
1251 createTestEntries();
1252 }
1253 }
1254
1255
1256 public synchronized void sync() throws LdapException
1257 {
1258 if ( !started )
1259 {
1260 return;
1261 }
1262
1263 this.changeLog.sync();
1264 this.partitionNexus.sync();
1265 }
1266
1267
1268 public synchronized void shutdown() throws LdapException
1269 {
1270 LOG.debug( "+++ DirectoryService Shutdown required" );
1271
1272 if ( !started )
1273 {
1274 return;
1275 }
1276
1277
1278
1279
1280 LOG.debug( "--- Syncing the nexus " );
1281 LOG.debug( "--- Flushing everything before quitting" );
1282 operationManager.lockWrite();
1283 partitionNexus.sync();
1284 operationManager.unlockWrite();
1285
1286
1287
1288
1289 LOG.debug( "--- Syncing the changeLog " );
1290 changeLog.sync();
1291 changeLog.destroy();
1292
1293
1294
1295
1296 if ( journal.isEnabled() )
1297 {
1298 LOG.debug( "--- Destroying the journal " );
1299 journal.destroy();
1300 }
1301
1302
1303
1304
1305
1306
1307 LOG.debug( "--- Destroying the nexus" );
1308 partitionNexus.destroy( null );
1309
1310
1311
1312
1313 LOG.debug( "--- Destroying the interceptors" );
1314
1315 for ( Interceptor interceptor : interceptors )
1316 {
1317 interceptor.destroy();
1318 }
1319
1320
1321
1322
1323 LOG.debug( "---Deleting the DnCache" );
1324 dnFactory = null;
1325
1326 if ( lockFile != null )
1327 {
1328 try
1329 {
1330 lockFile.close();
1331
1332 }
1333 catch ( IOException e )
1334 {
1335 LOG.warn( "couldn't delete the lock file {}", LOCK_FILE_NAME );
1336 }
1337 }
1338
1339 LOG.debug( "+++ DirectoryService stopped" );
1340 started = false;
1341 }
1342
1343
1344
1345
1346
1347 public ReferralManager getReferralManager()
1348 {
1349 return referralManager;
1350 }
1351
1352
1353
1354
1355
1356
1357 public void setReferralManager( ReferralManager referralManager )
1358 {
1359 this.referralManager = referralManager;
1360 }
1361
1362
1363
1364
1365
1366 public SchemaManager getSchemaManager()
1367 {
1368 return schemaManager;
1369 }
1370
1371
1372
1373
1374
1375
1376
1377 public void setSchemaManager( SchemaManager schemaManager )
1378 {
1379 this.schemaManager = schemaManager;
1380 }
1381
1382
1383 public LdapApiService getLdapCodecService()
1384 {
1385 return ldapCodecService;
1386 }
1387
1388
1389
1390
1391
1392 public SchemaPartition getSchemaPartition()
1393 {
1394 return schemaPartition;
1395 }
1396
1397
1398
1399
1400
1401 public void setSchemaPartition( SchemaPartition schemaPartition )
1402 {
1403 this.schemaPartition = schemaPartition;
1404 }
1405
1406
1407 public DefaultPartitionNexus getPartitionNexus()
1408 {
1409 return partitionNexus;
1410 }
1411
1412
1413 public boolean isFirstStart()
1414 {
1415 return firstStart;
1416 }
1417
1418
1419 public synchronized boolean isStarted()
1420 {
1421 return started;
1422 }
1423
1424
1425 public Entry newEntry( Dn dn )
1426 {
1427 return new DefaultEntry( schemaManager, dn );
1428 }
1429
1430
1431
1432
1433
1434 private void addEntry( Entry serverEntry ) throws LdapException
1435 {
1436 Partition partition = partitionNexus.getPartition( serverEntry.getDn() );
1437 AddOperationContextceptor/context/AddOperationContext.html#AddOperationContext">AddOperationContext addContext = new AddOperationContext( adminSession, serverEntry );
1438 PartitionTxn partitionTxn = null;
1439
1440 try
1441 {
1442 partitionTxn = partition.beginWriteTransaction();
1443 addContext.setTransaction( partitionTxn );
1444 addContext.setPartition( partition );
1445 partitionNexus.add( addContext );
1446 partitionTxn.commit();
1447 }
1448 catch ( LdapException le )
1449 {
1450 try
1451 {
1452 partitionTxn.abort();
1453 }
1454 catch ( IOException ioe )
1455 {
1456 throw new LdapOtherException( ioe.getMessage(), ioe );
1457 }
1458
1459 throw le;
1460 }
1461 catch ( IOException ioe )
1462 {
1463 try
1464 {
1465 partitionTxn.abort();
1466 }
1467 catch ( IOException ioe2 )
1468 {
1469 throw new LdapOtherException( ioe2.getMessage(), ioe2 );
1470 }
1471
1472 throw new LdapOtherException( ioe.getMessage(), ioe );
1473 }
1474 }
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485 private boolean createBootstrapEntries() throws LdapException, IOException
1486 {
1487 boolean firstStart = false;
1488
1489
1490
1491
1492
1493
1494
1495
1496 Partition partition = partitionNexus.getPartition( adminDn );
1497
1498 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() )
1499 {
1500 HasEntryOperationContexttext/HasEntryOperationContext.html#HasEntryOperationContext">HasEntryOperationContext hasEntryContext = new HasEntryOperationContext( adminSession, adminDn );
1501 hasEntryContext.setPartition( partition );
1502 hasEntryContext.setTransaction( partitionTxn );
1503
1504 if ( !partitionNexus.hasEntry( hasEntryContext ) )
1505 {
1506 firstStart = true;
1507
1508 Entry serverEntry = new DefaultEntry( schemaManager, adminDn );
1509
1510 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT,
1511 SchemaConstants.TOP_OC,
1512 SchemaConstants.PERSON_OC,
1513 SchemaConstants.ORGANIZATIONAL_PERSON_OC,
1514 SchemaConstants.INET_ORG_PERSON_OC );
1515
1516 serverEntry.put( SchemaConstants.UID_AT, PartitionNexus.ADMIN_UID );
1517 serverEntry.put( SchemaConstants.USER_PASSWORD_AT, PartitionNexus.ADMIN_PASSWORD_BYTES );
1518 serverEntry.put( SchemaConstants.DISPLAY_NAME_AT, "Directory Superuser" );
1519 serverEntry.put( SchemaConstants.CN_AT, "system administrator" );
1520 serverEntry.put( SchemaConstants.SN_AT, "administrator" );
1521 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1522 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime( getTimeProvider() ) );
1523 serverEntry.put( SchemaConstants.DISPLAY_NAME_AT, "Directory Superuser" );
1524 serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1525 serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1526
1527 addEntry( serverEntry );
1528 }
1529 }
1530
1531
1532
1533
1534
1535 Dn userDn = getDnFactory().create( ServerDNConstants.USERS_SYSTEM_DN );
1536 partition = partitionNexus.getPartition( userDn );
1537
1538 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() )
1539 {
1540 HasEntryOperationContexttext/HasEntryOperationContext.html#HasEntryOperationContext">HasEntryOperationContext hasEntryContext = new HasEntryOperationContext( adminSession, userDn );
1541 hasEntryContext.setPartition( partition );
1542 hasEntryContext.setTransaction( partitionTxn );
1543
1544 if ( !partitionNexus.hasEntry( hasEntryContext ) )
1545 {
1546 firstStart = true;
1547
1548 Entry serverEntry = new DefaultEntry( schemaManager, userDn );
1549
1550 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT,
1551 SchemaConstants.TOP_OC,
1552 SchemaConstants.ORGANIZATIONAL_UNIT_OC );
1553
1554 serverEntry.put( SchemaConstants.OU_AT, "users" );
1555 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1556 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime( getTimeProvider() ) );
1557 serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1558 serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1559
1560 addEntry( serverEntry );
1561 }
1562 }
1563
1564
1565
1566
1567
1568 Dn groupDn = getDnFactory().create( ServerDNConstants.GROUPS_SYSTEM_DN );
1569 partition = partitionNexus.getPartition( groupDn );
1570
1571 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() )
1572 {
1573 HasEntryOperationContexttext/HasEntryOperationContext.html#HasEntryOperationContext">HasEntryOperationContext hasEntryContext = new HasEntryOperationContext( adminSession, groupDn );
1574 hasEntryContext.setPartition( partition );
1575 hasEntryContext.setTransaction( partitionTxn );
1576
1577 if ( !partitionNexus.hasEntry( hasEntryContext ) )
1578 {
1579 firstStart = true;
1580
1581 Entry serverEntry = new DefaultEntry( schemaManager, groupDn );
1582
1583 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT,
1584 SchemaConstants.TOP_OC,
1585 SchemaConstants.ORGANIZATIONAL_UNIT_OC );
1586
1587 serverEntry.put( SchemaConstants.OU_AT, "groups" );
1588 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1589 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime( getTimeProvider() ) );
1590 serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1591 serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1592
1593 addEntry( serverEntry );
1594 }
1595 }
1596
1597
1598
1599
1600
1601 Dn name = getDnFactory().create( ServerDNConstants.ADMINISTRATORS_GROUP_DN );
1602 partition = partitionNexus.getPartition( name );
1603
1604 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() )
1605 {
1606 HasEntryOperationContexttext/HasEntryOperationContext.html#HasEntryOperationContext">HasEntryOperationContext hasEntryContext = new HasEntryOperationContext( adminSession, name );
1607 hasEntryContext.setPartition( partition );
1608 hasEntryContext.setTransaction( partitionTxn );
1609
1610 if ( !partitionNexus.hasEntry( hasEntryContext ) )
1611 {
1612 firstStart = true;
1613
1614 Entry serverEntry = new DefaultEntry( schemaManager, name );
1615
1616 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT,
1617 SchemaConstants.TOP_OC,
1618 SchemaConstants.GROUP_OF_UNIQUE_NAMES_OC );
1619
1620 serverEntry.put( SchemaConstants.CN_AT, "Administrators" );
1621 serverEntry.put( SchemaConstants.UNIQUE_MEMBER_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1622 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1623 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime( getTimeProvider() ) );
1624 serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1625 serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1626
1627 addEntry( serverEntry );
1628 }
1629 }
1630
1631
1632
1633
1634
1635 Dn configurationDn = getDnFactory().create( "ou=configuration,ou=system" );
1636 partition = partitionNexus.getPartition( configurationDn );
1637
1638 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() )
1639 {
1640 HasEntryOperationContexttext/HasEntryOperationContext.html#HasEntryOperationContext">HasEntryOperationContext hasEntryContext = new HasEntryOperationContext( adminSession, configurationDn );
1641 hasEntryContext.setPartition( partition );
1642 hasEntryContext.setTransaction( partitionTxn );
1643
1644 if ( !partitionNexus.hasEntry( hasEntryContext ) )
1645 {
1646 firstStart = true;
1647
1648 Entry serverEntry = new DefaultEntry( schemaManager, configurationDn );
1649 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC,
1650 SchemaConstants.ORGANIZATIONAL_UNIT_OC );
1651
1652 serverEntry.put( SchemaConstants.OU_AT, "configuration" );
1653 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1654 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime( getTimeProvider() ) );
1655 serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1656 serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1657
1658 addEntry( serverEntry );
1659 }
1660 }
1661
1662
1663
1664
1665
1666 Dn partitionsDn = getDnFactory().create( "ou=partitions,ou=configuration,ou=system" );
1667 partition = partitionNexus.getPartition( partitionsDn );
1668
1669 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() )
1670 {
1671 HasEntryOperationContexttext/HasEntryOperationContext.html#HasEntryOperationContext">HasEntryOperationContext hasEntryContext = new HasEntryOperationContext( adminSession, partitionsDn );
1672 hasEntryContext.setPartition( partition );
1673 hasEntryContext.setTransaction( partitionTxn );
1674
1675 if ( !partitionNexus.hasEntry( hasEntryContext ) )
1676 {
1677 firstStart = true;
1678
1679 Entry serverEntry = new DefaultEntry( schemaManager, partitionsDn );
1680 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC,
1681 SchemaConstants.ORGANIZATIONAL_UNIT_OC );
1682 serverEntry.put( SchemaConstants.OU_AT, "partitions" );
1683 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1684 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime( getTimeProvider() ) );
1685 serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1686 serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1687
1688 addEntry( serverEntry );
1689 }
1690 }
1691
1692
1693
1694
1695
1696 Dn servicesDn = getDnFactory().create( "ou=services,ou=configuration,ou=system" );
1697 partition = partitionNexus.getPartition( servicesDn );
1698
1699 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() )
1700 {
1701 HasEntryOperationContexttext/HasEntryOperationContext.html#HasEntryOperationContext">HasEntryOperationContext hasEntryContext = new HasEntryOperationContext( adminSession, servicesDn );
1702 hasEntryContext.setPartition( partition );
1703 hasEntryContext.setTransaction( partitionTxn );
1704
1705 if ( !partitionNexus.hasEntry( hasEntryContext ) )
1706 {
1707 firstStart = true;
1708
1709 Entry serverEntry = new DefaultEntry( schemaManager, servicesDn );
1710 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC,
1711 SchemaConstants.ORGANIZATIONAL_UNIT_OC );
1712
1713 serverEntry.put( SchemaConstants.OU_AT, "services" );
1714 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1715 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime( getTimeProvider() ) );
1716 serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1717 serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1718
1719 addEntry( serverEntry );
1720 }
1721 }
1722
1723
1724
1725
1726
1727 Dn interceptorsDn = getDnFactory().create( "ou=interceptors,ou=configuration,ou=system" );
1728 partition = partitionNexus.getPartition( interceptorsDn );
1729
1730 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() )
1731 {
1732 HasEntryOperationContexttext/HasEntryOperationContext.html#HasEntryOperationContext">HasEntryOperationContext hasEntryContext = new HasEntryOperationContext( adminSession, interceptorsDn );
1733 hasEntryContext.setPartition( partition );
1734 hasEntryContext.setTransaction( partitionTxn );
1735
1736 if ( !partitionNexus.hasEntry( hasEntryContext ) )
1737 {
1738 firstStart = true;
1739
1740 Entry serverEntry = new DefaultEntry( schemaManager, interceptorsDn );
1741 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC,
1742 SchemaConstants.ORGANIZATIONAL_UNIT_OC );
1743
1744 serverEntry.put( SchemaConstants.OU_AT, "interceptors" );
1745 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1746 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime( getTimeProvider() ) );
1747 serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1748 serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1749
1750 addEntry( serverEntry );
1751 }
1752 }
1753
1754
1755
1756
1757
1758 Dn sysPrefRootDn = getDnFactory().create( ServerDNConstants.SYSPREFROOT_SYSTEM_DN );
1759 partition = partitionNexus.getPartition( sysPrefRootDn );
1760
1761 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() )
1762 {
1763 HasEntryOperationContexttext/HasEntryOperationContext.html#HasEntryOperationContext">HasEntryOperationContext hasEntryContext = new HasEntryOperationContext( adminSession, sysPrefRootDn );
1764 hasEntryContext.setPartition( partition );
1765 hasEntryContext.setTransaction( partitionTxn );
1766
1767 if ( !partitionNexus.hasEntry( hasEntryContext ) )
1768 {
1769 firstStart = true;
1770
1771 Entry serverEntry = new DefaultEntry( schemaManager, sysPrefRootDn );
1772 serverEntry.put( SchemaConstants.OBJECT_CLASS_AT,
1773 SchemaConstants.TOP_OC,
1774 SchemaConstants.ORGANIZATIONAL_UNIT_OC,
1775 SchemaConstants.EXTENSIBLE_OBJECT_OC );
1776
1777 serverEntry.put( "prefNodeName", "sysPrefRoot" );
1778 serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1779 serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime( getTimeProvider() ) );
1780 serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1781 serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1782
1783 addEntry( serverEntry );
1784 }
1785 }
1786
1787 return firstStart;
1788 }
1789
1790
1791
1792
1793
1794
1795
1796 protected void showSecurityWarnings() throws LdapException
1797 {
1798
1799 boolean needToChangeAdminPassword;
1800
1801 Dn admin = getDnFactory().create( ServerDNConstants.ADMIN_SYSTEM_DN );
1802 Partition partition = partitionNexus.getPartition( admin );
1803 LookupOperationContext/context/LookupOperationContext.html#LookupOperationContext">LookupOperationContext lookupContext = new LookupOperationContext( adminSession, admin );
1804 lookupContext.setPartition( partition );
1805
1806 Entry adminEntry;
1807
1808 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() )
1809 {
1810 lookupContext.setTransaction( partitionTxn );
1811 adminEntry = partitionNexus.lookup( lookupContext );
1812 }
1813 catch ( IOException ioe )
1814 {
1815 throw new LdapOtherException( ioe.getMessage(), ioe );
1816 }
1817
1818 Value userPassword = adminEntry.get( SchemaConstants.USER_PASSWORD_AT ).get();
1819 needToChangeAdminPassword = MessageDigest.isEqual( PartitionNexus.ADMIN_PASSWORD_BYTES, userPassword.getBytes() );
1820
1821 if ( needToChangeAdminPassword )
1822 {
1823 LOG.warn( "You didn't change the admin password of directory service instance '{}'. "
1824 + "Please update the admin password as soon as possible to prevent a possible security breach.", instanceId );
1825 }
1826 }
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836 private void createTestEntries() throws LdapException
1837 {
1838 for ( LdifEntry testEntry : testEntries )
1839 {
1840 try
1841 {
1842 LdifEntry ldifEntry = testEntry.clone();
1843 Entry entry = ldifEntry.getEntry();
1844 String dn = ldifEntry.getDn().getName();
1845
1846 try
1847 {
1848 getAdminSession().add( new DefaultEntry( schemaManager, entry ) );
1849 }
1850 catch ( Exception e )
1851 {
1852 LOG.warn( dn + " test entry already exists.", e );
1853 }
1854 }
1855 catch ( CloneNotSupportedException cnse )
1856 {
1857 LOG.warn( "Cannot clone the entry ", cnse );
1858 }
1859 }
1860 }
1861
1862
1863 private void initializeSystemPartition() throws LdapException, IOException
1864 {
1865 Partition system = getSystemPartition();
1866
1867
1868 Dn systemSuffixDn = getDnFactory().create( ServerDNConstants.SYSTEM_DN );
1869 CoreSession admin = getAdminSession();
1870
1871 HasEntryOperationContexttext/HasEntryOperationContext.html#HasEntryOperationContext">HasEntryOperationContext hasEntryContext = new HasEntryOperationContext( admin, systemSuffixDn );
1872 Partition partition = getPartitionNexus().getPartition( systemSuffixDn );
1873 hasEntryContext.setPartition( partition );
1874
1875 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() )
1876 {
1877 hasEntryContext.setTransaction( partitionTxn );
1878
1879 if ( !system.hasEntry( hasEntryContext ) )
1880 {
1881 Entry systemEntry = new DefaultEntry( schemaManager, systemSuffixDn );
1882
1883
1884 systemEntry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC,
1885 SchemaConstants.ORGANIZATIONAL_UNIT_OC, SchemaConstants.EXTENSIBLE_OBJECT_OC );
1886
1887
1888 systemEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN );
1889 systemEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime( getTimeProvider() ) );
1890 systemEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1891 systemEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1892 systemEntry.put( DnUtils.getRdnAttributeType( ServerDNConstants.SYSTEM_DN ), DnUtils
1893 .getRdnValue( ServerDNConstants.SYSTEM_DN ) );
1894
1895 AddOperationContextntext/AddOperationContext.html#AddOperationContext">AddOperationContext addOperationContext = new AddOperationContext( admin, systemEntry );
1896 addOperationContext.setPartition( partition );
1897
1898 PartitionTxn writeTxn = null;
1899
1900 try
1901 {
1902 writeTxn = partition.beginWriteTransaction();
1903 addOperationContext.setTransaction( writeTxn );
1904 system.add( addOperationContext );
1905
1906 writeTxn.commit();
1907 }
1908 catch ( LdapException le )
1909 {
1910 try
1911 {
1912 writeTxn.abort();
1913 }
1914 catch ( IOException ioe )
1915 {
1916 throw new LdapOtherException( ioe.getMessage(), ioe );
1917 }
1918
1919 throw le;
1920 }
1921 catch ( IOException ioe )
1922 {
1923 try
1924 {
1925 writeTxn.abort();
1926 }
1927 catch ( IOException ioe2 )
1928 {
1929 throw new LdapOtherException( ioe2.getMessage(), ioe2 );
1930 }
1931
1932 throw new LdapOtherException( ioe.getMessage(), ioe );
1933 }
1934 }
1935 }
1936 }
1937
1938
1939
1940
1941
1942
1943
1944 private void initialize() throws LdapException
1945 {
1946 if ( LOG.isDebugEnabled() )
1947 {
1948 LOG.debug( "---> Initializing the DefaultDirectoryService " );
1949 }
1950
1951 csnFactory.setReplicaId( replicaId );
1952
1953
1954 if ( interceptors == null )
1955 {
1956 setDefaultInterceptorConfigurations();
1957 }
1958
1959
1960 accessControlAPCache = new DnNode<>();
1961 collectiveAttributeAPCache = new DnNode<>();
1962 subschemaAPCache = new DnNode<>();
1963 triggerExecutionAPCache = new DnNode<>();
1964
1965 if ( dnFactory == null )
1966 {
1967 dnFactory = new DefaultDnFactory( schemaManager, 10000 );
1968 }
1969
1970
1971 schemaPartition.initialize();
1972 partitions.add( schemaPartition );
1973
1974 if ( !systemPartition.getSuffixDn().isSchemaAware() )
1975 {
1976 systemPartition.setSuffixDn( new Dn( schemaManager, systemPartition.getSuffixDn() ) );
1977 }
1978
1979 adminDn = getDnFactory().create( ServerDNConstants.ADMIN_SYSTEM_DN );
1980 adminSession = new DefaultCoreSession( new LdapPrincipal( schemaManager, adminDn, AuthenticationLevel.STRONG ),
1981 this );
1982
1983
1984 partitionNexus = new DefaultPartitionNexus( new DefaultEntry( schemaManager, Dn.ROOT_DSE ) );
1985 partitionNexus.setDirectoryService( this );
1986 partitionNexus.initialize();
1987
1988 try
1989 {
1990 initializeSystemPartition();
1991 }
1992 catch ( IOException ioe )
1993 {
1994 throw new LdapException( ioe.getMessage(), ioe );
1995 }
1996
1997
1998
1999
2000
2001 try
2002 {
2003 firstStart = createBootstrapEntries();
2004 }
2005 catch ( IOException ioe )
2006 {
2007 throw new LdapException( ioe.getMessage(), ioe );
2008 }
2009
2010
2011 atProvider = new AttributeTypeProvider( schemaManager );
2012 ocProvider = new ObjectClassProvider( schemaManager );
2013
2014
2015 initInterceptors();
2016
2017
2018
2019
2020
2021 if ( changeLog.isEnabled() )
2022 {
2023 changeLog.init( this );
2024
2025 if ( changeLog.isExposed() && changeLog.isTagSearchSupported() )
2026 {
2027 String clSuffix = ( ( TaggableSearchableChangeLogStore ) changeLog.getChangeLogStore() ).getPartition()
2028 .getSuffixDn().getName();
2029 partitionNexus.getRootDse( null ).add( ApacheSchemaConstants.CHANGELOG_CONTEXT_AT, clSuffix );
2030 }
2031 }
2032
2033
2034
2035
2036 if ( journal.isEnabled() )
2037 {
2038 journal.init( this );
2039 }
2040
2041 if ( LOG.isDebugEnabled() )
2042 {
2043 LOG.debug( "<--- DefaultDirectoryService initialized" );
2044 }
2045 }
2046
2047
2048
2049
2050
2051
2052
2053
2054 private Entry readEntry( String text )
2055 {
2056 StringReader strIn = new StringReader( text );
2057 BufferedReader in = new BufferedReader( strIn );
2058
2059 String line = null;
2060 Entry entry = new DefaultEntry();
2061
2062 try
2063 {
2064 while ( ( line = in.readLine() ) != null )
2065 {
2066 if ( line.length() == 0 )
2067 {
2068 continue;
2069 }
2070
2071 String addedLine = line.trim();
2072
2073 if ( Strings.isEmpty( addedLine ) )
2074 {
2075 continue;
2076 }
2077
2078 Attribute attribute = LdifReader.parseAttributeValue( addedLine );
2079 Attribute oldAttribute = entry.get( attribute.getId() );
2080
2081 if ( oldAttribute != null )
2082 {
2083 try
2084 {
2085 oldAttribute.add( attribute.get() );
2086 entry.put( oldAttribute );
2087 }
2088 catch ( LdapException ne )
2089 {
2090
2091 }
2092 }
2093 else
2094 {
2095 try
2096 {
2097 entry.put( attribute );
2098 }
2099 catch ( LdapException ne )
2100 {
2101
2102 }
2103 }
2104 }
2105 }
2106 catch ( IOException ioe )
2107 {
2108
2109 }
2110
2111 return entry;
2112 }
2113
2114
2115
2116
2117
2118
2119
2120
2121 public Entry newEntry( String ldif, String dn )
2122 {
2123 try
2124 {
2125 Entry entry = readEntry( ldif );
2126 Dn newDn = getDnFactory().create( dn );
2127
2128 entry.setDn( newDn );
2129
2130 return new DefaultEntry( schemaManager, entry );
2131 }
2132 catch ( Exception e )
2133 {
2134 LOG.error( I18n.err( I18n.ERR_78, ldif, dn ) );
2135
2136 return null;
2137 }
2138 }
2139
2140
2141 public EventService getEventService()
2142 {
2143 return eventService;
2144 }
2145
2146
2147 public void setEventService( EventService eventService )
2148 {
2149 this.eventService = eventService;
2150 }
2151
2152
2153
2154
2155
2156 public boolean isPasswordHidden()
2157 {
2158 return passwordHidden;
2159 }
2160
2161
2162
2163
2164
2165 public void setPasswordHidden( boolean passwordHidden )
2166 {
2167 this.passwordHidden = passwordHidden;
2168 }
2169
2170
2171
2172
2173
2174 public int getMaxPDUSize()
2175 {
2176 return maxPDUSize;
2177 }
2178
2179
2180
2181
2182
2183
2184
2185 public void setMaxPDUSize( int maxPDUSize )
2186 {
2187 if ( maxPDUSize <= 0 )
2188 {
2189 maxPDUSize = Integer.MAX_VALUE;
2190 }
2191
2192 this.maxPDUSize = maxPDUSize;
2193 }
2194
2195
2196
2197
2198
2199 public Interceptor getInterceptor( String interceptorName )
2200 {
2201 return interceptorNames.get( interceptorName );
2202 }
2203
2204
2205
2206
2207
2208 public void addFirst( Interceptor interceptor ) throws LdapException
2209 {
2210 addInterceptor( interceptor, 0 );
2211 }
2212
2213
2214
2215
2216
2217 public void addLast( Interceptor interceptor ) throws LdapException
2218 {
2219 addInterceptor( interceptor, -1 );
2220 }
2221
2222
2223
2224
2225
2226 public void addAfter( String interceptorName, Interceptor interceptor )
2227 {
2228 writeLock.lock();
2229
2230 try
2231 {
2232 int position = 0;
2233
2234
2235 for ( Interceptor inter : interceptors )
2236 {
2237 if ( interceptorName.equals( inter.getName() ) )
2238 {
2239 break;
2240 }
2241
2242 position++;
2243 }
2244
2245 if ( position == interceptors.size() )
2246 {
2247 interceptors.add( interceptor );
2248 }
2249 else
2250 {
2251 interceptors.add( position, interceptor );
2252 }
2253 }
2254 finally
2255 {
2256 writeLock.unlock();
2257 }
2258 }
2259
2260
2261
2262
2263
2264 public void remove( String interceptorName )
2265 {
2266 removeOperationsList( interceptorName );
2267 }
2268
2269
2270
2271
2272
2273
2274 public Csn getCSN()
2275 {
2276 return csnFactory.newInstance();
2277 }
2278
2279
2280
2281
2282
2283 public int getReplicaId()
2284 {
2285 return replicaId;
2286 }
2287
2288
2289
2290
2291
2292 public void setReplicaId( int replicaId )
2293 {
2294 if ( ( replicaId < 0 ) || ( replicaId > 999 ) )
2295 {
2296 LOG.error( I18n.err( I18n.ERR_79 ) );
2297 this.replicaId = 0;
2298 }
2299 else
2300 {
2301 this.replicaId = replicaId;
2302 }
2303 }
2304
2305
2306
2307
2308
2309 public long getSyncPeriodMillis()
2310 {
2311 return syncPeriodMillis;
2312 }
2313
2314
2315
2316
2317
2318 public void setSyncPeriodMillis( long syncPeriodMillis )
2319 {
2320 this.syncPeriodMillis = syncPeriodMillis;
2321 }
2322
2323
2324
2325
2326
2327
2328 private void lockWorkDir()
2329 {
2330 FileLock fileLock = null;
2331
2332 try
2333 {
2334 lockFile = new RandomAccessFile( new File( instanceLayout.getInstanceDirectory(), LOCK_FILE_NAME ), "rw" );
2335 try
2336 {
2337 fileLock = lockFile.getChannel().tryLock( 0, 1, false );
2338 }
2339 catch ( IOException e )
2340 {
2341
2342 LOG.error( "failed to lock the work directory", e );
2343 }
2344 catch ( OverlappingFileLockException e )
2345 {
2346 fileLock = null;
2347 }
2348 }
2349 catch ( FileNotFoundException e )
2350 {
2351
2352 LOG.error( "failed to lock the work directory", e );
2353 }
2354
2355 if ( ( fileLock == null ) || ( !fileLock.isValid() ) )
2356 {
2357 String message = "the working directory " + instanceLayout.getRunDirectory()
2358 + " has been locked by another directory service.";
2359 LOG.error( message );
2360 throw new RuntimeException( message );
2361 }
2362
2363 }
2364
2365
2366
2367
2368
2369 public DnNode<AccessControlAdministrativePoint> getAccessControlAPCache()
2370 {
2371 return accessControlAPCache;
2372 }
2373
2374
2375
2376
2377
2378 public DnNode<CollectiveAttributeAdministrativePoint> getCollectiveAttributeAPCache()
2379 {
2380 return collectiveAttributeAPCache;
2381 }
2382
2383
2384
2385
2386
2387 public DnNode<SubschemaAdministrativePoint> getSubschemaAPCache()
2388 {
2389 return subschemaAPCache;
2390 }
2391
2392
2393
2394
2395
2396 public DnNode<TriggerExecutionAdministrativePoint> getTriggerExecutionAPCache()
2397 {
2398 return triggerExecutionAPCache;
2399 }
2400
2401
2402
2403
2404
2405 public boolean isPwdPolicyEnabled()
2406 {
2407 AuthenticationInterceptorver/core/authn/AuthenticationInterceptor.html#AuthenticationInterceptor">AuthenticationInterceptor authenticationInterceptor = ( AuthenticationInterceptor ) getInterceptor( InterceptorEnum.AUTHENTICATION_INTERCEPTOR
2408 .getName() );
2409
2410 if ( authenticationInterceptor == null )
2411 {
2412 return false;
2413 }
2414
2415 PpolicyConfigContainer pwdPolicyContainer = authenticationInterceptor.getPwdPolicyContainer();
2416
2417 return ( ( pwdPolicyContainer != null )
2418 && ( ( pwdPolicyContainer.getDefaultPolicy() != null )
2419 || ( pwdPolicyContainer.hasCustomConfigs() ) ) );
2420 }
2421
2422
2423
2424
2425
2426 public DnFactory getDnFactory()
2427 {
2428 return dnFactory;
2429 }
2430
2431
2432
2433
2434
2435 public void setDnFactory( DnFactory dnFactory )
2436 {
2437 this.dnFactory = dnFactory;
2438 }
2439
2440
2441
2442
2443
2444 public SubentryCache getSubentryCache()
2445 {
2446 return subentryCache;
2447 }
2448
2449
2450
2451
2452
2453 public SubtreeEvaluator getEvaluator()
2454 {
2455 return evaluator;
2456 }
2457
2458
2459
2460
2461
2462 @Override
2463 public AttributeTypeProvider getAtProvider()
2464 {
2465 return atProvider;
2466 }
2467
2468
2469
2470
2471
2472 @Override
2473 public ObjectClassProvider getOcProvider()
2474 {
2475 return ocProvider;
2476 }
2477
2478
2479
2480
2481
2482 @Override
2483 public TimeProvider getTimeProvider()
2484 {
2485 return timeProvider;
2486 }
2487
2488
2489
2490
2491
2492 @Override
2493 public void setTimeProvider( TimeProvider timeProvider )
2494 {
2495 this.timeProvider = timeProvider;
2496 }
2497 }