From e433824f46514e6ed863eb6b95c70038331c8c24 Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Tue, 24 Nov 2015 12:49:54 +0000
Subject: [PATCH] OPENDJ-2260 OPENDJ-2271 Integration of common audit into the server
---
opendj-server-legacy/src/main/java/org/opends/server/loggers/AccessLogger.java | 1
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CommonAuditHttpAccessAuditFilter.java | 169 ++
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LdapHttpApplication.java | 18
opendj-server-legacy/src/main/java/org/opends/server/core/ConnectionHandlerConfigManager.java | 4
opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java | 11
opendj-server-legacy/src/main/java/org/opends/server/loggers/CsvFileAccessLogPublisher.java | 63
opendj-server-legacy/resource/schema/02-config.ldif | 84 +
opendj-server-legacy/src/main/java/org/opends/server/loggers/AbstractLogger.java | 71
opendj-server-legacy/src/messages/org/opends/messages/protocol.properties | 2
opendj-server-legacy/src/main/java/org/opends/server/loggers/OpenDJAccessEventBuilder.java | 267 +++
opendj-server-legacy/resource/config/config.ldif | 37
opendj-server-legacy/pom.xml | 18
opendj-server-legacy/src/main/java/org/opends/server/protocols/jmx/JmxConnectionHandler.java | 3
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ExternalAccessLogPublisherConfiguration.xml | 100 +
opendj-server-legacy/src/messages/org/opends/messages/config.properties | 6
opendj-server-legacy/src/main/java/org/opends/server/protocols/internal/InternalConnectionHandler.java | 6
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ExternalHTTPAccessLogPublisherConfiguration.xml | 82 +
opendj-server-legacy/src/main/java/org/opends/server/controls/TransactionIdControl.java | 129 +
opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditLogPublisher.java | 44
opendj-server-legacy/src/main/java/org/opends/server/protocols/LDIFConnectionHandler.java | 3
opendj-server-legacy/src/snmp/src/org/opends/server/snmp/SNMPConnectionHandler.java | 10
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/CsvFileAccessLogPublisherConfiguration.xml | 348 +++++
opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java | 8
opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditDependencyProvider.java | 85 +
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/CsvFileHTTPAccessLogPublisherConfiguration.xml | 330 ++++
opendj-server-legacy/src/main/java/org/opends/server/admin/AdministrationConnector.java | 15
opendj-server-legacy/src/test/java/org/opends/server/protocols/internal/InternalConnectionHandlerTestCase.java | 6
opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditAccessLogPublisher.java | 554 ++++++++
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java | 10
opendj-server-legacy/src/main/resources/org/opends/server/loggers/audit-config.json | 402 +++++
opendj-server-legacy/src/main/java/org/opends/server/api/ConnectionHandler.java | 7
opendj-server-legacy/src/main/java/org/opends/server/util/ServerConstants.java | 5
opendj-server-legacy/src/main/java/org/opends/server/loggers/ExternalAccessLogPublisher.java | 63
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CommonAuditHttpAccessCheckEnabledFilter.java | 68
opendj-server-legacy/src/messages/org/opends/messages/logger.properties | 31
opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAudit.java | 943 +++++++++++++
opendj-server-legacy/src/main/java/org/opends/server/loggers/HTTPAccessLogger.java | 1
opendj-server-legacy/src/test/java/org/opends/server/protocols/ldap/LdapTestCase.java | 5
opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPConnectionHandler.java | 3
opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditHTTPAccessLogPublisher.java | 109 +
40 files changed, 4,084 insertions(+), 37 deletions(-)
diff --git a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/CsvFileAccessLogPublisherConfiguration.xml b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/CsvFileAccessLogPublisherConfiguration.xml
new file mode 100644
index 0000000..70e1844
--- /dev/null
+++ b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/CsvFileAccessLogPublisherConfiguration.xml
@@ -0,0 +1,348 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ! 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.
+ ! -->
+<adm:managed-object name="csv-file-access-log-publisher"
+ plural-name="csv-file-access-log-publishers"
+ package="org.forgerock.opendj.server.config" extends="access-log-publisher"
+ xmlns:adm="http://opendj.forgerock.org/admin"
+ xmlns:ldap="http://opendj.forgerock.org/admin-ldap">
+ <adm:synopsis>
+ <adm:user-friendly-plural-name />
+ publish access messages to CSV files.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:name>ds-cfg-csv-file-access-log-publisher</ldap:name>
+ <ldap:superior>ds-cfg-access-log-publisher</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property-override name="java-class" advanced="true">
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>
+ org.opends.server.loggers.CommonAuditAccessLogPublisher
+ </adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ </adm:property-override>
+ <adm:property name="log-directory" mandatory="true">
+ <adm:synopsis>
+ The directory to use for the log files generated by the
+ <adm:user-friendly-name />.
+ The path to the directory is relative to the server root.
+ </adm:synopsis>
+ <adm:requires-admin-action>
+ <adm:component-restart />
+ </adm:requires-admin-action>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>logs</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string>
+ <adm:pattern>
+ <adm:regex>.*</adm:regex>
+ <adm:usage>DIRECTORY</adm:usage>
+ <adm:synopsis>
+ A path to an existing directory that is readable and writable by the server.
+ </adm:synopsis>
+ </adm:pattern>
+ </adm:string>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-log-directory</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="asynchronous" mandatory="true" advanced="true">
+ <adm:synopsis>
+ Indicates whether the
+ <adm:user-friendly-name />
+ will publish records asynchronously.
+ </adm:synopsis>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>true</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-asynchronous</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="auto-flush" advanced="true">
+ <adm:synopsis>
+ Specifies whether to flush the writer after every log record.
+ </adm:synopsis>
+ <adm:description>
+ If the asynchronous writes option is used, the writer is
+ flushed after all the log records in the queue are written.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>true</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-auto-flush</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="rotation-policy" multi-valued="true">
+ <adm:synopsis>
+ The rotation policy to use for the
+ <adm:user-friendly-name />
+ .
+ </adm:synopsis>
+ <adm:description>
+ When multiple policies are used, rotation will occur if any
+ policy's conditions are met.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ No rotation policy is used and log rotation will not occur.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:aggregation parent-path="/"
+ relation-name="log-rotation-policy" />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-rotation-policy</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="retention-policy" multi-valued="true">
+ <adm:synopsis>
+ The retention policy to use for the
+ <adm:user-friendly-name />
+ .
+ </adm:synopsis>
+ <adm:description>
+ When multiple policies are used, log files are cleaned when
+ any of the policy's conditions are met.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ No retention policy is used and log files are never cleaned.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:aggregation parent-path="/"
+ relation-name="log-retention-policy" />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-retention-policy</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="log-control-oids">
+ <adm:synopsis>
+ Specifies whether control OIDs will be included in operation log records.
+ </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-log-control-oids</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="tamper-evident">
+ <adm:synopsis>
+ Specifies whether the log should be signed in order to detect tampering.
+ </adm:synopsis>
+ <adm:description>
+ Every log record will be signed, making it possible to verify that the log has not been tampered with.
+ This feature has a significative impact on performance of the server.
+ </adm:description>
+ <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-tamper-evident</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="signature-time-interval" advanced="true">
+ <adm:synopsis>
+ Specifies the interval at which to sign the log file when the tamper-evident option
+ is enabled.
+ </adm:synopsis>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>3s</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:duration base-unit="ms" lower-limit="1" />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-signature-time-interval</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="key-store-file">
+ <adm:synopsis>
+ Specifies the path to the file that contains the private key
+ information. This may be an absolute path, or a path that is
+ relative to the <adm:product-name /> instance root.
+ </adm:synopsis>
+ <adm:description>
+ Changes to this property will take effect the next
+ time that the key store is accessed.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:undefined />
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string>
+ <adm:pattern>
+ <adm:regex>.*</adm:regex>
+ <adm:usage>FILE</adm:usage>
+ <adm:synopsis>
+ A path to an existing file that is readable by the server.
+ </adm:synopsis>
+ </adm:pattern>
+ </adm:string>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-key-store-file</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property-reference name="key-store-pin-file" />
+ <adm:property name="csv-quote-char" advanced="true">
+ <adm:synopsis>
+ The character to append and prepend to a CSV field when writing in CSV format.
+ </adm:synopsis>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>\"</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string>
+ <adm:pattern>
+ <adm:regex>.*</adm:regex>
+ <adm:usage>QUOTE CHARACTER</adm:usage>
+ <adm:synopsis>
+ The quote character to use when writting in CSV format.
+ </adm:synopsis>
+ </adm:pattern>
+ </adm:string>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-csv-quote-char</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="csv-delimiter-char">
+ <adm:synopsis>
+ The delimiter character to use when writing in CSV format.
+ </adm:synopsis>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>,</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string>
+ <adm:pattern>
+ <adm:regex>.*</adm:regex>
+ <adm:usage>DELIMITER CHARACTER</adm:usage>
+ <adm:synopsis>
+ The delimiter character to use when writing in CSV format.
+ </adm:synopsis>
+ </adm:pattern>
+ </adm:string>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-csv-delimiter-char</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="csv-eol-symbols" advanced="true">
+ <adm:synopsis>
+ The string that marks the end of a line.
+ </adm:synopsis>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ Use the platform specific end of line character sequence.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string>
+ <adm:pattern>
+ <adm:regex>.*</adm:regex>
+ <adm:usage>STRING</adm:usage>
+ <adm:synopsis>
+ The string that marks the end of a line.
+ </adm:synopsis>
+ </adm:pattern>
+ </adm:string>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-csv-eol-symbols</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
diff --git a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/CsvFileHTTPAccessLogPublisherConfiguration.xml b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/CsvFileHTTPAccessLogPublisherConfiguration.xml
new file mode 100644
index 0000000..b095c33
--- /dev/null
+++ b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/CsvFileHTTPAccessLogPublisherConfiguration.xml
@@ -0,0 +1,330 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ! 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.
+ ! -->
+<adm:managed-object name="csv-file-http-access-log-publisher"
+ plural-name="csv-file-http-access-log-publishers"
+ package="org.forgerock.opendj.server.config" extends="http-access-log-publisher"
+ xmlns:adm="http://opendj.forgerock.org/admin"
+ xmlns:ldap="http://opendj.forgerock.org/admin-ldap">
+ <adm:synopsis>
+ <adm:user-friendly-plural-name />
+ publish HTTP access messages to CSV files.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:name>ds-cfg-csv-file-http-access-log-publisher</ldap:name>
+ <ldap:superior>ds-cfg-http-access-log-publisher</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property-override name="java-class" advanced="true">
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>
+ org.opends.server.loggers.CommonAuditHTTPAccessLogPublisher
+ </adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ </adm:property-override>
+ <adm:property name="log-directory" mandatory="true">
+ <adm:synopsis>
+ The directory to use for the log files generated by the
+ <adm:user-friendly-name />.
+ The path to the directory is relative to the server root.
+ </adm:synopsis>
+ <adm:requires-admin-action>
+ <adm:component-restart />
+ </adm:requires-admin-action>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>logs</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string>
+ <adm:pattern>
+ <adm:regex>.*</adm:regex>
+ <adm:usage>DIRECTORY</adm:usage>
+ <adm:synopsis>
+ A path to an existing directory that is readable and writable by the server.
+ </adm:synopsis>
+ </adm:pattern>
+ </adm:string>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-log-directory</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="asynchronous" mandatory="true" advanced="true">
+ <adm:synopsis>
+ Indicates whether the
+ <adm:user-friendly-name />
+ will publish records asynchronously.
+ </adm:synopsis>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>true</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-asynchronous</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="auto-flush" advanced="true">
+ <adm:synopsis>
+ Specifies whether to flush the writer after every log record.
+ </adm:synopsis>
+ <adm:description>
+ If the asynchronous writes option is used, the writer is
+ flushed after all the log records in the queue are written.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>true</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:boolean />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-auto-flush</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="rotation-policy" multi-valued="true">
+ <adm:synopsis>
+ The rotation policy to use for the
+ <adm:user-friendly-name />
+ .
+ </adm:synopsis>
+ <adm:description>
+ When multiple policies are used, rotation will occur if any
+ policy's conditions are met.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ No rotation policy is used and log rotation will not occur.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:aggregation parent-path="/"
+ relation-name="log-rotation-policy" />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-rotation-policy</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="retention-policy" multi-valued="true">
+ <adm:synopsis>
+ The retention policy to use for the
+ <adm:user-friendly-name />
+ .
+ </adm:synopsis>
+ <adm:description>
+ When multiple policies are used, log files are cleaned when
+ any of the policy's conditions are met.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ No retention policy is used and log files are never cleaned.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:aggregation parent-path="/"
+ relation-name="log-retention-policy" />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-retention-policy</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="tamper-evident">
+ <adm:synopsis>
+ Specifies whether the log should be signed in order to detect tampering.
+ </adm:synopsis>
+ <adm:description>
+ Every log record will be signed, making it possible to verify that the log has not been tampered with.
+ This feature has a significative impact on performance of the server.
+ </adm:description>
+ <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-tamper-evident</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="signature-time-interval" advanced="true">
+ <adm:synopsis>
+ Specifies the interval at which to sign the log file when secure option
+ is enabled.
+ </adm:synopsis>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>3s</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:duration base-unit="ms" lower-limit="1" />
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-signature-time-interval</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="key-store-file">
+ <adm:synopsis>
+ Specifies the path to the file that contains the private key
+ information. This may be an absolute path, or a path that is
+ relative to the <adm:product-name /> instance root.
+ </adm:synopsis>
+ <adm:description>
+ Changes to this property will take effect the next
+ time that the key store is accessed.
+ </adm:description>
+ <adm:default-behavior>
+ <adm:undefined />
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string>
+ <adm:pattern>
+ <adm:regex>.*</adm:regex>
+ <adm:usage>FILE</adm:usage>
+ <adm:synopsis>
+ A path to an existing file that is readable by the server.
+ </adm:synopsis>
+ </adm:pattern>
+ </adm:string>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-key-store-file</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property-reference name="key-store-pin-file" />
+ <adm:property name="csv-quote-char" advanced="true">
+ <adm:synopsis>
+ The character to append and prepend to a CSV field when writing in CSV format.
+ </adm:synopsis>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>\"</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string>
+ <adm:pattern>
+ <adm:regex>.*</adm:regex>
+ <adm:usage>QUOTE CHARACTER</adm:usage>
+ <adm:synopsis>
+ The quote character to use when writing in CSV format.
+ </adm:synopsis>
+ </adm:pattern>
+ </adm:string>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-csv-quote-char</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="csv-delimiter-char">
+ <adm:synopsis>
+ The delimiter character to use when writing in CSV format.
+ </adm:synopsis>
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>,</adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string>
+ <adm:pattern>
+ <adm:regex>.*</adm:regex>
+ <adm:usage>DELIMITER CHARACTER</adm:usage>
+ <adm:synopsis>
+ The delimiter character to use when writing in CSV format.
+ </adm:synopsis>
+ </adm:pattern>
+ </adm:string>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-csv-delimiter-char</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="csv-eol-symbols" advanced="true">
+ <adm:synopsis>
+ The string that marks the end of a line.
+ </adm:synopsis>
+ <adm:default-behavior>
+ <adm:alias>
+ <adm:synopsis>
+ Use the platform specific end of line character sequence.
+ </adm:synopsis>
+ </adm:alias>
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string>
+ <adm:pattern>
+ <adm:regex>.*</adm:regex>
+ <adm:usage>EOL SYMBOLS</adm:usage>
+ <adm:synopsis>
+ The string that marks the end of a line.
+ </adm:synopsis>
+ </adm:pattern>
+ </adm:string>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-csv-eol-symbols</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
diff --git a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ExternalAccessLogPublisherConfiguration.xml b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ExternalAccessLogPublisherConfiguration.xml
new file mode 100644
index 0000000..fa2ff14
--- /dev/null
+++ b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ExternalAccessLogPublisherConfiguration.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ! 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.
+ ! -->
+<adm:managed-object name="external-access-log-publisher"
+ plural-name="external-access-log-publishers"
+ package="org.forgerock.opendj.server.config" extends="access-log-publisher"
+ xmlns:adm="http://opendj.forgerock.org/admin"
+ xmlns:ldap="http://opendj.forgerock.org/admin-ldap">
+ <adm:synopsis>
+ <adm:user-friendly-plural-name />
+ publish access messages to an external handler.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:name>ds-cfg-external-access-log-publisher</ldap:name>
+ <ldap:superior>ds-cfg-access-log-publisher</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property-override name="java-class" advanced="true">
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>
+ org.opends.server.loggers.CommonAuditAccessLogPublisher
+ </adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ </adm:property-override>
+ <adm:property name="config-file" mandatory="true">
+ <adm:synopsis>
+ The JSON configuration file that defines the
+ <adm:user-friendly-name />.
+ The content of the JSON configuration file depends on
+ the type of external audit event handler.
+ The path to the file is relative to the server root.
+ </adm:synopsis>
+ <adm:requires-admin-action>
+ <adm:component-restart />
+ </adm:requires-admin-action>
+ <adm:default-behavior>
+ <adm:undefined />
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string>
+ <adm:pattern>
+ <adm:regex>.*</adm:regex>
+ <adm:usage>FILE</adm:usage>
+ <adm:synopsis>
+ A path to an existing file that is readable by the server.
+ </adm:synopsis>
+ </adm:pattern>
+ </adm:string>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-config-file</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+ <adm:property name="log-control-oids">
+ <adm:synopsis>
+ Specifies whether control OIDs will be included in operation log records.
+ </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-log-control-oids</ldap:name>
+ </ldap:attribute>
+ </adm:profile>
+ </adm:property>
+</adm:managed-object>
diff --git a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ExternalHTTPAccessLogPublisherConfiguration.xml b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ExternalHTTPAccessLogPublisherConfiguration.xml
new file mode 100644
index 0000000..268bca9
--- /dev/null
+++ b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ExternalHTTPAccessLogPublisherConfiguration.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ! 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.
+ ! -->
+<adm:managed-object name="external-http-access-log-publisher"
+ plural-name="external-http-access-log-publishers"
+ package="org.forgerock.opendj.server.config" extends="http-access-log-publisher"
+ xmlns:adm="http://opendj.forgerock.org/admin"
+ xmlns:ldap="http://opendj.forgerock.org/admin-ldap">
+ <adm:synopsis>
+ <adm:user-friendly-plural-name />
+ publish HTTP access messages to an external handler.
+ </adm:synopsis>
+ <adm:profile name="ldap">
+ <ldap:object-class>
+ <ldap:name>ds-cfg-external-http-access-log-publisher</ldap:name>
+ <ldap:superior>ds-cfg-http-access-log-publisher</ldap:superior>
+ </ldap:object-class>
+ </adm:profile>
+ <adm:property-override name="java-class" advanced="true">
+ <adm:default-behavior>
+ <adm:defined>
+ <adm:value>
+ org.opends.server.loggers.CommonAuditHTTPAccessLogPublisher
+ </adm:value>
+ </adm:defined>
+ </adm:default-behavior>
+ </adm:property-override>
+ <adm:property name="config-file" mandatory="true">
+ <adm:synopsis>
+ The JSON configuration file that defines the
+ <adm:user-friendly-name />.
+ The content of the JSON configuration file depends on
+ the type of external audit event handler.
+ The path to the file is relative to the server root.
+ </adm:synopsis>
+ <adm:requires-admin-action>
+ <adm:component-restart />
+ </adm:requires-admin-action>
+ <adm:default-behavior>
+ <adm:undefined />
+ </adm:default-behavior>
+ <adm:syntax>
+ <adm:string>
+ <adm:pattern>
+ <adm:regex>.*</adm:regex>
+ <adm:usage>FILE</adm:usage>
+ <adm:synopsis>
+ A path to an existing file that is readable by the server.
+ </adm:synopsis>
+ </adm:pattern>
+ </adm:string>
+ </adm:syntax>
+ <adm:profile name="ldap">
+ <ldap:attribute>
+ <ldap:name>ds-cfg-config-file</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 30e7813..8575a65 100644
--- a/opendj-server-legacy/pom.xml
+++ b/opendj-server-legacy/pom.xml
@@ -125,6 +125,11 @@
<dependency>
<groupId>org.forgerock.commons</groupId>
+ <artifactId>forgerock-util</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.forgerock.commons</groupId>
<artifactId>json-resource</artifactId>
</dependency>
@@ -142,6 +147,19 @@
<groupId>org.forgerock.http</groupId>
<artifactId>chf-http-servlet</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>org.forgerock.commons</groupId>
+ <artifactId>forgerock-audit-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.forgerock.commons</groupId>
+ <artifactId>forgerock-audit-handler-csv</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.forgerock.commons</groupId>
+ <artifactId>forgerock-audit-json</artifactId>
+ </dependency>
<!-- servlet and mail -->
<dependency>
diff --git a/opendj-server-legacy/resource/config/config.ldif b/opendj-server-legacy/resource/config/config.ldif
index fe9b509..1fca49c 100644
--- a/opendj-server-legacy/resource/config/config.ldif
+++ b/opendj-server-legacy/resource/config/config.ldif
@@ -605,6 +605,26 @@
ds-cfg-rotation-policy: cn=Size Limit Rotation Policy,cn=Log Rotation Policies,cn=config
ds-cfg-retention-policy: cn=File Count Retention Policy,cn=Log Retention Policies,cn=config
+dn: cn=Common Audit Csv File Access Logger,cn=Loggers,cn=config
+objectClass: top
+objectClass: ds-cfg-log-publisher
+objectClass: ds-cfg-access-log-publisher
+objectClass: ds-cfg-csv-file-access-log-publisher
+cn: Csv File Access Logger
+ds-cfg-java-class: org.opends.server.loggers.CsvFileAccessLogPublisher
+ds-cfg-enabled: false
+ds-cfg-log-directory: logs
+ds-cfg-suppress-internal-operations: true
+ds-cfg-suppress-synchronization-operations: false
+ds-cfg-log-control-oids: false
+ds-cfg-asynchronous: true
+ds-cfg-rotation-policy: cn=24 Hours Time Limit Rotation Policy,cn=Log Rotation Policies,cn=config
+ds-cfg-rotation-policy: cn=Size Limit Rotation Policy,cn=Log Rotation Policies,cn=config
+ds-cfg-retention-policy: cn=File Count Retention Policy,cn=Log Retention Policies,cn=config
+ds-cfg-tamper-evident: false
+ds-cfg-key-store-file: config/audit-keystore
+ds-cfg-key-store-pin-file: config/audit-keystore.pin
+
dn: cn=File-Based HTTP Access Logger,cn=Loggers,cn=config
objectClass: top
objectClass: ds-cfg-log-publisher
@@ -620,6 +640,23 @@
ds-cfg-rotation-policy: cn=Size Limit Rotation Policy,cn=Log Rotation Policies,cn=config
ds-cfg-retention-policy: cn=File Count Retention Policy,cn=Log Retention Policies,cn=config
+dn: cn=Common Audit Csv File HTTP Access Logger,cn=Loggers,cn=config
+objectClass: top
+objectClass: ds-cfg-log-publisher
+objectClass: ds-cfg-http-access-log-publisher
+objectClass: ds-cfg-csv-file-http-access-log-publisher
+cn: Csv File HTTP Access Logger
+ds-cfg-java-class: org.opends.server.loggers.CommonAuditHTTPAccessLogPublisher
+ds-cfg-enabled: false
+ds-cfg-log-directory: logs
+ds-cfg-asynchronous: true
+ds-cfg-rotation-policy: cn=24 Hours Time Limit Rotation Policy,cn=Log Rotation Policies,cn=config
+ds-cfg-rotation-policy: cn=Size Limit Rotation Policy,cn=Log Rotation Policies,cn=config
+ds-cfg-retention-policy: cn=File Count Retention Policy,cn=Log Retention Policies,cn=config
+ds-cfg-tamper-evident: false
+ds-cfg-key-store-file: config/audit-keystore
+ds-cfg-key-store-pin-file: config/audit-keystore.pin
+
dn: cn=File-Based Audit Logger,cn=Loggers,cn=config
objectClass: top
objectClass: ds-cfg-log-publisher
diff --git a/opendj-server-legacy/resource/schema/02-config.ldif b/opendj-server-legacy/resource/schema/02-config.ldif
index 867d159..e04673b 100644
--- a/opendj-server-legacy/resource/schema/02-config.ldif
+++ b/opendj-server-legacy/resource/schema/02-config.ldif
@@ -3806,6 +3806,41 @@
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.149
+ NAME 'ds-cfg-signature-time-interval'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.150
+ NAME 'ds-cfg-log-directory'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE
+ X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.151
+ NAME 'ds-cfg-csv-quote-char'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE
+ X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.152
+ NAME 'ds-cfg-csv-delimiter-char'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE
+ X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.153
+ NAME 'ds-cfg-csv-eol-symbols'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+ SINGLE-VALUE
+ X-ORIGIN 'OpenDJ Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.154
+ NAME 'ds-cfg-tamper-evident'
+ 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
@@ -5844,8 +5879,55 @@
objectClasses: ( 1.3.6.1.4.1.36733.2.1.2.27
NAME 'ds-task-reset-change-number'
SUP ds-task
- STRUCTURAL
MUST ( ds-task-reset-change-number-to $
ds-task-reset-change-number-base-dn $
ds-task-reset-change-number-csn )
X-ORIGIN 'OpenDS Directory Server' )
+objectClasses: ( 1.3.6.1.4.1.36733.2.1.2.28
+ NAME 'ds-cfg-csv-file-access-log-publisher'
+ SUP ds-cfg-access-log-publisher
+ STRUCTURAL
+ MUST ( ds-cfg-log-directory )
+ MAY ( ds-cfg-log-control-oids $
+ ds-cfg-csv-quote-char $
+ ds-cfg-csv-delimiter-char $
+ ds-cfg-csv-eol-symbols $
+ ds-cfg-auto-flush $
+ ds-cfg-asynchronous $
+ ds-cfg-rotation-policy $
+ ds-cfg-retention-policy $
+ ds-cfg-tamper-evident $
+ ds-cfg-signature-time-interval $
+ ds-cfg-key-store-file $
+ ds-cfg-key-store-pin-file )
+ X-ORIGIN 'OpenDJ Directory Server' )
+objectClasses: ( 1.3.6.1.4.1.36733.2.1.2.29
+ NAME 'ds-cfg-csv-file-http-access-log-publisher'
+ SUP ds-cfg-http-access-log-publisher
+ STRUCTURAL
+ MUST ( ds-cfg-log-directory )
+ MAY ( ds-cfg-csv-quote-char $
+ ds-cfg-csv-delimiter-char $
+ ds-cfg-csv-eol-symbols $
+ ds-cfg-auto-flush $
+ ds-cfg-asynchronous $
+ ds-cfg-rotation-policy $
+ ds-cfg-retention-policy $
+ ds-cfg-tamper-evident $
+ ds-cfg-signature-time-interval $
+ ds-cfg-key-store-file $
+ ds-cfg-key-store-pin-file )
+ X-ORIGIN 'OpenDJ Directory Server' )
+objectClasses: ( 1.3.6.1.4.1.36733.2.1.2.30
+ NAME 'ds-cfg-external-access-log-publisher'
+ SUP ds-cfg-access-log-publisher
+ STRUCTURAL
+ MUST ( ds-cfg-config-file )
+ MAY ( ds-cfg-log-control-oids )
+ X-ORIGIN 'OpenDJ Directory Server' )
+objectClasses: ( 1.3.6.1.4.1.36733.2.1.2.31
+ NAME 'ds-cfg-external-http-access-log-publisher'
+ SUP ds-cfg-http-access-log-publisher
+ STRUCTURAL
+ MUST ( ds-cfg-config-file )
+ X-ORIGIN 'OpenDJ Directory Server' )
\ No newline at end of file
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/admin/AdministrationConnector.java b/opendj-server-legacy/src/main/java/org/opends/server/admin/AdministrationConnector.java
index 8be8b54..7056193 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/admin/AdministrationConnector.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/admin/AdministrationConnector.java
@@ -116,6 +116,8 @@
private static final SSLClientAuthPolicy ADMIN_SSL_CLIENT_AUTH_POLICY =
SSLClientAuthPolicy.DISABLED;
+ private final ServerContext serverContext;
+
/**
* Initializes this administration connector provider based on the
* information in the provided administration connector
@@ -142,7 +144,7 @@
// Administration Connector uses the LDAP connection handler implementation
adminConnectionHandler = new LDAPConnectionHandler(
new SynchronousStrategy(), FRIENDLY_NAME);
- adminConnectionHandler.initializeConnectionHandler(new LDAPConnectionCfgAdapter(config));
+ adminConnectionHandler.initializeConnectionHandler(serverContext, new LDAPConnectionCfgAdapter(config));
adminConnectionHandler.setAdminConnectionHandler();
// Register this as a change listener.
@@ -150,10 +152,15 @@
}
- /** Create an instance of the administration connector. */
- public AdministrationConnector()
+ /**
+ * Creates an instance of the administration connector.
+ *
+ * @param serverContext
+ * The server context.
+ **/
+ public AdministrationConnector(ServerContext serverContext)
{
- // Do nothing.
+ this.serverContext = serverContext;
}
/**
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/api/ConnectionHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/api/ConnectionHandler.java
index ad3ce9f..6a6036b 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/api/ConnectionHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/api/ConnectionHandler.java
@@ -27,13 +27,16 @@
package org.opends.server.api;
import static org.opends.messages.ProtocolMessages.*;
+
import org.forgerock.i18n.slf4j.LocalizedLogger;
+
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.forgerock.i18n.LocalizableMessage;
import org.opends.server.admin.std.server.ConnectionHandlerCfg;
+import org.opends.server.core.ServerContext;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.monitors.ConnectionHandlerMonitor;
import org.opends.server.types.DN;
@@ -191,6 +194,8 @@
* Initializes this connection handler provider based on the
* information in the provided connection handler configuration.
*
+ * @param serverContext
+ * The server context.
* @param configuration
* The connection handler configuration that contains the
* information to use to initialize this connection
@@ -203,7 +208,7 @@
* If a problem occurs during initialization that is not
* related to the server configuration.
*/
- public abstract void initializeConnectionHandler(T configuration)
+ public abstract void initializeConnectionHandler(ServerContext serverContext, T configuration)
throws ConfigException, InitializationException;
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/controls/TransactionIdControl.java b/opendj-server-legacy/src/main/java/org/opends/server/controls/TransactionIdControl.java
new file mode 100644
index 0000000..3d454fd
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/controls/TransactionIdControl.java
@@ -0,0 +1,129 @@
+/*
+ * 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.controls;
+
+import static org.opends.server.util.ServerConstants.OID_TRANSACTION_ID_CONTROL;
+
+import java.io.IOException;
+
+import org.forgerock.opendj.io.ASN1Writer;
+import org.forgerock.opendj.ldap.ByteString;
+import org.forgerock.opendj.ldap.ResultCode;
+import org.opends.messages.ProtocolMessages;
+import org.opends.server.types.Control;
+import org.opends.server.types.DirectoryException;
+
+/**
+ * Control that provides a transaction ID.
+ * <p>
+ * The transaction ID is related to Common Audit : it is used for tracking the
+ * processing of a user-interaction as it passes through the Forgerock stack
+ * <p>
+ * The control's value is the UTF-8 encoding of the transaction ID.
+ */
+public class TransactionIdControl extends Control
+{
+ /** ControlDecoder implementation to decode this control from a ByteString. */
+ private static final class Decoder implements ControlDecoder<TransactionIdControl>
+ {
+ @Override
+ public TransactionIdControl decode(boolean isCritical, ByteString value) throws DirectoryException
+ {
+ if (value == null)
+ {
+ throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
+ ProtocolMessages.ERR_TRANSACTION_ID_CONTROL_HAS_NO_VALUE.get());
+ }
+ return new TransactionIdControl(isCritical, value.toString());
+ }
+
+
+ @Override
+ public String getOID()
+ {
+ return OID_TRANSACTION_ID_CONTROL;
+ }
+
+ }
+
+ /** The Control Decoder that can be used to decode this control. */
+ public static final ControlDecoder<TransactionIdControl> DECODER = new Decoder();
+
+ /** The id value of this control. */
+ private final String transactionId;
+
+ /**
+ * Creates a new Transaction Id Control.
+ *
+ * @param isCritical Indicates whether this control should be considered
+ * critical to the operation processing.
+ * @param transactionId The id to pass through this control.
+ */
+ public TransactionIdControl(boolean isCritical, String transactionId)
+ {
+ super(OID_TRANSACTION_ID_CONTROL, isCritical);
+ this.transactionId = transactionId;
+ }
+
+ /**
+ * Writes this control's value to an ASN.1 writer. The value (if any) must be
+ * written as an ASN1OctetString.
+ *
+ * @param writer
+ * The ASN.1 output stream to write to.
+ * @throws IOException
+ * If a problem occurs while writing to the stream.
+ */
+ @Override
+ public void writeValue(ASN1Writer writer) throws IOException
+ {
+ writer.writeOctetString(transactionId);
+ }
+
+ /**
+ * Retrieves the transaction id associated with this control.
+ *
+ * @return The transaction id associated with this control.
+ */
+ public String getTransactionId()
+ {
+ return transactionId;
+ }
+
+ /**
+ * Appends a string representation of this control to the provided buffer.
+ *
+ * @param buffer
+ * The buffer to which the information should be appended.
+ */
+ @Override
+ public void toString(StringBuilder buffer)
+ {
+ buffer.append("TransactionIdControl(id=");
+ buffer.append(transactionId);
+ buffer.append(")");
+ }
+}
\ No newline at end of file
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/ConnectionHandlerConfigManager.java b/opendj-server-legacy/src/main/java/org/opends/server/core/ConnectionHandlerConfigManager.java
index 3664da4..e5eaef5 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/ConnectionHandlerConfigManager.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/core/ConnectionHandlerConfigManager.java
@@ -294,7 +294,7 @@
AdministrationConnectorCfg administrationConnectorCfg =
root.getAdministrationConnector();
- AdministrationConnector ac = new AdministrationConnector();
+ AdministrationConnector ac = new AdministrationConnector(serverContext);
ac.initializeAdministrationConnector(administrationConnectorCfg);
// Put this connection handler in the hash so that we will be
@@ -354,7 +354,7 @@
pd.loadClass(className, ConnectionHandler.class);
ConnectionHandler<T> connectionHandler = theClass.newInstance();
- connectionHandler.initializeConnectionHandler(config);
+ connectionHandler.initializeConnectionHandler(serverContext, config);
return connectionHandler;
} catch (Exception e) {
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 5d08ae7..ad3bfd2 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
@@ -138,6 +138,7 @@
import org.opends.server.extensions.DiskSpaceMonitor;
import org.opends.server.extensions.JMXAlertHandler;
import org.opends.server.loggers.AccessLogger;
+import org.opends.server.loggers.CommonAudit;
import org.opends.server.loggers.DebugLogPublisher;
import org.opends.server.loggers.DebugLogger;
import org.opends.server.loggers.ErrorLogPublisher;
@@ -726,6 +727,9 @@
/** Entry point for server configuration. */
private org.forgerock.opendj.config.server.ServerManagementContext serverManagementContext;
+ /** Entry point to common audit service, where all audit events must be published. */
+ private CommonAudit commonAudit;
+
/** Class that prints the version of OpenDJ server to System.out. */
public static final class DirectoryServerVersionHandler implements VersionHandler
{
@@ -824,6 +828,12 @@
{
return directoryServer.diskSpaceMonitor;
}
+
+ @Override
+ public CommonAudit getCommonAudit()
+ {
+ return directoryServer.commonAudit;
+ }
}
/**
@@ -1354,6 +1364,7 @@
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/core/ServerContext.java b/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java
index ba1db9a..829e974 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java
@@ -27,6 +27,7 @@
import org.forgerock.opendj.config.server.ServerManagementContext;
import org.opends.server.extensions.DiskSpaceMonitor;
+import org.opends.server.loggers.CommonAudit;
import org.opends.server.schema.SchemaUpdater;
import org.opends.server.types.DirectoryEnvironmentConfig;
import org.opends.server.types.Schema;
@@ -107,4 +108,11 @@
* @return the Disk Space Monioring service
*/
DiskSpaceMonitor getDiskSpaceMonitor();
+
+ /**
+ * Returns the common audit manager.
+ *
+ * @return the common audit manager
+ */
+ CommonAudit getCommonAudit();
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/AbstractLogger.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/AbstractLogger.java
index 3c03ba8..d00339f 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/AbstractLogger.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/AbstractLogger.java
@@ -26,6 +26,7 @@
*/
package org.opends.server.loggers;
+import static org.opends.server.loggers.CommonAudit.*;
import static org.opends.messages.ConfigMessages.*;
import static org.opends.server.util.StaticUtils.*;
@@ -185,7 +186,7 @@
private final Arg3<Object, Object, Object>
invalidLoggerClassErrorMessage;
- ServerContext serverContext;
+ private ServerContext serverContext;
/**
* The constructor for this class.
@@ -226,13 +227,20 @@
{
config.addChangeListener((ConfigurationChangeListener) this);
- if(config.isEnabled())
+ if (config.isEnabled())
{
- addLogPublisher(getLogPublisher(config));
+ final P logPublisher = isCommonAuditConfig(config) ?
+ getLogPublisherForCommonAudit(config) : getLogPublisher(config);
+ addLogPublisher(logPublisher);
}
}
}
+ ServerContext getServerContext()
+ {
+ return serverContext;
+ }
+
/** {@inheritDoc} */
@Override
public boolean isConfigurationAddAcceptable(C config,
@@ -263,7 +271,9 @@
{
try
{
- addLogPublisher(getLogPublisher(config));
+ final P logPublisher = isCommonAuditConfig(config) ?
+ getLogPublisherForCommonAudit(config) : getLogPublisher(config);
+ addLogPublisher(logPublisher);
}
catch(ConfigException e)
{
@@ -274,8 +284,7 @@
catch (Exception e)
{
LocalizedLogger.getLoggerForThisClass().traceException(e);
- ccr.addMessage(ERR_CONFIG_LOGGER_CANNOT_CREATE_LOGGER.get(
- config.dn(), stackTraceToSingleLineString(e)));
+ ccr.addMessage(ERR_CONFIG_LOGGER_CANNOT_CREATE_LOGGER.get(config.dn(), stackTraceToSingleLineString(e)));
ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
}
}
@@ -301,9 +310,9 @@
final ConfigChangeResult ccr = new ConfigChangeResult();
P logPublisher = findLogPublisher(config.dn());
- if(logPublisher == null)
+ if (logPublisher == null)
{
- if(config.isEnabled())
+ if (config.isEnabled())
{
// Needs to be added and enabled.
return applyConfigurationAdd(config);
@@ -311,26 +320,38 @@
}
else
{
- if(config.isEnabled())
+ if (config.isEnabled())
{
- // The publisher is currently active, so we don't need to do anything.
// Changes to the class name cannot be
// applied dynamically, so if the class name did change then
// indicate that administrative action is required for that
// change to take effect.
String className = config.getJavaClass();
- if(!className.equals(logPublisher.getClass().getName()))
+ if (!className.equals(logPublisher.getClass().getName()))
{
ccr.setAdminActionRequired(true);
}
+ try
+ {
+ if (isCommonAuditConfig(config))
+ {
+ serverContext.getCommonAudit().addOrUpdatePublisher(config);
+ } // else the publisher is currently active, so we don't need to do
+ // anything.
+ }
+ catch (Exception e)
+ {
+ LocalizedLogger.getLoggerForThisClass().traceException(e);
+ ccr.addMessage(ERR_CONFIG_LOGGER_CANNOT_UPDATE_LOGGER.get(config.dn(), stackTraceToSingleLineString(e)));
+ ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
+ }
}
else
{
// The publisher is being disabled so shut down and remove.
- removeLogPublisher(logPublisher);
+ return applyConfigurationDelete(config);
}
}
-
return ccr;
}
@@ -342,7 +363,6 @@
return findLogPublisher(config.dn()) != null;
}
- /** {@inheritDoc} */
@Override
public ConfigChangeResult applyConfigurationDelete(C config)
{
@@ -352,6 +372,19 @@
if(logPublisher != null)
{
removeLogPublisher(logPublisher);
+ try
+ {
+ if (isCommonAuditConfig(config))
+ {
+ serverContext.getCommonAudit().removePublisher(config);
+ }
+ }
+ catch (ConfigException e)
+ {
+ LocalizedLogger.getLoggerForThisClass().traceException(e);
+ ccr.addMessage(ERR_CONFIG_LOGGER_CANNOT_DELETE_LOGGER.get(config.dn(), stackTraceToSingleLineString(e)));
+ ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
+ }
}
else
{
@@ -391,4 +424,14 @@
}
}
+ private P getLogPublisherForCommonAudit(C config) throws InitializationException, ConfigException
+ {
+ CommonAudit commonAudit = serverContext.getCommonAudit();
+ commonAudit.addOrUpdatePublisher(config);
+ P logPublisher = getLogPublisher(config);
+ CommonAuditLogPublisher publisher = (CommonAuditLogPublisher) logPublisher;
+ publisher.setRequestHandler(commonAudit.getRequestHandler(config));
+ return logPublisher;
+ }
+
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/AccessLogger.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/AccessLogger.java
index 0ae3ead..fd2df90 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/AccessLogger.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/AccessLogger.java
@@ -521,6 +521,7 @@
public final synchronized void removeAllLogPublishers()
{
loggerStorage.removeAllLogPublishers();
+ getServerContext().getCommonAudit().shutdown();
}
}
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
new file mode 100644
index 0000000..aa413b1
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAudit.java
@@ -0,0 +1,943 @@
+/*
+ * 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.loggers;
+
+import static org.opends.messages.LoggerMessages.*;
+import static java.util.Collections.newSetFromMap;
+import static org.forgerock.audit.AuditServiceBuilder.newAuditService;
+import static org.forgerock.audit.events.EventTopicsMetaDataBuilder.coreTopicSchemas;
+import static org.forgerock.audit.json.AuditJsonConfig.registerHandlerToService;
+import static org.opends.server.util.StaticUtils.getFileForPath;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Pattern;
+
+import org.forgerock.audit.AuditException;
+import org.forgerock.audit.AuditService;
+import org.forgerock.audit.AuditServiceBuilder;
+import org.forgerock.audit.AuditServiceConfiguration;
+import org.forgerock.audit.AuditServiceProxy;
+import org.forgerock.audit.DependencyProvider;
+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.handlers.csv.CsvAuditEventHandler;
+import org.forgerock.audit.handlers.csv.CsvAuditEventHandlerConfiguration;
+import org.forgerock.audit.handlers.csv.CsvAuditEventHandlerConfiguration.CsvFormatting;
+import org.forgerock.audit.handlers.csv.CsvAuditEventHandlerConfiguration.CsvSecurity;
+import org.forgerock.audit.handlers.csv.CsvAuditEventHandlerConfiguration.EventBufferingConfiguration;
+import org.forgerock.audit.json.AuditJsonConfig;
+import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.forgerock.json.JsonValue;
+import org.forgerock.json.resource.RequestHandler;
+import org.forgerock.opendj.config.ConfigurationFramework;
+import org.forgerock.opendj.config.server.ConfigException;
+import org.opends.server.admin.Configuration;
+import org.opends.server.admin.server.ServerManagementContext;
+import org.opends.server.admin.std.server.CsvFileAccessLogPublisherCfg;
+import org.opends.server.admin.std.server.CsvFileHTTPAccessLogPublisherCfg;
+import org.opends.server.admin.std.server.ExternalAccessLogPublisherCfg;
+import org.opends.server.admin.std.server.ExternalHTTPAccessLogPublisherCfg;
+import org.opends.server.admin.std.server.FileCountLogRetentionPolicyCfg;
+import org.opends.server.admin.std.server.FixedTimeLogRotationPolicyCfg;
+import org.opends.server.admin.std.server.FreeDiskSpaceLogRetentionPolicyCfg;
+import org.opends.server.admin.std.server.LogPublisherCfg;
+import org.opends.server.admin.std.server.LogRetentionPolicyCfg;
+import org.opends.server.admin.std.server.LogRotationPolicyCfg;
+import org.opends.server.admin.std.server.RootCfg;
+import org.opends.server.admin.std.server.SizeLimitLogRetentionPolicyCfg;
+import org.opends.server.admin.std.server.SizeLimitLogRotationPolicyCfg;
+import org.opends.server.admin.std.server.TimeLimitLogRotationPolicyCfg;
+import org.opends.server.config.ConfigEntry;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.types.DN;
+import org.opends.server.util.StaticUtils;
+
+/**
+ * Entry point for the common audit facility.
+ * <p>
+ * This class manages the AuditService instances and Audit Event Handlers that correspond to the
+ * publishers defined in OpenDJ configuration.
+ * <p>
+ * In theory there should be only one instance of AuditService for all the event handlers but
+ * defining one service per handler allow to perform filtering at the DJ server level.
+ */
+public class CommonAudit
+{
+
+ private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
+
+ private static final String AUDIT_SERVICE_JSON_CONFIGURATION_FILE = "audit-config.json";
+
+ /** Dependency provider used to instantiate the handlers. */
+ private final DependencyProvider dependencyProvider;
+
+ /** Configuration framework is used to get an up-to-date class loader with any external library available. */
+ private final ConfigurationFramework configurationFramework;
+
+ /** Cache of audit services per configuration entry name. */
+ private final Map<String, AuditServiceProxy> auditServiceCache = new ConcurrentHashMap<>(10);
+
+ private final Set<PublisherConfig> httpAccessPublishers =
+ newSetFromMap(new ConcurrentHashMap<PublisherConfig, Boolean>(10));
+
+ /** Audit service shared by all HTTP access publishers. */
+ private final AuditServiceProxy httpAccessAuditService;
+
+
+ /**
+ * Creates the common audit.
+ *
+ * @throws ConfigException
+ * If an error occurs.
+ */
+ public CommonAudit() throws ConfigException
+ {
+ configurationFramework = ConfigurationFramework.getInstance();
+ this.dependencyProvider = new CommonAuditDependencyProvider();
+ this.httpAccessAuditService = createAuditServiceWithoutHandlers();
+ }
+
+ private AuditServiceProxy createAuditServiceWithoutHandlers() throws ConfigException
+ {
+ try
+ {
+ return buildAuditService(new AuditServiceSetup()
+ {
+ @Override
+ public void addHandlers(AuditServiceBuilder builder)
+ {
+ // no handler to add
+ }
+ });
+ }
+ catch (IOException | ConfigException | AuditException e)
+ {
+ throw new ConfigException(ERR_COMMON_AUDIT_CREATE.get(e), e);
+ }
+ }
+
+ /**
+ * Returns the Common Audit request handler for the provided configuration.
+ *
+ * @param config
+ * The log publisher configuration
+ * @return the request handler associated to the log publisher
+ * @throws ConfigException
+ * If an error occurs
+ */
+ public RequestHandler getRequestHandler(LogPublisherCfg config) throws ConfigException
+ {
+ if (new PublisherConfig(config).isHttpAccessLog())
+ {
+ return httpAccessAuditService;
+ }
+ return auditServiceCache.get(getNameFromConfig(config));
+ }
+
+ /**
+ * Adds or updates the publisher corresponding to the provided configuration to common audit.
+ *
+ * @param newConfig
+ * Configuration of the publisher
+ * @throws ConfigException
+ * If an error occurs.
+ */
+ public void addOrUpdatePublisher(final LogPublisherCfg newConfig) throws ConfigException
+ {
+ if (newConfig.isEnabled())
+ {
+ logger.trace("Setting up common audit for configuration entry: " + newConfig.dn());
+ try
+ {
+ final PublisherConfig newPublisher = new PublisherConfig(newConfig);
+ if (newPublisher.isHttpAccessLog())
+ {
+ if (httpAccessPublishers.contains(newPublisher))
+ {
+ // remove the old version before adding the new one
+ httpAccessPublishers.remove(newPublisher);
+ }
+ httpAccessPublishers.add(newPublisher);
+ buildAuditService(httpAccessAuditServiceSetup());
+ }
+ else // all other logs
+ {
+ String name = newPublisher.getName();
+ final AuditServiceProxy existingService =
+ auditServiceCache.containsKey(name) ? auditServiceCache.get(name): null;
+ AuditServiceProxy auditService = buildAuditService(new AuditServiceSetup(existingService)
+ {
+ @Override
+ public void addHandlers(AuditServiceBuilder builder) throws ConfigException
+ {
+ registerHandlerName(newPublisher.getName());
+ addHandlerToBuilder(newPublisher, builder);
+ }
+ });
+ auditServiceCache.put(name, auditService);
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ConfigException(ERR_COMMON_AUDIT_ADD_OR_UPDATE_LOG_PUBLISHER.get(newConfig.dn(), e), e);
+ }
+ }
+ }
+
+ /**
+ * Removes the publisher corresponding to the provided configuration from common audit.
+ *
+ * @param config
+ * Configuration of publisher to remove
+ * @throws ConfigException
+ * If an error occurs.
+ */
+ public void removePublisher(LogPublisherCfg config) throws ConfigException
+ {
+ final PublisherConfig publisher = new PublisherConfig(config);
+ logger.trace("Shutting down common audit for configuration entry:" + config.dn());
+ try
+ {
+ if (publisher.isHttpAccessLog())
+ {
+ httpAccessPublishers.remove(publisher);
+ buildAuditService(httpAccessAuditServiceSetup());
+ }
+ else // all other logs
+ {
+ AuditServiceProxy auditService = auditServiceCache.remove(publisher.getName());
+ if (auditService != null)
+ {
+ auditService.shutdown();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ConfigException(ERR_COMMON_AUDIT_REMOVE_LOG_PUBLISHER.get(config.dn(), e), e);
+ }
+ }
+
+ /** Shutdown common audit. */
+ public void shutdown()
+ {
+ httpAccessAuditService.shutdown();
+ for (AuditServiceProxy service : auditServiceCache.values())
+ {
+ service.shutdown();
+ }
+ }
+
+ private AuditServiceSetup httpAccessAuditServiceSetup()
+ {
+ return new AuditServiceSetup(httpAccessAuditService)
+ {
+ @Override
+ public void addHandlers(AuditServiceBuilder builder) throws ConfigException
+ {
+ for (PublisherConfig publisher : httpAccessPublishers)
+ {
+ registerHandlerName(publisher.getName());
+ addHandlerToBuilder(publisher, builder);
+ }
+ }
+ };
+ }
+
+ /**
+ * Strategy for the setup of AuditService.
+ * <p>
+ * Unless no handler must be added, this class should be extended and
+ * implementations should override the {@code addHandlers()} method.
+ */
+ static abstract class AuditServiceSetup
+ {
+ private final AuditServiceProxy existingAuditServiceProxy;
+ private final List<String> names = new ArrayList<>();
+
+ /** Creation with no existing audit service. */
+ AuditServiceSetup()
+ {
+ this.existingAuditServiceProxy = null;
+ }
+
+ /** Creation with an existing audit service. */
+ AuditServiceSetup(AuditServiceProxy existingAuditService)
+ {
+ this.existingAuditServiceProxy = existingAuditService;
+ }
+
+ abstract void addHandlers(AuditServiceBuilder builder) throws ConfigException;
+
+ void registerHandlerName(String name)
+ {
+ names.add(name);
+ }
+
+ List<String> getHandlerNames()
+ {
+ return names;
+ }
+
+ boolean mustCreateAuditServiceProxy()
+ {
+ return existingAuditServiceProxy == null;
+ }
+
+ AuditServiceProxy getExistingAuditServiceProxy()
+ {
+ return existingAuditServiceProxy;
+ }
+
+ }
+
+ private AuditServiceProxy buildAuditService(AuditServiceSetup setup)
+ throws IOException, AuditException, ConfigException
+ {
+ final JsonValue jsonConfig;
+ try (InputStream input = getClass().getResourceAsStream(AUDIT_SERVICE_JSON_CONFIGURATION_FILE))
+ {
+ jsonConfig = AuditJsonConfig.getJson(input);
+ }
+
+ EventTopicsMetaData eventTopicsMetaData = coreTopicSchemas()
+ .withCoreTopicSchemaExtensions(jsonConfig.get("extensions"))
+ .withAdditionalTopicSchemas(jsonConfig.get("additionalTopics"))
+ .build();
+ AuditServiceBuilder builder = newAuditService()
+ .withEventTopicsMetaData(eventTopicsMetaData)
+ .withDependencyProvider(dependencyProvider);
+
+ setup.addHandlers(builder);
+
+ AuditServiceConfiguration auditConfig = new AuditServiceConfiguration();
+ auditConfig.setAvailableAuditEventHandlers(setup.getHandlerNames());
+ builder.withConfiguration(auditConfig);
+ AuditService audit = builder.build();
+
+ final AuditServiceProxy proxy;
+ if (setup.mustCreateAuditServiceProxy())
+ {
+ proxy = new AuditServiceProxy(audit);
+ logger.trace("Starting up new common audit service");
+ proxy.startup();
+ }
+ else
+ {
+ proxy = setup.getExistingAuditServiceProxy();
+ proxy.setDelegate(audit);
+ logger.trace("Starting up existing updated common audit service");
+ }
+ return proxy;
+ }
+
+ private void addHandlerToBuilder(PublisherConfig publisher, AuditServiceBuilder builder) throws ConfigException
+ {
+ if (publisher.isCsv())
+ {
+ addCsvHandler(publisher, builder);
+ }
+ else if (publisher.isExternal())
+ {
+ addExternalHandler(publisher, builder);
+ }
+ else
+ {
+ throw new ConfigException(ERR_COMMON_AUDIT_UNSUPPORTED_HANDLER_TYPE.get(publisher.getDn()));
+ }
+ }
+
+ /** Add a handler defined externally in a JSON configuration file. */
+ private void addExternalHandler(PublisherConfig publisher, AuditServiceBuilder builder) throws ConfigException
+ {
+ ExternalConfigData config = publisher.getExternalConfig();
+ File configFile = getFileForPath(config.getConfigurationFile());
+ try (InputStream input = new BufferedInputStream(new FileInputStream(configFile)))
+ {
+ JsonValue jsonConfig = AuditJsonConfig.getJson(input);
+ registerHandlerToService(jsonConfig, builder, configurationFramework.getClassLoader());
+ }
+ catch (IOException e)
+ {
+ throw new ConfigException(ERR_COMMON_AUDIT_EXTERNAL_HANDLER_JSON_FILE.get(configFile, publisher.getDn(), e), e);
+ }
+ catch (Exception e)
+ {
+ throw new ConfigException(ERR_COMMON_AUDIT_EXTERNAL_HANDLER_CREATION.get(publisher.getDn(), e), e);
+ }
+ }
+
+ private void addCsvHandler(PublisherConfig publisher, AuditServiceBuilder builder) throws ConfigException
+ {
+ String name = publisher.getName();
+ try
+ {
+ CsvConfigData config = publisher.getCsvConfig();
+ CsvAuditEventHandlerConfiguration csvConfig = new CsvAuditEventHandlerConfiguration();
+ File logDirectory = getFileForPath(config.getLogDirectory());
+ csvConfig.setLogDirectory(logDirectory.getAbsolutePath());
+ csvConfig.setName(name);
+ csvConfig.setTopics(Collections.singleton(publisher.getCommonAuditTopic()));
+
+ addCsvHandlerFormattingConfig(config, csvConfig);
+ addCsvHandlerBufferingConfig(config, csvConfig);
+ addCsvHandlerSecureConfig(config, csvConfig);
+ addCsvHandlerRotationConfig(publisher, config, csvConfig);
+ addCsvHandlerRetentionConfig(publisher, config, csvConfig);
+
+ builder.withAuditEventHandler(CsvAuditEventHandler.class, csvConfig);
+ }
+ catch (Exception e)
+ {
+ throw new ConfigException(ERR_COMMON_AUDIT_CSV_HANDLER_CREATION.get(publisher.getDn(), e), e);
+ }
+ }
+
+ private void addCsvHandlerFormattingConfig(CsvConfigData config, CsvAuditEventHandlerConfiguration auditConfig)
+ throws ConfigException
+ {
+ CsvFormatting formatting = new CsvFormatting();
+ formatting.setQuoteChar(config.getQuoteChar());
+ formatting.setDelimiterChar(config.getDelimiterChar());
+ String endOfLineSymbols = config.getEndOfLineSymbols();
+ if (endOfLineSymbols != null && !endOfLineSymbols.isEmpty())
+ {
+ formatting.setEndOfLineSymbols(endOfLineSymbols);
+ }
+ auditConfig.setFormatting(formatting);
+ }
+
+ private void addCsvHandlerBufferingConfig(CsvConfigData config, CsvAuditEventHandlerConfiguration auditConfig)
+ {
+ EventBufferingConfiguration bufferingConfig = new EventBufferingConfiguration();
+ bufferingConfig.setEnabled(config.isAsynchronous());
+ bufferingConfig.setAutoFlush(config.isAutoFlush());
+ auditConfig.setBufferingConfiguration(bufferingConfig);
+ }
+
+ private void addCsvHandlerSecureConfig(CsvConfigData config, CsvAuditEventHandlerConfiguration auditConfig)
+ {
+ if (config.isTamperEvident())
+ {
+ CsvSecurity security = new CsvSecurity();
+ security.setSignatureInterval(config.getSignatureTimeInterval() + "ms");
+ security.setEnabled(true);
+ String keyStoreFile = config.getKeystoreFile();
+ security.setFilename(getFileForPath(keyStoreFile).getPath());
+ security.setPassword(getSecurePassword(config));
+ auditConfig.setSecurity(security);
+ }
+ }
+
+ private void addCsvHandlerRotationConfig(PublisherConfig publisher, CsvConfigData config,
+ CsvAuditEventHandlerConfiguration auditConfig) throws ConfigException
+ {
+ RootCfg root = ServerManagementContext.getInstance().getRootConfiguration();
+ SortedSet<String> rotationPolicies = config.getRotationPolicies();
+ if (rotationPolicies.isEmpty())
+ {
+ return;
+ }
+
+ FileRotation fileRotation = new FileRotation();
+ fileRotation.setRotationEnabled(true);
+ for (final String policy : rotationPolicies)
+ {
+ LogRotationPolicyCfg policyConfig = root.getLogRotationPolicy(policy);
+ if (policyConfig instanceof FixedTimeLogRotationPolicyCfg)
+ {
+ List<String> times = convertTimesOfDay(publisher, (FixedTimeLogRotationPolicyCfg) policyConfig);
+ fileRotation.setRotationTimes(times);
+ }
+ else if (policyConfig instanceof SizeLimitLogRotationPolicyCfg)
+ {
+ fileRotation.setMaxFileSize(((SizeLimitLogRotationPolicyCfg) policyConfig).getFileSizeLimit());
+ }
+ else if (policyConfig instanceof TimeLimitLogRotationPolicyCfg)
+ {
+ long rotationInterval = ((TimeLimitLogRotationPolicyCfg) policyConfig).getRotationInterval();
+ fileRotation.setRotationInterval(String.valueOf(rotationInterval) + " ms");
+ }
+ else
+ {
+ throw new ConfigException(
+ ERR_COMMON_AUDIT_UNSUPPORTED_LOG_ROTATION_POLICY.get(publisher.getDn(), policyConfig.dn()));
+ }
+ }
+ auditConfig.setFileRotation(fileRotation);
+ }
+
+ private void addCsvHandlerRetentionConfig(PublisherConfig publisher, CsvConfigData config,
+ CsvAuditEventHandlerConfiguration auditConfig) throws ConfigException
+ {
+ RootCfg root = ServerManagementContext.getInstance().getRootConfiguration();
+ SortedSet<String> retentionPolicies = config.getRetentionPolicies();
+ if (retentionPolicies.isEmpty())
+ {
+ return;
+ }
+
+ FileRetention fileRetention = new FileRetention();
+ for (final String policy : retentionPolicies)
+ {
+ LogRetentionPolicyCfg policyConfig = root.getLogRetentionPolicy(policy);
+ if (policyConfig instanceof FileCountLogRetentionPolicyCfg)
+ {
+ fileRetention.setMaxNumberOfHistoryFiles(((FileCountLogRetentionPolicyCfg) policyConfig).getNumberOfFiles());
+ }
+ else if (policyConfig instanceof FreeDiskSpaceLogRetentionPolicyCfg)
+ {
+ // TODO: remove the cast to int when fixed
+ fileRetention.setMinFreeSpaceRequired(
+ (int)((FreeDiskSpaceLogRetentionPolicyCfg) policyConfig).getFreeDiskSpace());
+ }
+ else if (policyConfig instanceof SizeLimitLogRetentionPolicyCfg)
+ {
+ fileRetention.setMaxDiskSpaceToUse(((SizeLimitLogRetentionPolicyCfg) policyConfig).getDiskSpaceUsed());
+ }
+ else
+ {
+ throw new ConfigException(
+ ERR_COMMON_AUDIT_UNSUPPORTED_LOG_RETENTION_POLICY.get(publisher.getDn(), policyConfig.dn()));
+ }
+ }
+ auditConfig.setFileRetention(fileRetention);
+ }
+
+ /**
+ * Convert the set of provided times of day using 24-hour format "HHmm" to a list of
+ * times of day using duration in minutes, e.g "20 minutes".
+ * <p>
+ * Example: "0230" => "150 minutes"
+ */
+ private List<String> convertTimesOfDay(PublisherConfig publisher, FixedTimeLogRotationPolicyCfg policyConfig)
+ throws ConfigException
+ {
+ SortedSet<String> timesOfDay = policyConfig.getTimeOfDay();
+ List<String> times = new ArrayList<>();
+ for (String timeOfDay : timesOfDay)
+ {
+ try
+ {
+ int time = Integer.valueOf(timeOfDay.substring(0, 2)) * 60 + Integer.valueOf(timeOfDay.substring(2, 4));
+ times.add(String.valueOf(time) + " minutes");
+ }
+ catch (NumberFormatException | IndexOutOfBoundsException e)
+ {
+ throw new ConfigException(ERR_COMMON_AUDIT_INVALID_TIME_OF_DAY.get(publisher.getDn(), timeOfDay,
+ StaticUtils.stackTraceToSingleLineString(e)));
+ }
+ }
+ return times;
+ }
+
+ // TODO : this method will be deleted, because a keystore handler will be used instead
+ private String getSecurePassword(CsvConfigData config)
+ {
+ String fileName = config.getKeystorePinFile();
+ File pinFile = getFileForPath(fileName);
+
+ if (!pinFile.exists())
+ {
+ // should log error "no pin file"
+ }
+ else
+ {
+ String pinStr = null;
+ BufferedReader br = null;
+ try {
+ br = new BufferedReader(new FileReader(pinFile));
+ pinStr = br.readLine();
+ }
+ catch (IOException ioe)
+ {
+ // should log error "unable to read pin file"
+ }
+ finally
+ {
+ StaticUtils.close(br);
+ }
+
+ if (pinStr == null)
+ {
+ // should log error pin file empty
+ }
+ else
+ {
+ return pinStr;
+ }
+ }
+ return "";
+ }
+
+ private String getNameFromConfig(Configuration config)
+ {
+ return config.dn().getRDN(0).getAttributeValue(0).toString();
+ }
+
+ /**
+ * Indicates if the provided log publisher configuration corresponds to a common audit publisher.
+ *
+ * @param config
+ * The log publisher configuration.
+ * @return {@code true} if publisher is for common audit
+ * @throws ConfigException
+ * If an error occurs
+ */
+ public static boolean isCommonAuditConfig(LogPublisherCfg config) throws ConfigException
+ {
+ return new PublisherConfig(config).isCommonAudit();
+ }
+
+ /**
+ * Indicates if HTTP access logging is enabled for common audit.
+ *
+ * @return {@code true} if there is at least one HTTP access logger enabled for common audit.
+ */
+ public boolean isHttpAccessLogEnabled()
+ {
+ return !httpAccessPublishers.isEmpty();
+ }
+
+ /**
+ * Returns the audit service that manages HTTP Access logging.
+ *
+ * @return the request handler that accepts audit events
+ */
+ public RequestHandler getAuditServiceForHttpAccessLog()
+ {
+ return httpAccessAuditService;
+ }
+
+ /**
+ * This class hides all ugly code needed to determine which type of publisher and audit event handler is needed.
+ * <p>
+ * In particular, it allows to retrieve a common configuration that can be used for log publishers that
+ * publish to the same kind of handler.
+ * For example: for CSV handler, DJ configurations for the log publishers contain the same methods but
+ * do not have a common interface (CsvFileAccessLogPublisherCfg vs CsvFileHTTPAccessLogPublisherCfg).
+ */
+ private static class PublisherConfig
+ {
+ private final LogPublisherCfg config;
+ private final boolean isCommonAudit;
+ private LogType logType;
+ private AuditType auditType;
+
+ PublisherConfig(LogPublisherCfg config) throws ConfigException
+ {
+ this.config = config;
+ ConfigEntry configEntry = DirectoryServer.getConfigEntry(config.dn());
+ if (configEntry.hasObjectClass("ds-cfg-csv-file-access-log-publisher"))
+ {
+ auditType = AuditType.CSV;
+ logType = LogType.ACCESS;
+ }
+ else if (configEntry.hasObjectClass("ds-cfg-csv-file-http-access-log-publisher"))
+ {
+ auditType = AuditType.CSV;
+ logType = LogType.HTTP_ACCESS;
+ }
+ else if (configEntry.hasObjectClass("ds-cfg-external-access-log-publisher"))
+ {
+ auditType = AuditType.EXTERNAL;
+ logType = LogType.ACCESS;
+ }
+ else if (configEntry.hasObjectClass("ds-cfg-external-http-access-log-publisher"))
+ {
+ auditType = AuditType.EXTERNAL;
+ logType = LogType.HTTP_ACCESS;
+ }
+ isCommonAudit = auditType != null;
+ }
+
+ DN getDn()
+ {
+ return config.dn();
+ }
+
+ String getName()
+ {
+ return config.dn().getRDN(0).getAttributeValue(0).toString();
+ }
+
+ String getCommonAuditTopic() throws ConfigException
+ {
+ if (isAccessLog())
+ {
+ return "ldap-access";
+ }
+ else if (isHttpAccessLog())
+ {
+ return "http-access";
+ }
+ throw new ConfigException(ERR_COMMON_AUDIT_UNSUPPORTED_LOG_PUBLISHER.get(config.dn()));
+ }
+
+ boolean isExternal()
+ {
+ return AuditType.EXTERNAL == auditType;
+ }
+
+ boolean isCsv()
+ {
+ return AuditType.CSV == auditType;
+ }
+
+ boolean isAccessLog()
+ {
+ return LogType.ACCESS == logType;
+ }
+
+ boolean isHttpAccessLog()
+ {
+ return LogType.HTTP_ACCESS == logType;
+ }
+
+ boolean isCommonAudit()
+ {
+ return isCommonAudit;
+ }
+
+ CsvConfigData getCsvConfig() throws ConfigException
+ {
+ if (isAccessLog())
+ {
+ CsvFileAccessLogPublisherCfg conf = (CsvFileAccessLogPublisherCfg) config;
+ return new CsvConfigData(conf.getLogDirectory(), conf.getCsvQuoteChar(), conf.getCsvDelimiterChar(), conf
+ .getCsvEolSymbols(), conf.isAsynchronous(), conf.isAutoFlush(), conf.isTamperEvident(), conf
+ .getSignatureTimeInterval(), conf.getKeyStoreFile(), conf.getKeyStorePinFile(), conf.getRotationPolicy(),
+ conf.getRetentionPolicy());
+ }
+ if (isHttpAccessLog())
+ {
+ CsvFileHTTPAccessLogPublisherCfg conf = (CsvFileHTTPAccessLogPublisherCfg) config;
+ return new CsvConfigData(conf.getLogDirectory(), conf.getCsvQuoteChar(), conf.getCsvDelimiterChar(), conf
+ .getCsvEolSymbols(), conf.isAsynchronous(), conf.isAutoFlush(), conf.isTamperEvident(), conf
+ .getSignatureTimeInterval(), conf.getKeyStoreFile(), conf.getKeyStorePinFile(), conf.getRotationPolicy(),
+ conf.getRetentionPolicy());
+ }
+ throw new ConfigException(ERR_COMMON_AUDIT_UNSUPPORTED_LOG_PUBLISHER.get(config.dn()));
+ }
+
+ ExternalConfigData getExternalConfig() throws ConfigException
+ {
+ if (isAccessLog())
+ {
+ ExternalAccessLogPublisherCfg conf = (ExternalAccessLogPublisherCfg) config;
+ return new ExternalConfigData(conf.getConfigFile());
+ }
+ if (isHttpAccessLog())
+ {
+ ExternalHTTPAccessLogPublisherCfg conf = (ExternalHTTPAccessLogPublisherCfg) config;
+ return new ExternalConfigData(conf.getConfigFile());
+ }
+ throw new ConfigException(ERR_COMMON_AUDIT_UNSUPPORTED_LOG_PUBLISHER.get(config.dn()));
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (!(obj instanceof PublisherConfig))
+ {
+ return false;
+ }
+ PublisherConfig other = (PublisherConfig) obj;
+ return config.dn().equals(other.config.dn());
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return config.dn().hashCode();
+ }
+
+ }
+
+ /** Types of audit handlers managed. */
+ private enum AuditType
+ {
+ CSV, EXTERNAL
+ }
+
+ /** Types of log managed. */
+ private enum LogType
+ {
+ ACCESS, HTTP_ACCESS
+ }
+
+ /**
+ * Contains the parameters for a CSV handler.
+ * <p>
+ * OpenDJ log publishers that logs to a CSV handler have the same parameters but do not share
+ * a common ancestor with all the parameters (e.g Access Log, HTTP Access Log, ...), hence this class
+ * is necessary to avoid duplicating code that setup the configuration of the CSV handler.
+ */
+ private static class CsvConfigData
+ {
+ private final String logDirectory;
+ private final String eolSymbols;
+ private final String delimiterChar;
+ private final String quoteChar;
+ private final boolean asynchronous;
+ private final boolean autoFlush;
+ private final boolean tamperEvident;
+ private final long signatureTimeInterval;
+ private final String keystoreFile;
+ private final String keystorePinFile;
+ private final SortedSet<String> rotationPolicies;
+ private final SortedSet<String> retentionPolicies;
+
+ CsvConfigData(String logDirectory, String quoteChar, String delimiterChar, String eolSymbols, boolean asynchronous,
+ boolean autoFlush, boolean tamperEvident, long signatureTimeInterval, String keystoreFile,
+ String keystorePinFile, SortedSet<String> rotationPolicies, SortedSet<String> retentionPolicies)
+ {
+ this.logDirectory = logDirectory;
+ this.quoteChar = quoteChar;
+ this.delimiterChar = delimiterChar;
+ this.eolSymbols = eolSymbols;
+ this.asynchronous = asynchronous;
+ this.autoFlush = autoFlush;
+ this.tamperEvident = tamperEvident;
+ this.signatureTimeInterval = signatureTimeInterval;
+ this.keystoreFile = keystoreFile;
+ this.keystorePinFile = keystorePinFile;
+ this.rotationPolicies = rotationPolicies;
+ this.retentionPolicies = retentionPolicies;
+ }
+
+ String getEndOfLineSymbols()
+ {
+ return eolSymbols;
+ }
+
+ char getDelimiterChar() throws ConfigException
+ {
+ String filtered = delimiterChar.replaceAll(Pattern.quote("\\"), "");
+ if (filtered.length() != 1)
+ {
+ throw new ConfigException(ERR_COMMON_AUDIT_CSV_HANDLER_DELIMITER_CHAR.get("", filtered));
+ }
+ return filtered.charAt(0);
+ }
+
+ public char getQuoteChar() throws ConfigException
+ {
+ String filtered = quoteChar.replaceAll(Pattern.quote("\\"), "");
+ if (filtered.length() != 1)
+ {
+ throw new ConfigException(ERR_COMMON_AUDIT_CSV_HANDLER_QUOTE_CHAR.get("", filtered));
+ }
+ return filtered.charAt(0);
+ }
+
+ String getLogDirectory()
+ {
+ return logDirectory;
+ }
+
+ boolean isAsynchronous()
+ {
+ return asynchronous;
+ }
+
+ boolean isAutoFlush()
+ {
+ return autoFlush;
+ }
+
+ boolean isTamperEvident()
+ {
+ return tamperEvident;
+ }
+
+ long getSignatureTimeInterval()
+ {
+ return signatureTimeInterval;
+ }
+
+ String getKeystoreFile()
+ {
+ return keystoreFile;
+ }
+
+ String getKeystorePinFile()
+ {
+ return keystorePinFile;
+ }
+
+ SortedSet<String> getRotationPolicies()
+ {
+ return rotationPolicies;
+ }
+
+ SortedSet<String> getRetentionPolicies()
+ {
+ return retentionPolicies;
+ }
+ }
+
+ /**
+ * Contains the parameters for an external handler.
+ * <p>
+ * OpenDJ log publishers that logs to an external handler have the same parameters but do not share
+ * a common ancestor with all the parameters (e.g Access Log, HTTP Access Log, ...), hence this class
+ * is necessary to avoid duplicating code that setup the configuration of an external handler.
+ */
+ private static class ExternalConfigData
+ {
+ private final String configurationFile;
+
+ ExternalConfigData(String configurationFile)
+ {
+ this.configurationFile = configurationFile;
+ }
+
+ String getConfigurationFile()
+ {
+ return configurationFile;
+ }
+ }
+
+}
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
new file mode 100644
index 0000000..ffa63f6
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditAccessLogPublisher.java
@@ -0,0 +1,554 @@
+/*
+ * 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.loggers;
+
+import static org.opends.messages.LoggerMessages.*;
+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.OpenDJAccessAuditEventBuilder.openDJAccessEvent;
+import static org.opends.server.types.AuthenticationType.SASL;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.forgerock.audit.events.AccessAuditEventBuilder.ResponseStatus;
+import org.forgerock.audit.events.AuditEvent;
+import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.i18n.LocalizableMessageBuilder;
+import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.forgerock.json.resource.CreateRequest;
+import org.forgerock.json.resource.RequestHandler;
+import org.forgerock.json.resource.ResourceException;
+import org.forgerock.opendj.config.server.ConfigException;
+import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.services.context.RootContext;
+import org.forgerock.util.Pair;
+import org.forgerock.util.promise.ExceptionHandler;
+import org.forgerock.util.promise.RuntimeExceptionHandler;
+import org.opends.server.admin.std.server.AccessLogPublisherCfg;
+import org.opends.server.api.ClientConnection;
+import org.opends.server.api.ExtendedOperationHandler;
+import org.opends.server.controls.TransactionIdControl;
+import org.opends.server.core.AbandonOperation;
+import org.opends.server.core.AddOperation;
+import org.opends.server.core.BindOperation;
+import org.opends.server.core.CompareOperation;
+import org.opends.server.core.DeleteOperation;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.ExtendedOperation;
+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.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;
+
+/**
+ * Publishes access events to Common Audit.
+ *
+ * @param <T> the type of configuration
+ */
+abstract class CommonAuditAccessLogPublisher<T extends AccessLogPublisherCfg>
+ extends AbstractTextAccessLogPublisher<T>
+ implements CommonAuditLogPublisher
+{
+
+ 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;
+
+ @Override
+ public void setRequestHandler(RequestHandler handler)
+ {
+ this.requestHandler = handler;
+ }
+
+ abstract boolean shouldLogControlOids();
+
+ T getConfig()
+ {
+ return config;
+ }
+
+ void setConfig(T config)
+ {
+ this.config = config;
+ }
+
+ @Override
+ public void initializeLogPublisher(final T cfg, ServerContext serverContext)
+ throws ConfigException, InitializationException
+ {
+ initializeFilters(cfg);
+ config = cfg;
+ }
+
+ @Override
+ public boolean isConfigurationAcceptable(final T configuration, final List<LocalizableMessage> unacceptableReasons)
+ {
+ return isFilterConfigurationAcceptable(configuration, unacceptableReasons);
+ }
+
+ @Override
+ public void logAbandonResult(final AbandonOperation abandonOperation)
+ {
+ if (!isResponseLoggable(abandonOperation))
+ {
+ return;
+ }
+ OpenDJAccessAuditEventBuilder<?> builder = getEventBuilder(abandonOperation, "ABANDON");
+ appendAbandonRequest(abandonOperation, builder);
+ appendResultCodeAndMessage(abandonOperation, builder);
+
+ sendEvent(builder.toEvent());
+ }
+
+ @Override
+ public void logAddResponse(final AddOperation addOperation)
+ {
+ if (!isResponseLoggable(addOperation))
+ {
+ return;
+ }
+ OpenDJAccessAuditEventBuilder<?> builder = getEventBuilder(addOperation, "ADD");
+ appendAddRequest(addOperation, builder);
+ appendResultCodeAndMessage(addOperation, builder);
+ DN proxiedAuthorizationDN = addOperation.getProxiedAuthorizationDN();
+ appendProxiedAuthorizationDNIfNeeded(builder, proxiedAuthorizationDN);
+
+ sendEvent(builder.toEvent());
+ }
+
+ @Override
+ public void logBindResponse(final BindOperation bindOperation)
+ {
+ if (!isResponseLoggable(bindOperation))
+ {
+ return;
+ }
+
+ OpenDJAccessAuditEventBuilder<?> builder = getEventBuilder(bindOperation, "BIND");
+ appendBindRequest(bindOperation, builder);
+ appendResultCodeAndMessage(bindOperation, builder);
+
+ final LocalizableMessage failureMessage = bindOperation.getAuthFailureReason();
+ if (failureMessage != null)
+ {
+ // this code path is mutually exclusive with the if result code is success
+ // down below
+ builder.ldapFailureMessage(failureMessage.toString());
+ if (bindOperation.getSASLMechanism() != null && bindOperation.getSASLAuthUserEntry() != null)
+ { // SASL bind and we have successfully found a user entry for auth
+ builder.userId(bindOperation.getSASLAuthUserEntry().getName().toString());
+ }
+ else
+ { // SASL bind failed to find user entry for auth or simple bind
+ builder.userId(bindOperation.getRawBindDN().toString());
+ }
+ }
+
+ if (bindOperation.getResultCode() == ResultCode.SUCCESS)
+ {
+ // this code path is mutually exclusive with the if failure message exist
+ // just above
+ final AuthenticationInfo authInfo = bindOperation.getAuthenticationInfo();
+ if (authInfo != null)
+ {
+ final DN authDN = authInfo.getAuthenticationDN();
+ if (authDN != null)
+ {
+ builder.userId(authDN.toString());
+
+ final DN authzDN = authInfo.getAuthorizationDN();
+ if (!authDN.equals(authzDN))
+ {
+ builder.runAs(authzDN.toString());
+ }
+ }
+ else
+ {
+ builder.userId("");
+ }
+ }
+ }
+
+ sendEvent(builder.toEvent());
+ }
+
+ @Override
+ public void logCompareResponse(final CompareOperation compareOperation)
+ {
+ if (!isResponseLoggable(compareOperation))
+ {
+ return;
+ }
+ OpenDJAccessAuditEventBuilder<?> builder = getEventBuilder(compareOperation, "COMPARE");
+ appendCompareRequest(compareOperation, builder);
+ appendResultCodeAndMessage(compareOperation, builder);
+ DN proxiedAuthorizationDN = compareOperation.getProxiedAuthorizationDN();
+ appendProxiedAuthorizationDNIfNeeded(builder, proxiedAuthorizationDN);
+
+ sendEvent(builder.toEvent());
+ }
+
+ private void appendProxiedAuthorizationDNIfNeeded(OpenDJAccessAuditEventBuilder<?> builder, DN proxiedAuthorizationDN)
+ {
+ if (proxiedAuthorizationDN != null)
+ {
+ builder.runAs(proxiedAuthorizationDN.toString());
+ }
+ }
+
+ @Override
+ public void logConnect(final ClientConnection clientConnection)
+ {
+ if (!isConnectLoggable(clientConnection))
+ {
+ return;
+ }
+ OpenDJAccessAuditEventBuilder<?> builder = openDJAccessEvent()
+ .eventName("DJ-" + clientConnection.getProtocol() + "-" + "CONNECT")
+ .client(clientConnection.getClientAddress(), clientConnection.getClientPort())
+ .server(clientConnection.getServerAddress(), clientConnection.getServerPort())
+ .request(clientConnection.getProtocol(), "CONNECT")
+ .transactionId(DEFAULT_TRANSACTION_ID)
+ .response(ResponseStatus.SUCCESSFUL, String.valueOf(ResultCode.SUCCESS.intValue()), 0, TimeUnit.MILLISECONDS)
+ .ldapConnectionId(clientConnection.getConnectionID());
+
+ sendEvent(builder.toEvent());
+ }
+
+ @Override
+ public void logDeleteResponse(final DeleteOperation deleteOperation)
+ {
+ if (!isResponseLoggable(deleteOperation))
+ {
+ return;
+ }
+ OpenDJAccessAuditEventBuilder<?> builder = getEventBuilder(deleteOperation, "DELETE");
+ appendDeleteRequest(deleteOperation, builder);
+ appendResultCodeAndMessage(deleteOperation, builder);
+ DN proxiedAuthorizationDN = deleteOperation.getProxiedAuthorizationDN();
+ appendProxiedAuthorizationDNIfNeeded(builder, proxiedAuthorizationDN);
+
+ sendEvent(builder.toEvent());
+ }
+
+ @Override
+ public void logDisconnect(final ClientConnection clientConnection, final DisconnectReason disconnectReason,
+ final LocalizableMessage message)
+ {
+ if (!isDisconnectLoggable(clientConnection))
+ {
+ return;
+ }
+ OpenDJAccessAuditEventBuilder<?> builder = openDJAccessEvent()
+ .eventName("DJ-" + clientConnection.getProtocol() + "-" + "DISCONNECT")
+ .client(clientConnection.getClientAddress(), clientConnection.getClientPort())
+ .server(clientConnection.getServerAddress(), clientConnection.getServerPort())
+ .request(clientConnection.getProtocol(),"DISCONNECT")
+ .transactionId(DEFAULT_TRANSACTION_ID)
+ .response(ResponseStatus.SUCCESSFUL, String.valueOf(ResultCode.SUCCESS.intValue()), 0, TimeUnit.MILLISECONDS)
+ .ldapConnectionId(clientConnection.getConnectionID())
+ .ldapReason(disconnectReason.toString())
+ .ldapMessage(message.toString());
+
+ sendEvent(builder.toEvent());
+ }
+
+ @Override
+ public void logExtendedResponse(final ExtendedOperation extendedOperation)
+ {
+ if (!isResponseLoggable(extendedOperation))
+ {
+ return;
+ }
+ OpenDJAccessAuditEventBuilder<?> builder = getEventBuilder(extendedOperation, "EXTENDED");
+ appendExtendedRequest(extendedOperation, builder);
+ appendResultCodeAndMessage(extendedOperation, builder);
+ final String oid = extendedOperation.getResponseOID();
+ if (oid != null)
+ {
+ final ExtendedOperationHandler<?> extOpHandler = DirectoryServer.getExtendedOperationHandler(oid);
+ if (extOpHandler != null)
+ {
+ String name = extOpHandler.getExtendedOperationName();
+ builder.ldapName(name);
+ }
+ builder.ldapOid(oid);
+ }
+ sendEvent(builder.toEvent());
+ }
+
+ @Override
+ public void logModifyDNResponse(final ModifyDNOperation modifyDNOperation)
+ {
+ if (!isResponseLoggable(modifyDNOperation))
+ {
+ return;
+ }
+ OpenDJAccessAuditEventBuilder<?> builder = getEventBuilder(modifyDNOperation, "MODIFYDN");
+ appendModifyDNRequest(modifyDNOperation, builder);
+ appendResultCodeAndMessage(modifyDNOperation, builder);
+ DN proxiedAuthorizationDN = modifyDNOperation.getProxiedAuthorizationDN();
+ appendProxiedAuthorizationDNIfNeeded(builder, proxiedAuthorizationDN);
+
+ sendEvent(builder.toEvent());
+ }
+
+ @Override
+ public void logModifyResponse(final ModifyOperation modifyOperation)
+ {
+ if (!isResponseLoggable(modifyOperation))
+ {
+ return;
+ }
+ OpenDJAccessAuditEventBuilder<?> builder = getEventBuilder(modifyOperation, "MODIFY");
+ appendModifyRequest(modifyOperation, builder);
+ appendResultCodeAndMessage(modifyOperation, builder);
+ DN proxiedAuthorizationDN = modifyOperation.getProxiedAuthorizationDN();
+ appendProxiedAuthorizationDNIfNeeded(builder, proxiedAuthorizationDN);
+
+ sendEvent(builder.toEvent());
+ }
+
+ @Override
+ public void logSearchResultDone(final SearchOperation searchOperation)
+ {
+ if (!isResponseLoggable(searchOperation))
+ {
+ return;
+ }
+ OpenDJAccessAuditEventBuilder<?> builder = getEventBuilder(searchOperation, "SEARCH");
+ builder
+ .ldapSearch(searchOperation)
+ .ldapNEntries(searchOperation.getEntriesSent());
+ appendResultCodeAndMessage(searchOperation, builder);
+ DN proxiedAuthorizationDN = searchOperation.getProxiedAuthorizationDN();
+ appendProxiedAuthorizationDNIfNeeded(builder, proxiedAuthorizationDN);
+
+ sendEvent(builder.toEvent());
+ }
+
+ @Override
+ public void logUnbind(final UnbindOperation unbindOperation)
+ {
+ if (!isRequestLoggable(unbindOperation))
+ {
+ return;
+ }
+ sendEvent(getEventBuilder(unbindOperation, "UNBIND").toEvent());
+ }
+
+ @Override
+ protected void close0()
+ {
+ // nothing to do because closing is managed in the CommonAudit class
+ }
+
+ private void appendAbandonRequest(final AbandonOperation abandonOperation,
+ final OpenDJAccessAuditEventBuilder<?> builder)
+ {
+ builder.ldapIdToAbandon(abandonOperation.getIDToAbandon());
+ }
+
+ private void appendAddRequest(final AddOperation addOperation, OpenDJAccessAuditEventBuilder<?> builder)
+ {
+ builder.ldapDn(addOperation.getRawEntryDN().toString());
+ }
+
+ private void appendBindRequest(final BindOperation bindOperation, final OpenDJAccessAuditEventBuilder<?> builder)
+ {
+ builder.ldapProtocolVersion(bindOperation.getProtocolVersion());
+ final String authType = bindOperation.getAuthenticationType() != SASL ?
+ bindOperation.getAuthenticationType().toString() : "SASL mechanism=" + bindOperation.getSASLMechanism();
+ builder.ldapAuthType(authType);
+
+ builder.ldapDn(bindOperation.getRawBindDN().toString());
+
+ }
+
+ private void appendCompareRequest(final CompareOperation compareOperation,
+ final OpenDJAccessAuditEventBuilder<?> builder)
+ {
+ builder.ldapDn(compareOperation.getRawEntryDN().toString());
+ builder.ldapAttr(compareOperation.getAttributeType().getNameOrOID());
+ }
+
+ private void appendDeleteRequest(final DeleteOperation deleteOperation,
+ final OpenDJAccessAuditEventBuilder<?> builder)
+ {
+ builder.ldapDn(deleteOperation.getRawEntryDN().toString());
+ }
+
+ private void appendExtendedRequest(final ExtendedOperation extendedOperation,
+ final OpenDJAccessAuditEventBuilder<?> builder)
+ {
+ final String oid = extendedOperation.getRequestOID();
+ final ExtendedOperationHandler<?> extOpHandler = DirectoryServer.getExtendedOperationHandler(oid);
+ if (extOpHandler != null)
+ {
+ final String name = extOpHandler.getExtendedOperationName();
+ builder.ldapName(name);
+ }
+ builder.ldapOid(oid);
+ }
+
+ private void appendModifyDNRequest(final ModifyDNOperation modifyDNOperation,
+ final OpenDJAccessAuditEventBuilder<?> builder)
+ {
+ builder.ldapDn(modifyDNOperation.getRawEntryDN().toString());
+ builder.ldapModifyDN(modifyDNOperation);
+ }
+
+ private void appendModifyRequest(final ModifyOperation modifyOperation,
+ final OpenDJAccessAuditEventBuilder<?> builder)
+ {
+ builder.ldapDn(modifyOperation.getRawEntryDN().toString());
+ }
+
+ private OpenDJAccessAuditEventBuilder<?> appendResultCodeAndMessage(
+ Operation operation, OpenDJAccessAuditEventBuilder<?> builder)
+ {
+ final LocalizableMessageBuilder message = operation.getErrorMessage();
+ int resultCode = operation.getResultCode().intValue();
+ ResponseStatus status = resultCode == 0 ? ResponseStatus.SUCCESSFUL : ResponseStatus.FAILED;
+ Pair<Long, TimeUnit> executionTime = getExecutionTime(operation);
+ if (message != null && message.length() > 0)
+ {
+ builder.responseWithDetail(status, String.valueOf(resultCode), executionTime.getFirst(),
+ executionTime.getSecond(), json(message.toString()));
+ }
+ else
+ {
+ builder.response(status, String.valueOf(resultCode), executionTime.getFirst(), executionTime.getSecond());
+ }
+ builder.ldapMaskedResultAndMessage(operation);
+ return builder;
+ }
+
+ /** Returns an event builder with all common fields filled. */
+ private OpenDJAccessAuditEventBuilder<?> getEventBuilder(final Operation operation, final String opType)
+ {
+ ClientConnection clientConn = operation.getClientConnection();
+
+ OpenDJAccessAuditEventBuilder<?> builder = openDJAccessEvent()
+ .eventName("DJ-" + clientConn.getProtocol() + "-" + opType)
+ .client(clientConn.getClientAddress(), clientConn.getClientPort())
+ .server(clientConn.getServerAddress(), clientConn.getServerPort())
+ .request(clientConn.getProtocol(), opType)
+ .ldapAdditionalItems(operation)
+ .ldapSync(operation)
+ .ldapIds(operation)
+ .transactionId(getTransactionId(operation));
+
+ if (shouldLogControlOids())
+ {
+ builder.ldapControls(operation);
+ }
+ return builder;
+ }
+
+ private String getTransactionId(Operation operation)
+ {
+ String transactionId = getTransactionIdFromControl(operation);
+ if (transactionId == null)
+ {
+ // use a default value because transaction id has no usage in this case
+ transactionId = DEFAULT_TRANSACTION_ID;
+ }
+ return transactionId;
+ }
+
+ private String getTransactionIdFromControl(Operation operation)
+ {
+ for (Control control : operation.getRequestControls())
+ {
+ 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)));
+ }
+ }
+ }
+ return null;
+ }
+
+ private Pair<Long,TimeUnit> getExecutionTime(final Operation operation)
+ {
+ Long etime = operation.getProcessingNanoTime();
+ // if not configured for nanos, use millis
+ return etime <= -1 ?
+ Pair.of(operation.getProcessingTime(), TimeUnit.MILLISECONDS) :
+ Pair.of(etime, TimeUnit.NANOSECONDS);
+ }
+
+ /** Sends an JSON-encoded event to the audit service. */
+ private void sendEvent(AuditEvent event)
+ {
+ CreateRequest request = newCreateRequest(resourcePath("/ldap-access"), event.getValue());
+ requestHandler
+ .handleCreate(new RootContext(), request)
+ .thenOnException(new ExceptionHandler<ResourceException>()
+ {
+ @Override
+ public void handleException(ResourceException e)
+ {
+ logger.error(ERR_COMMON_AUDIT_UNABLE_TO_PROCESS_LOG_EVENT.get(StaticUtils.stackTraceToSingleLineString(e)));
+ }
+ })
+ .thenOnRuntimeException(new RuntimeExceptionHandler()
+ {
+ @Override
+ public void handleRuntimeException(RuntimeException e)
+ {
+ logger.error(ERR_COMMON_AUDIT_UNABLE_TO_PROCESS_LOG_EVENT.get(StaticUtils.stackTraceToSingleLineString(e)));
+ }
+ });
+ }
+
+}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditDependencyProvider.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditDependencyProvider.java
new file mode 100644
index 0000000..345bb7a
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditDependencyProvider.java
@@ -0,0 +1,85 @@
+/*
+ * 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 2013-2015 ForgeRock AS
+ */
+package org.opends.server.loggers;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import org.forgerock.audit.DependencyProvider;
+import org.forgerock.audit.providers.LocalHostNameProvider;
+import org.forgerock.audit.providers.ProductInfoProvider;
+import org.opends.server.util.DynamicConstants;
+
+/**
+ * Simple implementation of dependency provider for common audit.
+ */
+class CommonAuditDependencyProvider implements DependencyProvider
+{
+
+ @Override
+ public <T> T getDependency(Class<T> clazz) throws ClassNotFoundException
+ {
+ if (clazz.isAssignableFrom(LocalHostNameProvider.class))
+ {
+ return (T) new DJLocalHostNameProvider();
+ }
+ else if (clazz.isAssignableFrom(ProductInfoProvider.class))
+ {
+ return (T) new DJProductInfoProvider();
+ }
+ throw new ClassNotFoundException(String.format("Class %s could not be found", clazz));
+ }
+
+ /** DJ implementation for LocalHostNameProvider. */
+ private static class DJLocalHostNameProvider implements LocalHostNameProvider
+ {
+ @Override
+ public String getLocalHostName()
+ {
+ try
+ {
+ return InetAddress.getLocalHost().getHostName();
+ }
+ catch (UnknownHostException uhe)
+ {
+ return null;
+ }
+ }
+ }
+
+ /** DJ implementation for ProductInfoProvider. */
+ private static class DJProductInfoProvider implements ProductInfoProvider
+ {
+
+ @Override
+ public String getProductName()
+ {
+ return DynamicConstants.PRODUCT_NAME;
+ }
+
+ }
+
+}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditHTTPAccessLogPublisher.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditHTTPAccessLogPublisher.java
new file mode 100644
index 0000000..8e63998
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditHTTPAccessLogPublisher.java
@@ -0,0 +1,109 @@
+/*
+ * 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.loggers;
+
+import java.util.List;
+
+import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.json.resource.RequestHandler;
+import org.forgerock.opendj.config.server.ConfigChangeResult;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.HTTPAccessLogPublisherCfg;
+import org.opends.server.core.ServerContext;
+import org.opends.server.types.DN;
+
+/**
+ * Publishes HTTP access events to the common audit service.
+ * <p>
+ * This class actually does nothing because HTTP access logging is managed by a CHF filter.
+ * (See LdapHttpApplication)
+ *
+ * @param <T> the type of configuration
+ */
+class CommonAuditHTTPAccessLogPublisher<T extends HTTPAccessLogPublisherCfg>
+ extends HTTPAccessLogPublisher<T>
+ implements CommonAuditLogPublisher, ConfigurationChangeListener<T>
+{
+
+ /** Current configuration for this publisher. */
+ private T config;
+
+ @Override
+ public void setRequestHandler(RequestHandler handler)
+ {
+ // nothing to do
+ }
+
+ T getConfig()
+ {
+ return config;
+ }
+
+ @Override
+ public void initializeLogPublisher(final T cfg, ServerContext serverContext)
+ {
+ config = cfg;
+ }
+
+ @Override
+ public final DN getDN()
+ {
+ return config != null ? config.dn() : null;
+ }
+
+ @Override
+ public ConfigChangeResult applyConfigurationChange(final T config)
+ {
+ this.config = config;
+ return new ConfigChangeResult();
+ }
+
+ @Override
+ public boolean isConfigurationAcceptable(final T configuration,
+ final List<LocalizableMessage> unacceptableReasons)
+ {
+ return true;
+ }
+
+ @Override
+ public boolean isConfigurationChangeAcceptable(final T config, final List<LocalizableMessage> unacceptableReasons)
+ {
+ return true;
+ }
+
+ @Override
+ public void logRequestInfo(HTTPRequestInfo requestInfo)
+ {
+ // nothing to do
+ }
+
+ @Override
+ public void close()
+ {
+ // nothing to do
+ }
+
+}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditLogPublisher.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditLogPublisher.java
new file mode 100644
index 0000000..72cd1b8
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditLogPublisher.java
@@ -0,0 +1,44 @@
+/*
+ * 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.loggers;
+
+import org.forgerock.json.resource.RequestHandler;
+
+/**
+ * Common interface for all log publisher that log to Common Audit.
+ */
+interface CommonAuditLogPublisher
+{
+
+ /**
+ * Sets the handler to use for publishing audit events.
+ *
+ * @param handler
+ * The common audit handler accepting requests.
+ */
+ void setRequestHandler(RequestHandler handler);
+
+}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/CsvFileAccessLogPublisher.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/CsvFileAccessLogPublisher.java
new file mode 100644
index 0000000..4fdacd0
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/CsvFileAccessLogPublisher.java
@@ -0,0 +1,63 @@
+/*
+ * 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.loggers;
+
+import java.util.List;
+
+import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.opendj.config.server.ConfigChangeResult;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.CsvFileAccessLogPublisherCfg;
+
+/**
+ * Common Audit publisher which publishes access events to CSV files.
+ */
+final class CsvFileAccessLogPublisher
+ extends CommonAuditAccessLogPublisher<CsvFileAccessLogPublisherCfg>
+ implements ConfigurationChangeListener<CsvFileAccessLogPublisherCfg>
+{
+
+ @Override
+ boolean shouldLogControlOids()
+ {
+ return getConfig().isLogControlOids();
+ }
+
+ @Override
+ public ConfigChangeResult applyConfigurationChange(final CsvFileAccessLogPublisherCfg config)
+ {
+ setConfig(config);
+ return new ConfigChangeResult();
+ }
+
+ @Override
+ public boolean isConfigurationChangeAcceptable(final CsvFileAccessLogPublisherCfg config,
+ final List<LocalizableMessage> unacceptableReasons)
+ {
+ return true;
+ }
+
+}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/ExternalAccessLogPublisher.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/ExternalAccessLogPublisher.java
new file mode 100644
index 0000000..a6c2f13
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/ExternalAccessLogPublisher.java
@@ -0,0 +1,63 @@
+/*
+ * 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.loggers;
+
+import java.util.List;
+
+import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.opendj.config.server.ConfigChangeResult;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.ExternalAccessLogPublisherCfg;
+
+/**
+ * Common audit publisher which publishes access events to some external
+ * publisher.
+ */
+final class ExternalAccessLogPublisher
+ extends CommonAuditAccessLogPublisher<ExternalAccessLogPublisherCfg>
+ implements ConfigurationChangeListener<ExternalAccessLogPublisherCfg>
+{
+
+ @Override
+ boolean shouldLogControlOids()
+ {
+ return getConfig().isLogControlOids();
+ }
+
+ @Override
+ public ConfigChangeResult applyConfigurationChange(final ExternalAccessLogPublisherCfg config)
+ {
+ setConfig(config);
+ return new ConfigChangeResult();
+ }
+
+ @Override
+ public boolean isConfigurationChangeAcceptable(final ExternalAccessLogPublisherCfg config,
+ final List<LocalizableMessage> unacceptableReasons)
+ {
+ return true;
+ }
+}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/HTTPAccessLogger.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/HTTPAccessLogger.java
index 7a04082..a7d1dd2 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/loggers/HTTPAccessLogger.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/HTTPAccessLogger.java
@@ -128,6 +128,7 @@
public final synchronized void removeAllLogPublishers()
{
loggerStorage.removeAllLogPublishers();
+ getServerContext().getCommonAudit().shutdown();
}
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/loggers/OpenDJAccessEventBuilder.java b/opendj-server-legacy/src/main/java/org/opends/server/loggers/OpenDJAccessEventBuilder.java
new file mode 100644
index 0000000..a4dc445
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/loggers/OpenDJAccessEventBuilder.java
@@ -0,0 +1,267 @@
+/*
+ * 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.loggers;
+
+import static org.forgerock.json.JsonValue.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import org.forgerock.audit.events.AccessAuditEventBuilder;
+import org.forgerock.i18n.LocalizableMessageBuilder;
+import org.forgerock.json.JsonValue;
+import org.forgerock.util.Reject;
+import org.opends.server.core.ModifyDNOperation;
+import org.opends.server.core.SearchOperation;
+import org.opends.server.types.AdditionalLogItem;
+import org.opends.server.types.Control;
+import org.opends.server.types.Operation;
+
+/**
+ * Builder for /audit/access events specific to OpenDJ. This builder add LDAP
+ * specific fields to the common fields defined in AccessAuditEventBuilder.
+ *
+ * @param <T>
+ * This builder.
+ */
+class OpenDJAccessAuditEventBuilder<T extends OpenDJAccessAuditEventBuilder<T>> extends AccessAuditEventBuilder<T>
+{
+
+ private OpenDJAccessAuditEventBuilder()
+ {
+ super();
+ }
+
+ @SuppressWarnings("rawtypes")
+ public static <T> OpenDJAccessAuditEventBuilder<?> openDJAccessEvent()
+ {
+ return new OpenDJAccessAuditEventBuilder();
+ }
+
+ public T ldapAdditionalItems(Operation op)
+ {
+ String items = getAdditionalItemsAsString(op);
+ if (!items.isEmpty())
+ {
+ getLdapValue().put("items", items);
+ }
+ return self();
+ }
+
+ public T ldapAttr(String attr)
+ {
+ getLdapValue().put("attr", attr);
+ return self();
+ }
+
+ public T ldapConnectionId(long id)
+ {
+ getLdapValue().put("connId", id);
+ return self();
+ }
+
+ public T ldapControls(Operation operation)
+ {
+ JsonValue ldapValue = getLdapValue();
+ List<Control> requestControls = operation.getRequestControls();
+ if (!requestControls.isEmpty())
+ {
+ ldapValue.put("reqControls", getControlsAsString(requestControls));
+ }
+ List<Control> responseControls = operation.getResponseControls();
+ if (!responseControls.isEmpty())
+ {
+ ldapValue.put("respControls", getControlsAsString(responseControls));
+ }
+ return self();
+ }
+
+ public T ldapDn(String dn)
+ {
+ getLdapValue().put("dn", dn);
+ return self();
+ }
+
+ public T ldapFailureMessage(String msg)
+ {
+ getLdapValue().put("failureReason", msg);
+ return self();
+ }
+
+ public T ldapIds(Operation op)
+ {
+ JsonValue ldapValue = getLdapValue();
+ ldapValue.put("connId", op.getConnectionID());
+ ldapValue.put("msgId", op.getMessageID());
+ return self();
+ }
+
+ public T ldapIdToAbandon(int id)
+ {
+ getLdapValue().put("idToAbandon", id);
+ return self();
+ }
+
+ public T ldapMaskedResultAndMessage(Operation operation)
+ {
+ JsonValue ldapValue = getLdapValue();
+ if (operation.getMaskedResultCode() != null)
+ {
+ ldapValue.put("maskedResult", operation.getMaskedResultCode().intValue());
+ }
+ final LocalizableMessageBuilder maskedMsg = operation.getMaskedErrorMessage();
+ if (maskedMsg != null && maskedMsg.length() > 0)
+ {
+ ldapValue.put("maskedMessage", maskedMsg.toString());
+ }
+ return self();
+ }
+
+ public T ldapMessage(String msg)
+ {
+ getLdapValue().put("message", msg);
+ return self();
+ }
+
+ public T ldapName(String name)
+ {
+ getLdapValue().put("name", name);
+ return self();
+ }
+
+ public T ldapModifyDN(ModifyDNOperation modifyDNOperation)
+ {
+ JsonValue ldapValue = getLdapValue();
+ ldapValue.put("newRDN", modifyDNOperation.getRawNewRDN().toString());
+ ldapValue.put("newSup", modifyDNOperation.getRawNewSuperior().toString());
+ ldapValue.put("deleteOldRDN", modifyDNOperation.deleteOldRDN());
+ return self();
+ }
+
+ public T ldapNEntries(int nbEntries)
+ {
+ getLdapValue().put("nentries", nbEntries);
+ return self();
+ }
+
+ public T ldapOid(String oid)
+ {
+ getLdapValue().put("oid", oid);
+ return self();
+ }
+
+ public T ldapProtocolVersion(String version)
+ {
+ getLdapValue().put("version", version);
+ return self();
+ }
+
+ public T ldapReason(String msg)
+ {
+ getLdapValue().put("reason", msg);
+ return self();
+ }
+
+ public T ldapSearch(SearchOperation searchOperation)
+ {
+ JsonValue ldapValue = getLdapValue();
+ // for search base, re-uses the "dn" field
+ ldapValue.put("dn", searchOperation.getRawBaseDN().toString());
+ ldapValue.put("scope", searchOperation.getScope().toString());
+ ldapValue.put("filter", searchOperation.getRawFilter().toString());
+
+ final Set<String> attrs = searchOperation.getAttributes();
+ if ((attrs == null) || attrs.isEmpty())
+ {
+ ldapValue.put("attrs", Arrays.asList("ALL"));
+ }
+ else
+ {
+ ldapValue.put("attrs", new ArrayList<>(attrs));
+ }
+ return self();
+ }
+
+ public T ldapSync(Operation operation)
+ {
+ if (operation.isSynchronizationOperation())
+ {
+ getLdapValue().put("opType", "sync");
+ }
+ return self();
+ }
+
+ public T ldapAuthType(String type)
+ {
+ getLdapValue().put("authType", type);
+ return self();
+ }
+
+ public T runAs(String id)
+ {
+ Reject.ifNull(id);
+ jsonValue.put("runAs", id);
+ return self();
+ }
+
+ private List<String> getControlsAsString(List<Control> controls)
+ {
+ List<String> list = new ArrayList<>();
+ for (final Control control : controls)
+ {
+ list.add(control.getOID());
+ }
+ return list;
+ }
+
+ private String getAdditionalItemsAsString(Operation operation)
+ {
+ StringBuilder items = new StringBuilder();
+ for (final AdditionalLogItem item : operation.getAdditionalLogItems())
+ {
+ items.append(' ');
+ item.toString(items);
+ }
+ return items.toString();
+ }
+
+ private JsonValue getLdapValue()
+ {
+ final JsonValue ldapValue;
+ if (jsonValue.isDefined("ldap"))
+ {
+ ldapValue = jsonValue.get("ldap");
+ }
+ else
+ {
+ ldapValue = json(object());
+ jsonValue.put("ldap", ldapValue);
+ }
+ return ldapValue;
+ }
+}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/LDIFConnectionHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/LDIFConnectionHandler.java
index a252c8b..90c4fa8 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/LDIFConnectionHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/LDIFConnectionHandler.java
@@ -42,6 +42,7 @@
import org.opends.server.api.ClientConnection;
import org.opends.server.api.ConnectionHandler;
import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.ServerContext;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.forgerock.opendj.config.server.ConfigChangeResult;
@@ -122,7 +123,7 @@
/** {@inheritDoc} */
@Override
- public void initializeConnectionHandler(LDIFConnectionHandlerCfg
+ public void initializeConnectionHandler(ServerContext serverContext, LDIFConnectionHandlerCfg
configuration)
{
String ldifDirectoryPath = configuration.getLDIFDirectory();
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CommonAuditHttpAccessAuditFilter.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CommonAuditHttpAccessAuditFilter.java
new file mode 100644
index 0000000..83d2f26
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CommonAuditHttpAccessAuditFilter.java
@@ -0,0 +1,169 @@
+/*
+ * 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 2013-2015 ForgeRock AS
+ */
+package org.opends.server.protocols.http;
+
+import static org.forgerock.audit.events.AccessAuditEventBuilder.accessEvent;
+import static org.forgerock.json.resource.Requests.newCreateRequest;
+import static org.forgerock.json.resource.ResourcePath.resourcePath;
+
+import java.util.concurrent.TimeUnit;
+
+import org.forgerock.audit.events.AccessAuditEventBuilder;
+import org.forgerock.http.Filter;
+import org.forgerock.http.Handler;
+import org.forgerock.http.MutableUri;
+import org.forgerock.http.protocol.Form;
+import org.forgerock.http.protocol.Request;
+import org.forgerock.http.protocol.Response;
+import org.forgerock.http.protocol.Status;
+import org.forgerock.json.resource.CreateRequest;
+import org.forgerock.json.resource.RequestHandler;
+import org.forgerock.services.context.ClientContext;
+import org.forgerock.services.context.Context;
+import org.forgerock.services.context.RequestAuditContext;
+import org.forgerock.services.context.TransactionIdContext;
+import org.forgerock.util.promise.NeverThrowsException;
+import org.forgerock.util.promise.Promise;
+import org.forgerock.util.promise.ResultHandler;
+import org.forgerock.util.promise.RuntimeExceptionHandler;
+import org.forgerock.util.time.TimeService;
+
+/**
+ * This filter aims to send some access audit events to the AuditService managed as a CREST handler.
+ */
+public class CommonAuditHttpAccessAuditFilter implements Filter {
+
+ private final RequestHandler auditServiceHandler;
+ private final TimeService time;
+ private final String productName;
+
+ /**
+ * Constructs a new HttpAccessAuditFilter.
+ *
+ * @param productName The name of product generating the event.
+ * @param auditServiceHandler The {@link RequestHandler} to publish the events.
+ * @param time The {@link TimeService} to use.
+ */
+ public CommonAuditHttpAccessAuditFilter(String productName, RequestHandler auditServiceHandler, TimeService time) {
+ this.productName = productName;
+ this.auditServiceHandler = auditServiceHandler;
+ this.time = time;
+ }
+
+ @Override
+ public Promise<Response, NeverThrowsException> filter(Context context, Request request, Handler next) {
+ TransactionIdContext txContext = context.asContext(TransactionIdContext.class);
+ ClientContext clientContext = context.asContext(ClientContext.class);
+
+ AccessAuditEventBuilder<?> accessAuditEventBuilder = accessEvent();
+
+ String protocol = clientContext.isSecure() ? "HTTPS" : "HTTP";
+ accessAuditEventBuilder
+ .eventName(productName + "-" + protocol + "-ACCESS")
+ .timestamp(time.now())
+ .transactionId(txContext.getTransactionId().getValue())
+ .server(clientContext.getLocalAddress(),
+ clientContext.getLocalPort(),
+ clientContext.getLocalName())
+ .client(clientContext.getRemoteAddress(),
+ clientContext.getRemotePort(),
+ clientContext.getRemoteHost())
+ .httpRequest(clientContext.isSecure(),
+ request.getMethod(),
+ getRequestPath(request.getUri()),
+ new Form().fromRequestQuery(request),
+ request.getHeaders().copyAsMultiMapOfStrings());
+
+ try {
+ final Promise<Response, NeverThrowsException> promise;
+ promise = next.handle(context, request)
+ .thenOnResult(onResult(context, accessAuditEventBuilder));
+ promise.thenOnRuntimeException(onRuntimeException(context, accessAuditEventBuilder));
+ return promise;
+ } catch (RuntimeException re) {
+ onRuntimeException(context, accessAuditEventBuilder).handleRuntimeException(re);
+ throw re;
+ }
+ }
+
+ // See HttpContext.getRequestPath
+ private String getRequestPath(MutableUri uri) {
+ return new StringBuilder()
+ .append(uri.getScheme())
+ .append("://")
+ .append(uri.getRawAuthority())
+ .append(uri.getRawPath()).toString();
+ }
+
+ private ResultHandler<? super Response> onResult(final Context context,
+ final AccessAuditEventBuilder<?> accessAuditEventBuilder) {
+ return new ResultHandler<Response>() {
+ @Override
+ public void handleResult(Response response) {
+ sendAuditEvent(response, context, accessAuditEventBuilder);
+ }
+
+ };
+ }
+
+ private RuntimeExceptionHandler onRuntimeException(final Context context,
+ final AccessAuditEventBuilder<?> accessAuditEventBuilder) {
+ return new RuntimeExceptionHandler() {
+ @Override
+ public void handleRuntimeException(RuntimeException exception) {
+ // TODO How to be sure that the final status code sent back with the response will be a 500 ?
+ Response response = new Response(Status.INTERNAL_SERVER_ERROR);
+ sendAuditEvent(response, context, accessAuditEventBuilder);
+ }
+ };
+ }
+
+ private void sendAuditEvent(final Response response,
+ final Context context,
+ final AccessAuditEventBuilder<?> accessAuditEventBuilder) {
+ RequestAuditContext requestAuditContext = context.asContext(RequestAuditContext.class);
+ long elapsedTime = time.now() - requestAuditContext.getRequestReceivedTime();
+ accessAuditEventBuilder.httpResponse(response.getHeaders().copyAsMultiMapOfStrings());
+ accessAuditEventBuilder.response(mapResponseStatus(response.getStatus()),
+ String.valueOf(response.getStatus().getCode()),
+ elapsedTime,
+ TimeUnit.MILLISECONDS);
+
+ CreateRequest request =
+ newCreateRequest(resourcePath("/http-access"), accessAuditEventBuilder.toEvent().getValue());
+ auditServiceHandler.handleCreate(context, request);
+ }
+
+ private static AccessAuditEventBuilder.ResponseStatus mapResponseStatus(Status status) {
+ switch(status.getFamily()) {
+ case CLIENT_ERROR:
+ case SERVER_ERROR:
+ return AccessAuditEventBuilder.ResponseStatus.FAILED;
+ default:
+ return AccessAuditEventBuilder.ResponseStatus.SUCCESSFUL;
+ }
+ }
+}
\ No newline at end of file
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CommonAuditHttpAccessCheckEnabledFilter.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CommonAuditHttpAccessCheckEnabledFilter.java
new file mode 100644
index 0000000..47e3024
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CommonAuditHttpAccessCheckEnabledFilter.java
@@ -0,0 +1,68 @@
+/*
+ * 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 2013-2015 ForgeRock AS
+ */
+package org.opends.server.protocols.http;
+
+import org.forgerock.http.Filter;
+import org.forgerock.http.Handler;
+import org.forgerock.http.protocol.Request;
+import org.forgerock.http.protocol.Response;
+import org.forgerock.services.context.Context;
+import org.forgerock.util.promise.NeverThrowsException;
+import org.forgerock.util.promise.Promise;
+import org.opends.server.core.ServerContext;
+
+/**
+ * Filter that checks if at least one HTTP access logger is enabled for common audit, and short-circuit
+ * the corresponding filter if this is not the case.
+ */
+class CommonAuditHttpAccessCheckEnabledFilter implements Filter
+{
+
+ private final ServerContext serverContext;
+
+ /** The HTTP access audit filter to go through if HTTP access logger is enabled. */
+ private final Filter httpAccessAuditFilter;
+
+ CommonAuditHttpAccessCheckEnabledFilter(ServerContext serverContext, Filter httpAccessAuditFilter)
+ {
+ this.serverContext = serverContext;
+ this.httpAccessAuditFilter = httpAccessAuditFilter;
+ }
+
+ @Override
+ public Promise<Response, NeverThrowsException> filter(
+ final Context context, final Request request, final Handler next)
+ {
+ if (serverContext.getCommonAudit().isHttpAccessLogEnabled())
+ {
+ // introduce HttpAccessAuditFilter into the filter chain
+ return httpAccessAuditFilter.filter(context, request, next);
+ }
+ // avoid HttpAccessAuditFilter, follow the filter chain
+ return next.handle(context, request);
+ }
+
+}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
index aaaef27..ed36968 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
@@ -36,6 +36,7 @@
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
+
import java.io.IOException;
import java.net.InetAddress;
import java.util.Arrays;
@@ -80,6 +81,7 @@
import org.opends.server.api.ServerShutdownListener;
import org.opends.server.api.TrustManagerProvider;
import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.ServerContext;
import org.opends.server.extensions.NullKeyManagerProvider;
import org.opends.server.extensions.NullTrustManagerProvider;
import org.opends.server.loggers.HTTPAccessLogger;
@@ -162,6 +164,8 @@
/** The SSL engine configurator is used for obtaining default SSL parameters. */
private SSLEngineConfigurator sslEngineConfigurator;
+ private ServerContext serverContext;
+
/** Default constructor. It is invoked by reflection to create this {@link ConnectionHandler}. */
public HTTPConnectionHandler()
{
@@ -419,9 +423,10 @@
}
@Override
- public void initializeConnectionHandler(HTTPConnectionHandlerCfg config)
+ public void initializeConnectionHandler(ServerContext serverContext, HTTPConnectionHandlerCfg config)
throws ConfigException, InitializationException
{
+ this.serverContext = serverContext;
this.enabled = config.isEnabled();
if (friendlyName == null)
@@ -782,7 +787,8 @@
{
// Create and deploy the Web app context
final WebappContext ctx = new WebappContext(servletName);
- ctx.addServlet(servletName, new HttpFrameworkServlet(new LdapHttpApplication(this))).addMapping(urlPatterns);
+ ctx.addServlet(servletName,
+ new HttpFrameworkServlet(new LdapHttpApplication(serverContext, this))).addMapping(urlPatterns);
ctx.deploy(this.httpServer);
}
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 0850d8c..0dd19b6 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,6 +34,7 @@
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;
@@ -57,7 +58,10 @@
import org.forgerock.util.Factory;
import org.forgerock.util.promise.NeverThrowsException;
import org.forgerock.util.promise.Promise;
+import org.forgerock.util.time.TimeService;
import org.opends.messages.ProtocolMessages;
+import org.opends.server.core.ServerContext;
+import org.opends.server.util.DynamicConstants;
/** Main class of the HTTP Connection Handler web application */
class LdapHttpApplication implements HttpApplication
@@ -115,9 +119,11 @@
private HTTPConnectionHandler connectionHandler;
private LdapHttpHandler handler;
private CollectClientConnectionsFilter filter;
+ private final ServerContext serverContext;
- LdapHttpApplication(HTTPConnectionHandler connectionHandler)
+ LdapHttpApplication(ServerContext serverContext, HTTPConnectionHandler connectionHandler)
{
+ this.serverContext = serverContext;
this.connectionHandler = connectionHandler;
}
@@ -132,7 +138,15 @@
handler = new LdapHttpHandler(configuration);
filter = new CollectClientConnectionsFilter(connectionHandler, getAuthenticationConfig(configuration));
configuration.verifyAllKeysAccessed();
- return Handlers.chainOf(handler, filter);
+
+ TransactionIdInboundFilter transactionIdFilter = new TransactionIdInboundFilter();
+ RequestHandler requestHandler = serverContext.getCommonAudit().getAuditServiceForHttpAccessLog();
+ CommonAuditHttpAccessAuditFilter httpAccessFilter =
+ new CommonAuditHttpAccessAuditFilter(DynamicConstants.PRODUCT_NAME, requestHandler, TimeService.SYSTEM);
+ CommonAuditHttpAccessCheckEnabledFilter checkFilter =
+ new CommonAuditHttpAccessCheckEnabledFilter(serverContext, httpAccessFilter);
+
+ return Handlers.chainOf(handler, transactionIdFilter, checkFilter, filter);
}
catch (final Exception e)
{
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/internal/InternalConnectionHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/internal/InternalConnectionHandler.java
index 377cc06..2a346d3 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/internal/InternalConnectionHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/internal/InternalConnectionHandler.java
@@ -29,12 +29,14 @@
+
import java.util.Collection;
import java.util.LinkedList;
import org.opends.server.admin.std.server.*;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.ConnectionHandler;
+import org.opends.server.core.ServerContext;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.types.DN;
import org.opends.server.types.InitializationException;
@@ -108,6 +110,7 @@
* Initializes this connection handler provider based on the
* information in the provided connection handler configuration.
*
+ * @param serverContext The server context.
* @param configuration The connection handler configuration that
* contains the information to use to
* initialize this connection handler.
@@ -123,8 +126,7 @@
* configuration.
*/
@Override
- public void initializeConnectionHandler(
- ConnectionHandlerCfg configuration)
+ public void initializeConnectionHandler(ServerContext serverContext, ConnectionHandlerCfg configuration)
throws ConfigException, InitializationException
{
this.configuration = configuration;
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/jmx/JmxConnectionHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/jmx/JmxConnectionHandler.java
index 8e1201e..2f33cab 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/jmx/JmxConnectionHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/jmx/JmxConnectionHandler.java
@@ -49,6 +49,7 @@
import org.opends.server.api.ConnectionHandler;
import org.opends.server.api.ServerShutdownListener;
import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.ServerContext;
import org.forgerock.opendj.config.server.ConfigChangeResult;
import org.opends.server.types.DN;
import org.opends.server.types.HostPort;
@@ -299,7 +300,7 @@
/** {@inheritDoc} */
@Override
- public void initializeConnectionHandler(JMXConnectionHandlerCfg config)
+ public void initializeConnectionHandler(ServerContext serverContext, JMXConnectionHandlerCfg config)
throws ConfigException, InitializationException
{
// Configuration is ok.
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPConnectionHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
index b358ea2..032a100 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
@@ -58,6 +58,7 @@
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.PluginConfigManager;
import org.opends.server.core.QueueingStrategy;
+import org.opends.server.core.ServerContext;
import org.opends.server.core.WorkQueueStrategy;
import org.opends.server.extensions.NullKeyManagerProvider;
import org.opends.server.extensions.NullTrustManagerProvider;
@@ -642,7 +643,7 @@
/** {@inheritDoc} */
@Override
- public void initializeConnectionHandler(LDAPConnectionHandlerCfg config)
+ public void initializeConnectionHandler(ServerContext serverContext, LDAPConnectionHandlerCfg config)
throws ConfigException, InitializationException
{
if (friendlyName == null)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/util/ServerConstants.java b/opendj-server-legacy/src/main/java/org/opends/server/util/ServerConstants.java
index 825edbb..9e34a29 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/util/ServerConstants.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/util/ServerConstants.java
@@ -2305,7 +2305,10 @@
public static final String OID_SUBTREE_DELETE_CONTROL =
"1.2.840.113556.1.4.805";
-
+ /**
+ * The OID for the transactionId control.
+ */
+ public static final String OID_TRANSACTION_ID_CONTROL = "1.3.6.1.4.1.36733.2.1.5.1";
/**
* The OID for the paged results control defined in RFC 2696.
diff --git a/opendj-server-legacy/src/main/resources/org/opends/server/loggers/audit-config.json b/opendj-server-legacy/src/main/resources/org/opends/server/loggers/audit-config.json
new file mode 100644
index 0000000..f010de4
--- /dev/null
+++ b/opendj-server-legacy/src/main/resources/org/opends/server/loggers/audit-config.json
@@ -0,0 +1,402 @@
+{
+ "additionalTopics" : {
+ "http-access": {
+ "schema": {
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "id": "/",
+ "type": "object",
+ "properties": {
+ "_id": {
+ "description": "org.forgerock.audit.events.access.id",
+ "type": "string"
+ },
+ "timestamp": {
+ "description": "org.forgerock.audit.events.access.timestamp",
+ "type": "string"
+ },
+ "eventName": {
+ "description": "org.forgerock.audit.events.access.eventName",
+ "type": "string"
+ },
+ "transactionId": {
+ "description": "org.forgerock.audit.events.access.transactionId",
+ "type": "string"
+ },
+ "userId": {
+ "description": "org.forgerock.audit.events.access.userId",
+ "type": "string"
+ },
+ "trackingIds": {
+ "description": "org.forgerock.audit.events.access.trackingIds",
+ "type": "array",
+ "items": {
+ "id": "0",
+ "type": "string"
+ }
+ },
+ "server": {
+ "type": "object",
+ "properties": {
+ "ip": {
+ "description": "org.forgerock.audit.events.access.server.ip",
+ "type": "string"
+ },
+ "port": {
+ "description": "org.forgerock.audit.events.access.server.port",
+ "type": "string"
+ }
+ }
+ },
+ "client": {
+ "type": "object",
+ "properties": {
+ "host": {
+ "description": "org.forgerock.audit.events.access.client.host",
+ "type": "string"
+ },
+ "ip": {
+ "description": "org.forgerock.audit.events.access.client.ip",
+ "type": "string"
+ },
+ "port": {
+ "description": "org.forgerock.audit.events.access.client.port",
+ "type": "string"
+ }
+ }
+ },
+ "request": {
+ "type": "object",
+ "properties": {
+ "protocol": {
+ "description": "org.forgerock.audit.events.access.request.protocol",
+ "type": "string"
+ },
+ "operation": {
+ "description": "org.forgerock.audit.events.access.request.operation",
+ "type": "string"
+ },
+ "detail": {
+ "description": "org.forgerock.audit.events.access.request.detail",
+ "type": "object"
+ }
+ }
+ },
+ "http": {
+ "type": "object",
+ "properties": {
+ "request": {
+ "description": "org.forgerock.audit.events.access.http.request",
+ "type": "object",
+ "properties": {
+ "secure": {
+ "description": "org.forgerock.audit.events.access.http.secure",
+ "type": "boolean"
+ },
+ "method": {
+ "description": "org.forgerock.audit.events.access.http.method",
+ "type": "string"
+ },
+ "path": {
+ "description": "org.forgerock.audit.events.access.http.path",
+ "type": "string"
+ },
+ "queryParameters": {
+ "description": "org.forgerock.audit.events.access.http.queryParameters",
+ "type": "object",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "headers": {
+ "description": "org.forgerock.audit.events.access.http.headers",
+ "type": "object",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ },
+ "cookies": {
+ "description": "org.forgerock.audit.events.access.http.cookies",
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "response": {
+ "description": "org.forgerock.audit.events.access.http.response",
+ "type": "object",
+ "properties": {
+ "headers": {
+ "description": "org.forgerock.audit.events.access.http.request.headers",
+ "type": "object",
+ "additionalProperties": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "response": {
+ "type": "object",
+ "properties": {
+ "status": {
+ "description": "org.forgerock.audit.events.access.response.status",
+ "type": "string"
+ },
+ "statusCode": {
+ "description": "org.forgerock.audit.events.access.response.statusCode",
+ "type": "string"
+ },
+ "detail": {
+ "description": "org.forgerock.audit.events.access.response.detail",
+ "type": "string"
+ },
+ "elapsedTime": {
+ "description": "org.forgerock.audit.events.access.response.elapsedTime",
+ "type": "integer"
+ },
+ "elapsedTimeUnits": {
+ "description": "org.forgerock.audit.events.access.response.elapsedTimeUnits",
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ },
+ "ldap-access": {
+ "schema": {
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "id": "/",
+ "type": "object",
+ "properties": {
+ "_id": {
+ "description": "org.forgerock.audit.events.access.id",
+ "type": "string"
+ },
+ "timestamp": {
+ "description": "org.forgerock.audit.events.access.timestamp",
+ "type": "string"
+ },
+ "eventName": {
+ "description": "org.forgerock.audit.events.access.eventName",
+ "type": "string"
+ },
+ "transactionId": {
+ "description": "org.forgerock.audit.events.access.transactionId",
+ "type": "string"
+ },
+ "userId": {
+ "description": "org.forgerock.audit.events.access.userId",
+ "type": "string"
+ },
+ "runAs": {
+ "description": "org.forgerock.audit.events.activity.runAs",
+ "type": "string"
+ },
+ "server": {
+ "type": "object",
+ "properties": {
+ "ip": {
+ "description": "org.forgerock.audit.events.access.server.ip",
+ "type": "string"
+ },
+ "port": {
+ "description": "org.forgerock.audit.events.access.server.port",
+ "type": "string"
+ }
+ }
+ },
+ "client": {
+ "type": "object",
+ "properties": {
+ "host": {
+ "description": "org.forgerock.audit.events.access.client.host",
+ "type": "string"
+ },
+ "ip": {
+ "description": "org.forgerock.audit.events.access.client.ip",
+ "type": "string"
+ },
+ "port": {
+ "description": "org.forgerock.audit.events.access.client.port",
+ "type": "string"
+ }
+ }
+ },
+ "request": {
+ "type": "object",
+ "properties": {
+ "protocol": {
+ "description": "org.forgerock.audit.events.access.request.protocol",
+ "type": "string"
+ },
+ "operation": {
+ "description": "org.forgerock.audit.events.access.request.operation",
+ "type": "string"
+ }
+ }
+ },
+ "response": {
+ "type": "object",
+ "properties": {
+ "status": {
+ "description": "org.forgerock.audit.events.access.response.status",
+ "type": "string"
+ },
+ "statusCode": {
+ "description": "org.forgerock.audit.events.access.response.statusCode",
+ "type": "string"
+ },
+ "detail": {
+ "description": "org.forgerock.audit.events.access.response.detail",
+ "type": "string"
+ },
+ "elapsedTime": {
+ "description": "org.forgerock.audit.events.access.response.elapsedTime",
+ "type": "integer"
+ },
+ "elapsedTimeUnits": {
+ "description": "org.forgerock.audit.events.access.response.elapsedTimeUnits",
+ "type": "string"
+ }
+ }
+ },
+ "ldap": {
+ "id": "ldap",
+ "type": "object",
+ "properties": {
+ "connId": {
+ "id": "connId",
+ "type": "string"
+ },
+ "msgId": {
+ "id": "msgId",
+ "type": "string"
+ },
+ "dn": {
+ "id": "dn",
+ "type": "string"
+ },
+ "scope": {
+ "id": "scope",
+ "type": "string"
+ },
+ "filter": {
+ "id": "filter",
+ "type": "string"
+ },
+ "attrs": {
+ "id": "attrs",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "nentries": {
+ "id": "nentries",
+ "type": "string"
+ },
+ "authType": {
+ "id": "authType",
+ "type": "string"
+ },
+ "reqControls": {
+ "id": "reqControls",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "respControls": {
+ "id": "respControls",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "additionalItems": {
+ "id": "additionalItems",
+ "type": "string"
+ },
+ "items" : {
+ "id" : "items",
+ "type" : "string"
+ },
+ "attr" : {
+ "id" : "attr",
+ "type" : "string"
+ },
+ "failureReason" : {
+ "id" : "failureReason",
+ "type" : "string"
+ },
+ "idToAbandon" : {
+ "id" : "idToAbandon",
+ "type" : "integer"
+ },
+ "maskedResult" : {
+ "id" : "maskedResult",
+ "type" : "integer"
+ },
+ "maskedMessage" : {
+ "id" : "maskedMessage",
+ "type" : "string"
+ },
+ "message" : {
+ "id" : "message",
+ "type" : "string"
+ },
+ "name" : {
+ "id" : "name",
+ "type" : "string"
+ },
+ "newRDN" : {
+ "id" : "newRDN",
+ "type" : "string"
+ },
+ "newSup" : {
+ "id" : "newSup",
+ "type" : "string"
+ },
+ "deleteOldRDN" : {
+ "id" : "deleteOldRDN",
+ "type" : "boolean"
+ },
+ "oid" : {
+ "id" : "oid",
+ "type" : "string"
+ },
+ "version" : {
+ "id" : "version",
+ "type" : "string"
+ },
+ "reason" : {
+ "id" : "reason",
+ "type" : "string"
+ },
+ "opType": {
+ "id": "opType",
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/opendj-server-legacy/src/messages/org/opends/messages/config.properties b/opendj-server-legacy/src/messages/org/opends/messages/config.properties
index 0d138a9..2123ab5 100644
--- a/opendj-server-legacy/src/messages/org/opends/messages/config.properties
+++ b/opendj-server-legacy/src/messages/org/opends/messages/config.properties
@@ -942,3 +942,9 @@
WARN_CONFIG_LOGGING_UNSUPPORTED_FIELDS_IN_LOG_FORMAT_734=The log format \
for %s contains the folowing unsupported fields: %s. Their output will be \
replaced with a dash ("-") character
+ERR_CONFIG_LOGGER_CANNOT_UPDATE_LOGGER_735=An error occurred while \
+ attempting to update a Directory Server logger from the information in \
+ configuration entry %s: %s
+ERR_CONFIG_LOGGER_CANNOT_DELETE_LOGGER_736=An error occurred while \
+ attempting to delete a Directory Server logger from the information in \
+ configuration entry %s: %s
\ No newline at end of file
diff --git a/opendj-server-legacy/src/messages/org/opends/messages/logger.properties b/opendj-server-legacy/src/messages/org/opends/messages/logger.properties
index 8625a26..658cb57 100644
--- a/opendj-server-legacy/src/messages/org/opends/messages/logger.properties
+++ b/opendj-server-legacy/src/messages/org/opends/messages/logger.properties
@@ -69,3 +69,34 @@
free disk space in the partition containing log file %s: %s
ERR_LOGGER_ERROR_ENFORCING_RETENTION_POLICY_12=Error occurred while \
enforcing retention policy %s for logger %s: %s
+ERR_COMMON_AUDIT_CREATE_13=Error occurred while creating common audit \
+ facility: %s
+ERR_COMMON_AUDIT_ADD_OR_UPDATE_LOG_PUBLISHER_14=Error while creating \
+ or updating common audit log publisher %s: %s
+ERR_COMMON_AUDIT_REMOVE_LOG_PUBLISHER_15=Error while removing common audit log \
+ publisher %s: %s
+ERR_COMMON_AUDIT_UNSUPPORTED_HANDLER_TYPE_16=Error while adding common audit log \
+ publisher %s, the publisher has an unsupported handler type
+ERR_COMMON_AUDIT_EXTERNAL_HANDLER_JSON_FILE_17=Error while reading \
+ JSON configuration file %s while creating common audit external log publisher %s: %s
+ERR_COMMON_AUDIT_EXTERNAL_HANDLER_CREATION_18=Error while creating \
+ common audit external log publisher %s: %s
+ERR_COMMON_AUDIT_CSV_HANDLER_CREATION_19=Error while creating \
+ CSV log publisher %s: %s
+ERR_COMMON_AUDIT_UNSUPPORTED_LOG_ROTATION_POLICY_20=Error while adding common audit \
+ CSV log publisher %s, the publisher defines an unsupported log rotation policy %s
+ERR_COMMON_AUDIT_UNSUPPORTED_LOG_RETENTION_POLICY_21=Error while adding common audit \
+ CSV log publisher %s, the publisher defines an unsupported log retention policy %s
+ERR_COMMON_AUDIT_UNSUPPORTED_LOG_PUBLISHER_22=Error while processing common audit \
+ log publisher %s, this type of log publisher is unsupported
+ERR_COMMON_AUDIT_CSV_HANDLER_DELIMITER_CHAR_23=Error while processing common audit \
+ log publisher %s, delimiter char '%s' should not contains more than one character
+ERR_COMMON_AUDIT_CSV_HANDLER_QUOTE_CHAR_24=Error while processing common audit \
+ log publisher %s, quote char '%s' should not contains more than one character
+ERR_COMMON_AUDIT_INVALID_TIME_OF_DAY_25=Error while processing common audit \
+ log publisher %s, time of the day value '%s' for fixed time log rotation policy \
+ is not valid, it should use a 24-hour format "HHmm" : %s
+ERR_COMMON_AUDIT_INVALID_TRANSACTION_ID_26=Error while decoding a transaction id control \
+ received from a request: %s
+ERR_COMMON_AUDIT_UNABLE_TO_PROCESS_LOG_EVENT_27=Error while processing a log event \
+ for common audit: %s
\ No newline at end of file
diff --git a/opendj-server-legacy/src/messages/org/opends/messages/protocol.properties b/opendj-server-legacy/src/messages/org/opends/messages/protocol.properties
index 9560963..92e750d 100644
--- a/opendj-server-legacy/src/messages/org/opends/messages/protocol.properties
+++ b/opendj-server-legacy/src/messages/org/opends/messages/protocol.properties
@@ -917,3 +917,5 @@
ERR_INVALID_KEYSTORE_1527=No usable key was found for '%s'. Verify the keystore content
INFO_DISABLE_CONNECTION_1528=Disabling %s
ERR_INITIALIZE_HTTP_CONNECTION_HANDLER_1529=Failed to initialize Http Connection Handler
+ERR_TRANSACTION_ID_CONTROL_HAS_NO_VALUE_1530=No value was provided for the transaction \
+ id control, whereas an UTF-8 encoded value is expected
\ No newline at end of file
diff --git a/opendj-server-legacy/src/snmp/src/org/opends/server/snmp/SNMPConnectionHandler.java b/opendj-server-legacy/src/snmp/src/org/opends/server/snmp/SNMPConnectionHandler.java
index 612fbf0..01ae2f6 100644
--- a/opendj-server-legacy/src/snmp/src/org/opends/server/snmp/SNMPConnectionHandler.java
+++ b/opendj-server-legacy/src/snmp/src/org/opends/server/snmp/SNMPConnectionHandler.java
@@ -47,6 +47,7 @@
import org.opends.server.admin.std.server.SNMPConnectionHandlerCfg;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.ServerContext;
import org.opends.server.types.InitializationException;
import static org.opends.messages.ProtocolMessages.*;
@@ -95,8 +96,8 @@
/**
* {@inheritDoc}
*/
- public void initializeConnectionHandler(
- SNMPConnectionHandlerCfg configuration)
+ @Override
+ public void initializeConnectionHandler(ServerContext serverContext, SNMPConnectionHandlerCfg configuration)
throws ConfigException, InitializationException {
if (configuration == null) {
@@ -207,6 +208,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public boolean isConfigurationChangeAcceptable(
SNMPConnectionHandlerCfg configuration,
List<LocalizableMessage> unacceptableReasons) {
@@ -217,6 +219,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public ConfigChangeResult applyConfigurationChange(
SNMPConnectionHandlerCfg configuration) {
if ((this.isOperational) && (this.provider!=null)){
@@ -228,6 +231,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public DN getComponentEntryDN() {
return this.currentConfig.dn();
}
@@ -235,6 +239,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public String getClassName() {
return SNMPConnectionHandler.class.getName();
}
@@ -242,6 +247,7 @@
/**
* {@inheritDoc}
*/
+ @Override
public LinkedHashMap<String, String> getAlerts() {
LinkedHashMap<String, String> alerts =
new LinkedHashMap<String, String>();
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/protocols/internal/InternalConnectionHandlerTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/protocols/internal/InternalConnectionHandlerTestCase.java
index a58dc48..06c961d 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/protocols/internal/InternalConnectionHandlerTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/protocols/internal/InternalConnectionHandlerTestCase.java
@@ -28,11 +28,13 @@
+import static org.mockito.Mockito.mock;
+
import java.util.Collection;
import org.testng.annotations.Test;
-
import org.opends.server.api.ClientConnection;
+import org.opends.server.core.ServerContext;
import static org.testng.Assert.*;
@@ -57,7 +59,7 @@
InternalConnectionHandler handler = InternalConnectionHandler.getInstance();
assertNotNull(handler);
- handler.initializeConnectionHandler(null);
+ handler.initializeConnectionHandler(mock(ServerContext.class), null);
}
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/protocols/ldap/LdapTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/protocols/ldap/LdapTestCase.java
index ca16b5b..bf328a0 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/protocols/ldap/LdapTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/protocols/ldap/LdapTestCase.java
@@ -26,6 +26,8 @@
*/
package org.opends.server.protocols.ldap ;
+import static org.mockito.Mockito.mock;
+
import static org.opends.server.config.ConfigConstants.*;
import java.util.Iterator;
@@ -36,6 +38,7 @@
import org.opends.server.admin.server.AdminTestCaseUtils;
import org.opends.server.admin.std.meta.LDAPConnectionHandlerCfgDefn;
import org.opends.server.admin.std.server.LDAPConnectionHandlerCfg;
+import org.opends.server.core.ServerContext;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.types.Attribute;
import org.opends.server.types.Attributes;
@@ -112,7 +115,7 @@
handlerEntry.addAttribute(a, null);
LDAPConnectionHandlerCfg config = getConfiguration(handlerEntry);
LDAPConnectionHandler handler = new LDAPConnectionHandler();
- handler.initializeConnectionHandler(config);
+ handler.initializeConnectionHandler(mock(ServerContext.class), config);
return handler;
}
--
Gitblit v1.10.0