mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

neil_a_wilson
30.26.2007 f9411cf977892773761a0fbb80bb8c8041f0a2b0
opendj-sdk/opends/resource/config/config.ldif
@@ -47,6 +47,7 @@
ds-cfg-reject-unauthenticated-requests: false
ds-cfg-default-password-policy: cn=Default Password Policy,cn=Password Policies,cn=config
ds-cfg-return-bind-error-messages: false
ds-cfg-idle-time-limit: 0 seconds
ds-cfg-allowed-task: org.opends.server.tasks.AddSchemaFileTask
ds-cfg-allowed-task: org.opends.server.tasks.BackupTask
ds-cfg-allowed-task: org.opends.server.tasks.DisconnectClientTask
@@ -1380,6 +1381,7 @@
ds-cfg-alternate-bind-dn: cn=Directory Manager
ds-rlim-size-limit: 0
ds-rlim-time-limit: 0
ds-rlim-idle-time-limit: 0
ds-rlim-lookthrough-limit: 0
ds-pwp-password-policy-dn: cn=Root Password Policy,cn=Password Policies,cn=config
opendj-sdk/opends/resource/schema/02-config.ldif
@@ -1547,6 +1547,12 @@
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.462 NAME 'ds-cfg-ssl-cipher-suite'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.463 NAME 'ds-cfg-idle-time-limit'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE
  X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.464 NAME 'ds-rlim-idle-time-limit'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE USAGE directoryOperation
  X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.1
  NAME 'ds-cfg-access-control-handler' SUP top STRUCTURAL
  MUST ( cn $ ds-cfg-acl-handler-class $ ds-cfg-acl-handler-enabled )
@@ -1764,7 +1770,8 @@
  ds-cfg-reject-unauthenticated-requests  $
  ds-cfg-bind-with-dn-requires-password $ ds-cfg-lookthrough-limit $
  ds-cfg-smtp-server $ ds-cfg-allowed-task $ ds-cfg-disabled-privilege $
  ds-cfg-return-bind-error-messages ) X-ORIGIN 'OpenDS Directory Server' )
  ds-cfg-return-bind-error-messages $ ds-cfg-idle-time-limit )
  X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.41 NAME 'ds-cfg-root-dn' SUP top
  AUXILIARY MAY ds-cfg-alternate-bind-dn X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.42 NAME 'ds-cfg-root-dse'
opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/GlobalConfiguration.xml
@@ -693,5 +693,27 @@
    </adm:profile>
  </adm:property>
  <adm:property name="idle-time-limit" mandatory="false" multi-valued="false">
    <adm:synopsis>
      Specifies the maximum lenght of time that a client connection may remain
      established since its last completed operation.  A value of "0 seconds"
      indicates that no idle time limit will be enforced.
    </adm:synopsis>
    <adm:default-behavior>
      <adm:defined>
        <adm:value>0 seconds</adm:value>
      </adm:defined>
    </adm:default-behavior>
    <adm:syntax>
      <adm:duration base-unit="ms" lower-limit="0"/>
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:oid>1.3.6.1.4.1.26027.1.1.463</ldap:oid>
        <ldap:name>ds-cfg-idle-time-limit</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
</adm:managed-object>
opendj-sdk/opends/src/server/org/opends/server/api/ClientConnection.java
@@ -108,6 +108,9 @@
  // The time that this client connection was established.
  private long connectTime;
  // The idle time limit for this client connection.
  private long idleTimeLimit;
  // The opaque information used for storing intermediate state
  // information needed across multi-stage SASL binds.
  private Object saslAuthState;
@@ -138,6 +141,7 @@
    persistentSearches = new CopyOnWriteArrayList<PersistentSearch>();
    sizeLimit          = DirectoryServer.getSizeLimit();
    timeLimit          = DirectoryServer.getTimeLimit();
    idleTimeLimit      = DirectoryServer.getIdleTimeLimit();
    lookthroughLimit   = DirectoryServer.getLookthroughLimit();
    finalized          = false;
    privileges         = new HashSet<Privilege>();
