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