From 14e18aed316e2d0f051d7140659a2ce83ceabed7 Mon Sep 17 00:00:00 2001
From: "Endi S. Dewata" <edewata@redhat.com>
Date: Tue, 24 Sep 2013 15:23:00 -0400
Subject: [PATCH] Added TPS audit resource.

A new REST service and clients have been added to manage the audit
configuration in the TPS configuration file.

Ticket #652
---
 .../src/com/netscape/certsrv/tps/TPSClient.java    |   2 +
 .../netscape/certsrv/tps/audit/AuditClient.java    |  56 +++++
 .../netscape/certsrv/tps/audit/AuditConfig.java    | 268 +++++++++++++++++++++
 .../netscape/certsrv/tps/audit/AuditResource.java  |  46 ++++
 .../certsrv/tps/config/ConfigCollection.java       |  65 -----
 .../src/com/netscape/cmstools/cli/TPSCLI.java      |   2 +
 .../com/netscape/cmstools/tps/audit/AuditCLI.java  |  71 ++++++
 .../cmstools/tps/audit/AuditModifyCLI.java         | 115 +++++++++
 .../netscape/cmstools/tps/audit/AuditShowCLI.java  |  86 +++++++
 base/tps-tomcat/shared/conf/CS.cfg.in              |   4 +-
 .../org/dogtagpki/server/tps/TPSApplication.java   |   4 +
 .../dogtagpki/server/tps/audit/AuditService.java   | 176 ++++++++++++++
 12 files changed, 829 insertions(+), 66 deletions(-)
 create mode 100644 base/common/src/com/netscape/certsrv/tps/audit/AuditClient.java
 create mode 100644 base/common/src/com/netscape/certsrv/tps/audit/AuditConfig.java
 create mode 100644 base/common/src/com/netscape/certsrv/tps/audit/AuditResource.java
 delete mode 100644 base/common/src/com/netscape/certsrv/tps/config/ConfigCollection.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/tps/audit/AuditCLI.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/tps/audit/AuditModifyCLI.java
 create mode 100644 base/java-tools/src/com/netscape/cmstools/tps/audit/AuditShowCLI.java
 create mode 100644 base/tps-tomcat/src/org/dogtagpki/server/tps/audit/AuditService.java

diff --git a/base/common/src/com/netscape/certsrv/tps/TPSClient.java b/base/common/src/com/netscape/certsrv/tps/TPSClient.java
index 1c4cd3860e7625fc8e23878a60690e0ab151b140..1b6ab0aa8f23557bff2164f398700f4764c96dfe 100644
--- a/base/common/src/com/netscape/certsrv/tps/TPSClient.java
+++ b/base/common/src/com/netscape/certsrv/tps/TPSClient.java
@@ -23,6 +23,7 @@ import com.netscape.certsrv.client.PKIClient;
 import com.netscape.certsrv.client.SubsystemClient;
 import com.netscape.certsrv.group.GroupClient;
 import com.netscape.certsrv.logging.ActivityClient;
+import com.netscape.certsrv.tps.audit.AuditClient;
 import com.netscape.certsrv.tps.authenticator.AuthenticatorClient;
 import com.netscape.certsrv.tps.cert.TPSCertClient;
 import com.netscape.certsrv.tps.config.ConfigClient;