@@ -1274,6 +1278,39 @@
  /**
   * Retrieves the maximum length of time in milliseconds that this
   * client connection will be allowed to remain idle before it should
   * be disconnected.
   *
   * @return  The maximum length of time in milliseconds that this
   *          client connection will be allowed to remain idle before
   *          it should be disconnected.
   */
  public final long getIdleTimeLimit()
  {
    return idleTimeLimit;
  }
  /**
   * Specifies the maximum length of time in milliseconds that this
   * client connection will be allowed to remain idle before it should
   * be disconnected.
   *
   * @param  idleTimeLimit  The maximum length of time in milliseconds
   *                        that this client connection will be
   *                        allowed to remain idle before it should be
   *                        disconnected.
   */
  public void setIdleTimeLimit(long idleTimeLimit)
  {
    this.idleTimeLimit = idleTimeLimit;
  }
  /**
   * Retrieves the default maximum number of entries that should
   * checked for matches during a search.
   *
@@ -1575,5 +1612,23 @@
    this.networkGroup = networkGroup;
  }
  /**
   * Retrieves the length of time in milliseconds that this client
   * connection has been idle.
   * <BR><BR>
   * Note that the default implementation will always return zero.
   * Subclasses associated with connection handlers should override
   * this method if they wish to provided idle time limit
   * functionality.
   *
   * @return  The length of time in milliseconds that this client
   *          connection has been idle.
   */
  public long getIdleTime()
  {
    return 0L;
  }
}
opendj-sdk/opends/src/server/org/opends/server/config/ConfigConstants.java
@@ -3541,6 +3541,15 @@
  /**
   * The name of the operational attribute that may be included in user entries
   * to specify an idle time limit to be applied for that user.
   */
  public static final String OP_ATTR_USER_IDLE_TIME_LIMIT =
      NAME_PREFIX_RLIM + "idle-time-limit";
  /**
   * The name of the operational attribute that may be included in user
   * entries to specify a size limit to be applied for that user.
   */
opendj-sdk/opends/src/server/org/opends/server/core/CoreConfigManager.java
@@ -337,6 +337,8 @@
    DirectoryServer.setReturnBindErrorMessages(
         globalConfig.isReturnBindErrorMessages());
    DirectoryServer.setIdleTimeLimit(globalConfig.getIdleTimeLimit());
  }
opendj-sdk/opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -463,6 +463,9 @@
  // The number of connections currently established to the server.
  private long currentConnections;
  // The idle time limit for the server.
  private long idleTimeLimit;
  // The maximum number of connections that will be allowed at any given time.
  private long maxAllowedConnections;
@@ -731,6 +734,7 @@
    directoryServer.allowedTasks = new LinkedHashSet<String>(0);
    directoryServer.disabledPrivileges = new LinkedHashSet<Privilege>(0);
    directoryServer.returnBindErrorMessages = false;
    directoryServer.idleTimeLimit = 0L;
  }
@@ -1204,6 +1208,7 @@
      if (startConnectionHandlers)
      {
        startConnectionHandlers();
        new IdleTimeLimitThread().start();
      }
@@ -7526,6 +7531,35 @@
  /**
   * Retrieves the maximum length of time in milliseconds that client
   * connections should be allowed to remain idle without being disconnected.
   *
   * @return  The maximum length of time in milliseconds that client connections
   *          should be allowed to remain idle without being disconnected.
   */
  public static long getIdleTimeLimit()
  {
    return directoryServer.idleTimeLimit;
  }
  /**
   * Specifies the maximum length of time in milliseconds that client
   * connections should be allowed to remain idle without being disconnected.
   *
   * @param  idleTimeLimit  The maximum length of time in milliseconds that
   *                        client connections should be allowed to remain idle
   *                        without being disconnected.
   */
  public static void setIdleTimeLimit(long idleTimeLimit)
  {
    directoryServer.idleTimeLimit = idleTimeLimit;
  }
  /**
   * Registers the provided backup task listener with the Directory Server.
   *
   * @param  listener  The backup task listener to register with the Directory
opendj-sdk/opends/src/server/org/opends/server/core/IdleTimeLimitThread.java
New file
@@ -0,0 +1,193 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.core;
import org.opends.server.admin.std.server.ConnectionHandlerCfg;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.ConnectionHandler;
import org.opends.server.api.DirectoryThread;
import org.opends.server.api.ServerShutdownListener;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.ErrorLogCategory;
import org.opends.server.types.ErrorLogSeverity;
import org.opends.server.types.DisconnectReason;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.messages.CoreMessages.*;
import static org.opends.server.messages.MessageHandler.*;
import static org.opends.server.util.StaticUtils.*;
/**
 * This class defines a thread that will be used to teriminate client
 * connections if they have been idle for too long.
 */
