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