001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.server.core; 021 022 023import java.io.BufferedReader; 024import java.io.File; 025import java.io.FileNotFoundException; 026import java.io.IOException; 027import java.io.RandomAccessFile; 028import java.io.StringReader; 029import java.lang.reflect.Method; 030import java.nio.channels.FileLock; 031import java.nio.channels.OverlappingFileLockException; 032import java.security.MessageDigest; 033import java.util.ArrayList; 034import java.util.HashSet; 035import java.util.List; 036import java.util.Map; 037import java.util.Set; 038import java.util.UUID; 039import java.util.concurrent.ConcurrentHashMap; 040import java.util.concurrent.locks.Lock; 041import java.util.concurrent.locks.ReadWriteLock; 042import java.util.concurrent.locks.ReentrantReadWriteLock; 043 044import org.apache.directory.api.ldap.codec.api.LdapApiService; 045import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory; 046import org.apache.directory.api.ldap.model.constants.AuthenticationLevel; 047import org.apache.directory.api.ldap.model.constants.SchemaConstants; 048import org.apache.directory.api.ldap.model.csn.Csn; 049import org.apache.directory.api.ldap.model.csn.CsnFactory; 050import org.apache.directory.api.ldap.model.cursor.Cursor; 051import org.apache.directory.api.ldap.model.entry.Attribute; 052import org.apache.directory.api.ldap.model.entry.DefaultEntry; 053import org.apache.directory.api.ldap.model.entry.Entry; 054import org.apache.directory.api.ldap.model.entry.Modification; 055import org.apache.directory.api.ldap.model.entry.Value; 056import org.apache.directory.api.ldap.model.exception.LdapException; 057import org.apache.directory.api.ldap.model.exception.LdapNoPermissionException; 058import org.apache.directory.api.ldap.model.exception.LdapOperationException; 059import org.apache.directory.api.ldap.model.exception.LdapOtherException; 060import org.apache.directory.api.ldap.model.ldif.ChangeType; 061import org.apache.directory.api.ldap.model.ldif.LdifEntry; 062import org.apache.directory.api.ldap.model.ldif.LdifReader; 063import org.apache.directory.api.ldap.model.name.Dn; 064import org.apache.directory.api.ldap.model.name.DnUtils; 065import org.apache.directory.api.ldap.model.name.Rdn; 066import org.apache.directory.api.ldap.model.schema.SchemaManager; 067import org.apache.directory.api.ldap.util.tree.DnNode; 068import org.apache.directory.api.util.TimeProvider; 069import org.apache.directory.api.util.DateUtils; 070import org.apache.directory.api.util.Strings; 071import org.apache.directory.api.util.exception.NotImplementedException; 072import org.apache.directory.server.constants.ApacheSchemaConstants; 073import org.apache.directory.server.constants.ServerDNConstants; 074import org.apache.directory.server.core.admin.AdministrativePointInterceptor; 075import org.apache.directory.server.core.api.AttributeTypeProvider; 076import org.apache.directory.server.core.api.CoreSession; 077import org.apache.directory.server.core.api.DirectoryService; 078import org.apache.directory.server.core.api.DnFactory; 079import org.apache.directory.server.core.api.InstanceLayout; 080import org.apache.directory.server.core.api.InterceptorEnum; 081import org.apache.directory.server.core.api.LdapPrincipal; 082import org.apache.directory.server.core.api.ObjectClassProvider; 083import org.apache.directory.server.core.api.OperationEnum; 084import org.apache.directory.server.core.api.OperationManager; 085import org.apache.directory.server.core.api.ReferralManager; 086import org.apache.directory.server.core.api.administrative.AccessControlAdministrativePoint; 087import org.apache.directory.server.core.api.administrative.CollectiveAttributeAdministrativePoint; 088import org.apache.directory.server.core.api.administrative.SubschemaAdministrativePoint; 089import org.apache.directory.server.core.api.administrative.TriggerExecutionAdministrativePoint; 090import org.apache.directory.server.core.api.changelog.ChangeLog; 091import org.apache.directory.server.core.api.changelog.ChangeLogEvent; 092import org.apache.directory.server.core.api.changelog.Tag; 093import org.apache.directory.server.core.api.changelog.TaggableSearchableChangeLogStore; 094import org.apache.directory.server.core.api.event.EventService; 095import org.apache.directory.server.core.api.interceptor.BaseInterceptor; 096import org.apache.directory.server.core.api.interceptor.Interceptor; 097import org.apache.directory.server.core.api.interceptor.context.AddOperationContext; 098import org.apache.directory.server.core.api.interceptor.context.BindOperationContext; 099import org.apache.directory.server.core.api.interceptor.context.HasEntryOperationContext; 100import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext; 101import org.apache.directory.server.core.api.interceptor.context.OperationContext; 102import org.apache.directory.server.core.api.journal.Journal; 103import org.apache.directory.server.core.api.partition.Partition; 104import org.apache.directory.server.core.api.partition.PartitionNexus; 105import org.apache.directory.server.core.api.partition.PartitionTxn; 106import org.apache.directory.server.core.api.schema.SchemaPartition; 107import org.apache.directory.server.core.api.subtree.SubentryCache; 108import org.apache.directory.server.core.api.subtree.SubtreeEvaluator; 109import org.apache.directory.server.core.authn.AuthenticationInterceptor; 110import org.apache.directory.server.core.authn.ppolicy.PpolicyConfigContainer; 111import org.apache.directory.server.core.authz.AciAuthorizationInterceptor; 112import org.apache.directory.server.core.authz.DefaultAuthorizationInterceptor; 113import org.apache.directory.server.core.changelog.ChangeLogInterceptor; 114import org.apache.directory.server.core.changelog.DefaultChangeLog; 115import org.apache.directory.server.core.collective.CollectiveAttributeInterceptor; 116import org.apache.directory.server.core.event.EventInterceptor; 117import org.apache.directory.server.core.exception.ExceptionInterceptor; 118import org.apache.directory.server.core.journal.DefaultJournal; 119import org.apache.directory.server.core.journal.JournalInterceptor; 120import org.apache.directory.server.core.normalization.NormalizationInterceptor; 121import org.apache.directory.server.core.operational.OperationalAttributeInterceptor; 122import org.apache.directory.server.core.referral.ReferralInterceptor; 123import org.apache.directory.server.core.schema.SchemaInterceptor; 124import org.apache.directory.server.core.shared.DefaultCoreSession; 125import org.apache.directory.server.core.shared.DefaultDnFactory; 126import org.apache.directory.server.core.shared.partition.DefaultPartitionNexus; 127import org.apache.directory.server.core.subtree.SubentryInterceptor; 128import org.apache.directory.server.core.trigger.TriggerInterceptor; 129import org.apache.directory.server.i18n.I18n; 130import org.slf4j.Logger; 131import org.slf4j.LoggerFactory; 132 133 134/** 135 * Default implementation of {@link DirectoryService}. 136 * 137 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 138 */ 139public class DefaultDirectoryService implements DirectoryService 140{ 141 /** The logger */ 142 private static final Logger LOG = LoggerFactory.getLogger( DefaultDirectoryService.class ); 143 144 private SchemaPartition schemaPartition; 145 146 /** A reference on the SchemaManager */ 147 private SchemaManager schemaManager; 148 149 /** The LDAP Codec Service */ 150 private LdapApiService ldapCodecService = LdapApiServiceFactory.getSingleton(); 151 152 /** the root nexus */ 153 private DefaultPartitionNexus partitionNexus; 154 155 /** whether or not server is started for the first time */ 156 private boolean firstStart; 157 158 /** whether or not this instance has been shutdown */ 159 private boolean started; 160 161 /** the change log service */ 162 private ChangeLog changeLog; 163 164 /** the journal service */ 165 private Journal journal; 166 167 /** 168 * the interface used to perform various operations on this 169 * DirectoryService 170 */ 171 private OperationManager operationManager = new DefaultOperationManager( this ); 172 173 /** the distinguished name of the administrative user */ 174 private Dn adminDn; 175 176 /** session used as admin for internal operations */ 177 private CoreSession adminSession; 178 179 /** The referral manager */ 180 private ReferralManager referralManager; 181 182 /** A flag to tell if the userPassword attribute's value must be hidden */ 183 private boolean passwordHidden = false; 184 185 /** The service's CSN factory */ 186 private CsnFactory csnFactory; 187 188 /** The directory instance replication ID */ 189 private int replicaId; 190 191 /** remove me after implementation is completed */ 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 /** The delay to wait between each sync on disk */ 199 private long syncPeriodMillis; 200 201 /** The default delay to wait between sync on disk : 15 seconds */ 202 private static final long DEFAULT_SYNC_PERIOD = 15000; 203 204 /** The default timeLimit : 100 entries */ 205 public static final int MAX_SIZE_LIMIT_DEFAULT = 100; 206 207 /** The default timeLimit : 10 seconds */ 208 public static final int MAX_TIME_LIMIT_DEFAULT = 10000; 209 210 /** The instance Id */ 211 private String instanceId; 212 213 /** The server directory layout*/ 214 private InstanceLayout instanceLayout; 215 216 /** 217 * A flag used to shutdown the VM when stopping the server. Useful 218 * when the server is standalone. If the server is embedded, we don't 219 * want to shutdown the VM 220 */ 221 private boolean exitVmOnShutdown = true; // allow by default 222 223 /** A flag used to indicate that a shutdown hook has been installed */ 224 private boolean shutdownHookEnabled = true; // allow by default 225 226 /** Manage anonymous access to entries other than the RootDSE */ 227 private boolean allowAnonymousAccess = false; // forbid by default 228 229 /** Manage the basic access control checks */ 230 private boolean accessControlEnabled; // off by default 231 232 /** Manage the operational attributes denormalization */ 233 private boolean denormalizeOpAttrsEnabled; // off by default 234 235 /** The list of declared interceptors */ 236 private List<Interceptor> interceptors; 237 private Map<String, Interceptor> interceptorNames; 238 239 /** A lock to protect the interceptors List */ 240 private ReadWriteLock interceptorsLock = new ReentrantReadWriteLock(); 241 242 /** The read and write locks */ 243 private Lock readLock = interceptorsLock.readLock(); 244 private Lock writeLock = interceptorsLock.writeLock(); 245 246 /** A map associating a list of interceptor to each operation */ 247 private Map<OperationEnum, List<String>> operationInterceptors; 248 249 /** The System partition */ 250 private Partition systemPartition; 251 252 /** The set of all declared partitions */ 253 private Set<Partition> partitions = new HashSet<>(); 254 255 /** A list of LDIF entries to inject at startup */ 256 private List<? extends LdifEntry> testEntries = new ArrayList<>(); // List<Attributes> 257 258 /** The event service */ 259 private EventService eventService; 260 261 /** The maximum size for an incoming PDU */ 262 private int maxPDUSize = Integer.MAX_VALUE; 263 264 /** lock file for directory service's working directory */ 265 private RandomAccessFile lockFile = null; 266 267 private static final String LOCK_FILE_NAME = ".dirservice.lock"; 268 269 /** The AccessControl AdministrativePoint cache */ 270 private DnNode<AccessControlAdministrativePoint> accessControlAPCache; 271 272 /** The CollectiveAttribute AdministrativePoint cache */ 273 private DnNode<CollectiveAttributeAdministrativePoint> collectiveAttributeAPCache; 274 275 /** The Subschema AdministrativePoint cache */ 276 private DnNode<SubschemaAdministrativePoint> subschemaAPCache; 277 278 /** The TriggerExecution AdministrativePoint cache */ 279 private DnNode<TriggerExecutionAdministrativePoint> triggerExecutionAPCache; 280 281 /** The Dn factory */ 282 private DnFactory dnFactory; 283 284 /** The Subentry cache */ 285 SubentryCache subentryCache = new SubentryCache(); 286 287 /** The Subtree evaluator instance */ 288 private SubtreeEvaluator evaluator; 289 290 /** The attribute type provider */ 291 private AttributeTypeProvider atProvider; 292 293 /** The object class provider */ 294 private ObjectClassProvider ocProvider; 295 296 private TimeProvider timeProvider; 297 298 299 // ------------------------------------------------------------------------ 300 // Constructor 301 // ------------------------------------------------------------------------ 302 303 /** 304 * Creates a new instance of the directory service. 305 * 306 * @throws LdapException If the instance cannot be created 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 // C O N F I G U R A T I O N M E T H O D S 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 * Gets the {@link Partition}s used by this DirectoryService. 338 * 339 * @return the set of partitions used 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 * Sets {@link Partition}s used by this DirectoryService. 351 * 352 * @param partitions the partitions to used 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 * Returns <tt>true</tt> if access control checks are enabled. 378 * 379 * @return true if access control checks are enabled, false otherwise 380 */ 381 public boolean isAccessControlEnabled() 382 { 383 return accessControlEnabled; 384 } 385 386 387 /** 388 * Sets whether to enable basic access control checks or not. 389 * 390 * @param accessControlEnabled true to enable access control checks, false otherwise 391 */ 392 public void setAccessControlEnabled( boolean accessControlEnabled ) 393 { 394 this.accessControlEnabled = accessControlEnabled; 395 } 396 397 398 /** 399 * Returns <tt>true</tt> if anonymous access is allowed on entries besides the RootDSE. 400 * If the access control subsystem is enabled then access to some entries may not be 401 * allowed even when full anonymous access is enabled. 402 * 403 * @return true if anonymous access is allowed on entries besides the RootDSE, false 404 * if anonymous access is allowed to all entries. 405 */ 406 public boolean isAllowAnonymousAccess() 407 { 408 return allowAnonymousAccess; 409 } 410 411 412 /** 413 * Sets whether to allow anonymous access to entries other than the RootDSE. If the 414 * access control subsystem is enabled then access to some entries may not be allowed 415 * even when full anonymous access is enabled. 416 * 417 * @param enableAnonymousAccess true to enable anonymous access, false to disable it 418 */ 419 public void setAllowAnonymousAccess( boolean enableAnonymousAccess ) 420 { 421 this.allowAnonymousAccess = enableAnonymousAccess; 422 } 423 424 425 /** 426 * Returns interceptors in the server. 427 * 428 * @return the interceptors in the server. 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 * Returns interceptors in the server for a given operation. 451 * 452 * @return the interceptors in the server for the given operation. 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 * Compute the list of to call for each operation 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 * Recursively checks if the given interceptor can be added to the list of interceptors for a given 506 * operation and adds to the list of interceptors if it implements the respective operation 507 * 508 * @param interceptor the instance of the interceptor 509 * @param interceptorClz the class of the interceptor 510 * @param operation type of operation 511 * @param selectedInterceptorList the list of selected interceptors 512 */ 513 private void gatherInterceptors( Interceptor interceptor, Class<?> interceptorClz, OperationEnum operation, 514 List<String> selectedInterceptorList ) 515 { 516 // We stop recursing when we reach the Base class 517 if ( ( interceptorClz == null ) || ( interceptorClz == BaseInterceptor.class ) ) 518 { 519 return; 520 } 521 522 // We don't call getMethods() because it would get back the default methods 523 // from the BaseInterceptor, something we don't want. 524 Method[] methods = interceptorClz.getDeclaredMethods(); 525 526 for ( Method method : methods ) 527 { 528 Class<?>[] param = method.getParameterTypes(); 529 530 // check for the correct signature 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 // Recurse on extended classes, as we have used getDeclaredMethods() instead of getmethods() 544 gatherInterceptors( interceptor, interceptorClz.getSuperclass(), operation, selectedInterceptorList ); 545 } 546 547 548 /** 549 * Add an interceptor to the list of interceptors to call for each operation 550 * @throws LdapException 551 */ 552 private void addInterceptor( Interceptor interceptor, int position ) throws LdapException 553 { 554 // First, init the interceptor 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 * Remove an interceptor to the list of interceptors to call for each operation 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 * Sets the interceptors in the server. 643 * 644 * @param interceptors the interceptors to be used in the server. 645 */ 646 public void setInterceptors( List<Interceptor> interceptors ) 647 { 648 Map<String, Interceptor> interceptorNames = new ConcurrentHashMap<>(); 649 650 // Check if we don't have duplicate names in the interceptors list 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 // Now update the Map that connect each operation with the list of interceptors. 666 initOperationsList(); 667 } 668 669 670 /** 671 * Initialize the interceptors 672 */ 673 private void initInterceptors() throws LdapException 674 { 675 for ( Interceptor interceptor : interceptors ) 676 { 677 interceptor.init( this ); 678 } 679 } 680 681 682 /** 683 * Returns test directory entries({@link LdifEntry}) to be loaded while 684 * bootstrapping. 685 * 686 * @return test entries to load during bootstrapping 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 * Sets test directory entries to be loaded while bootstrapping. 699 * 700 * @param testEntries the test entries to load while bootstrapping 701 */ 702 public void setTestEntries( List<? extends LdifEntry> testEntries ) 703 { 704 //noinspection MismatchedQueryAndUpdateOfCollection 705 List<LdifEntry> cloned = new ArrayList<>(); 706 cloned.addAll( testEntries ); 707 this.testEntries = testEntries; 708 } 709 710 711 /** 712 * {@inheritDoc} 713 */ 714 public InstanceLayout getInstanceLayout() 715 { 716 return instanceLayout; 717 } 718 719 720 /** 721 * {@inheritDoc} 722 */ 723 public void setInstanceLayout( InstanceLayout instanceLayout ) throws IOException 724 { 725 this.instanceLayout = instanceLayout; 726 727 // Create the directories if they are missing 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 * return true if the operational attributes must be normalized when returned 798 */ 799 public boolean isDenormalizeOpAttrsEnabled() 800 { 801 return denormalizeOpAttrsEnabled; 802 } 803 804 805 /** 806 * Sets whether the operational attributes are denormalized when returned 807 * @param denormalizeOpAttrsEnabled The flag value 808 */ 809 public void setDenormalizeOpAttrsEnabled( boolean denormalizeOpAttrsEnabled ) 810 { 811 this.denormalizeOpAttrsEnabled = denormalizeOpAttrsEnabled; 812 } 813 814 815 /** 816 * {@inheritDoc} 817 */ 818 public ChangeLog getChangeLog() 819 { 820 return changeLog; 821 } 822 823 824 /** 825 * {@inheritDoc} 826 */ 827 public Journal getJournal() 828 { 829 return journal; 830 } 831 832 833 /** 834 * {@inheritDoc} 835 */ 836 public void setChangeLog( ChangeLog changeLog ) 837 { 838 this.changeLog = changeLog; 839 } 840 841 842 /** 843 * {@inheritDoc} 844 */ 845 public void setJournal( Journal journal ) 846 { 847 this.journal = journal; 848 } 849 850 851 /** 852 * {@inheritDoc} 853 */ 854 public void addPartition( Partition partition ) throws LdapException 855 { 856 partition.setSchemaManager( schemaManager ); 857 858 // can be null when called before starting up 859 if ( partitionNexus != null ) 860 { 861 partitionNexus.addContextPartition( partition ); 862 } 863 864 // Now, add the partition to the set of managed partitions 865 partitions.add( partition ); 866 } 867 868 869 /** 870 * {@inheritDoc} 871 */ 872 public void removePartition( Partition partition ) throws LdapException 873 { 874 // Do the backend cleanup first 875 // can be null when called before starting up 876 if ( partitionNexus != null ) 877 { 878 partitionNexus.removeContextPartition( partition.getSuffixDn().getNormName() ); 879 } 880 881 // And update the set of managed partitions 882 partitions.remove( partition ); 883 } 884 885 886 // ------------------------------------------------------------------------ 887 // BackendSubsystem Interface Method Implementations 888 // ------------------------------------------------------------------------ 889 /** 890 * Define a default list of interceptors that has to be used if no other 891 * configuration is defined. 892 */ 893 private void setDefaultInterceptorConfigurations() 894 { 895 // Set default interceptor chains 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 * Get back an anonymous session 926 */ 927 public CoreSession getSession() 928 { 929 return new DefaultCoreSession( new LdapPrincipal( schemaManager ), this ); 930 } 931 932 933 /** 934 * Get back a session for a given principal 935 */ 936 public CoreSession getSession( LdapPrincipal principal ) 937 { 938 return new DefaultCoreSession( principal, this ); 939 } 940 941 942 /** 943 * Get back a session for the give user and credentials bound with Simple Bind 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 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 * Get back a session for a given user bound with SASL Bind 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 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 * We handle the ModDN/ModRDN operation for the revert here. 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 // calculate parents 1049 Dn oldBase = oldDn.getParent(); 1050 Dn newBase = newDn.getParent(); 1051 1052 // Compute the Rdn for each of the Dn 1053 Rdn newRdn = newDn.getRdn(); 1054 Rdn oldRdn = oldDn.getRdn(); 1055 1056 /* 1057 * We need to determine if this rename operation corresponds to a simple 1058 * Rdn name change or a move operation. If the two names are the same 1059 * except for the Rdn then it is a simple modifyRdn operation. If the 1060 * names differ in size or have a different baseDN then the operation is 1061 * a move operation. Furthermore if the Rdn in the move operation 1062 * changes it is both an Rdn change and a move operation. 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 * BAD, BAD, BAD!!! 1105 * 1106 * No synchronization no nothing. Just getting this to work for now 1107 * so we can revert tests. Any production grade use of this feature 1108 * needs to synchronize on all changes while the revert is in progress. 1109 * 1110 * How about making this operation transactional? 1111 * 1112 * First of all just stop using JNDI and construct the operations to 1113 * feed into the interceptor pipeline. 1114 * 1115 * TODO review this code. 1116 */ 1117 PartitionTxn transaction = systemPartition.beginWriteTransaction(); 1118 // Speedup the addition by using a global transaction 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() ) // apply ldifs in reverse order 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 // NO BREAK - both ModDN and ModRDN handling is the same 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 * @throws LdapException if the LDAP server cannot be started 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 // Shutdown the sync thread 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 // Shutdown the changelog 1288 // -------------------------------------------------------------------- 1289 LOG.debug( "--- Syncing the changeLog " ); 1290 changeLog.sync(); 1291 changeLog.destroy(); 1292 1293 // -------------------------------------------------------------------- 1294 // Shutdown the journal if enabled 1295 // -------------------------------------------------------------------- 1296 if ( journal.isEnabled() ) 1297 { 1298 LOG.debug( "--- Destroying the journal " ); 1299 journal.destroy(); 1300 } 1301 1302 1303 // -------------------------------------------------------------------- 1304 // Shutdown the partition 1305 // -------------------------------------------------------------------- 1306 1307 LOG.debug( "--- Destroying the nexus" ); 1308 partitionNexus.destroy( null ); 1309 1310 // -------------------------------------------------------------------- 1311 // Shutdown the interceptors 1312 // -------------------------------------------------------------------- 1313 LOG.debug( "--- Destroying the interceptors" ); 1314 1315 for ( Interceptor interceptor : interceptors ) 1316 { 1317 interceptor.destroy(); 1318 } 1319 1320 // -------------------------------------------------------------------- 1321 // And shutdown the server 1322 // -------------------------------------------------------------------- 1323 LOG.debug( "---Deleting the DnCache" ); 1324 dnFactory = null; 1325 1326 if ( lockFile != null ) 1327 { 1328 try 1329 { 1330 lockFile.close(); 1331 // no need to delete the lock file 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 * @return The referral manager 1346 */ 1347 public ReferralManager getReferralManager() 1348 { 1349 return referralManager; 1350 } 1351 1352 1353 /** 1354 * Set the referralManager 1355 * @param referralManager The initialized referralManager 1356 */ 1357 public void setReferralManager( ReferralManager referralManager ) 1358 { 1359 this.referralManager = referralManager; 1360 } 1361 1362 1363 /** 1364 * @return the SchemaManager 1365 */ 1366 public SchemaManager getSchemaManager() 1367 { 1368 return schemaManager; 1369 } 1370 1371 1372 /** 1373 * Set the SchemaManager instance. 1374 * 1375 * @param schemaManager The server schemaManager 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 * {@inheritDoc} 1391 */ 1392 public SchemaPartition getSchemaPartition() 1393 { 1394 return schemaPartition; 1395 } 1396 1397 1398 /** 1399 * {@inheritDoc} 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 * Add a new entry into the server 1433 */ 1434 private void addEntry( Entry serverEntry ) throws LdapException 1435 { 1436 Partition partition = partitionNexus.getPartition( serverEntry.getDn() ); 1437 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 * Returns true if we had to create the bootstrap entries on the first 1479 * start of the server. Otherwise if all entries exist, meaning none 1480 * had to be created, then we are not starting for the first time. 1481 * 1482 * @return true if the bootstrap entries had to be created, false otherwise 1483 * @throws LdapException if entries cannot be created 1484 */ 1485 private boolean createBootstrapEntries() throws LdapException, IOException 1486 { 1487 boolean firstStart = false; 1488 1489 // ------------------------------------------------------------------- 1490 // create admin entry 1491 // ------------------------------------------------------------------- 1492 1493 /* 1494 * If the admin entry is there, then the database was already created 1495 */ 1496 Partition partition = partitionNexus.getPartition( adminDn ); 1497 1498 try ( PartitionTxn partitionTxn = partition.beginReadTransaction() ) 1499 { 1500 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 // create system users area 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 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 // create system groups area 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 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 // create administrator group 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 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 // create system configuration area 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 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 // create system configuration area for partition information 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 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 // create system configuration area for services 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 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 // create system configuration area for interceptors 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 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 // create system preferences area 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 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 * Displays security warning messages if any possible secutiry issue is found. 1793 * @throws LdapException if there are failures parsing and accessing internal structures 1794 */ 1795 // made protected as per the request in DIRSERVER-1920 1796 protected void showSecurityWarnings() throws LdapException 1797 { 1798 // Warn if the default password is not changed. 1799 boolean needToChangeAdminPassword; 1800 1801 Dn admin = getDnFactory().create( ServerDNConstants.ADMIN_SYSTEM_DN ); 1802 Partition partition = partitionNexus.getPartition( admin ); 1803 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 * Adds test entries into the core. 1831 * 1832 * TODO this may no longer be needed when JNDI is not used for bootstrapping 1833 * 1834 * @throws LdapException if the creation of test entries fails. 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 // Add root context entry for system partition 1868 Dn systemSuffixDn = getDnFactory().create( ServerDNConstants.SYSTEM_DN ); 1869 CoreSession admin = getAdminSession(); 1870 1871 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 // Add the ObjectClasses 1884 systemEntry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, 1885 SchemaConstants.ORGANIZATIONAL_UNIT_OC, SchemaConstants.EXTENSIBLE_OBJECT_OC ); 1886 1887 // Add some operational attributes 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 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 * Kicks off the initialization of the entire system. 1941 * 1942 * @throws LdapException if there are problems along the way 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 // If no interceptor list is defined, setup a default list 1954 if ( interceptors == null ) 1955 { 1956 setDefaultInterceptorConfigurations(); 1957 } 1958 1959 // Initialize the AP caches 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 // triggers partition to load schema fully from schema partition 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 // TODO - NOTE: Need to find a way to instantiate without dependency on DPN 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 // Create all the bootstrap entries before initializing chain 1999 // -------------------------------------------------------------------- 2000 2001 try 2002 { 2003 firstStart = createBootstrapEntries(); 2004 } 2005 catch ( IOException ioe ) 2006 { 2007 throw new LdapException( ioe.getMessage(), ioe ); 2008 } 2009 2010 // initialize schema providers 2011 atProvider = new AttributeTypeProvider( schemaManager ); 2012 ocProvider = new ObjectClassProvider( schemaManager ); 2013 2014 // Initialize the interceptors 2015 initInterceptors(); 2016 2017 // -------------------------------------------------------------------- 2018 // Initialize the changeLog if it's enabled 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 // Initialize the journal if it's enabled 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 * Read an entry (without Dn) 2050 * 2051 * @param text The ldif format file 2052 * @return An entry. 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 // Do nothing 2091 } 2092 } 2093 else 2094 { 2095 try 2096 { 2097 entry.put( attribute ); 2098 } 2099 catch ( LdapException ne ) 2100 { 2101 // TODO do nothing ... 2102 } 2103 } 2104 } 2105 } 2106 catch ( IOException ioe ) 2107 { 2108 // Do nothing : we can't reach this point ! 2109 } 2110 2111 return entry; 2112 } 2113 2114 2115 /** 2116 * Create a new Entry 2117 * 2118 * @param ldif The String representing the attributes, as a LDIF file 2119 * @param dn The Dn for this new entry 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 // do nothing 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 * {@inheritDoc} 2155 */ 2156 public boolean isPasswordHidden() 2157 { 2158 return passwordHidden; 2159 } 2160 2161 2162 /** 2163 * {@inheritDoc} 2164 */ 2165 public void setPasswordHidden( boolean passwordHidden ) 2166 { 2167 this.passwordHidden = passwordHidden; 2168 } 2169 2170 2171 /** 2172 * @return The maximum allowed size for an incoming PDU 2173 */ 2174 public int getMaxPDUSize() 2175 { 2176 return maxPDUSize; 2177 } 2178 2179 2180 /** 2181 * Set the maximum allowed size for an incoming PDU 2182 * @param maxPDUSize A positive number of bytes for the PDU. A negative or 2183 * null value will be transformed to {@link Integer#MAX_VALUE} 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 * {@inheritDoc} 2198 */ 2199 public Interceptor getInterceptor( String interceptorName ) 2200 { 2201 return interceptorNames.get( interceptorName ); 2202 } 2203 2204 2205 /** 2206 * {@inheritDoc} 2207 */ 2208 public void addFirst( Interceptor interceptor ) throws LdapException 2209 { 2210 addInterceptor( interceptor, 0 ); 2211 } 2212 2213 2214 /** 2215 * {@inheritDoc} 2216 */ 2217 public void addLast( Interceptor interceptor ) throws LdapException 2218 { 2219 addInterceptor( interceptor, -1 ); 2220 } 2221 2222 2223 /** 2224 * {@inheritDoc} 2225 */ 2226 public void addAfter( String interceptorName, Interceptor interceptor ) 2227 { 2228 writeLock.lock(); 2229 2230 try 2231 { 2232 int position = 0; 2233 2234 // Find the position 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 * {@inheritDoc} 2263 */ 2264 public void remove( String interceptorName ) 2265 { 2266 removeOperationsList( interceptorName ); 2267 } 2268 2269 2270 /** 2271 * Get a new CSN 2272 * @return The CSN generated for this directory service 2273 */ 2274 public Csn getCSN() 2275 { 2276 return csnFactory.newInstance(); 2277 } 2278 2279 2280 /** 2281 * @return the replicaId 2282 */ 2283 public int getReplicaId() 2284 { 2285 return replicaId; 2286 } 2287 2288 2289 /** 2290 * @param replicaId the replicaId to set 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 * {@inheritDoc} 2308 */ 2309 public long getSyncPeriodMillis() 2310 { 2311 return syncPeriodMillis; 2312 } 2313 2314 2315 /** 2316 * {@inheritDoc} 2317 */ 2318 public void setSyncPeriodMillis( long syncPeriodMillis ) 2319 { 2320 this.syncPeriodMillis = syncPeriodMillis; 2321 } 2322 2323 2324 /** 2325 * checks if the working directory is already in use by some other directory service, if yes 2326 * then throws a runtime exception else will obtain the lock on the working directory 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 // shoudn't happen, but log 2342 LOG.error( "failed to lock the work directory", e ); 2343 } 2344 catch ( OverlappingFileLockException e ) // thrown if we can't get a lock 2345 { 2346 fileLock = null; 2347 } 2348 } 2349 catch ( FileNotFoundException e ) 2350 { 2351 // shouldn't happen, but log anyway 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 * {@inheritDoc} 2368 */ 2369 public DnNode<AccessControlAdministrativePoint> getAccessControlAPCache() 2370 { 2371 return accessControlAPCache; 2372 } 2373 2374 2375 /** 2376 * {@inheritDoc} 2377 */ 2378 public DnNode<CollectiveAttributeAdministrativePoint> getCollectiveAttributeAPCache() 2379 { 2380 return collectiveAttributeAPCache; 2381 } 2382 2383 2384 /** 2385 * {@inheritDoc} 2386 */ 2387 public DnNode<SubschemaAdministrativePoint> getSubschemaAPCache() 2388 { 2389 return subschemaAPCache; 2390 } 2391 2392 2393 /** 2394 * {@inheritDoc} 2395 */ 2396 public DnNode<TriggerExecutionAdministrativePoint> getTriggerExecutionAPCache() 2397 { 2398 return triggerExecutionAPCache; 2399 } 2400 2401 2402 /** 2403 * {@inheritDoc} 2404 */ 2405 public boolean isPwdPolicyEnabled() 2406 { 2407 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 * {@inheritDoc} 2425 */ 2426 public DnFactory getDnFactory() 2427 { 2428 return dnFactory; 2429 } 2430 2431 2432 /** 2433 * {@inheritDoc} 2434 */ 2435 public void setDnFactory( DnFactory dnFactory ) 2436 { 2437 this.dnFactory = dnFactory; 2438 } 2439 2440 2441 /** 2442 * {@inheritDoc} 2443 */ 2444 public SubentryCache getSubentryCache() 2445 { 2446 return subentryCache; 2447 } 2448 2449 2450 /** 2451 * {@inheritDoc} 2452 */ 2453 public SubtreeEvaluator getEvaluator() 2454 { 2455 return evaluator; 2456 } 2457 2458 2459 /** 2460 * {@inheritDoc} 2461 */ 2462 @Override 2463 public AttributeTypeProvider getAtProvider() 2464 { 2465 return atProvider; 2466 } 2467 2468 2469 /** 2470 * {@inheritDoc} 2471 */ 2472 @Override 2473 public ObjectClassProvider getOcProvider() 2474 { 2475 return ocProvider; 2476 } 2477 2478 2479 /** 2480 * {@inheritDoc} 2481 */ 2482 @Override 2483 public TimeProvider getTimeProvider() 2484 { 2485 return timeProvider; 2486 } 2487 2488 2489 /** 2490 * {@inheritDoc} 2491 */ 2492 @Override 2493 public void setTimeProvider( TimeProvider timeProvider ) 2494 { 2495 this.timeProvider = timeProvider; 2496 } 2497}