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