public class IdleTimeLimitThread
       extends DirectoryThread
       implements ServerShutdownListener
{
  /**
   * The debug log tracer for this object.
   */
  private static final DebugTracer TRACER = getTracer();
  // Indicates whether a shutdown request has been received.
  private boolean shutdownRequested;
  /**
   * Creates a new instance of this idle time limit thread.
   */
  public IdleTimeLimitThread()
  {
    super("Idle Time Limit Thread");
    setDaemon(true);
    shutdownRequested = false;
    DirectoryServer.registerShutdownListener(this);
  }
  /**
   * Operates in a loop, teriminating any client connections that have been idle
   * for too long.
   */
  public void run()
  {
    int    disconnectMessageID = MSGID_IDLETIME_LIMIT_EXCEEDED;
    String disconnectMessage   = getMessage(disconnectMessageID);
    long sleepTime = 5000L;
    while (! shutdownRequested)
    {
      try
      {
        try
        {
          sleep(sleepTime);
        } catch (InterruptedException ie) {}
        sleepTime = 5000L;
        for (ConnectionHandler ch : DirectoryServer.getConnectionHandlers())
        {
          ConnectionHandler<? extends ConnectionHandlerCfg> connHandler =
               (ConnectionHandler<? extends ConnectionHandlerCfg>) ch;
          for (ClientConnection c : connHandler.getClientConnections())
          {
            long idleTime = c.getIdleTime();
            if (idleTime > 0)
            {
              long idleTimeLimit = c.getIdleTimeLimit();
              if (idleTimeLimit > 0)
              {
                if (idleTime > idleTimeLimit)
                {
                  if (debugEnabled())
                  {
                    TRACER.debugInfo("Terminating client connection " +
                                     c.getConnectionID() +
                                     " due to the idle time limit");
                  }
                  try
                  {
                    c.disconnect(DisconnectReason.IDLE_TIME_LIMIT_EXCEEDED,
                                 true, disconnectMessage, disconnectMessageID);
                  }
                  catch (Exception e)
                  {
                    if (debugEnabled())
                    {
                      TRACER.debugCaught(DebugLogLevel.ERROR, e);
                    }
                    int    msgID   = MSGID_IDLETIME_DISCONNECT_ERROR;
                    String message = getMessage(msgID, c.getConnectionID(),
                                          stackTraceToSingleLineString(e));
                    logError(ErrorLogCategory.CORE_SERVER,
                             ErrorLogSeverity.MILD_ERROR, message, msgID);
                  }
                }
                else
                {
                  long shouldSleepTime = idleTimeLimit - idleTime;
                  if (shouldSleepTime < sleepTime)
                  {
                    sleepTime = shouldSleepTime;
                  }
                }
              }
            }
          }
        }
      }
      catch (Exception e)
      {
        if (debugEnabled())
        {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        int    msgID   = MSGID_IDLETIME_UNEXPECTED_ERROR;
        String message = getMessage(msgID, stackTraceToSingleLineString(e));
        logError(ErrorLogCategory.CORE_SERVER, ErrorLogSeverity.SEVERE_ERROR,
                 message, msgID);
      }
    }
  }
  /**
   * {@inheritDoc}
   */
  public String getShutdownListenerName()
  {
    return "Idle Time Limit Thread";
  }
  /**
   * {@inheritDoc}
   */
  public void processServerShutdown(String reason)
  {
    shutdownRequested = true;
  }
}
opendj-sdk/opends/src/server/org/opends/server/messages/CoreMessages.java
@@ -6277,6 +6277,58 @@
  /**
   * The message ID for the message that will be used if a user entry contains
   * multiple values for the user-specific idle time limit attribute.  This
   * takes a single argument, which is the DN of the user entry.
   */
  public static final int MSGID_BIND_MULTIPLE_USER_IDLE_TIME_LIMITS =
       CATEGORY_MASK_CORE | SEVERITY_MASK_SEVERE_WARNING | 630;
  /**
   * The message ID for the message that will be used if an error occurs while
   * trying to parse a user-specific idle time limit value as an integer.  This
   * takes two arguments, which are the provided time limit value and the DN of
   * the user entry.
   */
  public static final int MSGID_BIND_CANNOT_PROCESS_USER_IDLE_TIME_LIMIT =
       CATEGORY_MASK_CORE | SEVERITY_MASK_SEVERE_WARNING | 631;
  /**
   * The message ID for the message that will be used to indicate that the idle
   * time limit has been exceeded for a client connection.  It does not take any
   * arguments.
   */
  public static final int MSGID_IDLETIME_LIMIT_EXCEEDED =
       CATEGORY_MASK_CORE | SEVERITY_MASK_INFORMATIONAL | 632;
  /**
   * The message ID for the message that will be used if an error occurred while
   * trying to terminate a client connection.  It takes two arguments, which are
   * the connection ID and a string representation of the exception that was
   * caught.
   */
  public static final int MSGID_IDLETIME_DISCONNECT_ERROR =
       CATEGORY_MASK_CORE | SEVERITY_MASK_MILD_ERROR | 632;
  /**
   * The message ID for the message that will be used if an unexpected error
   * occurred in the time thread.  It takes a single argument, which is a string
   * representation of the exception that was caught.
   */
  public static final int MSGID_IDLETIME_UNEXPECTED_ERROR =
       CATEGORY_MASK_CORE | SEVERITY_MASK_SEVERE_ERROR | 632;
  /**
   * Associates a set of generic messages with the message IDs defined
   * in this class.
   */
@@ -7104,6 +7156,14 @@
                    "The user-specific time limit value %s contained in " +
                    "user entry %s could not be parsed as an integer.  The " +
                    "default server time limit will be used");
    registerMessage(MSGID_BIND_MULTIPLE_USER_IDLE_TIME_LIMITS,
                    "There are multiple user-specific idle time limit values " +
                    "contained in user entry %s.  The default server idle " +
                    "time limit will be used");
    registerMessage(MSGID_BIND_CANNOT_PROCESS_USER_IDLE_TIME_LIMIT,
                    "The user-specific idle time limit value %s contained in " +
                    "user entry %s could not be parsed as an integer.  The " +
                    "default server idle time limit will be used");
    registerMessage(MSGID_BIND_PASSWORD_EXPIRING,
                    "The user password is about to expire (time to " +
                    "expiration:  %s)");
