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

Nicolas Capponi
25.38.2015 fcfeaa126e75c11cfb963f02c6f66a53bbca3109
OPENDJ-2465 Add support for transactionId in current DJ access and HTTP access loggers
1 files added
16 files modified
330 ■■■■ changed files
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/FileBasedHTTPAccessLogPublisherConfiguration.xml 7 ●●●●● patch | view | raw | blame | history
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/GlobalConfiguration.xml 20 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/pom.xml 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/resource/schema/02-config.ldif 9 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/core/CoreConfigManager.java 8 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java 3 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAudit.java 45 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditAccessLogPublisher.java 36 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/loggers/HTTPRequestInfo.java 9 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/loggers/TextAccessLogPublisher.java 33 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/loggers/TextHTTPAccessLogPublisher.java 4 ●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CollectClientConnectionsFilter.java 14 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CommonAuditTransactionIdFilter.java 86 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPClientConnection.java 40 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LdapHttpApplication.java 6 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/monitors/BackendMonitorTestCase.java 2 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/protocols/http/CollectClientConnectionsFilterTest.java 4 ●●● patch | view | raw | blame | history
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/FileBasedHTTPAccessLogPublisherConfiguration.xml
@@ -22,7 +22,7 @@
  ! CDDL HEADER END
  !
  !
  !      Copyright 2013 ForgeRock AS
  !      Copyright 2013-2015 ForgeRock AS
  ! -->
<adm:managed-object name="file-based-http-access-log-publisher"
  plural-name="file-based-http-access-log-publishers"
@@ -278,7 +278,7 @@
    <adm:default-behavior>
      <adm:defined>
        <adm:value>cs-host c-ip cs-username x-datetime cs-method cs-uri-query 
        cs-version sc-status cs(User-Agent) x-connection-id x-etime</adm:value>
        cs-version sc-status cs(User-Agent) x-connection-id x-etime x-transaction-id</adm:value>
      </adm:defined>
    </adm:default-behavior>
    <adm:syntax>
@@ -304,7 +304,8 @@
            date and time for the logged HTTP request and its ouput is
            controlled by the "ds-cfg-log-record-time-format" property,
            "x-etime"  displays the total execution time for the logged HTTP
            request.
            request, "x-transaction-id" displays the transaction id associated
            to a request
          </adm:synopsis>
        </adm:pattern>
      </adm:string>
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/GlobalConfiguration.xml
@@ -874,4 +874,24 @@
      </ldap:attribute>
    </adm:profile>
  </adm:property>
  <adm:property name="trust-transaction-ids" advanced="true">
    <adm:synopsis>
      Indicates whether the directory server should trust the
      transaction ids that may be received from requests, either
      through a LDAP control or through a HTTP header.
    </adm:synopsis>
    <adm:default-behavior>
      <adm:defined>
        <adm:value>false</adm:value>
      </adm:defined>
    </adm:default-behavior>
    <adm:syntax>
      <adm:boolean />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:name>ds-cfg-trust-transaction-ids</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
</adm:managed-object>
opendj-server-legacy/pom.xml
@@ -160,6 +160,10 @@
      <groupId>org.forgerock.commons</groupId>
      <artifactId>forgerock-audit-json</artifactId>
    </dependency>  
    <dependency>
      <groupId>org.forgerock.commons</groupId>
      <artifactId>forgerock-audit-handler-syslog</artifactId>
    </dependency>
    <!-- servlet and mail -->
    <dependency>
opendj-server-legacy/resource/schema/02-config.ldif
@@ -3829,6 +3829,12 @@
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
  SINGLE-VALUE
  X-ORIGIN 'OpenDJ Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.155
  NAME 'ds-cfg-trust-transaction-ids'
  EQUALITY booleanMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
  SINGLE-VALUE
  X-ORIGIN 'OpenDJ Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.1
  NAME 'ds-cfg-access-control-handler'
  SUP top
@@ -4240,7 +4246,8 @@
        ds-cfg-etime-resolution $
        ds-cfg-max-allowed-client-connections $
        ds-cfg-max-psearches $
        ds-cfg-max-internal-buffer-size )
        ds-cfg-max-internal-buffer-size $
        ds-cfg-trust-transaction-ids)
  X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.40
  NAME 'ds-cfg-root-dn-user'