@@ -44,6 +45,7 @@ public class TPSClient extends SubsystemClient {
 
     public void init() throws URISyntaxException {
         addClient(new ActivityClient(client, name));
+        addClient(new AuditClient(client, name));
         addClient(new AuthenticatorClient(client, name));
         addClient(new TPSCertClient(client, name));
         addClient(new ConfigClient(client, name));
diff --git a/base/common/src/com/netscape/certsrv/tps/audit/AuditClient.java b/base/common/src/com/netscape/certsrv/tps/audit/AuditClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a09ca5f4b71a010bf23a027d6e53704abe98522
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/tps/audit/AuditClient.java
@@ -0,0 +1,56 @@
+//--- BEGIN COPYRIGHT BLOCK ---
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; version 2 of the License.
+//
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//GNU General Public License for more details.
+//
+//You should have received a copy of the GNU General Public License along
+//with this program; if not, write to the Free Software Foundation, Inc.,
+//51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+//(C) 2013 Red Hat, Inc.
+//All rights reserved.
+//--- END COPYRIGHT BLOCK ---
+package com.netscape.certsrv.tps.audit;
+
+import java.net.URISyntaxException;
+
+import org.jboss.resteasy.client.ClientResponse;
+
+import com.netscape.certsrv.client.Client;
+import com.netscape.certsrv.client.PKIClient;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class AuditClient extends Client {
+
+    public AuditResource resource;
+
+    public AuditClient(PKIClient client) throws URISyntaxException {
+        this(client, client.getSubsystem());
+    }
+
+    public AuditClient(PKIClient client, String subsystem) throws URISyntaxException {
+        super(client, subsystem, "audit");
+        init();
+    }
+
+    public void init() throws URISyntaxException {
+        resource = createProxy(AuditResource.class);
+    }
+
+    public AuditConfig getAuditConfig() {
+        return resource.getAuditConfig();
+    }
+
+    public AuditConfig updateAuditConfig(AuditConfig auditConfig) {
+        @SuppressWarnings("unchecked")
+        ClientResponse<AuditConfig> response = (ClientResponse<AuditConfig>)resource.updateAuditConfig(auditConfig);
+        return client.getEntity(response);
+    }
+}
diff --git a/base/common/src/com/netscape/certsrv/tps/audit/AuditConfig.java b/base/common/src/com/netscape/certsrv/tps/audit/AuditConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..886fa43d8bbf1e199878055b389bc7f0f09f84c2
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/tps/audit/AuditConfig.java
@@ -0,0 +1,268 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.certsrv.tps.audit;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlValue;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import org.jboss.resteasy.plugins.providers.atom.Link;
+
+/**
+ * @author Endi S. Dewata
+ */
+@XmlRootElement(name="Audit")
+public class AuditConfig {
+
+    public static Marshaller marshaller;
+    public static Unmarshaller unmarshaller;
+
+    static {
+        try {
+            marshaller = JAXBContext.newInstance(AuditConfig.class).createMarshaller();
+            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+            unmarshaller = JAXBContext.newInstance(AuditConfig.class).createUnmarshaller();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    Boolean enabled;
+    Boolean signed;
+    Integer interval;
+    Integer bufferSize;
+    Map<String, String> events = new TreeMap<String, String>();
+
+    Link link;
+
+    @XmlElement(name="Enabled")
+    public Boolean getEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(Boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    @XmlElement(name="Signed")
+    public Boolean getSigned() {
+        return signed;
+    }
+
+    public void setSigned(Boolean signed) {
+        this.signed = signed;
+    }
+
+    @XmlElement(name="Interval")
+    public Integer getInterval() {
+        return interval;
+    }
+
+    public void setInterval(Integer interval) {
+        this.interval = interval;
+    }
+
+    @XmlElement(name="BufferSize")
+    public Integer getBufferSize() {
+        return bufferSize;
+    }
+
+    public void setBufferSize(Integer bufferSize) {
+        this.bufferSize = bufferSize;
+    }
+
+    @XmlElement(name="Events")
+    @XmlJavaTypeAdapter(MapAdapter.class)
+    public Map<String, String> getEvents() {
+        return events;
+    }
+
+    public void setEvents(Map<String, String> events) {
+        this.events.clear();
+        this.events.putAll(events);
+    }
+
+    public Collection<String> getEventNames() {
+        return events.keySet();
+    }
+
+    public String getEvent(String name) {
+        return events.get(name);
+    }
+
+    public void setEvent(String name, String value) {
+        events.put(name, value);
+    }
+
+    public String removeEvent(String name) {
+        return events.remove(name);
+    }
+
+    public static class MapAdapter extends XmlAdapter<EventList, Map<String, String>> {
+
+        public EventList marshal(Map<String, String> map) {
+            EventList list = new EventList();
+            for (Map.Entry<String, String> entry : map.entrySet()) {
+                Event event = new Event();
+                event.name = entry.getKey();
+                event.value = entry.getValue();
+                list.entries.add(event);
+            }
+            return list;
+        }
+
+        public Map<String, String> unmarshal(EventList list) {
+            Map<String, String> map = new LinkedHashMap<String, String>();
+            for (Event event : list.entries) {
+                map.put(event.name, event.value);
+            }
+            return map;
+        }
+    }
+
+    public static class EventList {
+        @XmlElement(name="Event")
+        public List<Event> entries = new ArrayList<Event>();
+    }
+
+    public static class Event {
+
+        @XmlAttribute
+        public String name;
+
+        @XmlValue
+        public String value;
+    }
+
+    @XmlElement(name="Link")
+    public Link getLink() {
+        return link;
+    }
+
+    public void setLink(Link link) {
+        this.link = link;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((bufferSize == null) ? 0 : bufferSize.hashCode());
+        result = prime * result + ((enabled == null) ? 0 : enabled.hashCode());
+        result = prime * result + ((interval == null) ? 0 : interval.hashCode());
+        result = prime * result + ((link == null) ? 0 : link.hashCode());
+        result = prime * result + ((events == null) ? 0 : events.hashCode());
+        result = prime * result + ((signed == null) ? 0 : signed.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        AuditConfig other = (AuditConfig) obj;
+        if (bufferSize == null) {
+            if (other.bufferSize != null)
+                return false;
+        } else if (!bufferSize.equals(other.bufferSize))
+            return false;
+        if (enabled == null) {
+            if (other.enabled != null)
+                return false;
+        } else if (!enabled.equals(other.enabled))
+            return false;
+        if (interval == null) {
+            if (other.interval != null)
+                return false;
+        } else if (!interval.equals(other.interval))
+            return false;
+        if (link == null) {
+            if (other.link != null)
+                return false;
+        } else if (!link.equals(other.link))
+            return false;
+        if (events == null) {
+            if (other.events != null)
+                return false;
+        } else if (!events.equals(other.events))
+            return false;
+        if (signed == null) {
+            if (other.signed != null)
+                return false;
+        } else if (!signed.equals(other.signed))
+            return false;
+        return true;
+    }
+
+    public String toString() {
+        try {
+            StringWriter sw = new StringWriter();
+            marshaller.marshal(this, sw);
+            return sw.toString();
+
+        } catch (Exception e) {
+            return super.toString();
+        }
+    }
+
+    public static AuditConfig valueOf(String string) throws Exception {
+        try {
+            return (AuditConfig)unmarshaller.unmarshal(new StringReader(string));
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+
+        AuditConfig before = new AuditConfig();
+        before.setEnabled(true);
+        before.setSigned(false);
+        before.setInterval(10);
+        before.setBufferSize(512);
+        before.setEvent("event1", "true");
+        before.setEvent("event2", "false");
+        before.setEvent("event3", "always");
+
+        String string = before.toString();
+        System.out.println(string);
+
+        AuditConfig after = AuditConfig.valueOf(string);
+        System.out.println(before.equals(after));
+    }
+}
diff --git a/base/common/src/com/netscape/certsrv/tps/audit/AuditResource.java b/base/common/src/com/netscape/certsrv/tps/audit/AuditResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..23b9fee39e223f74dd8d98749b6aac38ff74e46e
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/tps/audit/AuditResource.java
@@ -0,0 +1,46 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.certsrv.tps.audit;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.jboss.resteasy.annotations.ClientResponseType;
+
+
+/**
+ * @author Endi S. Dewata
+ */
+@Path("audit")
+public interface AuditResource {
+
+    @GET
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    public AuditConfig getAuditConfig();
+
+    @PUT
+    @ClientResponseType(entityType=AuditConfig.class)
+    @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    public Response updateAuditConfig(AuditConfig configData);
+}
diff --git a/base/common/src/com/netscape/certsrv/tps/config/ConfigCollection.java b/base/common/src/com/netscape/certsrv/tps/config/ConfigCollection.java
deleted file mode 100644
index a36f61fd174ffe07562f3e5010c3418860ebe054..0000000000000000000000000000000000000000
--- a/base/common/src/com/netscape/certsrv/tps/config/ConfigCollection.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// --- BEGIN COPYRIGHT BLOCK ---
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation; version 2 of the License.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License along
-// with this program; if not, write to the Free Software Foundation, Inc.,
-// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-//
-// (C) 2013 Red Hat, Inc.
-// All rights reserved.
-// --- END COPYRIGHT BLOCK ---
-
-package com.netscape.certsrv.tps.config;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlElementRef;
-import javax.xml.bind.annotation.XmlRootElement;
-
-import org.jboss.resteasy.plugins.providers.atom.Link;
-
-
-/**
- * @author Endi S. Dewata
- */
-@XmlRootElement(name="Configurations")
-public class ConfigCollection {
-
-    Collection<ConfigData> configs = new ArrayList<ConfigData>();
-    Collection<Link> links = new ArrayList<Link>();
-
-    @XmlElementRef
-    public Collection<ConfigData> getConfigs() {
-        return configs;
-    }
-
-    public void setConfigs(Collection<ConfigData> configs) {
-        this.configs = configs;
-    }
-
-    public void addConfig(ConfigData configData) {
-        configs.add(configData);
-    }
-
-    @XmlElement(name="Link")
-    public Collection<Link> getLinks() {
-        return links;
-    }
-
-    public void setLink(Collection<Link> links) {
-        this.links = links;
-    }
-
-    public void addLink(Link link) {
-        links.add(link);
-    }
-}
diff --git a/base/java-tools/src/com/netscape/cmstools/cli/TPSCLI.java b/base/java-tools/src/com/netscape/cmstools/cli/TPSCLI.java
index 09596fae7718528affa381192036c949515585c7..4dd012e17654d938a9e4bd1b43129b526a4c62b1 100644
--- a/base/java-tools/src/com/netscape/cmstools/cli/TPSCLI.java
+++ b/base/java-tools/src/com/netscape/cmstools/cli/TPSCLI.java
@@ -22,6 +22,7 @@ import com.netscape.certsrv.client.Client;
 import com.netscape.certsrv.tps.TPSClient;
 import com.netscape.cmstools.group.GroupCLI;
 import com.netscape.cmstools.logging.ActivityCLI;
+import com.netscape.cmstools.tps.audit.AuditCLI;
 import com.netscape.cmstools.tps.authenticator.AuthenticatorCLI;
 import com.netscape.cmstools.tps.cert.TPSCertCLI;
 import com.netscape.cmstools.tps.config.ConfigCLI;
@@ -41,6 +42,7 @@ public class TPSCLI extends SubsystemCLI {
         super("tps", "TPS management commands", mainCLI);
 
         addModule(new ActivityCLI(this));
+        addModule(new AuditCLI(this));
         addModule(new AuthenticatorCLI(this));
         addModule(new TPSCertCLI(this));
         addModule(new ConfigCLI(this));
diff --git a/base/java-tools/src/com/netscape/cmstools/tps/audit/AuditCLI.java b/base/java-tools/src/com/netscape/cmstools/tps/audit/AuditCLI.java
new file mode 100644
index 0000000000000000000000000000000000000000..2201a29b85d962f8f8dd32f35e126fb639275c65
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/tps/audit/AuditCLI.java
@@ -0,0 +1,71 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.tps.audit;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.jboss.resteasy.plugins.providers.atom.Link;
+
+import com.netscape.certsrv.tps.audit.AuditClient;
+import com.netscape.certsrv.tps.audit.AuditConfig;
+import com.netscape.cmstools.cli.CLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class AuditCLI extends CLI {
+
+    public AuditClient auditClient;
+
+    public AuditCLI(CLI parent) {
+        super("audit", "Audit management commands", parent);
+
+        addModule(new AuditModifyCLI(this));
+        addModule(new AuditShowCLI(this));
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        client = parent.getClient();
+        auditClient = (AuditClient)parent.getClient("audit");
+
+        super.execute(args);
+    }
+
+    public static void printAuditConfig(AuditConfig auditConfig) throws IOException {
+
+        if (auditConfig.getEnabled() != null) System.out.println("  Enabled: " + auditConfig.getEnabled());
+        if (auditConfig.getSigned() != null) System.out.println("  Signed: " + auditConfig.getSigned());
+        if (auditConfig.getInterval() != null) System.out.println("  Interval (seconds): " + auditConfig.getInterval());
+        if (auditConfig.getBufferSize() != null) System.out.println("  Buffer size (bytes): " + auditConfig.getBufferSize());
+
+        System.out.println("  Events:");
+        Map<String, String> events = auditConfig.getEvents();
+        for (String name : events.keySet()) {
+            String value = events.get(name);
+            System.out.println("    " + name + ": " + value);
+        }
+
+        Link link = auditConfig.getLink();
+        if (verbose && link != null) {
+            System.out.println("  Link: " + link.getHref());
+        }
+    }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/tps/audit/AuditModifyCLI.java b/base/java-tools/src/com/netscape/cmstools/tps/audit/AuditModifyCLI.java
new file mode 100644
index 0000000000000000000000000000000000000000..481e18cf595b3154c54a1058649a7050b52377e1
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/tps/audit/AuditModifyCLI.java
@@ -0,0 +1,115 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.tps.audit;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+
+import com.netscape.certsrv.tps.audit.AuditConfig;
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class AuditModifyCLI extends CLI {
+
+    public AuditCLI auditCLI;
+
+    public AuditModifyCLI(AuditCLI auditCLI) {
+        super("mod", "Modify audit configuration", auditCLI);
+        this.auditCLI = auditCLI;
+    }
+
+    public void printHelp() {
+        formatter.printHelp(getFullName() + " [OPTIONS...]", options);
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        Option option = new Option(null, "input", true, "Input file containing audit configuration.");
+        option.setArgName("file");
+        option.setRequired(true);
+        options.addOption(option);
+
+        option = new Option(null, "output", true, "Output file to store audit configuration.");
+        option.setArgName("file");
+        options.addOption(option);
+
+        CommandLine cmd = null;
+
+        try {
+            cmd = parser.parse(options, args);
+
+        } catch (Exception e) {
+            System.err.println("Error: " + e.getMessage());
+            printHelp();
+            System.exit(1);
+        }
+
+        String[] cmdArgs = cmd.getArgs();
+
+        if (cmdArgs.length != 0) {
+            printHelp();
+            System.exit(1);
+        }
+
+        String input = cmd.getOptionValue("input");
+        String output = cmd.getOptionValue("output");
+
+        if (input == null) {
+            System.err.println("Error: Input file is required.");
+            printHelp();
+            System.exit(1);
+        }
+
+        AuditConfig auditConfig;
+
+        try (BufferedReader in = new BufferedReader(new FileReader(input));
+            StringWriter sw = new StringWriter();
+            PrintWriter out = new PrintWriter(sw, true)) {
+
+            String line;
+            while ((line = in.readLine()) != null) {
+                out.println(line);
+            }
+
+            auditConfig = AuditConfig.valueOf(sw.toString());
+        }
+
+        auditConfig = auditCLI.auditClient.updateAuditConfig(auditConfig);
+
+        MainCLI.printMessage("Updated audit configuration");
+
+        if (output == null) {
+            AuditCLI.printAuditConfig(auditConfig);
+
+        } else {
+            try (PrintWriter out = new PrintWriter(new FileWriter(output))) {
+                out.println(auditConfig);
+            }
+        }
+    }
+}
diff --git a/base/java-tools/src/com/netscape/cmstools/tps/audit/AuditShowCLI.java b/base/java-tools/src/com/netscape/cmstools/tps/audit/AuditShowCLI.java
new file mode 100644
index 0000000000000000000000000000000000000000..01358de16624f911bc82dbde7b5d30ceeece3dcb
--- /dev/null
+++ b/base/java-tools/src/com/netscape/cmstools/tps/audit/AuditShowCLI.java
@@ -0,0 +1,86 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.cmstools.tps.audit;
+
+import java.io.FileWriter;
+import java.io.PrintWriter;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Option;
+
+import com.netscape.certsrv.tps.audit.AuditConfig;
+import com.netscape.cmstools.cli.CLI;
+import com.netscape.cmstools.cli.MainCLI;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class AuditShowCLI extends CLI {
+
+    public AuditCLI auditCLI;
+
+    public AuditShowCLI(AuditCLI auditCLI) {
+        super("show", "Show audit configuration", auditCLI);
+        this.auditCLI = auditCLI;
+    }
+
+    public void printHelp() {
+        formatter.printHelp(getFullName(), options);
+    }
+
+    public void execute(String[] args) throws Exception {
+
+        Option option = new Option(null, "output", true, "Output file to store audit configuration.");
+        option.setArgName("file");
+        options.addOption(option);
+
+        CommandLine cmd = null;
+
+        try {
+            cmd = parser.parse(options, args);
+
+        } catch (Exception e) {
+            System.err.println("Error: " + e.getMessage());
+            printHelp();
+            System.exit(1);
+        }
+
+        String[] cmdArgs = cmd.getArgs();
+
+        if (cmdArgs.length != 0) {
+            printHelp();
+            System.exit(1);
+        }
+
+        String output = cmd.getOptionValue("output");
+
+        AuditConfig auditConfig = auditCLI.auditClient.getAuditConfig();
+
+        if (output == null) {
+            MainCLI.printMessage("Audit configuration");
+            AuditCLI.printAuditConfig(auditConfig);
+
+        } else {
+            try (PrintWriter out = new PrintWriter(new FileWriter(output))) {
+                out.println(auditConfig);
+            }
+            MainCLI.printMessage("Stored audit configuration into " + output);
+        }
+    }
+}
diff --git a/base/tps-tomcat/shared/conf/CS.cfg.in b/base/tps-tomcat/shared/conf/CS.cfg.in
index 02ab97415ab99acb2d910b196df6601350667c78..7cac93185deda50ae605aff5026eb5cef368fa7c 100644
--- a/base/tps-tomcat/shared/conf/CS.cfg.in
+++ b/base/tps-tomcat/shared/conf/CS.cfg.in
@@ -275,7 +275,9 @@ log.instance.SignedAudit._005=## AUDIT_LOG_STARTUP,AUDIT_LOG_SHUTDOWN,ROLE_ASSUM
 log.instance.SignedAudit._006=##
 log.instance.SignedAudit.bufferSize=512
 log.instance.SignedAudit.enable=true
-log.instance.SignedAudit.events=AUDIT_LOG_STARTUP,AUDIT_LOG_SHUTDOWN,ROLE_ASSUME,CONFIG_CERT_POLICY,CONFIG_CERT_PROFILE,CONFIG_CRL_PROFILE,CONFIG_OCSP_PROFILE,CONFIG_AUTH,CONFIG_ROLE,CONFIG_ACL,CONFIG_SIGNED_AUDIT,CONFIG_ENCRYPTION,CONFIG_TRUSTED_PUBLIC_KEY,CONFIG_DRM,SELFTESTS_EXECUTION,AUDIT_LOG_DELETE,LOG_PATH_CHANGE,LOG_EXPIRATION_CHANGE,PRIVATE_KEY_ARCHIVE_REQUEST,PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED,PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_SUCCESS,PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_FAILURE,KEY_RECOVERY_REQUEST,KEY_RECOVERY_REQUEST_ASYNC,KEY_RECOVERY_AGENT_LOGIN,KEY_RECOVERY_REQUEST_PROCESSED,KEY_RECOVERY_REQUEST_PROCESSED_ASYNC,KEY_GEN_ASYMMETRIC,NON_PROFILE_CERT_REQUEST,PROFILE_CERT_REQUEST,CERT_REQUEST_PROCESSED,CERT_STATUS_CHANGE_REQUEST,CERT_STATUS_CHANGE_REQUEST_PROCESSED,AUTHZ_SUCCESS,AUTHZ_FAIL,INTER_BOUNDARY,AUTH_FAIL,AUTH_SUCCESS,CERT_PROFILE_APPROVAL,PROOF_OF_POSSESSION,CRL_RETRIEVAL,CRL_VALIDATION,CMC_SIGNED_REQUEST_SIG_VERIFY,SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_FAILURE,SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_SUCCESS,SERVER_SIDE_KEYGEN_REQUEST,COMPUTE_SESSION_KEY_REQUEST,COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS, COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE,DIVERSIFY_KEY_REQUEST,DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS, DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE,ENCRYPT_DATA_REQUEST,ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS,ENCRYPT_DATA_REQUEST_PROCESSED_FAILURE,OCSP_ADD_CA_REQUEST,OCSP_ADD_CA_REQUEST_PROCESSED,OCSP_REMOVE_CA_REQUEST,OCSP_REMOVE_CA_REQUEST_PROCESSED_SUCCESS,OCSP_REMOVE_CA_REQUEST_PROCESSED_FAILURE,COMPUTE_RANDOM_DATA_REQUEST,COMPUTE_RANDOM_DATA_REQUEST_PROCESSED_SUCCESS,COMPUTE_RANDOM_DATA_REQUEST_PROCESSED_FAILURE,CIMC_CERT_VERIFICATION,LOGGING_SIGNED_AUDIT_SIGNING,ENROLLMENT,PIN_RESET,FORMAT,CONFIG,CONFIG_TOKEN,CONFIG_PROFILE,APPLET_UPGRADE,KEY_CHANGEOVER,RENEWAL,CIMC_CERT_VERIFICATION
+log.instance.SignedAudit.events=ROLE_ASSUME,CONFIG_CERT_POLICY,CONFIG_CERT_PROFILE,CONFIG_CRL_PROFILE,CONFIG_OCSP_PROFILE,CONFIG_AUTH,CONFIG_ROLE,CONFIG_ACL,CONFIG_SIGNED_AUDIT,CONFIG_ENCRYPTION,CONFIG_TRUSTED_PUBLIC_KEY,CONFIG_DRM,SELFTESTS_EXECUTION,AUDIT_LOG_DELETE,LOG_PATH_CHANGE,LOG_EXPIRATION_CHANGE,PRIVATE_KEY_ARCHIVE_REQUEST,PRIVATE_KEY_ARCHIVE_REQUEST_PROCESSED,PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_SUCCESS,PRIVATE_KEY_EXPORT_REQUEST_PROCESSED_FAILURE,KEY_RECOVERY_REQUEST,KEY_RECOVERY_REQUEST_ASYNC,KEY_RECOVERY_AGENT_LOGIN,KEY_RECOVERY_REQUEST_PROCESSED,KEY_RECOVERY_REQUEST_PROCESSED_ASYNC,KEY_GEN_ASYMMETRIC,NON_PROFILE_CERT_REQUEST,PROFILE_CERT_REQUEST,CERT_REQUEST_PROCESSED,CERT_STATUS_CHANGE_REQUEST,CERT_STATUS_CHANGE_REQUEST_PROCESSED,AUTHZ_SUCCESS,AUTHZ_FAIL,INTER_BOUNDARY,AUTH_FAIL,AUTH_SUCCESS,CERT_PROFILE_APPROVAL,PROOF_OF_POSSESSION,CRL_RETRIEVAL,CRL_VALIDATION,CMC_SIGNED_REQUEST_SIG_VERIFY,SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_FAILURE,SERVER_SIDE_KEYGEN_REQUEST_PROCESSED_SUCCESS,SERVER_SIDE_KEYGEN_REQUEST,COMPUTE_SESSION_KEY_REQUEST,COMPUTE_SESSION_KEY_REQUEST_PROCESSED_SUCCESS, COMPUTE_SESSION_KEY_REQUEST_PROCESSED_FAILURE,DIVERSIFY_KEY_REQUEST,DIVERSIFY_KEY_REQUEST_PROCESSED_SUCCESS, DIVERSIFY_KEY_REQUEST_PROCESSED_FAILURE,ENCRYPT_DATA_REQUEST,ENCRYPT_DATA_REQUEST_PROCESSED_SUCCESS,ENCRYPT_DATA_REQUEST_PROCESSED_FAILURE,OCSP_ADD_CA_REQUEST,OCSP_ADD_CA_REQUEST_PROCESSED,OCSP_REMOVE_CA_REQUEST,OCSP_REMOVE_CA_REQUEST_PROCESSED_SUCCESS,OCSP_REMOVE_CA_REQUEST_PROCESSED_FAILURE,COMPUTE_RANDOM_DATA_REQUEST,COMPUTE_RANDOM_DATA_REQUEST_PROCESSED_SUCCESS,COMPUTE_RANDOM_DATA_REQUEST_PROCESSED_FAILURE,CIMC_CERT_VERIFICATION,ENROLLMENT,PIN_RESET,FORMAT,CONFIG,CONFIG_TOKEN,CONFIG_PROFILE,APPLET_UPGRADE,KEY_CHANGEOVER,RENEWAL,CIMC_CERT_VERIFICATION
+log.instance.SignedAudit.selectable.events=
+log.instance.SignedAudit.nonselectable.events=AUDIT_LOG_STARTUP,AUDIT_LOG_SHUTDOWN,LOGGING_SIGNED_AUDIT_SIGNING
 log.instance.SignedAudit.expirationTime=0
 log.instance.SignedAudit.fileName=[PKI_INSTANCE_PATH]/logs/[PKI_SUBSYSTEM_TYPE]/signedAudit/tps_cert-tps_audit
 log.instance.SignedAudit.flushInterval=5
diff --git a/base/tps-tomcat/src/org/dogtagpki/server/tps/TPSApplication.java b/base/tps-tomcat/src/org/dogtagpki/server/tps/TPSApplication.java
index 83fa3aa1f5f79dba8b5ef91dd90fa2f61c41ef2d..fcfc739a5567b3177145284e632bac88c40cceb2 100644
--- a/base/tps-tomcat/src/org/dogtagpki/server/tps/TPSApplication.java
+++ b/base/tps-tomcat/src/org/dogtagpki/server/tps/TPSApplication.java
@@ -22,6 +22,7 @@ import java.util.Set;
 
 import javax.ws.rs.core.Application;
 
+import org.dogtagpki.server.tps.audit.AuditService;
 import org.dogtagpki.server.tps.authenticator.AuthenticatorService;
 import org.dogtagpki.server.tps.cert.TPSCertService;
 import org.dogtagpki.server.tps.config.ConfigService;
@@ -72,6 +73,9 @@ public class TPSApplication extends Application {
         // activities
         classes.add(ActivityService.class);
 
+        // audit
+        classes.add(AuditService.class);
+
         // authenticators
         classes.add(AuthenticatorService.class);
 
diff --git a/base/tps-tomcat/src/org/dogtagpki/server/tps/audit/AuditService.java b/base/tps-tomcat/src/org/dogtagpki/server/tps/audit/AuditService.java
new file mode 100644
index 0000000000000000000000000000000000000000..7129af39303d6572259f2febf8199c7c9dd5872c
--- /dev/null
+++ b/base/tps-tomcat/src/org/dogtagpki/server/tps/audit/AuditService.java
@@ -0,0 +1,176 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// (C) 2013 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package org.dogtagpki.server.tps.audit;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.commons.lang.StringUtils;
+import org.jboss.resteasy.plugins.providers.atom.Link;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.PKIException;
+import com.netscape.certsrv.tps.audit.AuditConfig;
+import com.netscape.certsrv.tps.audit.AuditResource;
+import com.netscape.cms.servlet.base.PKIService;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class AuditService extends PKIService implements AuditResource {
+
+    @Context
+    private UriInfo uriInfo;
+
+    @Context
+    private HttpHeaders headers;
+
+    @Context
+    private Request request;
+
+    @Context
+    private HttpServletRequest servletRequest;
+
+    public final static int DEFAULT_SIZE = 20;
+
+    public AuditService() {
+        CMS.debug("AuditService.<init>()");
+    }
+
+    public AuditConfig createAuditConfig() throws UnsupportedEncodingException, EBaseException {
+
+        IConfigStore cs = CMS.getConfigStore();
+
+        AuditConfig auditConfig = new AuditConfig();
+        auditConfig.setEnabled(cs.getBoolean("log.instance.SignedAudit.enable", false));
+        auditConfig.setSigned(cs.getBoolean("log.instance.SignedAudit.logSigning", false));
+        auditConfig.setInterval(cs.getInteger("log.instance.SignedAudit.flushInterval", 5));
+        auditConfig.setBufferSize(cs.getInteger("log.instance.SignedAudit.bufferSize", 512));
+
+        for (String event : cs.getString("log.instance.SignedAudit.events", "").split(",")) {
+            auditConfig.setEvent(event.trim(), "true");
+        }
+
+        for (String event : cs.getString("log.instance.SignedAudit.selectable.events", "").split(",")) {
+            auditConfig.setEvent(event.trim(), "false");
+        }
+
+        for (String event : cs.getString("log.instance.SignedAudit.nonselectable.events", "").split(",")) {
+            auditConfig.setEvent(event.trim(), "always");
+        }
+
+        URI uri = uriInfo.getBaseUriBuilder().path(AuditResource.class).build();
+        auditConfig.setLink(new Link("self", uri));
+
+        return auditConfig;
+    }
+
+    @Override
+    public AuditConfig getAuditConfig() {
+
+        CMS.debug("AuditService.getAuditConfig()");
+
+        try {
+            return createAuditConfig();
+
+        } catch (PKIException e) {
+            throw e;
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new PKIException(e.getMessage());
+        }
+    }
+
+    @Override
+    public Response updateAuditConfig(AuditConfig auditConfig) {
+
+        CMS.debug("AuditService.updateAuditConfig()");
+
+        try {
+            IConfigStore cs = CMS.getConfigStore();
+
+            if (auditConfig.getEnabled() != null) {
+                cs.putBoolean("log.instance.SignedAudit.enable", auditConfig.getEnabled());
+            }
+
+            if (auditConfig.getSigned() != null) {
+                cs.putBoolean("log.instance.SignedAudit.logSigning", auditConfig.getSigned());
+            }
+
+            if (auditConfig.getInterval() != null) {
+                cs.putInteger("log.instance.SignedAudit.flushInterval", auditConfig.getInterval());
+            }
+
+            if (auditConfig.getBufferSize() != null) {
+                cs.putInteger("log.instance.SignedAudit.bufferSize", auditConfig.getBufferSize());
+            }
+
+            Collection<String> selected = new ArrayList<String>();
+            Collection<String> selectable = new ArrayList<String>();
+            Collection<String> nonselectable = new ArrayList<String>();
+
+            for (String name : auditConfig.getEvents().keySet()) {
+                String value = auditConfig.getEvent(name).toLowerCase();
+
+                if ("true".equals(value)) {
+                    selected.add(name);
+
+                } else if ("false".equals(value)) {
+                    selectable.add(name);
+
+                } else if ("always".equals(value)) {
+                    nonselectable.add(name);
+                }
+            }
+
+            cs.putString("log.instance.SignedAudit.events", StringUtils.join(selected, ","));
+            cs.putString("log.instance.SignedAudit.selectable.events", StringUtils.join(selectable, ","));
+            cs.putString("log.instance.SignedAudit.nonselectable.events", StringUtils.join(nonselectable, ","));
+
+            cs.commit(true);
+
+            auditConfig = createAuditConfig();
+
+            return Response
+                    .ok(auditConfig)
+                    .type(MediaType.APPLICATION_XML)
+                    .build();
+
+        } catch (PKIException e) {
+            throw e;
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new PKIException(e.getMessage());
+        }
+    }
+}
-- 
1.8.1.4