@@ -8549,6 +8609,17 @@
    registerMessage(MSGID_ENTRYENCODECFG_INVALID_LENGTH,
                    "Unable to decode the provided entry encode " +
                    "configuration element because it has an invalid length");
    registerMessage(MSGID_IDLETIME_LIMIT_EXCEEDED,
                    "This connection has been teriminated because it has " +
                    "remained idle for too long");
    registerMessage(MSGID_IDLETIME_DISCONNECT_ERROR,
                    "An error occurred while attempting to disconnect " +
                    "client connection %d:  %s");
    registerMessage(MSGID_IDLETIME_UNEXPECTED_ERROR,
                    "An unexpected error occurred in the idle time limit " +
                    "thread:  %s");
  }
}
opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
@@ -89,6 +89,7 @@
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchResultReference;
import org.opends.server.util.TimeThread;
@@ -108,6 +109,9 @@
  // The time that the last operation was completed.
  private AtomicLong lastCompletionTime;
  // The next operation ID that should be used for this connection.
  private AtomicLong nextOperationID;
@@ -240,6 +244,7 @@
    ldapVersion          = 3;
    requestHandler       = null;
    lastCompletionTime   = new AtomicLong(TimeThread.getTime());
    nextOperationID      = new AtomicLong(0);
    connectionValid      = true;
    disconnectRequested  = false;