opendj-server-legacy/src/main/java/org/opends/server/core/CoreConfigManager.java
@@ -44,6 +44,7 @@
import org.opends.server.admin.std.server.GlobalCfg;
import org.opends.server.admin.std.server.RootCfg;
import org.opends.server.api.AuthenticationPolicy;
import org.opends.server.loggers.CommonAudit;
import org.opends.server.schema.SchemaUpdater;
import org.opends.server.types.*;
@@ -162,6 +163,13 @@
    setMaxPersistentSearchLimit(globalConfig.getMaxPsearches());
    setMaxInternalBufferSize((int) globalConfig.getMaxInternalBufferSize());
    // For tools, common audit may not be available
    CommonAudit commonAudit = serverContext.getCommonAudit();
    if (commonAudit != null)
    {
      commonAudit.setTrustTransactionIds(globalConfig.isTrustTransactionIds());
    }
    // Update the "new" schema with configuration changes
    SchemaUpdater schemaUpdater = serverContext.getSchemaUpdater();
    SchemaBuilder schemaBuilder = schemaUpdater.getSchemaBuilder();
opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
@@ -1347,6 +1347,8 @@
      initializeSchema();
      commonAudit = new CommonAudit();
      // Allow internal plugins to be registered.
      pluginConfigManager.initializePluginConfigManager();
@@ -1364,7 +1366,6 @@
      retentionPolicyConfigManager = new LogRetentionPolicyConfigManager(serverContext);
      retentionPolicyConfigManager.initializeLogRetentionPolicyConfig();
      commonAudit = new CommonAudit();
      loggerConfigManager = new LoggerConfigManager(serverContext);
      loggerConfigManager.initializeLoggerConfig();
opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAudit.java
@@ -25,6 +25,8 @@
 */
package org.opends.server.loggers;
import static java.util.Arrays.asList;
import static org.opends.messages.LoggerMessages.*;
import static java.util.Collections.newSetFromMap;
import static org.forgerock.audit.AuditServiceBuilder.newAuditService;
@@ -41,11 +43,13 @@
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
import org.forgerock.audit.AuditException;
@@ -57,6 +61,7 @@
import org.forgerock.audit.events.EventTopicsMetaData;
import org.forgerock.audit.events.handlers.FileBasedEventHandlerConfiguration.FileRetention;
import org.forgerock.audit.events.handlers.FileBasedEventHandlerConfiguration.FileRotation;
import org.forgerock.audit.filter.FilterPolicy;
import org.forgerock.audit.handlers.csv.CsvAuditEventHandler;
import org.forgerock.audit.handlers.csv.CsvAuditEventHandlerConfiguration;
import org.forgerock.audit.handlers.csv.CsvAuditEventHandlerConfiguration.CsvFormatting;
@@ -100,6 +105,8 @@
 */
