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