@@ -1210,6 +1215,7 @@
      }
      operationsInProgress.remove(messageID);
      lastCompletionTime.set(TimeThread.getTime());
      throw de;
    }
@@ -1247,7 +1253,15 @@
  public boolean removeOperationInProgress(int messageID)
  {
    AbstractOperation operation = operationsInProgress.remove(messageID);
    return (operation != null);
    if (operation == null)
    {
      return false;
    }
    else
    {
      lastCompletionTime.set(TimeThread.getTime());
      return true;
    }
  }
@@ -1333,6 +1347,12 @@
        }
      }
      if (! (operationsInProgress.isEmpty() &&
             getPersistentSearches().isEmpty()))
      {
        lastCompletionTime.set(TimeThread.getTime());
      }
      operationsInProgress.clear();
@@ -1401,12 +1421,14 @@
        }
        operationsInProgress.remove(msgID);
        lastCompletionTime.set(TimeThread.getTime());
      }
      for (PersistentSearch persistentSearch : getPersistentSearches())
      {
        DirectoryServer.deregisterPersistentSearch(persistentSearch);
        lastCompletionTime.set(TimeThread.getTime());
      }
    }
    catch (Exception e)
@@ -2789,5 +2811,32 @@
  {
    return connectionHandler.getSSLServerCertNickname();
  }
  /**
   * Retrieves the length of time in milliseconds that this client
   * connection has been idle.
   * <BR><BR>
   * Note that the default implementation will always return zero.
   * Subclasses associated with connection handlers should override
   * this method if they wish to provided idle time limit
   * functionality.
   *
   * @return  The length of time in milliseconds that this client
   *          connection has been idle.
   */
  public long getIdleTime()
  {
    if (operationsInProgress.isEmpty() && getPersistentSearches().isEmpty())
    {
      return (TimeThread.getTime() - lastCompletionTime.get());
    }
    else
    {
      // There's at least one operation in progress, so it's not idle.
      return 0L;
    }
  }
}
opendj-sdk/opends/src/server/org/opends/server/workflowelement/localbackend/LocalBackendWorkflowElement.java
@@ -3091,6 +3091,7 @@
    int     sizeLimit        = DirectoryServer.getSizeLimit();
    int     timeLimit        = DirectoryServer.getTimeLimit();
    int     lookthroughLimit = DirectoryServer.getLookthroughLimit();
    long    idleTimeLimit    = DirectoryServer.getIdleTimeLimit();
    boolean skipPostOperation = false;
    // The password policy state information for this bind operation.
