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