From fcfeaa126e75c11cfb963f02c6f66a53bbca3109 Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Thu, 26 Nov 2015 16:46:33 +0000
Subject: [PATCH] OPENDJ-2465 Add support for transactionId in current DJ access and HTTP access loggers

---
 opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LdapHttpApplication.java                                          |    6 
 opendj-server-legacy/src/main/java/org/opends/server/loggers/TextAccessLogPublisher.java                                              |   33 +++++
 opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/FileBasedHTTPAccessLogPublisherConfiguration.xml |    7 
 opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java                                                        |    3 
 opendj-server-legacy/resource/schema/02-config.ldif                                                                                   |    9 +
 opendj-server-legacy/src/test/java/org/opends/server/protocols/http/CollectClientConnectionsFilterTest.java                           |    4 
 opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditAccessLogPublisher.java                                       |   36 ++---
 opendj-server-legacy/pom.xml                                                                                                          |    4 
 opendj-server-legacy/src/main/java/org/opends/server/loggers/TextHTTPAccessLogPublisher.java                                          |    4 
 opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/GlobalConfiguration.xml                          |   20 +++
 opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAudit.java                                                         |   45 +++++++
 opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPClientConnection.java                                         |   40 ++++++
 opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CommonAuditTransactionIdFilter.java                               |   86 ++++++++++++++
 opendj-server-legacy/src/main/java/org/opends/server/core/CoreConfigManager.java                                                      |    8 +
 opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CollectClientConnectionsFilter.java                               |   14 +
 opendj-server-legacy/src/test/java/org/opends/server/monitors/BackendMonitorTestCase.java                                             |    2 
 opendj-server-legacy/src/main/java/org/opends/server/loggers/HTTPRequestInfo.java                                                     |    9 +
 17 files changed, 290 insertions(+), 40 deletions(-)

diff --git a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/FileBasedHTTPAccessLogPublisherConfiguration.xml b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/FileBasedHTTPAccessLogPublisherConfiguration.xml
index 841d210..06a4184 100644
--- a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/FileBasedHTTPAccessLogPublisherConfiguration.xml
+++ b/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>
diff --git a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/GlobalConfiguration.xml b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/GlobalConfiguration.xml
index 09f9252..185a5b8 100644
--- a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/GlobalConfiguration.xml
+++ b/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>
diff --git a/opendj-server-legacy/pom.xml b/opendj-server-legacy/pom.xml
index 7423f80..60428a2 100644
--- a/opendj-server-legacy/pom.xml
+++ b/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>
diff --git a/opendj-server-legacy/resource/schema/02-config.ldif b/opendj-server-legacy/resource/schema/02-config.ldif
index b7e9552..0e3730b 100644
--- a/opendj-server-legacy/resource/schema/02-config.ldif
+++ b/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'
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/CoreConfigManager.java b/opendj-server-legacy/src/main/java/org/opends/server/core/CoreConfigManager.java
index 67122ba..754f479 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/CoreConfigManager.java
+++ b/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();
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java b/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
index ad3bfd2..85e2902 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
+++ b/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();
 
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAudit.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAudit.java
index aa413b1..0bd29b3 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAudit.java
+++ b/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())
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditAccessLogPublisher.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditAccessLogPublisher.java
index ffa63f6..ab27fb1 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditAccessLogPublisher.java
+++ b/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;
   }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/HTTPRequestInfo.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/HTTPRequestInfo.java
index 75ca8b0..42eec3c 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/HTTPRequestInfo.java
+++ b/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
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextAccessLogPublisher.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextAccessLogPublisher.java
index 054f21d..c03cd86 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextAccessLogPublisher.java
+++ b/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());
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextHTTPAccessLogPublisher.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextHTTPAccessLogPublisher.java
index 2c37a58..42bfe33 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/TextHTTPAccessLogPublisher.java
+++ b/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);
   }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CollectClientConnectionsFilter.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CollectClientConnectionsFilter.java
index 5ea8110..0cab816 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CollectClientConnectionsFilter.java
+++ b/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())
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CommonAuditTransactionIdFilter.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CommonAuditTransactionIdFilter.java
new file mode 100644
index 0000000..ee7977d
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CommonAuditTransactionIdFilter.java
@@ -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();
+    }
+  }
+}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPClientConnection.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPClientConnection.java
index 83affaf..991d590 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPClientConnection.java
+++ b/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;
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LdapHttpApplication.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LdapHttpApplication.java
index 0dd19b6..f80fa63 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LdapHttpApplication.java
+++ b/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 =
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/monitors/BackendMonitorTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/monitors/BackendMonitorTestCase.java
index 3fb8b0d..1d60365 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/monitors/BackendMonitorTestCase.java
+++ b/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
 {
   /**
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/protocols/http/CollectClientConnectionsFilterTest.java b/opendj-server-legacy/src/test/java/org/opends/server/protocols/http/CollectClientConnectionsFilterTest.java
index ad82137..7c5c758 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/protocols/http/CollectClientConnectionsFilterTest.java
+++ b/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")

--
Gitblit v1.10.0