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.shared; 021 022 023import java.io.File; 024import java.io.IOException; 025import java.net.SocketAddress; 026import java.nio.file.Files; 027import java.text.ParseException; 028import java.util.ArrayList; 029import java.util.Arrays; 030import java.util.HashMap; 031import java.util.List; 032import java.util.Map; 033import java.util.Set; 034import java.util.concurrent.atomic.AtomicLong; 035 036import jdbm.recman.BaseRecordManager; 037 038import org.apache.directory.api.ldap.extras.controls.syncrepl.syncRequest.SyncRequestValue; 039import org.apache.directory.api.ldap.model.constants.AuthenticationLevel; 040import org.apache.directory.api.ldap.model.constants.SchemaConstants; 041import org.apache.directory.api.ldap.model.cursor.Cursor; 042import org.apache.directory.api.ldap.model.cursor.CursorException; 043import org.apache.directory.api.ldap.model.cursor.EmptyCursor; 044import org.apache.directory.api.ldap.model.entry.DefaultModification; 045import org.apache.directory.api.ldap.model.entry.Entry; 046import org.apache.directory.api.ldap.model.entry.Modification; 047import org.apache.directory.api.ldap.model.entry.Value; 048import org.apache.directory.api.ldap.model.exception.LdapException; 049import org.apache.directory.api.ldap.model.exception.LdapInvalidSearchFilterException; 050import org.apache.directory.api.ldap.model.filter.ExprNode; 051import org.apache.directory.api.ldap.model.filter.FilterParser; 052import org.apache.directory.api.ldap.model.filter.PresenceNode; 053import org.apache.directory.api.ldap.model.message.AddRequest; 054import org.apache.directory.api.ldap.model.message.AliasDerefMode; 055import org.apache.directory.api.ldap.model.message.CompareRequest; 056import org.apache.directory.api.ldap.model.message.Control; 057import org.apache.directory.api.ldap.model.message.DeleteRequest; 058import org.apache.directory.api.ldap.model.message.LdapResult; 059import org.apache.directory.api.ldap.model.message.ModifyDnRequest; 060import org.apache.directory.api.ldap.model.message.ModifyRequest; 061import org.apache.directory.api.ldap.model.message.ResultCodeEnum; 062import org.apache.directory.api.ldap.model.message.ResultResponse; 063import org.apache.directory.api.ldap.model.message.SearchRequest; 064import org.apache.directory.api.ldap.model.message.SearchScope; 065import org.apache.directory.api.ldap.model.message.UnbindRequest; 066import org.apache.directory.api.ldap.model.message.controls.SortKey; 067import org.apache.directory.api.ldap.model.message.controls.SortRequest; 068import org.apache.directory.api.ldap.model.message.controls.SortResponse; 069import org.apache.directory.api.ldap.model.message.controls.SortResponseImpl; 070import org.apache.directory.api.ldap.model.message.controls.SortResultCode; 071import org.apache.directory.api.ldap.model.name.Dn; 072import org.apache.directory.api.ldap.model.name.Rdn; 073import org.apache.directory.api.ldap.model.schema.AttributeType; 074import org.apache.directory.api.ldap.model.schema.MatchingRule; 075import org.apache.directory.api.ldap.model.schema.SchemaManager; 076import org.apache.directory.api.util.Strings; 077import org.apache.directory.server.constants.ServerDNConstants; 078import org.apache.directory.server.core.api.CoreSession; 079import org.apache.directory.server.core.api.DirectoryService; 080import org.apache.directory.server.core.api.LdapPrincipal; 081import org.apache.directory.server.core.api.OperationManager; 082import org.apache.directory.server.core.api.changelog.LogChange; 083import org.apache.directory.server.core.api.interceptor.context.AbstractOperationContext; 084import org.apache.directory.server.core.api.interceptor.context.AddOperationContext; 085import org.apache.directory.server.core.api.interceptor.context.CompareOperationContext; 086import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext; 087import org.apache.directory.server.core.api.interceptor.context.HasEntryOperationContext; 088import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext; 089import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext; 090import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext; 091import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext; 092import org.apache.directory.server.core.api.interceptor.context.OperationContext; 093import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext; 094import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext; 095import org.apache.directory.server.core.api.interceptor.context.UnbindOperationContext; 096import org.apache.directory.server.core.api.partition.Partition; 097import org.apache.directory.server.core.api.partition.PartitionTxn; 098import org.apache.directory.server.i18n.I18n; 099import org.apache.mina.core.session.IoSession; 100import org.slf4j.Logger; 101import org.slf4j.LoggerFactory; 102 103 104/** 105 * The default CoreSession implementation. 106 * 107 * TODO - has not been completed yet 108 * TODO - need to supply controls and other parameters to setup opContexts 109 * 110 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 111 */ 112public class DefaultCoreSession implements CoreSession 113{ 114 /** A logger for this class */ 115 private static final Logger LOG = LoggerFactory.getLogger( DefaultCoreSession.class ); 116 117 /** The DirectoryService we are connected to */ 118 private final DirectoryService directoryService; 119 120 /** The Principal used to process operations */ 121 private final LdapPrincipal authenticatedPrincipal; 122 123 /** The anonymous principal, if we have to process operation as anonymous */ 124 private final LdapPrincipal anonymousPrincipal; 125 126 /** The authorized principal, which will be used when a user has been authorized */ 127 private LdapPrincipal authorizedPrincipal; 128 129 /** A reference to the ObjectClass AT */ 130 protected AttributeType objectClassAT; 131 132 /** The associated IoSession */ 133 private IoSession ioSession; 134 135 /** flag to indicate if the password must be changed */ 136 private boolean pwdMustChange; 137 138 /** A flag set when the startTransaction extended operation has been received */ 139 private boolean hasSessionTransaction; 140 141 /** The Map containing the transactions associated with each partition */ 142 private Map<String, PartitionTxn> transactionMap = new HashMap<>(); 143 144 /** The transaction ID */ 145 private AtomicLong transactionId = new AtomicLong( 0 ); 146 147 /** 148 * Creates a new instance of a DefaultCoreSession 149 * @param principal The principal to use to process operation for this session 150 * @param directoryService The DirectoryService to which we will send requests 151 */ 152 public DefaultCoreSession( LdapPrincipal principal, DirectoryService directoryService ) 153 { 154 this.directoryService = directoryService; 155 authenticatedPrincipal = principal; 156 157 if ( principal.getAuthenticationLevel() == AuthenticationLevel.NONE ) 158 { 159 anonymousPrincipal = principal; 160 } 161 else 162 { 163 anonymousPrincipal = new LdapPrincipal( directoryService.getSchemaManager() ); 164 } 165 166 // setup attribute type value 167 objectClassAT = directoryService.getSchemaManager().getAttributeType( SchemaConstants.OBJECT_CLASS_AT ); 168 } 169 170 171 /** 172 * Gets the IoSession from the CoreSession. This is only useful when the server is not embedded. 173 * 174 * @return ioSession The IoSession for this CoreSession 175 */ 176 public IoSession getIoSession() 177 { 178 return ioSession; 179 } 180 181 182 /** 183 * Stores the IoSession into the CoreSession. This is only useful when the server is not embedded. 184 * 185 * @param ioSession The IoSession for this CoreSession 186 */ 187 public void setIoSession( IoSession ioSession ) 188 { 189 this.ioSession = ioSession; 190 } 191 192 193 /** 194 * Set the ignoreRefferal flag for the current operationContext. 195 * 196 * @param opContext The current operationContext 197 * @param ignoreReferral The flag 198 */ 199 private void setReferralHandling( AbstractOperationContext opContext, boolean ignoreReferral ) 200 { 201 if ( ignoreReferral ) 202 { 203 opContext.ignoreReferral(); 204 } 205 else 206 { 207 opContext.throwReferral(); 208 } 209 } 210 211 212 /** 213 * {@inheritDoc} 214 */ 215 @Override 216 public void add( Entry entry ) throws LdapException 217 { 218 add( entry, LogChange.TRUE ); 219 } 220 221 222 /** 223 * {@inheritDoc} 224 */ 225 @Override 226 public void add( Entry entry, boolean ignoreReferral ) throws LdapException 227 { 228 add( entry, ignoreReferral, LogChange.TRUE ); 229 } 230 231 232 /** 233 * {@inheritDoc} 234 */ 235 @Override 236 public void add( Entry entry, LogChange log ) throws LdapException 237 { 238 AddOperationContext addContext = new AddOperationContext( this, entry ); 239 240 addContext.setLogChange( log ); 241 242 OperationManager operationManager = directoryService.getOperationManager(); 243 operationManager.add( addContext ); 244 } 245 246 247 /** 248 * {@inheritDoc} 249 */ 250 @Override 251 public void add( Entry entry, boolean ignoreReferral, LogChange log ) throws LdapException 252 { 253 AddOperationContext addContext = new AddOperationContext( this, entry ); 254 255 addContext.setLogChange( log ); 256 setReferralHandling( addContext, ignoreReferral ); 257 258 OperationManager operationManager = directoryService.getOperationManager(); 259 operationManager.add( addContext ); 260 } 261 262 263 /** 264 * {@inheritDoc} 265 */ 266 @Override 267 public void add( AddRequest addRequest ) throws LdapException 268 { 269 add( addRequest, LogChange.TRUE ); 270 } 271 272 273 /** 274 * {@inheritDoc} 275 */ 276 @Override 277 public void add( AddRequest addRequest, LogChange log ) throws LdapException 278 { 279 AddOperationContext addContext = new AddOperationContext( this, addRequest ); 280 281 addContext.setLogChange( log ); 282 283 OperationManager operationManager = directoryService.getOperationManager(); 284 285 try 286 { 287 operationManager.add( addContext ); 288 } 289 catch ( LdapException e ) 290 { 291 addRequest.getResultResponse().addAllControls( addContext.getResponseControls() ); 292 throw e; 293 } 294 295 addRequest.getResultResponse().addAllControls( addContext.getResponseControls() ); 296 } 297 298 299 private Value convertToValue( String oid, Object value ) throws LdapException 300 { 301 Value val; 302 303 AttributeType attributeType = directoryService.getSchemaManager().lookupAttributeTypeRegistry( oid ); 304 305 // make sure we add the request controls to operation 306 if ( attributeType.getSyntax().isHumanReadable() ) 307 { 308 if ( value instanceof String ) 309 { 310 val = new Value( attributeType, ( String ) value ); 311 } 312 else if ( value instanceof byte[] ) 313 { 314 val = new Value( attributeType, Strings.utf8ToString( ( byte[] ) value ) ); 315 } 316 else 317 { 318 throw new LdapException( I18n.err( I18n.ERR_309, oid ) ); 319 } 320 } 321 else 322 { 323 if ( value instanceof String ) 324 { 325 val = new Value( attributeType, Strings.getBytesUtf8( ( String ) value ) ); 326 } 327 else if ( value instanceof byte[] ) 328 { 329 val = new Value( attributeType, ( byte[] ) value ); 330 } 331 else 332 { 333 throw new LdapException( I18n.err( I18n.ERR_309, oid ) ); 334 } 335 } 336 337 return val; 338 } 339 340 341 /** 342 * {@inheritDoc} 343 */ 344 @Override 345 public boolean compare( Dn dn, String oid, Object value ) throws LdapException 346 { 347 OperationManager operationManager = directoryService.getOperationManager(); 348 349 return operationManager.compare( new CompareOperationContext( this, dn, oid, convertToValue( oid, value ) ) ); 350 } 351 352 353 /** 354 * {@inheritDoc} 355 */ 356 @Override 357 public boolean compare( Dn dn, String oid, Object value, boolean ignoreReferral ) throws LdapException 358 { 359 CompareOperationContext compareContext = new CompareOperationContext( this, dn, oid, 360 convertToValue( oid, value ) ); 361 362 setReferralHandling( compareContext, ignoreReferral ); 363 364 OperationManager operationManager = directoryService.getOperationManager(); 365 return operationManager.compare( compareContext ); 366 } 367 368 369 /** 370 * {@inheritDoc} 371 */ 372 @Override 373 public void delete( Dn dn ) throws LdapException 374 { 375 delete( dn, LogChange.TRUE ); 376 } 377 378 379 /** 380 * {@inheritDoc} 381 */ 382 @Override 383 public void delete( Dn dn, LogChange log ) throws LdapException 384 { 385 DeleteOperationContext deleteContext = new DeleteOperationContext( this, dn ); 386 387 deleteContext.setLogChange( log ); 388 389 OperationManager operationManager = directoryService.getOperationManager(); 390 operationManager.delete( deleteContext ); 391 } 392 393 394 /** 395 * {@inheritDoc} 396 */ 397 @Override 398 public void delete( Dn dn, boolean ignoreReferral ) throws LdapException 399 { 400 delete( dn, ignoreReferral, LogChange.TRUE ); 401 } 402 403 404 /** 405 * {@inheritDoc} 406 */ 407 @Override 408 public void delete( Dn dn, boolean ignoreReferral, LogChange log ) throws LdapException 409 { 410 DeleteOperationContext deleteContext = new DeleteOperationContext( this, dn ); 411 412 deleteContext.setLogChange( log ); 413 setReferralHandling( deleteContext, ignoreReferral ); 414 415 OperationManager operationManager = directoryService.getOperationManager(); 416 operationManager.delete( deleteContext ); 417 } 418 419 420 /** 421 * {@inheritDoc} 422 */ 423 @Override 424 public LdapPrincipal getAnonymousPrincipal() 425 { 426 return anonymousPrincipal; 427 } 428 429 430 /** 431 * {@inheritDoc} 432 */ 433 @Override 434 public LdapPrincipal getAuthenticatedPrincipal() 435 { 436 return authenticatedPrincipal; 437 } 438 439 440 /** 441 * {@inheritDoc} 442 */ 443 @Override 444 public AuthenticationLevel getAuthenticationLevel() 445 { 446 return getEffectivePrincipal().getAuthenticationLevel(); 447 } 448 449 450 /** 451 * {@inheritDoc} 452 */ 453 @Override 454 public SocketAddress getClientAddress() 455 { 456 if ( ioSession != null ) 457 { 458 return ioSession.getRemoteAddress(); 459 } 460 else 461 { 462 return null; 463 } 464 } 465 466 467 /** 468 * {@inheritDoc} 469 */ 470 @Override 471 public Set<Control> getControls() 472 { 473 // TODO Auto-generated method stub 474 return null; 475 } 476 477 478 /** 479 * {@inheritDoc} 480 */ 481 @Override 482 public DirectoryService getDirectoryService() 483 { 484 return directoryService; 485 } 486 487 488 /** 489 * {@inheritDoc} 490 */ 491 @Override 492 public LdapPrincipal getEffectivePrincipal() 493 { 494 if ( authorizedPrincipal == null ) 495 { 496 return authenticatedPrincipal; 497 } 498 499 return authorizedPrincipal; 500 } 501 502 503 /** 504 * {@inheritDoc} 505 */ 506 @Override 507 public Set<OperationContext> getOutstandingOperations() 508 { 509 // TODO Auto-generated method stub 510 return null; 511 } 512 513 514 /** 515 * {@inheritDoc} 516 */ 517 @Override 518 public SocketAddress getServiceAddress() 519 { 520 if ( ioSession != null ) 521 { 522 return ioSession.getServiceAddress(); 523 } 524 else 525 { 526 return null; 527 } 528 } 529 530 531 /** 532 * {@inheritDoc} 533 */ 534 @Override 535 public boolean isConfidential() 536 { 537 // TODO Auto-generated method stub 538 return false; 539 } 540 541 542 /** 543 * {@inheritDoc} 544 */ 545 @Override 546 public boolean isVirtual() 547 { 548 // TODO Auto-generated method stub 549 return true; 550 } 551 552 553 /** 554 * TODO - perhaps we should just use a flag that is calculated on creation 555 * of this session 556 * 557 * @see org.apache.directory.server.core.api.CoreSession#isAdministrator() 558 */ 559 @Override 560 public boolean isAdministrator() 561 { 562 String normName = getEffectivePrincipal().getName(); 563 564 return normName.equals( ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED ); 565 } 566 567 568 /** 569 * TODO - this method impl does not check to see if the principal is in 570 * the administrators group - it only returns true of the principal is 571 * the actual admin user. need to make it check groups. 572 * 573 * TODO - perhaps we should just use a flag that is calculated on creation 574 * of this session 575 * 576 * @see org.apache.directory.server.core.api.CoreSession#isAnAdministrator() 577 */ 578 @Override 579 public boolean isAnAdministrator() 580 { 581 if ( isAdministrator() ) 582 { 583 return true; 584 } 585 586 // TODO fix this so it checks groups 587 return false; 588 } 589 590 591 /** 592 * {@inheritDoc} 593 */ 594 @Override 595 public Cursor<Entry> list( Dn dn, AliasDerefMode aliasDerefMode, 596 String... returningAttributes ) throws LdapException 597 { 598 OperationManager operationManager = directoryService.getOperationManager(); 599 600 PresenceNode filter = new PresenceNode( objectClassAT ); 601 SearchOperationContext searchContext = new SearchOperationContext( this, dn, SearchScope.ONELEVEL, filter, 602 returningAttributes ); 603 searchContext.setAliasDerefMode( aliasDerefMode ); 604 605 return operationManager.search( searchContext ); 606 } 607 608 609 /** 610 * {@inheritDoc} 611 */ 612 @Override 613 public Entry lookup( Dn dn, String... attrIds ) throws LdapException 614 { 615 OperationManager operationManager = directoryService.getOperationManager(); 616 LookupOperationContext lookupContext = new LookupOperationContext( this, dn, attrIds ); 617 618 return operationManager.lookup( lookupContext ); 619 } 620 621 622 /** 623 * {@inheritDoc} 624 */ 625 @Override 626 public Entry lookup( Dn dn, Control[] controls, String... attrIds ) throws LdapException 627 { 628 OperationManager operationManager = directoryService.getOperationManager(); 629 LookupOperationContext lookupContext = new LookupOperationContext( this, dn, attrIds ); 630 631 if ( controls != null ) 632 { 633 lookupContext.addRequestControls( controls ); 634 } 635 636 return operationManager.lookup( lookupContext ); 637 } 638 639 640 /** 641 * {@inheritDoc} 642 */ 643 @Override 644 public void modify( Dn dn, Modification... mods ) throws LdapException 645 { 646 modify( dn, Arrays.asList( mods ), LogChange.TRUE ); 647 } 648 649 650 /** 651 * {@inheritDoc} 652 */ 653 @Override 654 public void modify( Dn dn, List<Modification> mods ) throws LdapException 655 { 656 modify( dn, mods, LogChange.TRUE ); 657 } 658 659 660 /** 661 * {@inheritDoc} 662 */ 663 @Override 664 public void modify( Dn dn, List<Modification> mods, LogChange log ) throws LdapException 665 { 666 if ( mods == null ) 667 { 668 return; 669 } 670 671 List<Modification> serverModifications = new ArrayList<>( mods.size() ); 672 673 for ( Modification mod : mods ) 674 { 675 serverModifications.add( new DefaultModification( directoryService.getSchemaManager(), mod ) ); 676 } 677 678 ModifyOperationContext modifyContext = new ModifyOperationContext( this, dn, serverModifications ); 679 680 modifyContext.setLogChange( log ); 681 682 OperationManager operationManager = directoryService.getOperationManager(); 683 684 operationManager.modify( modifyContext ); 685 } 686 687 688 /** 689 * {@inheritDoc} 690 */ 691 @Override 692 public void modify( Dn dn, List<Modification> mods, boolean ignoreReferral ) throws LdapException 693 { 694 modify( dn, mods, ignoreReferral, LogChange.TRUE ); 695 } 696 697 698 /** 699 * {@inheritDoc} 700 */ 701 @Override 702 public void modify( Dn dn, List<Modification> mods, boolean ignoreReferral, LogChange log ) throws LdapException 703 { 704 if ( mods == null ) 705 { 706 return; 707 } 708 709 List<Modification> serverModifications = new ArrayList<>( mods.size() ); 710 711 for ( Modification mod : mods ) 712 { 713 serverModifications.add( new DefaultModification( directoryService.getSchemaManager(), mod ) ); 714 } 715 716 ModifyOperationContext modifyContext = new ModifyOperationContext( this, dn, serverModifications ); 717 718 setReferralHandling( modifyContext, ignoreReferral ); 719 modifyContext.setLogChange( log ); 720 721 OperationManager operationManager = directoryService.getOperationManager(); 722 operationManager.modify( modifyContext ); 723 } 724 725 726 /** 727 * {@inheritDoc} 728 */ 729 @Override 730 public void move( Dn dn, Dn newParent ) throws LdapException 731 { 732 move( dn, newParent, LogChange.TRUE ); 733 } 734 735 736 /** 737 * {@inheritDoc} 738 */ 739 @Override 740 public void move( Dn dn, Dn newParent, LogChange log ) throws LdapException 741 { 742 MoveOperationContext moveContext = new MoveOperationContext( this, dn, newParent ); 743 moveContext.setLogChange( log ); 744 745 OperationManager operationManager = directoryService.getOperationManager(); 746 operationManager.move( moveContext ); 747 } 748 749 750 /** 751 * {@inheritDoc} 752 */ 753 @Override 754 public void move( Dn dn, Dn newParent, boolean ignoreReferral ) throws Exception 755 { 756 move( dn, newParent, ignoreReferral, LogChange.TRUE ); 757 } 758 759 760 /** 761 * {@inheritDoc} 762 */ 763 @Override 764 public void move( Dn dn, Dn newParent, boolean ignoreReferral, LogChange log ) throws LdapException 765 { 766 OperationManager operationManager = directoryService.getOperationManager(); 767 MoveOperationContext moveContext = new MoveOperationContext( this, dn, newParent ); 768 769 setReferralHandling( moveContext, ignoreReferral ); 770 moveContext.setLogChange( log ); 771 772 operationManager.move( moveContext ); 773 } 774 775 776 /** 777 * {@inheritDoc} 778 */ 779 @Override 780 public void moveAndRename( Dn dn, Dn newParent, Rdn newRdn, boolean deleteOldRdn ) throws LdapException 781 { 782 moveAndRename( dn, newParent, newRdn, deleteOldRdn, LogChange.TRUE ); 783 } 784 785 786 /** 787 * {@inheritDoc} 788 */ 789 @Override 790 public void moveAndRename( Dn dn, Dn newSuperiorDn, Rdn newRdn, boolean deleteOldRdn, LogChange log ) 791 throws LdapException 792 { 793 MoveAndRenameOperationContext moveAndRenameContext = new MoveAndRenameOperationContext( this, dn, 794 newSuperiorDn, newRdn, deleteOldRdn ); 795 796 moveAndRenameContext.setLogChange( log ); 797 798 OperationManager operationManager = directoryService.getOperationManager(); 799 operationManager.moveAndRename( moveAndRenameContext ); 800 } 801 802 803 /** 804 * {@inheritDoc} 805 */ 806 @Override 807 public void moveAndRename( Dn dn, Dn newParent, Rdn newRdn, boolean deleteOldRdn, boolean ignoreReferral ) 808 throws LdapException 809 { 810 moveAndRename( dn, newParent, newRdn, deleteOldRdn, ignoreReferral, LogChange.TRUE ); 811 } 812 813 814 /** 815 * {@inheritDoc} 816 */ 817 @Override 818 public void moveAndRename( Dn dn, Dn newParent, Rdn newRdn, boolean deleteOldRdn, boolean ignoreReferral, 819 LogChange log ) throws LdapException 820 { 821 OperationManager operationManager = directoryService.getOperationManager(); 822 MoveAndRenameOperationContext moveAndRenameContext = new MoveAndRenameOperationContext( this, dn, newParent, 823 newRdn, deleteOldRdn ); 824 825 moveAndRenameContext.setLogChange( log ); 826 setReferralHandling( moveAndRenameContext, ignoreReferral ); 827 828 operationManager.moveAndRename( moveAndRenameContext ); 829 } 830 831 832 /** 833 * {@inheritDoc} 834 */ 835 @Override 836 public void rename( Dn dn, Rdn newRdn, boolean deleteOldRdn ) throws LdapException 837 { 838 rename( dn, newRdn, deleteOldRdn, LogChange.TRUE ); 839 } 840 841 842 /** 843 * {@inheritDoc} 844 */ 845 @Override 846 public void rename( Dn dn, Rdn newRdn, boolean deleteOldRdn, LogChange log ) throws LdapException 847 { 848 RenameOperationContext renameContext = new RenameOperationContext( this, dn, newRdn, deleteOldRdn ); 849 850 renameContext.setLogChange( log ); 851 852 OperationManager operationManager = directoryService.getOperationManager(); 853 854 operationManager.rename( renameContext ); 855 } 856 857 858 /** 859 * {@inheritDoc} 860 */ 861 @Override 862 public void rename( Dn dn, Rdn newRdn, boolean deleteOldRdn, boolean ignoreReferral ) throws LdapException 863 { 864 rename( dn, newRdn, deleteOldRdn, ignoreReferral, LogChange.TRUE ); 865 } 866 867 868 /** 869 * {@inheritDoc} 870 */ 871 @Override 872 public void rename( Dn dn, Rdn newRdn, boolean deleteOldRdn, boolean ignoreReferral, LogChange log ) 873 throws LdapException 874 { 875 OperationManager operationManager = directoryService.getOperationManager(); 876 RenameOperationContext renameContext = new RenameOperationContext( this, dn, newRdn, deleteOldRdn ); 877 878 renameContext.setLogChange( log ); 879 setReferralHandling( renameContext, ignoreReferral ); 880 881 operationManager.rename( renameContext ); 882 } 883 884 885 /** 886 * {@inheritDoc} 887 */ 888 @Override 889 public Cursor<Entry> search( Dn dn, String filter ) throws LdapException 890 { 891 return search( dn, filter, true ); 892 } 893 894 895 /** 896 * {@inheritDoc} 897 */ 898 @Override 899 public Cursor<Entry> search( Dn dn, String filter, boolean ignoreReferrals ) throws LdapException 900 { 901 OperationManager operationManager = directoryService.getOperationManager(); 902 ExprNode filterNode = null; 903 904 try 905 { 906 filterNode = FilterParser.parse( directoryService.getSchemaManager(), filter ); 907 } 908 catch ( ParseException pe ) 909 { 910 throw new LdapInvalidSearchFilterException( pe.getMessage() ); 911 } 912 913 SearchOperationContext searchContext = new SearchOperationContext( this, dn, SearchScope.OBJECT, filterNode, 914 ( String ) null ); 915 searchContext.setAliasDerefMode( AliasDerefMode.DEREF_ALWAYS ); 916 setReferralHandling( searchContext, ignoreReferrals ); 917 918 return operationManager.search( searchContext ); 919 } 920 921 922 /** 923 * {@inheritDoc} 924 */ 925 @Override 926 public Cursor<Entry> search( Dn dn, SearchScope scope, ExprNode filter, AliasDerefMode aliasDerefMode, 927 String... returningAttributes ) throws LdapException 928 { 929 OperationManager operationManager = directoryService.getOperationManager(); 930 931 SearchOperationContext searchContext = new SearchOperationContext( this, dn, scope, filter, returningAttributes ); 932 searchContext.setAliasDerefMode( aliasDerefMode ); 933 934 return operationManager.search( searchContext ); 935 } 936 937 938 /** 939 * {@inheritDoc} 940 */ 941 @Override 942 public boolean isAnonymous() 943 { 944 if ( ( authorizedPrincipal == null ) && ( authenticatedPrincipal == null ) ) 945 { 946 return true; 947 } 948 else 949 { 950 return authenticatedPrincipal.getAuthenticationLevel() == AuthenticationLevel.NONE; 951 } 952 } 953 954 955 /** 956 * {@inheritDoc} 957 */ 958 @Override 959 public boolean compare( CompareRequest compareRequest ) throws LdapException 960 { 961 CompareOperationContext compareContext = new CompareOperationContext( this, compareRequest ); 962 OperationManager operationManager = directoryService.getOperationManager(); 963 boolean result = false; 964 try 965 { 966 result = operationManager.compare( compareContext ); 967 } 968 catch ( LdapException e ) 969 { 970 compareRequest.getResultResponse().addAllControls( compareContext.getResponseControls() ); 971 throw e; 972 } 973 974 compareRequest.getResultResponse().addAllControls( compareContext.getResponseControls() ); 975 return result; 976 } 977 978 979 /** 980 * {@inheritDoc} 981 */ 982 @Override 983 public void delete( DeleteRequest deleteRequest ) throws LdapException 984 { 985 delete( deleteRequest, LogChange.TRUE ); 986 } 987 988 989 /** 990 * {@inheritDoc} 991 */ 992 @Override 993 public void delete( DeleteRequest deleteRequest, LogChange log ) throws LdapException 994 { 995 DeleteOperationContext deleteContext = new DeleteOperationContext( this, deleteRequest ); 996 997 deleteContext.setLogChange( log ); 998 999 OperationManager operationManager = directoryService.getOperationManager(); 1000 1001 try 1002 { 1003 operationManager.delete( deleteContext ); 1004 } 1005 catch ( LdapException e ) 1006 { 1007 deleteRequest.getResultResponse().addAllControls( deleteContext.getResponseControls() ); 1008 throw e; 1009 } 1010 1011 deleteRequest.getResultResponse().addAllControls( deleteContext.getResponseControls() ); 1012 } 1013 1014 1015 /** 1016 * {@inheritDoc} 1017 */ 1018 @Override 1019 public boolean exists( String dn ) throws LdapException 1020 { 1021 return exists( new Dn( dn ) ); 1022 } 1023 1024 1025 /** 1026 * {@inheritDoc} 1027 */ 1028 @Override 1029 public boolean exists( Dn dn ) throws LdapException 1030 { 1031 HasEntryOperationContext hasEntryContext = new HasEntryOperationContext( this, dn ); 1032 OperationManager operationManager = directoryService.getOperationManager(); 1033 1034 return operationManager.hasEntry( hasEntryContext ); 1035 } 1036 1037 1038 /** 1039 * {@inheritDoc} 1040 */ 1041 @Override 1042 public void modify( ModifyRequest modifyRequest ) throws LdapException 1043 { 1044 modify( modifyRequest, LogChange.TRUE ); 1045 } 1046 1047 1048 /** 1049 * {@inheritDoc} 1050 */ 1051 @Override 1052 public void modify( ModifyRequest modifyRequest, LogChange log ) throws LdapException 1053 { 1054 ModifyOperationContext modifyContext = new ModifyOperationContext( this, modifyRequest ); 1055 1056 modifyContext.setLogChange( log ); 1057 1058 OperationManager operationManager = directoryService.getOperationManager(); 1059 1060 try 1061 { 1062 operationManager.modify( modifyContext ); 1063 } 1064 catch ( LdapException e ) 1065 { 1066 modifyRequest.getResultResponse().addAllControls( modifyContext.getResponseControls() ); 1067 throw e; 1068 } 1069 1070 modifyRequest.getResultResponse().addAllControls( modifyContext.getResponseControls() ); 1071 } 1072 1073 1074 /** 1075 * {@inheritDoc} 1076 */ 1077 @Override 1078 public void move( ModifyDnRequest modifyDnRequest ) throws LdapException 1079 { 1080 move( modifyDnRequest, LogChange.TRUE ); 1081 } 1082 1083 1084 /** 1085 * {@inheritDoc} 1086 */ 1087 @Override 1088 public void move( ModifyDnRequest modifyDnRequest, LogChange log ) throws LdapException 1089 { 1090 MoveOperationContext moveContext = new MoveOperationContext( this, modifyDnRequest ); 1091 1092 moveContext.setLogChange( log ); 1093 1094 OperationManager operationManager = directoryService.getOperationManager(); 1095 1096 try 1097 { 1098 operationManager.move( moveContext ); 1099 } 1100 catch ( LdapException e ) 1101 { 1102 modifyDnRequest.getResultResponse().addAllControls( moveContext.getResponseControls() ); 1103 throw e; 1104 } 1105 1106 modifyDnRequest.getResultResponse().addAllControls( moveContext.getResponseControls() ); 1107 } 1108 1109 1110 /** 1111 * {@inheritDoc} 1112 */ 1113 @Override 1114 public void moveAndRename( ModifyDnRequest modifyDnRequest ) throws LdapException 1115 { 1116 moveAndRename( modifyDnRequest, LogChange.TRUE ); 1117 } 1118 1119 1120 /** 1121 * {@inheritDoc} 1122 */ 1123 @Override 1124 public void moveAndRename( ModifyDnRequest modifyDnRequest, LogChange log ) throws LdapException 1125 { 1126 MoveAndRenameOperationContext moveAndRenameContext = new MoveAndRenameOperationContext( this, modifyDnRequest ); 1127 1128 moveAndRenameContext.setLogChange( log ); 1129 1130 OperationManager operationManager = directoryService.getOperationManager(); 1131 1132 try 1133 { 1134 operationManager.moveAndRename( moveAndRenameContext ); 1135 } 1136 catch ( LdapException e ) 1137 { 1138 modifyDnRequest.getResultResponse().addAllControls( moveAndRenameContext.getResponseControls() ); 1139 throw e; 1140 } 1141 1142 modifyDnRequest.getResultResponse().addAllControls( moveAndRenameContext.getResponseControls() ); 1143 } 1144 1145 1146 /** 1147 * {@inheritDoc} 1148 */ 1149 @Override 1150 public void rename( ModifyDnRequest modifyDnRequest ) throws LdapException 1151 { 1152 rename( modifyDnRequest, LogChange.TRUE ); 1153 } 1154 1155 1156 /** 1157 * {@inheritDoc} 1158 */ 1159 @Override 1160 public void rename( ModifyDnRequest modifyDnRequest, LogChange log ) throws LdapException 1161 { 1162 RenameOperationContext renameContext = new RenameOperationContext( this, modifyDnRequest ); 1163 1164 renameContext.setLogChange( log ); 1165 1166 OperationManager operationManager = directoryService.getOperationManager(); 1167 1168 try 1169 { 1170 operationManager.rename( renameContext ); 1171 } 1172 catch ( LdapException e ) 1173 { 1174 modifyDnRequest.getResultResponse().addAllControls( renameContext.getResponseControls() ); 1175 throw e; 1176 } 1177 1178 modifyDnRequest.getResultResponse().addAllControls( renameContext.getResponseControls() ); 1179 } 1180 1181 1182 /** 1183 * {@inheritDoc} 1184 */ 1185 @Override 1186 public Cursor<Entry> search( SearchRequest searchRequest ) throws LdapException 1187 { 1188 SearchOperationContext searchContext = new SearchOperationContext( this, searchRequest ); 1189 searchContext.setSyncreplSearch( searchRequest.getControls().containsKey( SyncRequestValue.OID ) ); 1190 1191 OperationManager operationManager = directoryService.getOperationManager(); 1192 1193 // Check if we received serverside sort Control 1194 SortRequest sortControl = ( SortRequest ) searchRequest.getControls().get( SortRequest.OID ); 1195 1196 SortResponse sortRespCtrl = null; 1197 1198 ResultResponse done = searchRequest.getResultResponse(); 1199 1200 LdapResult ldapResult = done.getLdapResult(); 1201 1202 if ( sortControl != null ) 1203 { 1204 sortRespCtrl = canSort( sortControl, ldapResult, getDirectoryService().getSchemaManager() ); 1205 1206 if ( sortControl.isCritical() && ( sortRespCtrl.getSortResult() != SortResultCode.SUCCESS ) ) 1207 { 1208 ldapResult.setResultCode( ResultCodeEnum.UNAVAILABLE_CRITICAL_EXTENSION ); 1209 done.addControl( sortRespCtrl ); 1210 1211 return new EmptyCursor<>(); 1212 } 1213 } 1214 1215 Cursor<Entry> cursor = null; 1216 1217 try 1218 { 1219 cursor = operationManager.search( searchContext ); 1220 1221 if ( ( sortRespCtrl != null ) && ( sortRespCtrl.getSortResult() == SortResultCode.SUCCESS ) ) 1222 { 1223 cursor = sortResults( cursor, sortControl, getDirectoryService().getSchemaManager() ); 1224 } 1225 1226 // the below condition is to satisfy the scenario 6 in section 2 of rfc2891 1227 if ( sortRespCtrl != null ) 1228 { 1229 cursor.beforeFirst(); 1230 1231 if ( !cursor.next() ) 1232 { 1233 sortRespCtrl = null; 1234 } 1235 else 1236 { 1237 // move the cursor back 1238 cursor.previous(); 1239 } 1240 } 1241 } 1242 catch ( LdapException e ) 1243 { 1244 done.addAllControls( searchContext.getResponseControls() ); 1245 throw e; 1246 } 1247 catch ( Exception e ) 1248 { 1249 done.addAllControls( searchContext.getResponseControls() ); 1250 throw new LdapException( e ); 1251 } 1252 finally 1253 { 1254 // Don't close the transaction !!! 1255 LOG.debug( "Search done, the transaction is still opened" ); 1256 } 1257 1258 if ( sortRespCtrl != null ) 1259 { 1260 done.addControl( sortRespCtrl ); 1261 } 1262 1263 done.addAllControls( searchContext.getResponseControls() ); 1264 1265 return cursor; 1266 } 1267 1268 1269 /** 1270 * {@inheritDoc} 1271 */ 1272 @Override 1273 public void unbind() throws LdapException 1274 { 1275 UnbindOperationContext unbindContext = new UnbindOperationContext( this ); 1276 1277 OperationManager operationManager = directoryService.getOperationManager(); 1278 operationManager.unbind( unbindContext ); 1279 } 1280 1281 1282 /** 1283 * {@inheritDoc} 1284 */ 1285 @Override 1286 public void unbind( UnbindRequest unbindRequest ) throws LdapException 1287 { 1288 UnbindOperationContext unbindContext = new UnbindOperationContext( this, unbindRequest ); 1289 1290 OperationManager operationManager = directoryService.getOperationManager(); 1291 operationManager.unbind( unbindContext ); 1292 } 1293 1294 1295 /** 1296 * Checks if the requested search results can be sorted 1297 * 1298 * @param sortControl the sort control 1299 * @param ldapResult the refrence to the LDAP result of the ongoing search operation 1300 * @param session the current session 1301 * @return a sort response control 1302 */ 1303 private SortResponse canSort( SortRequest sortControl, LdapResult ldapResult, SchemaManager schemaManager ) 1304 { 1305 SortResponse resp = new SortResponseImpl(); 1306 1307 List<SortKey> keys = sortControl.getSortKeys(); 1308 1309 // only ONE key is supported by the server for now 1310 if ( keys.size() > 1 ) 1311 { 1312 ldapResult.setDiagnosticMessage( "Cannot sort results based on more than one attribute" ); 1313 resp.setSortResult( SortResultCode.UNWILLINGTOPERFORM ); 1314 return resp; 1315 } 1316 1317 SortKey sk = keys.get( 0 ); 1318 1319 AttributeType at = schemaManager.getAttributeType( sk.getAttributeTypeDesc() ); 1320 1321 if ( at == null ) 1322 { 1323 ldapResult.setDiagnosticMessage( "No attribute with the name " + sk.getAttributeTypeDesc() 1324 + " exists in the server's schema" ); 1325 resp.setSortResult( SortResultCode.NOSUCHATTRIBUTE ); 1326 resp.setAttributeName( sk.getAttributeTypeDesc() ); 1327 return resp; 1328 } 1329 1330 String mrOid = sk.getMatchingRuleId(); 1331 1332 if ( mrOid != null ) 1333 { 1334 MatchingRule mr = at.getOrdering(); 1335 1336 if ( ( mr != null ) && ( !mrOid.equals( mr.getOid() ) ) ) 1337 { 1338 ldapResult.setDiagnosticMessage( "Given matchingrule " + mrOid 1339 + " is not applicable for the attribute " + sk.getAttributeTypeDesc() ); 1340 resp.setSortResult( SortResultCode.INAPPROPRIATEMATCHING ); 1341 resp.setAttributeName( sk.getAttributeTypeDesc() ); 1342 return resp; 1343 } 1344 1345 try 1346 { 1347 schemaManager.lookupComparatorRegistry( mrOid ); 1348 } 1349 catch ( LdapException e ) 1350 { 1351 ldapResult.setDiagnosticMessage( "Given matchingrule " + mrOid + " is not supported" ); 1352 resp.setSortResult( SortResultCode.INAPPROPRIATEMATCHING ); 1353 resp.setAttributeName( sk.getAttributeTypeDesc() ); 1354 return resp; 1355 } 1356 } 1357 else 1358 { 1359 MatchingRule mr = at.getOrdering(); 1360 1361 if ( mr == null ) 1362 { 1363 mr = at.getEquality(); 1364 } 1365 1366 ldapResult.setDiagnosticMessage( "Matchingrule is required for sorting by the attribute " 1367 + sk.getAttributeTypeDesc() ); 1368 resp.setSortResult( SortResultCode.INAPPROPRIATEMATCHING ); 1369 resp.setAttributeName( sk.getAttributeTypeDesc() ); 1370 1371 if ( mr == null ) 1372 { 1373 return resp; 1374 } 1375 1376 try 1377 { 1378 schemaManager.lookupComparatorRegistry( mr.getOid() ); 1379 } 1380 catch ( LdapException e ) 1381 { 1382 return resp; 1383 } 1384 } 1385 1386 resp.setSortResult( SortResultCode.SUCCESS ); 1387 1388 return resp; 1389 } 1390 1391 1392 /** 1393 * Sorts the entries based on the given sortkey and returns the cursor 1394 * 1395 * @param unsortedEntries the cursor containing un-sorted entries 1396 * @param control the sort control 1397 * @param schemaManager schema manager 1398 * @return a cursor containing sorted entries 1399 * @throws CursorException 1400 * @throws LdapException 1401 * @throws IOException 1402 * @throws KeyNotFoundException 1403 */ 1404 private Cursor<Entry> sortResults( Cursor<Entry> unsortedEntries, SortRequest control, SchemaManager schemaManager ) 1405 throws CursorException, LdapException, IOException 1406 { 1407 unsortedEntries.beforeFirst(); 1408 1409 Entry first = null; 1410 1411 if ( unsortedEntries.next() ) 1412 { 1413 first = unsortedEntries.get(); 1414 } 1415 1416 if ( !unsortedEntries.next() ) 1417 { 1418 unsortedEntries.beforeFirst(); 1419 1420 return unsortedEntries; 1421 } 1422 1423 SortKey sk = control.getSortKeys().get( 0 ); 1424 1425 AttributeType at = schemaManager.getAttributeType( sk.getAttributeTypeDesc() ); 1426 1427 SortedEntryComparator comparator = new SortedEntryComparator( at, sk.getMatchingRuleId(), sk.isReverseOrder(), 1428 schemaManager ); 1429 1430 SortedEntrySerializer keySerializer = new SortedEntrySerializer(); 1431 SortedEntrySerializer.setSchemaManager( schemaManager ); 1432 1433 File file = null; 1434 1435 try 1436 { 1437 file = Files.createTempFile( "replica", ".sorted-data" ).toFile(); // see DIRSERVER-2007 1438 } 1439 catch ( IOException e ) 1440 { 1441 // see DIRSERVER-2091 1442 LOG.error( "Error creating temp file in directory {} for sorting: {}", 1443 System.getProperty( "java.io.tmpdir" ), e.getMessage(), e ); 1444 throw e; 1445 } 1446 1447 BaseRecordManager recMan = new BaseRecordManager( file.getAbsolutePath() ); 1448 1449 jdbm.btree.BTree<Entry, String> btree = new jdbm.btree.BTree<>( recMan, comparator, keySerializer, NullStringSerializer.INSTANCE ); 1450 1451 1452 btree.insert( first, "", false ); 1453 1454 // at this stage the cursor will be _on_ the next element, so read it 1455 btree.insert( unsortedEntries.get(), "", false ); 1456 1457 while ( unsortedEntries.next() ) 1458 { 1459 Entry entry = unsortedEntries.get(); 1460 btree.insert( entry, "", false ); 1461 } 1462 1463 unsortedEntries.close(); 1464 1465 return new SortedEntryCursor( btree, recMan, file ); 1466 } 1467 1468 1469 /** 1470 * {@inheritDoc} 1471 */ 1472 @Override 1473 public boolean isPwdMustChange() 1474 { 1475 return pwdMustChange; 1476 } 1477 1478 1479 /** 1480 * {@inheritDoc} 1481 */ 1482 @Override 1483 public void setPwdMustChange( boolean pwdMustChange ) 1484 { 1485 this.pwdMustChange = pwdMustChange; 1486 } 1487 1488 1489 /** 1490 * {@inheritDoc} 1491 */ 1492 @Override 1493 public boolean hasSessionTransaction() 1494 { 1495 return hasSessionTransaction; 1496 } 1497 1498 1499 /** 1500 * {@inheritDoc} 1501 */ 1502 @Override 1503 public long beginSessionTransaction() 1504 { 1505 hasSessionTransaction = true; 1506 1507 return transactionId.getAndIncrement(); 1508 } 1509 1510 1511 /** 1512 * {@inheritDoc} 1513 */ 1514 @Override 1515 public void endSessionTransaction( boolean commit ) throws IOException 1516 { 1517 if ( commit ) 1518 { 1519 for ( Map.Entry<String, PartitionTxn> partitionTxn : transactionMap.entrySet() ) 1520 { 1521 partitionTxn.getValue().commit(); 1522 } 1523 } 1524 else 1525 { 1526 for ( Map.Entry<String, PartitionTxn> partitionTxn : transactionMap.entrySet() ) 1527 { 1528 partitionTxn.getValue().abort(); 1529 } 1530 } 1531 1532 hasSessionTransaction = false; 1533 } 1534 1535 1536 /** 1537 * {@inheritDoc} 1538 */ 1539 @Override 1540 public PartitionTxn getTransaction( Partition partition ) 1541 { 1542 return transactionMap.get( partition.getId() ); 1543 } 1544 1545 1546 /** 1547 * {@inheritDoc} 1548 */ 1549 @Override 1550 public void addTransaction( Partition partition, PartitionTxn transaction ) 1551 { 1552 if ( !transactionMap.containsKey( partition.getId() ) ) 1553 { 1554 transactionMap.put( partition.getId(), transaction ); 1555 } 1556 } 1557}