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