@@ -3705,6 +3706,53 @@
              }
              // See if the user's entry contains a custom idle time limit.
              attrType = DirectoryServer.getAttributeType(
                              OP_ATTR_USER_IDLE_TIME_LIMIT, true);
              attrList = userEntry.getAttribute(attrType);
              if ((attrList != null) && (attrList.size() == 1))
              {
                Attribute a = attrList.get(0);
                LinkedHashSet<AttributeValue>  values = a.getValues();
                Iterator<AttributeValue> iterator = values.iterator();
                if (iterator.hasNext())
                {
                  AttributeValue v = iterator.next();
                  if (iterator.hasNext())
                  {
                    int msgID = MSGID_BIND_MULTIPLE_USER_IDLE_TIME_LIMITS;
                    String message =
                         getMessage(msgID, String.valueOf(userEntry.getDN()));
                    logError(ErrorLogCategory.CORE_SERVER,
                             ErrorLogSeverity.SEVERE_WARNING, message, msgID);
                  }
                  else
                  {
                    try
                    {
                      idleTimeLimit =
                           1000L * Long.parseLong(v.getStringValue());
                    }
                    catch (Exception e)
                    {
                      if (debugEnabled())
                      {
                        TRACER.debugCaught(DebugLogLevel.ERROR, e);
                      }
                      int msgID =
                           MSGID_BIND_CANNOT_PROCESS_USER_IDLE_TIME_LIMIT;
                      String message =
                           getMessage(msgID, v.getStringValue(),
                                      String.valueOf(userEntry.getDN()));
                      logError(ErrorLogCategory.CORE_SERVER,
                               ErrorLogSeverity.SEVERE_WARNING, message, msgID);
                    }
                  }
                }
              }
              // See if the user's entry contains a custom lookthrough limit.
              attrType =
                   DirectoryServer.getAttributeType(
@@ -4272,6 +4320,53 @@
              }
              // See if the user's entry contains a custom idle time limit.
              attrType = DirectoryServer.getAttributeType(
                              OP_ATTR_USER_IDLE_TIME_LIMIT, true);
              attrList = saslAuthUserEntry.getAttribute(attrType);
              if ((attrList != null) && (attrList.size() == 1))
              {
                Attribute a = attrList.get(0);
                LinkedHashSet<AttributeValue>  values = a.getValues();
                Iterator<AttributeValue> iterator = values.iterator();
                if (iterator.hasNext())
                {
                  AttributeValue v = iterator.next();
                  if (iterator.hasNext())
                  {
                    int msgID = MSGID_BIND_MULTIPLE_USER_IDLE_TIME_LIMITS;
                    String message =
                         getMessage(msgID, String.valueOf(userDNString));
                    logError(ErrorLogCategory.CORE_SERVER,
                             ErrorLogSeverity.SEVERE_WARNING, message, msgID);
                  }
                  else
                  {
                    try
                    {
                      idleTimeLimit =
                           1000L * Long.parseLong(v.getStringValue());
                    }
                    catch (Exception e)
                    {
                      if (debugEnabled())
                      {
                        TRACER.debugCaught(DebugLogLevel.ERROR, e);
                      }
                      int msgID =
                           MSGID_BIND_CANNOT_PROCESS_USER_IDLE_TIME_LIMIT;
                      String message =
                           getMessage(msgID, v.getStringValue(),
                                      String.valueOf(userDNString));
                      logError(ErrorLogCategory.CORE_SERVER,
                               ErrorLogSeverity.SEVERE_WARNING, message, msgID);
                    }
                  }
                }
              }
              // See if the user's entry contains a custom lookthrough limit.
              attrType =
                   DirectoryServer.getAttributeType(
@@ -4422,6 +4517,7 @@
      clientConnection.setAuthenticationInfo(authInfo);
      clientConnection.setSizeLimit(sizeLimit);
      clientConnection.setTimeLimit(timeLimit);
      clientConnection.setIdleTimeLimit(idleTimeLimit);
      clientConnection.setLookthroughLimit(lookthroughLimit);
      clientConnection.setMustChangePassword(mustChangePassword);
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/IdleTimeLimitTestCase.java
New file
@@ -0,0 +1,275 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.core;
import java.net.Socket;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.opends.server.TestCaseUtils;
import org.opends.server.protocols.asn1.*;
import org.opends.server.protocols.ldap.*;
import org.opends.server.tools.dsconfig.DSConfig;
import static org.testng.Assert.*;
/**
 * A set of test cases that involve disconnecting clients due to the idle time
 * limit.
 */
public class IdleTimeLimitTestCase
       extends CoreTestCase
{
  /**
   * Ensures that the Directory Server is running.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @BeforeClass()
  public void startServer()
         throws Exception
  {
    TestCaseUtils.startServer();
  }
  /**
   * Tests the server-wide idle time limit for an anonymous connection.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(groups="slow")
  public void testServerWideAnonymousIdleTimeLimit()
         throws Exception
  {
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "set-global-configuration-prop",
      "--set", "idle-time-limit:5 seconds"
    };
    assertEquals(DSConfig.main(args, false, System.out, System.err), 0);
    Socket s = null;
    try
    {
      s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
      ASN1Writer w = new ASN1Writer(s);
      ASN1Reader r = new ASN1Reader(s);
      r.setIOTimeout(60000);
      LDAPMessage m = LDAPMessage.decode(r.readElement().decodeAsSequence());
      ExtendedResponseProtocolOp extendedResponse =
           m.getExtendedResponseProtocolOp();
      assertEquals(extendedResponse.getOID(),
                   LDAPConstants.OID_NOTICE_OF_DISCONNECTION);
      assertNull(r.readElement());
    }
    finally
    {
      try
      {
        s.close();
      } catch (Exception e) {}
      args = new String[]
      {
        "-h", "127.0.0.1",
        "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
        "-D", "cn=Directory Manager",
        "-w", "password",
        "set-global-configuration-prop",
        "--set", "idle-time-limit:0 seconds"
      };
      assertEquals(DSConfig.main(args, false, System.out, System.err), 0);
    }
  }
  /**
   * Tests the server-wide idle time limit for an authenticated connection.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(groups="slow")
  public void testServerWideAuthenticatedIdleTimeLimit()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
      "dn: uid=test.user,o=test",
      "objectClass: top",
      "objectClass: person",
      "objectClass: organizationalPerson",
      "objectClass: inetOrgPerson",
      "uid: test.user",
      "givenName: Test",
      "sn: User",
      "cn: Test User",
      "userPassword: password"
    );
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "set-global-configuration-prop",
      "--set", "idle-time-limit:5 seconds"
    };
    assertEquals(DSConfig.main(args, false, System.out, System.err), 0);
    Socket s = null;
    try
    {
      s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
      ASN1Writer w = new ASN1Writer(s);
      ASN1Reader r = new ASN1Reader(s);
      r.setIOTimeout(60000);
      BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
           new ASN1OctetString("uid=test.user,o=test"), 3,
           new ASN1OctetString("password"));
      LDAPMessage m = new LDAPMessage(1, bindRequest);
      w.writeElement(m.encode());
      m = LDAPMessage.decode(r.readElement().decodeAsSequence());
      BindResponseProtocolOp bindResponse = m.getBindResponseProtocolOp();
      assertEquals(bindResponse.getResultCode(), 0);
      m = LDAPMessage.decode(r.readElement().decodeAsSequence());
      ExtendedResponseProtocolOp extendedResponse =
           m.getExtendedResponseProtocolOp();
      assertEquals(extendedResponse.getOID(),
                   LDAPConstants.OID_NOTICE_OF_DISCONNECTION);
      assertNull(r.readElement());
    }
    finally
    {
      try
      {
        s.close();
      } catch (Exception e) {}
      args = new String[]
      {
        "-h", "127.0.0.1",
        "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
        "-D", "cn=Directory Manager",
        "-w", "password",
        "set-global-configuration-prop",
        "--set", "idle-time-limit:0 seconds"
      };
      assertEquals(DSConfig.main(args, false, System.out, System.err), 0);
    }
  }
  /**
   * Tests a user-specific idle time limit.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test(groups="slow")
  public void testUserSpecificIdleTimeLimit()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    TestCaseUtils.addEntry(
      "dn: uid=test.user,o=test",
      "objectClass: top",
      "objectClass: person",
      "objectClass: organizationalPerson",
      "objectClass: inetOrgPerson",
      "uid: test.user",
      "givenName: Test",
      "sn: User",
      "cn: Test User",
      "userPassword: password",
      "ds-rlim-idle-time-limit: 5"
    );
    Socket s = null;
    try
    {
      s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());
      ASN1Writer w = new ASN1Writer(s);
      ASN1Reader r = new ASN1Reader(s);
      r.setIOTimeout(60000);
      BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(
           new ASN1OctetString("uid=test.user,o=test"), 3,
           new ASN1OctetString("password"));
      LDAPMessage m = new LDAPMessage(1, bindRequest);
      w.writeElement(m.encode());
      m = LDAPMessage.decode(r.readElement().decodeAsSequence());
      BindResponseProtocolOp bindResponse = m.getBindResponseProtocolOp();
      assertEquals(bindResponse.getResultCode(), 0);
      m = LDAPMessage.decode(r.readElement().decodeAsSequence());
      ExtendedResponseProtocolOp extendedResponse =
           m.getExtendedResponseProtocolOp();
      assertEquals(extendedResponse.getOID(),
                   LDAPConstants.OID_NOTICE_OF_DISCONNECTION);
      assertNull(r.readElement());
    }
    finally
    {
      try
      {
        s.close();
      } catch (Exception e) {}
    }
  }
}