001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2006-2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.api; 028 029 030 031 import java.net.InetAddress; 032 import java.nio.ByteBuffer; 033 import java.nio.channels.Selector; 034 import java.util.Collection; 035 import java.util.HashSet; 036 import java.util.List; 037 import java.util.Set; 038 import java.util.concurrent.CopyOnWriteArrayList; 039 040 import org.opends.messages.Message; 041 import org.opends.server.api.plugin.PluginResult; 042 import org.opends.server.core.DirectoryServer; 043 import org.opends.server.core.PersistentSearch; 044 import org.opends.server.core.PluginConfigManager; 045 import org.opends.server.core.SearchOperation; 046 import org.opends.server.core.NetworkGroup; 047 import org.opends.server.loggers.debug.DebugTracer; 048 import org.opends.server.types.AbstractOperation; 049 import org.opends.server.types.Attribute; 050 import org.opends.server.types.AttributeType; 051 import org.opends.server.types.AttributeValue; 052 import org.opends.server.types.AuthenticationInfo; 053 import org.opends.server.types.CancelRequest; 054 import org.opends.server.types.CancelResult; 055 import org.opends.server.types.DebugLogLevel; 056 import org.opends.server.types.DirectoryException; 057 import org.opends.server.types.DisconnectReason; 058 import org.opends.server.types.DN; 059 import org.opends.server.types.Entry; 060 import org.opends.server.types.IntermediateResponse; 061 import org.opends.server.types.Operation; 062 import org.opends.server.types.Privilege; 063 import org.opends.server.types.SearchResultEntry; 064 import org.opends.server.types.SearchResultReference; 065 import org.opends.server.util.TimeThread; 066 067 import static org.opends.messages.CoreMessages.*; 068 import static org.opends.server.config.ConfigConstants.*; 069 import static org.opends.server.loggers.debug.DebugLogger.*; 070 import static org.opends.server.util.StaticUtils.*; 071 072 073 074 /** 075 * This class defines the set of methods and structures that must be 076 * implemented by a Directory Server client connection. 077 */ 078 @org.opends.server.types.PublicAPI( 079 stability=org.opends.server.types.StabilityLevel.VOLATILE, 080 mayInstantiate=true, 081 mayExtend=true, 082 mayInvoke=true) 083 public abstract class ClientConnection 084 { 085 /** 086 * The tracer object for the debug logger. 087 */ 088 private static final DebugTracer TRACER = getTracer(); 089 090 // The set of authentication information for this client connection. 091 private AuthenticationInfo authenticationInfo; 092 093 // Indicates whether a bind is currently in progress on this client 094 // connection. If so, then no other operations should be allowed 095 // until the bind completes. 096 private boolean bindInProgress; 097 098 // Indicates whether any necessary finalization work has been done 099 // for this client connection. 100 private boolean finalized; 101 102 // The set of privileges assigned to this client connection. 103 private HashSet<Privilege> privileges; 104 105 // The size limit for use with this client connection. 106 private int sizeLimit; 107 108 // The time limit for use with this client connection. 109 private int timeLimit; 110 111 // The lookthrough limit for use with this client connection. 112 private int lookthroughLimit; 113 114 // The time that this client connection was established. 115 private long connectTime; 116 117 // The idle time limit for this client connection. 118 private long idleTimeLimit; 119 120 // The opaque information used for storing intermediate state 121 // information needed across multi-stage SASL binds. 122 private Object saslAuthState; 123 124 // A string representation of the time that this client connection 125 // was established. 126 private String connectTimeString; 127 128 // A set of persistent searches registered for this client. 129 private CopyOnWriteArrayList<PersistentSearch> persistentSearches; 130 131 // The network group to which the connection belongs to. 132 private NetworkGroup networkGroup; 133 134 135 136 /** 137 * Performs the appropriate initialization generic to all client 138 * connections. 139 */ 140 protected ClientConnection() 141 { 142 connectTime = TimeThread.getTime(); 143 connectTimeString = TimeThread.getGMTTime(); 144 authenticationInfo = new AuthenticationInfo(); 145 saslAuthState = null; 146 bindInProgress = false; 147 persistentSearches = new CopyOnWriteArrayList<PersistentSearch>(); 148 sizeLimit = DirectoryServer.getSizeLimit(); 149 timeLimit = DirectoryServer.getTimeLimit(); 150 idleTimeLimit = DirectoryServer.getIdleTimeLimit(); 151 lookthroughLimit = DirectoryServer.getLookthroughLimit(); 152 finalized = false; 153 privileges = new HashSet<Privilege>(); 154 networkGroup = NetworkGroup.getDefaultNetworkGroup(); 155 } 156 157 158 159 /** 160 * Performs any internal cleanup that may be necessary when this 161 * client connection is disconnected, or if not on disconnec, then 162 * ultimately whenever it is reaped by the garbage collector. In 163 * this case, it will be used to ensure that the connection is 164 * deregistered with the {@code AuthenticatedUsers} manager, and 165 * will then invoke the {@code finalizeClientConnection} method. 166 */ 167 @org.opends.server.types.PublicAPI( 168 stability=org.opends.server.types.StabilityLevel.PRIVATE, 169 mayInstantiate=false, 170 mayExtend=false, 171 mayInvoke=true, 172 notes="This method should only be invoked by connection " + 173 "handlers.") 174 protected final void finalizeConnectionInternal() 175 { 176 if (finalized) 177 { 178 return; 179 } 180 181 finalized = true; 182 183 // Deregister with the set of authenticated users. 184 Entry authNEntry = authenticationInfo.getAuthenticationEntry(); 185 Entry authZEntry = authenticationInfo.getAuthorizationEntry(); 186 187 if (authNEntry != null) 188 { 189 if ((authZEntry == null) || 190 authZEntry.getDN().equals(authNEntry.getDN())) 191 { 192 DirectoryServer.getAuthenticatedUsers().remove( 193 authNEntry.getDN(), this); 194 } 195 else 196 { 197 DirectoryServer.getAuthenticatedUsers().remove( 198 authNEntry.getDN(), this); 199 DirectoryServer.getAuthenticatedUsers().remove( 200 authZEntry.getDN(), this); 201 } 202 } 203 else if (authZEntry != null) 204 { 205 DirectoryServer.getAuthenticatedUsers().remove( 206 authZEntry.getDN(), this); 207 } 208 209 try 210 { 211 finalizeClientConnection(); 212 } 213 catch (Exception e) 214 { 215 if (debugEnabled()) 216 { 217 TRACER.debugCaught(DebugLogLevel.ERROR, e); 218 } 219 } 220 } 221 222 223 224 /** 225 * Performs any cleanup work that may be necessary when this client 226 * connection is terminated. By default, no action is taken. 227 * <BR><BR> 228 * If possible, this method will be invoked when the client 229 * connection is disconnected. If it isn't invoked at that time, 230 * then it will be called when the client connection object is 231 * finalized by the garbage collector. 232 */ 233 @org.opends.server.types.PublicAPI( 234 stability=org.opends.server.types.StabilityLevel.VOLATILE, 235 mayInstantiate=false, 236 mayExtend=true, 237 mayInvoke=false) 238 protected void finalizeClientConnection() 239 { 240 // No implementation is required by default. 241 } 242 243 244 245 /** 246 * Retrieves the time that this connection was established, measured 247 * in the number of milliseconds since January 1, 1970 UTC. 248 * 249 * @return The time that this connection was established, measured 250 * in the number of milliseconds since January 1, 1970 UTC. 251 */ 252 public final long getConnectTime() 253 { 254 return connectTime; 255 } 256 257 258 259 /** 260 * Retrieves a string representation of the time that this 261 * connection was established. 262 * 263 * @return A string representation of the time that this connection 264 * was established. 265 */ 266 public final String getConnectTimeString() 267 { 268 return connectTimeString; 269 } 270 271 272 273 /** 274 * Retrieves the unique identifier that has been assigned to this 275 * connection. 276 * 277 * @return The unique identifier that has been assigned to this 278 * connection. 279 */ 280 public abstract long getConnectionID(); 281 282 283 284 /** 285 * Retrieves the connection handler that accepted this client 286 * connection. 287 * 288 * @return The connection handler that accepted this client 289 * connection. 290 */ 291 public abstract ConnectionHandler getConnectionHandler(); 292 293 294 295 /** 296 * Retrieves the protocol that the client is using to communicate 297 * with the Directory Server. 298 * 299 * @return The protocol that the client is using to communicate 300 * with the Directory Server. 301 */ 302 public abstract String getProtocol(); 303 304 305 306 /** 307 * Retrieves a string representation of the address of the client. 308 * 309 * @return A string representation of the address of the client. 310 */ 311 public abstract String getClientAddress(); 312 313 314 315 /** 316 * Retrieves a string representation of the address on the server to 317 * which the client connected. 318 * 319 * @return A string representation of the address on the server to 320 * which the client connected. 321 */ 322 public abstract String getServerAddress(); 323 324 325 326 /** 327 * Retrieves the {@code java.net.InetAddress} associated with the 328 * remote client system. 329 * 330 * @return The {@code java.net.InetAddress} associated with the 331 * remote client system. It may be {@code null} if the 332 * client is not connected over an IP-based connection. 333 */ 334 public abstract InetAddress getRemoteAddress(); 335 336 337 338 /** 339 * Retrieves the {@code java.net.InetAddress} for the Directory 340 * Server system to which the client has established the connection. 341 * 342 * @return The {@code java.net.InetAddress} for the Directory 343 * Server system to which the client has established the 344 * connection. It may be {@code null} if the client is not 345 * connected over an IP-based connection. 346 */ 347 public abstract InetAddress getLocalAddress(); 348 349 350 351 /** 352 * Indicates whether this client connection is currently using a 353 * secure mechanism to communicate with the server. Note that this 354 * may change over time based on operations performed by the client 355 * or server (e.g., it may go from {@code false} to {@code true} if 356 * if the client uses the StartTLS extended operation). 357 * 358 * @return {@code true} if the client connection is currently using 359 * a secure mechanism to communicate with the server, or 360 * {@code false} if not. 361 */ 362 public abstract boolean isSecure(); 363 364 365 366 /** 367 * Retrieves the connection security provider for this client 368 * connection. 369 * 370 * @return The connection security provider for this client 371 * connection. 372 */ 373 public abstract ConnectionSecurityProvider 374 getConnectionSecurityProvider(); 375 376 377 378 /** 379 * Specifies the connection security provider for this client 380 * connection. 381 * 382 * @param securityProvider The connection security provider to use 383 * for communication on this client 384 * connection. 385 */ 386 public abstract void setConnectionSecurityProvider( 387 ConnectionSecurityProvider 388 securityProvider); 389 390 391 392 /** 393 * Retrieves the human-readable name of the security mechanism that 394 * is used to protect communication with this client. 395 * 396 * @return The human-readable name of the security mechanism that 397 * is used to protect communication with this client, or 398 * {@code null} if no security is in place. 399 */ 400 public abstract String getSecurityMechanism(); 401 402 403 404 /** 405 * Retrieves a {@code Selector} that may be used to ensure that 406 * write operations complete in a timely manner, or terminate the 407 * connection in the event that they fail to do so. This is an 408 * optional method for client connections, and the default 409 * implementation returns {@code null} to indicate that the maximum 410 * blocked write time limit is not supported for this connection. 411 * Subclasses that do wish to support this functionality should 412 * return a valid {@code Selector} object. 413 * 414 * @return The {@code Selector} that may be used to ensure that 415 * write operations complete in a timely manner, or 416 * {@code null} if this client connection does not support 417 * maximum blocked write time limit functionality. 418 */ 419 public Selector getWriteSelector() 420 { 421 // There will not be a write selector in the default 422 // implementation. 423 return null; 424 } 425 426 427 428 /** 429 * Retrieves the maximum length of time in milliseconds that 430 * attempts to write data to the client should be allowed to block. 431 * A value of zero indicates there should be no limit. 432 * 433 * @return The maximum length of time in milliseconds that attempts 434 * to write data to the client should be allowed to block, 435 * or zero if there should be no limit. 436 */ 437 public long getMaxBlockedWriteTimeLimit() 438 { 439 // By default, we'll return 0, which indicates that there should 440 // be no maximum time limit. Subclasses should override this if 441 // they want to support a maximum blocked write time limit. 442 return 0L; 443 } 444 445 446 447 /** 448 * Indicates that the data in the provided buffer has been read from 449 * the client and should be processed. The contents of the provided 450 * buffer will be in clear-text (the data may have been passed 451 * through a connection security provider to obtain the clear-text 452 * version), and may contain part or all of one or more client 453 * requests. 454 * 455 * @param buffer The byte buffer containing the data available for 456 * reading. 457 * 458 * @return {@code true} if all the data in the provided buffer was 459 * processed and the client connection can remain 460 * established, or {@code false} if a decoding error 461 * occurred and requests from this client should no longer 462 * be processed. Note that if this method does return 463 * {@code false}, then it must have already disconnected 464 * the client. 465 */ 466 public abstract boolean processDataRead(ByteBuffer buffer); 467 468 469 470 /** 471 * Sends a response to the client based on the information in the 472 * provided operation. 473 * 474 * @param operation The operation for which to send the response. 475 */ 476 public abstract void sendResponse(Operation operation); 477 478 479 480 /** 481 * Sends the provided search result entry to the client. 482 * 483 * @param searchOperation The search operation with which the 484 * entry is associated. 485 * @param searchEntry The search result entry to be sent to 486 * the client. 487 * 488 * @throws DirectoryException If a problem occurs while attempting 489 * to send the entry to the client and 490 * the search should be terminated. 491 */ 492 public abstract void sendSearchEntry( 493 SearchOperation searchOperation, 494 SearchResultEntry searchEntry) 495 throws DirectoryException; 496 497 498 499 /** 500 * Sends the provided search result reference to the client. 501 * 502 * @param searchOperation The search operation with which the 503 * reference is associated. 504 * @param searchReference The search result reference to be sent 505 * to the client. 506 * 507 * @return {@code true} if the client is able to accept referrals, 508 * or {@code false} if the client cannot handle referrals 509 * and no more attempts should be made to send them for the 510 * associated search operation. 511 * 512 * @throws DirectoryException If a problem occurs while attempting 513 * to send the reference to the client 514 * and the search should be terminated. 515 */ 516 public abstract boolean sendSearchReference( 517 SearchOperation searchOperation, 518 SearchResultReference searchReference) 519 throws DirectoryException; 520 521 522 523 /** 524 * Invokes the intermediate response plugins on the provided 525 * response message and sends it to the client. 526 * 527 * @param intermediateResponse The intermediate response message 528 * to be sent. 529 * 530 * @return {@code true} if processing on the associated operation 531 * should continue, or {@code false} if not. 532 */ 533 public final boolean sendIntermediateResponse( 534 IntermediateResponse intermediateResponse) 535 { 536 // Invoke the intermediate response plugins for the response 537 // message. 538 PluginConfigManager pluginConfigManager = 539 DirectoryServer.getPluginConfigManager(); 540 PluginResult.IntermediateResponse pluginResult = 541 pluginConfigManager.invokeIntermediateResponsePlugins( 542 intermediateResponse); 543 544 boolean continueProcessing = true; 545 if (pluginResult.sendResponse()) 546 { 547 continueProcessing = 548 sendIntermediateResponseMessage(intermediateResponse); 549 } 550 551 return (continueProcessing && pluginResult.continueProcessing()); 552 } 553 554 555 556 557 /** 558 * Sends the provided intermediate response message to the client. 559 * 560 * @param intermediateResponse The intermediate response message 561 * to be sent. 562 * 563 * @return {@code true} if processing on the associated operation 564 * should continue, or {@code false} if not. 565 */ 566 protected abstract boolean 567 sendIntermediateResponseMessage( 568 IntermediateResponse intermediateResponse); 569 570 571 572 /** 573 * Closes the connection to the client, optionally sending it a 574 * message indicating the reason for the closure. Note that the 575 * ability to send a notice of disconnection may not be available 576 * for all protocols or under all circumstances. Also note that 577 * when attempting to disconnect a client connection as a part of 578 * operation processing (e.g., within a plugin or other extension), 579 * the {@code disconnectClient} method within that operation should 580 * be called rather than invoking this method directly. 581 * <BR><BR> 582 * All subclasses must invoke the {@code finalizeConnectionInternal} 583 * method during the course of processing this method. 584 * 585 * @param disconnectReason The disconnect reason that provides the 586 * generic cause for the disconnect. 587 * @param sendNotification Indicates whether to try to provide 588 * notification to the client that the 589 * connection will be closed. 590 * @param message The message to send to the client. It 591 * may be {@code null} if no notification 592 * is to be sent. 593 */ 594 public abstract void disconnect(DisconnectReason disconnectReason, 595 boolean sendNotification, 596 Message message); 597 598 599 600 /** 601 * Indicates whether a bind operation is in progress on this client 602 * connection. If so, then no new operations should be allowed 603 * until the bind has completed. 604 * 605 * @return {@code true} if a bind operation is in progress on this 606 * connection, or {@code false} if not. 607 */ 608 public boolean bindInProgress() 609 { 610 return bindInProgress; 611 } 612 613 614 615 /** 616 * Specifies whether a bind operation is in progress on this client 617 * connection. If so, then no new operations should be allowed 618 * until the bind has completed. 619 * 620 * @param bindInProgress Specifies whether a bind operation is in 621 * progress on this client connection. 622 */ 623 public void setBindInProgress(boolean bindInProgress) 624 { 625 this.bindInProgress = bindInProgress; 626 } 627 628 629 630 /** 631 * Indicates whether the user associated with this client connection 632 * must change their password before they will be allowed to do 633 * anything else. 634 * 635 * @return {@code true} if the user associated with this client 636 * connection must change their password before they will 637 * be allowed to do anything else, or {@code false} if not. 638 */ 639 public final boolean mustChangePassword() 640 { 641 if (authenticationInfo == null) 642 { 643 return false; 644 } 645 else 646 { 647 return authenticationInfo.mustChangePassword(); 648 } 649 } 650 651 652 653 /** 654 * Specifies whether the user associated with this client connection 655 * must change their password before they will be allowed to do 656 * anything else. 657 * 658 * @param mustChangePassword Specifies whether the user associated 659 * with this client connection must 660 * change their password before they 661 * will be allowed to do anything else. 662 */ 663 public final void setMustChangePassword(boolean mustChangePassword) 664 { 665 if (authenticationInfo == null) 666 { 667 setAuthenticationInfo(new AuthenticationInfo()); 668 } 669 670 authenticationInfo.setMustChangePassword(mustChangePassword); 671 } 672 673 674 675 /** 676 * Retrieves the set of operations in progress for this client 677 * connection. This list must not be altered by any caller. 678 * 679 * @return The set of operations in progress for this client 680 * connection. 681 */ 682 public abstract Collection<AbstractOperation> 683 getOperationsInProgress(); 684 685 686 687 /** 688 * Retrieves the operation in progress with the specified message 689 * ID. 690 * 691 * @param messageID The message ID of the operation to retrieve. 692 * 693 * @return The operation in progress with the specified message ID, 694 * or {@code null} if no such operation could be found. 695 */ 696 public abstract AbstractOperation 697 getOperationInProgress(int messageID); 698 699 700 701 /** 702 * Removes the provided operation from the set of operations in 703 * progress for this client connection. Note that this does not 704 * make any attempt to cancel any processing that may already be in 705 * progress for the operation. 706 * 707 * @param messageID The message ID of the operation to remove from 708 * the set of operations in progress. 709 * 710 * @return {@code true} if the operation was found and removed from 711 * the set of operations in progress, or {@code false} if 712 * not. 713 */ 714 public abstract boolean removeOperationInProgress(int messageID); 715 716 717 718 /** 719 * Retrieves the set of persistent searches registered for this 720 * client. 721 * 722 * @return The set of persistent searches registered for this 723 * client. 724 */ 725 public final CopyOnWriteArrayList<PersistentSearch> 726 getPersistentSearches() 727 { 728 return persistentSearches; 729 } 730 731 732 733 /** 734 * Registers the provided persistent search for this client. Note 735 * that this should only be called by 736 * {@code DirectoryServer.registerPersistentSearch} and not through 737 * any other means. 738 * 739 * @param persistentSearch The persistent search to register for 740 * this client. 741 */ 742 @org.opends.server.types.PublicAPI( 743 stability=org.opends.server.types.StabilityLevel.PRIVATE, 744 mayInstantiate=false, 745 mayExtend=false, 746 mayInvoke=false) 747 public final void registerPersistentSearch(PersistentSearch 748 persistentSearch) 749 { 750 persistentSearches.add(persistentSearch); 751 } 752 753 754 755 /** 756 * Deregisters the provided persistent search for this client. Note 757 * that this should only be called by 758 * {@code DirectoryServer.deregisterPersistentSearch} and not 759 * through any other means. 760 * 761 * @param persistentSearch The persistent search to deregister for 762 * this client. 763 */ 764 @org.opends.server.types.PublicAPI( 765 stability=org.opends.server.types.StabilityLevel.PRIVATE, 766 mayInstantiate=false, 767 mayExtend=false, 768 mayInvoke=false) 769 public final void deregisterPersistentSearch(PersistentSearch 770 persistentSearch) 771 { 772 persistentSearches.remove(persistentSearch); 773 } 774 775 776 777 /** 778 * Attempts to cancel the specified operation. 779 * 780 * @param messageID The message ID of the operation to cancel. 781 * @param cancelRequest An object providing additional information 782 * about how the cancel should be processed. 783 * 784 * @return A cancel result that either indicates that the cancel 785 * was successful or provides a reason that it was not. 786 */ 787 public abstract CancelResult cancelOperation(int messageID, 788 CancelRequest cancelRequest); 789 790 791 792 /** 793 * Attempts to cancel all operations in progress on this connection. 794 * 795 * @param cancelRequest An object providing additional information 796 * about how the cancel should be processed. 797 */ 798 public abstract void cancelAllOperations( 799 CancelRequest cancelRequest); 800 801 802 803 /** 804 * Attempts to cancel all operations in progress on this connection 805 * except the operation with the specified message ID. 806 * 807 * @param cancelRequest An object providing additional information 808 * about how the cancel should be processed. 809 * @param messageID The message ID of the operation that 810 * should not be canceled. 811 */ 812 public abstract void cancelAllOperationsExcept( 813 CancelRequest cancelRequest, 814 int messageID); 815 816 817 818 /** 819 * Retrieves information about the authentication that has been 820 * performed for this connection. 821 * 822 * @return Information about the user that is currently 823 * authenticated on this connection. 824 */ 825 public AuthenticationInfo getAuthenticationInfo() 826 { 827 return authenticationInfo; 828 } 829 830 831 832 /** 833 * Specifies information about the authentication that has been 834 * performed for this connection. 835 * 836 * @param authenticationInfo Information about the authentication 837 * that has been performed for this 838 * connection. It should not be 839 * {@code null}. 840 */ 841 public void setAuthenticationInfo(AuthenticationInfo 842 authenticationInfo) 843 { 844 if (this.authenticationInfo != null) 845 { 846 Entry authNEntry = 847 this.authenticationInfo.getAuthenticationEntry(); 848 Entry authZEntry = 849 this.authenticationInfo.getAuthorizationEntry(); 850 851 if (authNEntry != null) 852 { 853 if ((authZEntry == null) || 854 authZEntry.getDN().equals(authNEntry.getDN())) 855 { 856 DirectoryServer.getAuthenticatedUsers().remove( 857 authNEntry.getDN(), this); 858 } 859 else 860 { 861 DirectoryServer.getAuthenticatedUsers().remove( 862 authNEntry.getDN(), this); 863 DirectoryServer.getAuthenticatedUsers().remove( 864 authZEntry.getDN(), this); 865 } 866 } 867 else if (authZEntry != null) 868 { 869 DirectoryServer.getAuthenticatedUsers().remove( 870 authZEntry.getDN(), this); 871 } 872 } 873 874 if (authenticationInfo == null) 875 { 876 this.authenticationInfo = new AuthenticationInfo(); 877 updatePrivileges(null, false); 878 } 879 else 880 { 881 this.authenticationInfo = authenticationInfo; 882 883 Entry authNEntry = authenticationInfo.getAuthenticationEntry(); 884 Entry authZEntry = authenticationInfo.getAuthorizationEntry(); 885 886 if (authNEntry != null) 887 { 888 if ((authZEntry == null) || 889 authZEntry.getDN().equals(authNEntry.getDN())) 890 { 891 DirectoryServer.getAuthenticatedUsers().put( 892 authNEntry.getDN(), this); 893 } 894 else 895 { 896 DirectoryServer.getAuthenticatedUsers().put( 897 authNEntry.getDN(), this); 898 DirectoryServer.getAuthenticatedUsers().put( 899 authZEntry.getDN(), this); 900 } 901 } 902 else 903 { 904 if (authZEntry != null) 905 { 906 DirectoryServer.getAuthenticatedUsers().put( 907 authZEntry.getDN(), this); 908 } 909 } 910 911 updatePrivileges(authZEntry, authenticationInfo.isRoot()); 912 } 913 } 914 915 916 917 /** 918 * Updates the cached entry associated with either the 919 * authentication and/or authorization identity with the provided 920 * version. 921 * 922 * @param oldEntry The user entry currently serving as the 923 * authentication and/or authorization identity. 924 * @param newEntry The updated entry that should replace the 925 * existing entry. It may optionally have a 926 * different DN than the old entry. 927 */ 928 public final void updateAuthenticationInfo(Entry oldEntry, 929 Entry newEntry) 930 { 931 Entry authNEntry = authenticationInfo.getAuthenticationEntry(); 932 Entry authZEntry = authenticationInfo.getAuthorizationEntry(); 933 934 if ((authNEntry != null) && 935 authNEntry.getDN().equals(oldEntry.getDN())) 936 { 937 if ((authZEntry == null) || 938 (! authZEntry.getDN().equals(authNEntry.getDN()))) 939 { 940 setAuthenticationInfo( 941 authenticationInfo.duplicate(newEntry, authZEntry)); 942 updatePrivileges(newEntry, authenticationInfo.isRoot()); 943 } 944 else 945 { 946 setAuthenticationInfo( 947 authenticationInfo.duplicate(newEntry, newEntry)); 948 updatePrivileges(newEntry, authenticationInfo.isRoot()); 949 } 950 } 951 else if ((authZEntry != null) && 952 (authZEntry.getDN().equals(oldEntry.getDN()))) 953 { 954 setAuthenticationInfo( 955 authenticationInfo.duplicate(authNEntry, newEntry)); 956 } 957 } 958 959 960 961 /** 962 * Sets properties in this client connection to indicate that the 963 * client is unauthenticated. This includes setting the 964 * authentication info structure to an empty default, as well as 965 * setting the size and time limit values to their defaults. 966 */ 967 public void setUnauthenticated() 968 { 969 setAuthenticationInfo(new AuthenticationInfo()); 970 this.sizeLimit = DirectoryServer.getSizeLimit(); 971 this.timeLimit = DirectoryServer.getTimeLimit(); 972 } 973 974 975 976 /** 977 * Indicates whether the authenticated client has the specified 978 * privilege. 979 * 980 * @param privilege The privilege for which to make the 981 * determination. 982 * @param operation The operation being processed which needs to 983 * make the privilege determination, or 984 * {@code null} if there is no associated 985 * operation. 986 * 987 * @return {@code true} if the authenticated client has the 988 * specified privilege, or {@code false} if not. 989 */ 990 public boolean hasPrivilege(Privilege privilege, 991 Operation operation) 992 { 993 if (privilege == Privilege.PROXIED_AUTH) 994 { 995 // This determination should always be made against the 996 // authentication identity rather than the authorization 997 // identity. 998 Entry authEntry = authenticationInfo.getAuthenticationEntry(); 999 boolean isRoot = authenticationInfo.isRoot(); 1000 return getPrivileges(authEntry, 1001 isRoot).contains(Privilege.PROXIED_AUTH) || 1002 DirectoryServer.isDisabled(Privilege.PROXIED_AUTH); 1003 } 1004 1005 boolean result; 1006 if (operation == null) 1007 { 1008 result = privileges.contains(privilege); 1009 if (debugEnabled()) 1010 { 1011 DN authDN = authenticationInfo.getAuthenticationDN(); 1012 1013 Message message = INFO_CLIENTCONNECTION_AUDIT_HASPRIVILEGE 1014 .get(getConnectionID(), -1L, 1015 String.valueOf(authDN), 1016 privilege.getName(), result); 1017 TRACER.debugMessage(DebugLogLevel.INFO, message.toString()); 1018 } 1019 } 1020 else 1021 { 1022 if (operation.getAuthorizationDN().equals( 1023 authenticationInfo.getAuthorizationDN()) || 1024 (operation.getAuthorizationDN().equals(DN.NULL_DN) && 1025 !authenticationInfo.isAuthenticated())) { 1026 result = privileges.contains(privilege) || 1027 DirectoryServer.isDisabled(privilege); 1028 if (debugEnabled()) 1029 { 1030 DN authDN = authenticationInfo.getAuthenticationDN(); 1031 1032 Message message = 1033 INFO_CLIENTCONNECTION_AUDIT_HASPRIVILEGE.get( 1034 getConnectionID(), 1035 operation.getOperationID(), 1036 String.valueOf(authDN), 1037 privilege.getName(), result); 1038 TRACER.debugMessage(DebugLogLevel.INFO, message.toString()); 1039 } 1040 } 1041 else 1042 { 1043 Entry authorizationEntry = operation.getAuthorizationEntry(); 1044 if (authorizationEntry == null) 1045 { 1046 result = false; 1047 } 1048 else 1049 { 1050 boolean isRoot = 1051 DirectoryServer.isRootDN(authorizationEntry.getDN()); 1052 result = getPrivileges(authorizationEntry, 1053 isRoot).contains(privilege) || 1054 DirectoryServer.isDisabled(privilege); 1055 } 1056 } 1057 } 1058 1059 return result; 1060 } 1061 1062 1063 1064 /** 1065 * Indicates whether the authenticate client has all of the 1066 * specified privileges. 1067 * 1068 * @param privileges The array of privileges for which to make the 1069 * determination. 1070 * @param operation The operation being processed which needs to 1071 * make the privilege determination, or 1072 * {@code null} if there is no associated 1073 * operation. 1074 * 1075 * @return {@code true} if the authenticated client has all of the 1076 * specified privileges, or {@code false} if not. 1077 */ 1078 public boolean hasAllPrivileges(Privilege[] privileges, 1079 Operation operation) 1080 { 1081 HashSet<Privilege> privSet = this.privileges; 1082 1083 if (debugEnabled()) 1084 { 1085 for (Privilege p : privileges) 1086 { 1087 if (! privSet.contains(p)) 1088 { 1089 return false; 1090 } 1091 } 1092 1093 return true; 1094 } 1095 else 1096 { 1097 boolean result = true; 1098 StringBuilder buffer = new StringBuilder(); 1099 buffer.append("{"); 1100 1101 for (int i=0; i < privileges.length; i++) 1102 { 1103 if (i > 0) 1104 { 1105 buffer.append(","); 1106 } 1107 1108 buffer.append(privileges[i].getName()); 1109 1110 if (! privSet.contains(privileges[i])) 1111 { 1112 result = false; 1113 } 1114 } 1115 1116 buffer.append(" }"); 1117 1118 if (operation == null) 1119 { 1120 DN authDN = authenticationInfo.getAuthenticationDN(); 1121 1122 Message message = 1123 INFO_CLIENTCONNECTION_AUDIT_HASPRIVILEGES.get( 1124 getConnectionID(), -1L, 1125 String.valueOf(authDN), 1126 buffer.toString(), result); 1127 TRACER.debugMessage(DebugLogLevel.INFO, 1128 message.toString()); 1129 } 1130 else 1131 { 1132 DN authDN = authenticationInfo.getAuthenticationDN(); 1133 1134 Message message = INFO_CLIENTCONNECTION_AUDIT_HASPRIVILEGES 1135 .get( 1136 getConnectionID(), 1137 operation.getOperationID(), 1138 String.valueOf(authDN), 1139 buffer.toString(), result); 1140 TRACER.debugMessage(DebugLogLevel.INFO, message.toString()); 1141 } 1142 1143 return result; 1144 } 1145 } 1146 1147 1148 1149 /** 1150 * Retrieves the set of privileges encoded in the provided entry. 1151 * 1152 * @param entry The entry to use to obtain the privilege 1153 * information. 1154 * @param isRoot Indicates whether the set of root privileges 1155 * should be automatically included in the 1156 * privilege set. 1157 * 1158 * @return A set of the privileges that should be assigned. 1159 */ 1160 private HashSet<Privilege> getPrivileges(Entry entry, 1161 boolean isRoot) 1162 { 1163 if (entry == null) 1164 { 1165 return new HashSet<Privilege>(0); 1166 } 1167 1168 HashSet<Privilege> newPrivileges = new HashSet<Privilege>(); 1169 HashSet<Privilege> removePrivileges = new HashSet<Privilege>(); 1170 1171 if (isRoot) 1172 { 1173 newPrivileges.addAll(DirectoryServer.getRootPrivileges()); 1174 } 1175 1176 AttributeType privType = 1177 DirectoryServer.getAttributeType(OP_ATTR_PRIVILEGE_NAME); 1178 List<Attribute> attrList = entry.getAttribute(privType); 1179 if (attrList != null) 1180 { 1181 for (Attribute a : attrList) 1182 { 1183 for (AttributeValue v : a.getValues()) 1184 { 1185 String privName = toLowerCase(v.getStringValue()); 1186 1187 // If the name of the privilege is prefixed with a minus 1188 // sign, then we will take away that privilege from the 1189 // user. We'll handle that at the end so that we can make 1190 // sure it's not added back later. 1191 if (privName.startsWith("-")) 1192 { 1193 privName = privName.substring(1); 1194 Privilege p = Privilege.privilegeForName(privName); 1195 if (p == null) 1196 { 1197 // FIXME -- Generate an administrative alert. 1198 1199 // We don't know what privilege to remove, so we'll 1200 // remove all of them. 1201 newPrivileges.clear(); 1202 return newPrivileges; 1203 } 1204 else 1205 { 1206 removePrivileges.add(p); 1207 } 1208 } 1209 else 1210 { 1211 Privilege p = Privilege.privilegeForName(privName); 1212 if (p == null) 1213 { 1214 // FIXME -- Generate an administrative alert. 1215 } 1216 else 1217 { 1218 newPrivileges.add(p); 1219 } 1220 } 1221 } 1222 } 1223 } 1224 1225 for (Privilege p : removePrivileges) 1226 { 1227 newPrivileges.remove(p); 1228 } 1229 1230 return newPrivileges; 1231 } 1232 1233 1234 1235 /** 1236 * Updates the privileges associated with this client connection 1237 * object based on the provided entry for the authentication 1238 * identity. 1239 * 1240 * @param entry The entry for the authentication identity 1241 * associated with this client connection. 1242 * @param isRoot Indicates whether the associated user is a root 1243 * user and should automatically inherit the root 1244 * privilege set. 1245 */ 1246 private void updatePrivileges(Entry entry, boolean isRoot) 1247 { 1248 privileges = getPrivileges(entry, isRoot); 1249 } 1250 1251 1252 1253 /** 1254 * Retrieves an opaque set of information that may be used for 1255 * processing multi-stage SASL binds. 1256 * 1257 * @return An opaque set of information that may be used for 1258 * processing multi-stage SASL binds. 1259 */ 1260 public final Object getSASLAuthStateInfo() 1261 { 1262 return saslAuthState; 1263 } 1264 1265 1266 1267 /** 1268 * Specifies an opaque set of information that may be used for 1269 * processing multi-stage SASL binds. 1270 * 1271 * @param saslAuthState An opaque set of information that may be 1272 * used for processing multi-stage SASL 1273 * binds. 1274 */ 1275 public final void setSASLAuthStateInfo(Object saslAuthState) 1276 { 1277 this.saslAuthState = saslAuthState; 1278 } 1279 1280 1281 1282 /** 1283 * Retrieves the size limit that will be enforced for searches 1284 * performed using this client connection. 1285 * 1286 * @return The size limit that will be enforced for searches 1287 * performed using this client connection. 1288 */ 1289 public final int getSizeLimit() 1290 { 1291 return sizeLimit; 1292 } 1293 1294 1295 1296 /** 1297 * Specifies the size limit that will be enforced for searches 1298 * performed using this client connection. 1299 * 1300 * @param sizeLimit The size limit that will be enforced for 1301 * searches performed using this client 1302 * connection. 1303 */ 1304 public void setSizeLimit(int sizeLimit) 1305 { 1306 this.sizeLimit = sizeLimit; 1307 } 1308 1309 1310 1311 /** 1312 * Retrieves the maximum length of time in milliseconds that this 1313 * client connection will be allowed to remain idle before it should 1314 * be disconnected. 1315 * 1316 * @return The maximum length of time in milliseconds that this 1317 * client connection will be allowed to remain idle before 1318 * it should be disconnected. 1319 */ 1320 public final long getIdleTimeLimit() 1321 { 1322 return idleTimeLimit; 1323 } 1324 1325 1326 1327 /** 1328 * Specifies the maximum length of time in milliseconds that this 1329 * client connection will be allowed to remain idle before it should 1330 * be disconnected. 1331 * 1332 * @param idleTimeLimit The maximum length of time in milliseconds 1333 * that this client connection will be 1334 * allowed to remain idle before it should be 1335 * disconnected. 1336 */ 1337 public void setIdleTimeLimit(long idleTimeLimit) 1338 { 1339 this.idleTimeLimit = idleTimeLimit; 1340 } 1341 1342 1343 1344 /** 1345 * Retrieves the default maximum number of entries that should 1346 * checked for matches during a search. 1347 * 1348 * @return The default maximum number of entries that should 1349 * checked for matches during a search. 1350 */ 1351 public final int getLookthroughLimit() 1352 { 1353 return lookthroughLimit; 1354 } 1355 1356 1357 1358 /** 1359 * Specifies the default maximum number of entries that should 1360 * be checked for matches during a search. 1361 * 1362 * @param lookthroughLimit The default maximum number of 1363 * entries that should be check for 1364 * matches during a search. 1365 */ 1366 public void setLookthroughLimit(int lookthroughLimit) 1367 { 1368 this.lookthroughLimit = lookthroughLimit; 1369 } 1370 1371 1372 1373 /** 1374 * Retrieves the time limit that will be enforced for searches 1375 * performed using this client connection. 1376 * 1377 * @return The time limit that will be enforced for searches 1378 * performed using this client connection. 1379 */ 1380 public final int getTimeLimit() 1381 { 1382 return timeLimit; 1383 } 1384 1385 1386 1387 /** 1388 * Specifies the time limit that will be enforced for searches 1389 * performed using this client connection. 1390 * 1391 * @param timeLimit The time limit that will be enforced for 1392 * searches performed using this client 1393 * connection. 1394 */ 1395 public void setTimeLimit(int timeLimit) 1396 { 1397 this.timeLimit = timeLimit; 1398 } 1399 1400 1401 1402 /** 1403 * Retrieves a one-line summary of this client connection in a form 1404 * that is suitable for including in the monitor entry for the 1405 * associated connection handler. It should be in a format that is 1406 * both humand readable and machine parseable (e.g., a 1407 * space-delimited name-value list, with quotes around the values). 1408 * 1409 * @return A one-line summary of this client connection in a form 1410 * that is suitable for including in the monitor entry for 1411 * the associated connection handler. 1412 */ 1413 public abstract String getMonitorSummary(); 1414 1415 1416 1417 /** 1418 * Indicates whether the user associated with this client connection 1419 * should be considered a member of the specified group, optionally 1420 * evaluated within the context of the provided operation. If an 1421 * operation is given, then the determination should be made based 1422 * on the authorization identity for that operation. If the 1423 * operation is {@code null}, then the determination should be made 1424 * based on the authorization identity for this client connection. 1425 * Note that this is a point-in-time determination and the caller 1426 * must not cache the result. 1427 * 1428 * @param group The group for which to make the determination. 1429 * @param operation The operation to use to obtain the 1430 * authorization identity for which to make the 1431 * determination, or {@code null} if the 1432 * authorization identity should be obtained from 1433 * this client connection. 1434 * 1435 * @return {@code true} if the target user is currently a member of 1436 * the specified group, or {@code false} if not. 1437 * 1438 * @throws DirectoryException If a problem occurs while attempting 1439 * to make the determination. 1440 */ 1441 public boolean isMemberOf(Group group, Operation operation) 1442 throws DirectoryException 1443 { 1444 if (operation == null) 1445 { 1446 return group.isMember(authenticationInfo.getAuthorizationDN()); 1447 } 1448 else 1449 { 1450 return group.isMember(operation.getAuthorizationDN()); 1451 } 1452 } 1453 1454 1455 1456 /** 1457 * Retrieves the set of groups in which the user associated with 1458 * this client connection may be considered to be a member. If an 1459 * operation is provided, then the determination should be made 1460 * based on the authorization identity for that operation. If the 1461 * operation is {@code null}, then it should be made based on the 1462 * authorization identity for this client connection. Note that 1463 * this is a point-in-time determination and the caller must not 1464 * cache the result. 1465 * 1466 * @param operation The operation to use to obtain the 1467 * authorization identity for which to retrieve 1468 * the associated groups, or {@code null} if the 1469 * authorization identity should be obtained from 1470 * this client connection. 1471 * 1472 * @return The set of groups in which the target user is currently 1473 * a member. 1474 * 1475 * @throws DirectoryException If a problem occurs while attempting 1476 * to make the determination. 1477 */ 1478 public Set<Group> getGroups(Operation operation) 1479 throws DirectoryException 1480 { 1481 // FIXME -- This probably isn't the most efficient implementation. 1482 DN authzDN; 1483 if (operation == null) 1484 { 1485 if ((authenticationInfo == null) || 1486 (! authenticationInfo.isAuthenticated())) 1487 { 1488 authzDN = null; 1489 } 1490 else 1491 { 1492 authzDN = authenticationInfo.getAuthorizationDN(); 1493 } 1494 } 1495 else 1496 { 1497 authzDN = operation.getAuthorizationDN(); 1498 } 1499 1500 if ((authzDN == null) || authzDN.isNullDN()) 1501 { 1502 return java.util.Collections.<Group>emptySet(); 1503 } 1504 1505 Entry userEntry = DirectoryServer.getEntry(authzDN); 1506 if (userEntry == null) 1507 { 1508 return java.util.Collections.<Group>emptySet(); 1509 } 1510 1511 HashSet<Group> groupSet = new HashSet<Group>(); 1512 for (Group g : 1513 DirectoryServer.getGroupManager().getGroupInstances()) 1514 { 1515 if (g.isMember(userEntry)) 1516 { 1517 groupSet.add(g); 1518 } 1519 } 1520 1521 return groupSet; 1522 } 1523 1524 1525 1526 /** 1527 * Retrieves the DN of the key manager provider that should be used 1528 * for operations requiring access to a key manager. The default 1529 * implementation returns {@code null} to indicate that no key 1530 * manager provider is avaialble, but subclasses should override 1531 * this method to return a valid DN if they perform operations which 1532 * may need access to a key manager. 1533 * 1534 * @return The DN of the key manager provider that should be used 1535 * for operations requiring access to a key manager, or 1536 * {@code null} if there is no key manager provider 1537 * configured for this client connection. 1538 */ 1539 public DN getKeyManagerProviderDN() 1540 { 1541 // In the default implementation, we'll return null. 1542 return null; 1543 } 1544 1545 1546 1547 /** 1548 * Retrieves the DN of the trust manager provider that should be 1549 * used for operations requiring access to a trust manager. The 1550 * default implementation returns {@code null} to indicate that no 1551 * trust manager provider is avaialble, but subclasses should 1552 * override this method to return a valid DN if they perform 1553 * operations which may need access to a trust manager. 1554 * 1555 * @return The DN of the trust manager provider that should be used 1556 * for operations requiring access to a trust manager, or 1557 * {@code null} if there is no trust manager provider 1558 * configured for this client connection. 1559 */ 1560 public DN getTrustManagerProviderDN() 1561 { 1562 // In the default implementation, we'll return null. 1563 return null; 1564 } 1565 1566 1567 1568 /** 1569 * Retrieves the alias of the server certificate that should be used 1570 * for operations requiring a server certificate. The default 1571 * implementation returns {@code null} to indicate that any alias is 1572 * acceptable. 1573 * 1574 * @return The alias of the server certificate that should be used 1575 * for operations requring a server certificate, or 1576 * {@code null} if any alias is acceptable. 1577 */ 1578 public String getCertificateAlias() 1579 { 1580 // In the default implementation, we'll return null. 1581 return null; 1582 } 1583 1584 1585 1586 /** 1587 * Retrieves a string representation of this client connection. 1588 * 1589 * @return A string representation of this client connection. 1590 */ 1591 public final String toString() 1592 { 1593 StringBuilder buffer = new StringBuilder(); 1594 toString(buffer); 1595 return buffer.toString(); 1596 } 1597 1598 1599 1600 /** 1601 * Appends a string representation of this client connection to the 1602 * provided buffer. 1603 * 1604 * @param buffer The buffer to which the information should be 1605 * appended. 1606 */ 1607 public abstract void toString(StringBuilder buffer); 1608 1609 1610 1611 /** 1612 * Performs any work that may be needed before the JVM invokes 1613 * garbage collection for this object. In this case, it makes sure 1614 * to deregister with the Directory Server as a change notification 1615 * listener. If a subclass wishes to perform custom finalization 1616 * processing, then it should override this method and make sure to 1617 * invoke {@code super.finalize} as its first call. 1618 */ 1619 protected void finalize() 1620 { 1621 finalizeConnectionInternal(); 1622 } 1623 1624 1625 /** 1626 * Returns the network group to which the connection belongs. 1627 * 1628 * @return the network group attached to the connection 1629 */ 1630 public final NetworkGroup getNetworkGroup() 1631 { 1632 return networkGroup; 1633 } 1634 1635 /** 1636 * Sets the network group to which the connection belongs. 1637 * 1638 * @param networkGroup the network group to which the 1639 * connections belongs to 1640 */ 1641 public final void setNetworkGroup (NetworkGroup networkGroup) 1642 { 1643 this.networkGroup = networkGroup; 1644 } 1645 1646 1647 1648 /** 1649 * Retrieves the length of time in milliseconds that this client 1650 * connection has been idle. 1651 * <BR><BR> 1652 * Note that the default implementation will always return zero. 1653 * Subclasses associated with connection handlers should override 1654 * this method if they wish to provided idle time limit 1655 * functionality. 1656 * 1657 * @return The length of time in milliseconds that this client 1658 * connection has been idle. 1659 */ 1660 public long getIdleTime() 1661 { 1662 return 0L; 1663 } 1664 } 1665