opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/CsvFileAccessLogPublisherConfiguration.xml
New file @@ -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> opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/CsvFileHTTPAccessLogPublisherConfiguration.xml
New file @@ -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> opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ExternalAccessLogPublisherConfiguration.xml
New file @@ -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> opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/ExternalHTTPAccessLogPublisherConfiguration.xml
New file @@ -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> 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> 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 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' ) 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; } /** 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; opendj-server-legacy/src/main/java/org/opends/server/controls/TransactionIdControl.java
New file @@ -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(")"); } } 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) { 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(); 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(); } 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; } } 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(); } } opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAudit.java
New file @@ -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; } } } opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditAccessLogPublisher.java
New file @@ -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))); } }); } } opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditDependencyProvider.java
New file @@ -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; } } } opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditHTTPAccessLogPublisher.java
New file @@ -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 } } opendj-server-legacy/src/main/java/org/opends/server/loggers/CommonAuditLogPublisher.java
New file @@ -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); } opendj-server-legacy/src/main/java/org/opends/server/loggers/CsvFileAccessLogPublisher.java
New file @@ -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; } } opendj-server-legacy/src/main/java/org/opends/server/loggers/ExternalAccessLogPublisher.java
New file @@ -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; } } 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(); } } opendj-server-legacy/src/main/java/org/opends/server/loggers/OpenDJAccessEventBuilder.java
New file @@ -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; } } 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(); opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CommonAuditHttpAccessAuditFilter.java
New file @@ -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; } } } opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CommonAuditHttpAccessCheckEnabledFilter.java
New file @@ -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); } } 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); } 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) { 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; 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. 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) 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. opendj-server-legacy/src/main/resources/org/opends/server/loggers/audit-config.json
New file @@ -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" } } } } } } } } } } } 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 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 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 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>(); 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); } 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; }