public class CommonAudit
{
  /** Transaction id used when the incoming request does not contain a transaction id. */
  public static final String DEFAULT_TRANSACTION_ID = "0";
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
@@ -120,6 +127,7 @@
  /** Audit service shared by all HTTP access publishers. */
  private final AuditServiceProxy httpAccessAuditService;
  private final AtomicBoolean trustTransactionIds = new AtomicBoolean(false);
  /**
   * Creates the common audit.
@@ -134,6 +142,28 @@
    this.httpAccessAuditService = createAuditServiceWithoutHandlers();
  }
  /**
   * Indicates if transactionIds received from requests should be trusted.
   *
   * @return {@code true} if transactionIds should be trusted, {@code false} otherwise
   */
  public boolean shouldTrustTransactionIds()
  {
    return trustTransactionIds.get();
  }
  /**
   * Sets the indicator for transactionIds trusting.
   *
   * @param shouldTrust
   *          {@code true} if transactionIds should be trusted, {@code false}
   *          otherwise
   */
  public void setTrustTransactionIds(boolean shouldTrust)
  {
    trustTransactionIds.set(shouldTrust);
  }
  private AuditServiceProxy createAuditServiceWithoutHandlers() throws ConfigException
  {
    try
@@ -349,6 +379,7 @@
    AuditServiceConfiguration auditConfig = new AuditServiceConfiguration();
    auditConfig.setAvailableAuditEventHandlers(setup.getHandlerNames());
    auditConfig.setFilterPolicies(getFilterPoliciesToPreventHttpHeadersLogging());
    builder.withConfiguration(auditConfig);
    AuditService audit = builder.build();
@@ -368,6 +399,20 @@
    return proxy;
  }
  /**
   * Build filter policies at the AuditService level to prevent logging of the headers for HTTP requests.
   * <p>
   * HTTP Headers may contains authentication information.
   */
  private Map<String, FilterPolicy> getFilterPoliciesToPreventHttpHeadersLogging()
  {
    Map<String, FilterPolicy> filterPolicies = new HashMap<>();
    FilterPolicy policy = new FilterPolicy();
    policy.setExcludeIf(asList("/http-access/http/request/headers"));
    filterPolicies.put("field", policy);
    return filterPolicies;
  }
  private void addHandlerToBuilder(PublisherConfig publisher, AuditServiceBuilder builder) throws ConfigException
  {
    if (publisher.isCsv())
opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditAccessLogPublisher.java
@@ -29,6 +29,7 @@
import static org.forgerock.json.JsonValue.json;
import static org.forgerock.json.resource.Requests.newCreateRequest;
import static org.forgerock.json.resource.ResourcePath.resourcePath;
import static org.opends.server.loggers.CommonAudit.DEFAULT_TRANSACTION_ID;
import static org.opends.server.loggers.OpenDJAccessAuditEventBuilder.openDJAccessEvent;
import static org.opends.server.types.AuthenticationType.SASL;
@@ -66,13 +67,11 @@
import org.opends.server.core.ServerContext;
import org.opends.server.core.UnbindOperation;
import org.opends.server.types.AuthenticationInfo;
import org.opends.server.types.Control;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.DisconnectReason;
import org.opends.server.types.InitializationException;
import org.opends.server.types.Operation;
import org.opends.server.util.ServerConstants;
import org.opends.server.util.StaticUtils;
/**
@@ -87,15 +86,14 @@
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  /** Transaction id used when the incoming request does not contain a transaction id. */
  private static final String DEFAULT_TRANSACTION_ID = "0";
  /** Audit service handler. */
  private RequestHandler requestHandler;
  /** Current configuration for this publisher. */
  private T config;
  private ServerContext serverContext;
  @Override
  public void setRequestHandler(RequestHandler handler)
  {
@@ -118,6 +116,7 @@
  public void initializeLogPublisher(final T cfg, ServerContext serverContext)
      throws ConfigException, InitializationException
  {
    this.serverContext = serverContext;
    initializeFilters(cfg);
    config = cfg;
  }
@@ -250,7 +249,7 @@
        .client(clientConnection.getClientAddress(), clientConnection.getClientPort())
        .server(clientConnection.getServerAddress(), clientConnection.getServerPort())
        .request(clientConnection.getProtocol(), "CONNECT")
        .transactionId(DEFAULT_TRANSACTION_ID)
        .transactionId(CommonAudit.DEFAULT_TRANSACTION_ID)
        .response(ResponseStatus.SUCCESSFUL, String.valueOf(ResultCode.SUCCESS.intValue()), 0, TimeUnit.MILLISECONDS)
        .ldapConnectionId(clientConnection.getConnectionID());
@@ -286,7 +285,7 @@
        .client(clientConnection.getClientAddress(), clientConnection.getClientPort())
        .server(clientConnection.getServerAddress(), clientConnection.getServerPort())
        .request(clientConnection.getProtocol(),"DISCONNECT")
        .transactionId(DEFAULT_TRANSACTION_ID)
        .transactionId(CommonAudit.DEFAULT_TRANSACTION_ID)
        .response(ResponseStatus.SUCCESSFUL, String.valueOf(ResultCode.SUCCESS.intValue()), 0, TimeUnit.MILLISECONDS)
        .ldapConnectionId(clientConnection.getConnectionID())
        .ldapReason(disconnectReason.toString())
@@ -491,9 +490,9 @@
  private String getTransactionId(Operation operation)
  {
    String transactionId = getTransactionIdFromControl(operation);
    if (transactionId == null)
    if (transactionId == null || !serverContext.getCommonAudit().shouldTrustTransactionIds())
    {
      // use a default value because transaction id has no usage in this case
      // use a default value
      transactionId = DEFAULT_TRANSACTION_ID;
    }
    return transactionId;
@@ -501,19 +500,14 @@
  private String getTransactionIdFromControl(Operation operation)
  {
    for (Control control : operation.getRequestControls())
    try
    {
      if (control.getOID().equals(ServerConstants.OID_TRANSACTION_ID_CONTROL))
      {
        try
        {
          return operation.getRequestControl(TransactionIdControl.DECODER).getTransactionId();
        }
        catch (DirectoryException e)
        {
          logger.error(ERR_COMMON_AUDIT_INVALID_TRANSACTION_ID.get(StaticUtils.stackTraceToSingleLineString(e)));
        }
      }
      TransactionIdControl control = operation.getRequestControl(TransactionIdControl.DECODER);
      return control != null ? control.getTransactionId() : null;
    }
    catch (DirectoryException e)
    {
      logger.error(ERR_COMMON_AUDIT_INVALID_TRANSACTION_ID.get(StaticUtils.stackTraceToSingleLineString(e)));
    }
    return null;
  }
opendj-server-legacy/src/main/java/org/opends/server/loggers/HTTPRequestInfo.java
@@ -21,7 +21,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2013 ForgeRock AS
 *      Copyright 2013-2015 ForgeRock AS
 */
package org.opends.server.loggers;
@@ -140,6 +140,13 @@
  long getTotalProcessingTime();
  /**
   * Returns the transactionId for this request.
   *
   * @return the transactionId
   */
  String getTransactionId();
  /**
   * Logs the current request info in the HTTP access log.
   *
   * @param statusCode
opendj-server-legacy/src/main/java/org/opends/server/loggers/TextAccessLogPublisher.java
@@ -26,6 +26,7 @@
 */
package org.opends.server.loggers;
import static org.opends.messages.LoggerMessages.ERR_COMMON_AUDIT_INVALID_TRANSACTION_ID;
import static org.opends.messages.ConfigMessages.*;
import static org.opends.server.util.StaticUtils.*;
@@ -47,8 +48,10 @@
import org.opends.server.admin.std.server.FileBasedAccessLogPublisherCfg;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.ExtendedOperationHandler;
import org.opends.server.controls.TransactionIdControl;
import org.opends.server.core.*;
import org.opends.server.types.*;
import org.opends.server.util.StaticUtils;
import org.opends.server.util.TimeThread;
/** This class provides the implementation of the access logger used by the directory server. */
@@ -87,6 +90,7 @@
  private boolean isCombinedMode;
  private boolean includeControlOIDs;
  private String timeStampFormat = "dd/MMM/yyyy:HH:mm:ss Z";
  private ServerContext serverContext;
  @Override
  public ConfigChangeResult applyConfigurationChange(FileBasedAccessLogPublisherCfg config)
@@ -204,6 +208,7 @@
  public void initializeLogPublisher(final FileBasedAccessLogPublisherCfg cfg, ServerContext serverContext)
      throws ConfigException, InitializationException
  {
    this.serverContext = serverContext;
    final File logFile = getLogFile(cfg);
    final FileNamingPolicy fnPolicy = new TimeStampNaming(logFile);
@@ -916,6 +921,7 @@
    buffer.append(" conn=").append(operation.getConnectionID());
    buffer.append(" op=").append(operation.getOperationID());
    buffer.append(" msgID=").append(operation.getMessageID());
    appendTransactionId(operation, buffer);
  }
  private void appendModifyDNRequest(final ModifyDNOperation modifyDNOperation,
@@ -944,6 +950,33 @@
    }
  }
  private void appendTransactionId(Operation operation, final StringBuilder buffer)
  {
    // In test context, serverContext may be null
    if (serverContext != null && serverContext.getCommonAudit().shouldTrustTransactionIds())
    {
      String transactionId = getTransactionIdFromControl(operation);
      if (transactionId != null)
      {
        buffer.append(" transactionId=").append(transactionId);
      }
    }
  }
  private String getTransactionIdFromControl(Operation operation)
  {
    try
    {
      TransactionIdControl control = operation.getRequestControl(TransactionIdControl.DECODER);
      return control != null ? control.getTransactionId() : null;
    }
    catch (DirectoryException e)
    {
      logger.error(ERR_COMMON_AUDIT_INVALID_TRANSACTION_ID.get(StaticUtils.stackTraceToSingleLineString(e)));
    }
    return null;
  }
  private void appendRequestControls(final Operation operation, final StringBuilder buffer)
  {
    appendControls(buffer, " requestControls=", operation.getRequestControls());
opendj-server-legacy/src/main/java/org/opends/server/loggers/TextHTTPAccessLogPublisher.java
@@ -80,12 +80,13 @@
  private static final String X_CONNECTION_ID = "x-connection-id";
  private static final String X_DATETIME = "x-datetime";
  private static final String X_ETIME = "x-etime";
  private static final String X_TRANSACTION_ID = "x-transaction-id";
  private static final Set<String> ALL_SUPPORTED_FIELDS = new HashSet<>(
      Arrays.asList(ELF_C_IP, ELF_C_PORT, ELF_CS_HOST, ELF_CS_METHOD,
          ELF_CS_URI_QUERY, ELF_CS_USER_AGENT, ELF_CS_USERNAME, ELF_CS_VERSION,
          ELF_S_COMPUTERNAME, ELF_S_IP, ELF_S_PORT, ELF_SC_STATUS,
          X_CONNECTION_ID, X_DATETIME, X_ETIME));
          X_CONNECTION_ID, X_DATETIME, X_ETIME, X_TRANSACTION_ID));
  /**
   * Returns an instance of the text HTTP access log publisher that will print
@@ -440,6 +441,7 @@
    fields.put(X_CONNECTION_ID, ri.getConnectionID());
    fields.put(X_DATETIME, TimeThread.getUserDefinedTime(timeStampFormat));
    fields.put(X_ETIME, ri.getTotalProcessingTime());
    fields.put(X_TRANSACTION_ID, ri.getTransactionId());
    writeLogRecord(fields, logFormatFields);
  }
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CollectClientConnectionsFilter.java
@@ -61,6 +61,7 @@
import org.forgerock.util.promise.Promise;
import org.forgerock.util.promise.Promises;
import org.opends.server.admin.std.server.ConnectionHandlerCfg;
import org.opends.server.core.ServerContext;
import org.opends.server.schema.SchemaConstants;
import org.opends.server.types.DisconnectReason;
import org.opends.server.util.Base64;
@@ -87,18 +88,22 @@
   */
  private final HTTPAuthenticationConfig authConfig;
  private final ServerContext serverContext;
  /**
   * Constructs a new instance of this class.
   *
   * @param serverContext
   *            The server context.
   * @param connectionHandler
   *          the connection handler that accepted this connection
   * @param authenticationConfig
   *          configures how to perform the search for the username prior to
   *          authentication
   */
  public CollectClientConnectionsFilter(
      HTTPConnectionHandler connectionHandler, HTTPAuthenticationConfig authenticationConfig)
  public CollectClientConnectionsFilter(ServerContext serverContext, HTTPConnectionHandler connectionHandler,
      HTTPAuthenticationConfig authenticationConfig)
  {
    this.serverContext = serverContext;
    this.connectionHandler = connectionHandler;
    this.authConfig = authenticationConfig;
  }
@@ -106,7 +111,8 @@
  @Override
  public Promise<Response, NeverThrowsException> filter(Context context, Request request, Handler next)
  {
    final HTTPClientConnection clientConnection = new HTTPClientConnection(this.connectionHandler, context, request);
    final HTTPClientConnection clientConnection =
        new HTTPClientConnection(serverContext, this.connectionHandler, context, request);
    connectionHandler.addClientConnection(clientConnection);
    if (connectionHandler.keepStats())
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CommonAuditTransactionIdFilter.java
New file
@@ -0,0 +1,86 @@
/*
 * 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 legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * 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 legal-notices/CDDLv1_0.txt.
 * 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
 *
 *
 *      Copyright 2015 ForgeRock AS
 */
package org.opends.server.protocols.http;
import org.forgerock.http.Filter;
import org.forgerock.http.Handler;
import org.forgerock.http.header.MalformedHeaderException;
import org.forgerock.http.header.TransactionIdHeader;
import org.forgerock.http.protocol.Headers;
import org.forgerock.http.protocol.Request;
import org.forgerock.http.protocol.Response;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.services.TransactionId;
import org.forgerock.services.context.Context;
import org.forgerock.services.context.TransactionIdContext;
import org.forgerock.util.promise.NeverThrowsException;
import org.forgerock.util.promise.Promise;
import org.opends.server.core.ServerContext;
/**
 * This filter is responsible for creating a {@link TransactionIdContext} in the
 * context's chain.
 * <p>
 * This class is a copy of org.forgerock.http.filter.TransactionIdInboundFilter
 * in CHF, modified to not use a system property to indicate if transaction id
 * is trusted. Instead, it relies on DJ configuration to allow for runtime
 * modification It would be better if TransactionIdInboundFilter class could be
 * modified to be more generic and then usable by DJ, but it remains to be done.
 */
class CommonAuditTransactionIdFilter implements Filter
{
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  private final ServerContext serverContext;
  CommonAuditTransactionIdFilter(ServerContext serverContext)
  {
    this.serverContext = serverContext;
  }
  @Override
  public Promise<Response, NeverThrowsException> filter(Context context, Request request, Handler next)
  {
    final TransactionId transactionId = serverContext.getCommonAudit().shouldTrustTransactionIds() ?
        createTransactionId(request.getHeaders()) : new TransactionId();
    final Context newContext = new TransactionIdContext(context, transactionId);
    return next.handle(newContext, request);
  }
  private TransactionId createTransactionId(Headers headers)
  {
    try
    {
      TransactionIdHeader txHeader = headers.get(TransactionIdHeader.class);
      return txHeader == null ? new TransactionId() : txHeader.getTransactionId();
    }
    catch (MalformedHeaderException ex)
    {
      logger.trace("The TransactionId header is malformed.", ex);
      return new TransactionId();
    }
  }
}
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPClientConnection.java
@@ -29,6 +29,7 @@
import static org.forgerock.opendj.adapter.server3x.Converters.getResponseResult;
import static org.forgerock.opendj.ldap.LdapException.newLdapException;
import static org.opends.messages.ProtocolMessages.WARN_CLIENT_DISCONNECT_IN_PROGRESS;
import static org.opends.server.loggers.CommonAudit.DEFAULT_TRANSACTION_ID;
import static org.opends.server.loggers.AccessLogger.logDisconnect;
import java.net.InetAddress;
@@ -41,6 +42,8 @@
import java.util.concurrent.atomic.AtomicLong;
import org.forgerock.http.MutableUri;
import org.forgerock.http.header.MalformedHeaderException;
import org.forgerock.http.header.TransactionIdHeader;
import org.forgerock.http.protocol.Request;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizableMessageBuilder;
@@ -63,6 +66,7 @@
import org.opends.server.core.ModifyDNOperation;
import org.opends.server.core.ModifyOperation;
import org.opends.server.core.SearchOperation;
import org.opends.server.core.ServerContext;
import org.opends.server.loggers.HTTPAccessLogger;
import org.opends.server.loggers.HTTPRequestInfo;
import org.opends.server.protocols.ldap.AddResponseProtocolOp;
@@ -122,7 +126,7 @@
    }
  }
  /** {@inheritDoc} */
  /** Search Operation with a promise. */
  private static final class SearchOperationWithPromise extends OperationWithPromise
  {
@@ -243,15 +247,20 @@
  /** Security-Strength Factor extracted from the request attribute. */
  private final int securityStrengthFactor;
  /** TransactionId for tracking of ForgeRock stack transactions. */
  private final String transactionId;
  /**
   * Constructs an instance of this class.
   *
   * @param serverContext
   *            The server context.
   * @param connectionHandler
   *          the connection handler that accepted this connection
   * @param context
   *          represents the context of this client connection.
   */
  public HTTPClientConnection(HTTPConnectionHandler connectionHandler, Context context, Request request)
  public HTTPClientConnection(ServerContext serverContext, HTTPConnectionHandler connectionHandler, Context context,
      Request request)
  {
    this.connectionHandler = connectionHandler;
    final ClientContext clientCtx = context.asContext(ClientContext.class);
@@ -280,10 +289,27 @@
      this.statTracker.updateConnect();
      this.useNanoTime = DirectoryServer.getUseNanoTime();
    }
    this.transactionId = getTransactionId(serverContext, request);
    this.connectionID = DirectoryServer.newConnectionAccepted(this);
  }
  private String getTransactionId(ServerContext serverContext, Request request)
  {
    if (serverContext.getCommonAudit().shouldTrustTransactionIds())
    {
      try
      {
        TransactionIdHeader txHeader = request.getHeaders().get(TransactionIdHeader.class);
        return txHeader == null ? DEFAULT_TRANSACTION_ID :  txHeader.getTransactionId().getValue();
      }
      catch (MalformedHeaderException e)
      {
        // ignore it
      }
    }
    return DEFAULT_TRANSACTION_ID;
  }
  @Override
  public String getAuthUser()
  {
@@ -363,6 +389,12 @@
  }
  @Override
  public String getTransactionId()
  {
    return transactionId;
  }
  @Override
  public boolean isSecure()
  {
    return isSecure;
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LdapHttpApplication.java
@@ -34,7 +34,6 @@
import org.forgerock.http.Handler;
import org.forgerock.http.HttpApplication;
import org.forgerock.http.HttpApplicationException;
import org.forgerock.http.filter.TransactionIdInboundFilter;
import org.forgerock.http.handler.Handlers;
import org.forgerock.http.io.Buffer;
import org.forgerock.http.protocol.Request;
@@ -136,11 +135,12 @@
      final Object jsonElems = Json.readJsonLenient(new FileReader(configFile));
      final JsonValue configuration = new JsonValue(jsonElems).recordKeyAccesses();
      handler = new LdapHttpHandler(configuration);
      filter = new CollectClientConnectionsFilter(connectionHandler, getAuthenticationConfig(configuration));
      filter =
          new CollectClientConnectionsFilter(serverContext, connectionHandler, getAuthenticationConfig(configuration));
      configuration.verifyAllKeysAccessed();
      TransactionIdInboundFilter transactionIdFilter = new TransactionIdInboundFilter();
      RequestHandler requestHandler = serverContext.getCommonAudit().getAuditServiceForHttpAccessLog();
      CommonAuditTransactionIdFilter transactionIdFilter = new CommonAuditTransactionIdFilter(serverContext);
      CommonAuditHttpAccessAuditFilter httpAccessFilter =
          new CommonAuditHttpAccessAuditFilter(DynamicConstants.PRODUCT_NAME, requestHandler, TimeService.SYSTEM);
      CommonAuditHttpAccessCheckEnabledFilter checkFilter =
opendj-server-legacy/src/test/java/org/opends/server/monitors/BackendMonitorTestCase.java
@@ -29,8 +29,10 @@
import org.opends.server.admin.std.server.MonitorProviderCfg;
import org.opends.server.api.MonitorProvider;
import org.opends.server.core.DirectoryServer;
import org.testng.annotations.Test;
/** This class defines a set of tests for the {@link BackendMonitor} class. */
@Test
public class BackendMonitorTestCase extends GenericMonitorTestCase
{
  /**
opendj-server-legacy/src/test/java/org/opends/server/protocols/http/CollectClientConnectionsFilterTest.java
@@ -25,6 +25,7 @@
 */
package org.opends.server.protocols.http;
import static org.mockito.Mockito.mock;
import static org.assertj.core.api.Assertions.*;
import static org.opends.server.protocols.http.CollectClientConnectionsFilter.*;
@@ -35,6 +36,7 @@
import org.forgerock.http.protocol.Response;
import org.forgerock.json.resource.ResourceException;
import org.opends.server.DirectoryServerTestCase;
import org.opends.server.core.ServerContext;
import org.opends.server.util.Base64;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
@@ -54,7 +56,7 @@
  private void createConfigAndFilter()
  {
    authConfig = new HTTPAuthenticationConfig();
    filter = new CollectClientConnectionsFilter(null, authConfig);
    filter = new CollectClientConnectionsFilter(mock(ServerContext.class), null, authConfig);
  }
  @DataProvider(name = "Invalid HTTP basic auth strings")