From a65f3659221bba82f65c389c60abddcb3ba9c0e8 Mon Sep 17 00:00:00 2001
From: Endi Sukma Dewata <edewata@redhat.com>
Date: Sat, 19 May 2012 10:52:07 -0500
Subject: [PATCH] Refactored audit service.

Previously the audit service was only available to subclasses of AdminServlet.
This functionality has been moved into a more generic Auditor service which
can be used by others including REST services. In the future the AdminServlet
should be modified to use the Auditor service.

Ticket #160
---
 base/common/src/CMakeLists.txt                     |    2 +
 base/common/src/com/netscape/certsrv/apps/CMS.java |   12 +
 .../src/com/netscape/certsrv/apps/ICMSEngine.java  |   10 +
 .../src/com/netscape/certsrv/audit/Auditor.java    |  232 ++++++++++++++++++++
 .../src/com/netscape/certsrv/audit/IAuditor.java   |   37 +++
 .../src/com/netscape/cmscore/apps/CMSEngine.java   |    6 +
 .../netscape/certsrv/app/CMSEngineDefaultStub.java |    5 +
 7 files changed, 304 insertions(+), 0 deletions(-)
 create mode 100644 base/common/src/com/netscape/certsrv/audit/Auditor.java
 create mode 100644 base/common/src/com/netscape/certsrv/audit/IAuditor.java

diff --git a/base/common/src/CMakeLists.txt b/base/common/src/CMakeLists.txt
index 0a9fcddfb85ddf1f52a01ab3c595c14b799071b6..df33b13677c858ffd100f8aecc27f95486704a7c 100644
--- a/base/common/src/CMakeLists.txt
+++ b/base/common/src/CMakeLists.txt
@@ -252,6 +252,8 @@ set(pki-certsrv_java_SRCS
     com/netscape/certsrv/kra/IKeyRecoveryAuthority.java
     com/netscape/certsrv/kra/IProofOfArchival.java
     com/netscape/certsrv/kra/KRAResources.java
+    com/netscape/certsrv/audit/IAuditor.java
+    com/netscape/certsrv/audit/Auditor.java
     com/netscape/certsrv/authentication/ISharedToken.java
     com/netscape/certsrv/authentication/AuthMgrPlugin.java
     com/netscape/certsrv/authentication/EInvalidCredentials.java
diff --git a/base/common/src/com/netscape/certsrv/apps/CMS.java b/base/common/src/com/netscape/certsrv/apps/CMS.java
index 4d45777778dfa416f93d21ee7ea944c3cc78f2c3..40c8b3c5e8e58efe608d4ec62a18b050968280f6 100644
--- a/base/common/src/com/netscape/certsrv/apps/CMS.java
+++ b/base/common/src/com/netscape/certsrv/apps/CMS.java
@@ -44,6 +44,7 @@ import org.mozilla.jss.util.PasswordCallback;
 
 import com.netscape.certsrv.acls.EACLsException;
 import com.netscape.certsrv.acls.IACL;
+import com.netscape.certsrv.audit.IAuditor;
 import com.netscape.certsrv.authentication.IAuthSubsystem;
 import com.netscape.certsrv.authority.IAuthority;
 import com.netscape.certsrv.authorization.IAuthzSubsystem;
@@ -288,6 +289,17 @@ public final class CMS {
     }
 
     /**
+     * Returns the auditor of the current server. The auditor can
+     * be used to audit critical informational or critical error
+     * messages.
+     *
+     * @return auditor
+     */
+    public static IAuditor getAuditor() {
+        return _engine.getAuditor();
+    }
+
+    /**
      * Returns the signed audit logger of the current server. This logger can
      * be used to log critical informational or critical error
      * messages.
diff --git a/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java b/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java
index 41f4c348e7b1524b95ed5fb329164f95ed41ae62..06fe3ee316d4dbb79d48a77e83e61bd23812cab7 100644
--- a/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java
+++ b/base/common/src/com/netscape/certsrv/apps/ICMSEngine.java
@@ -42,6 +42,7 @@ import org.mozilla.jss.util.PasswordCallback;
 
 import com.netscape.certsrv.acls.EACLsException;
 import com.netscape.certsrv.acls.IACL;
+import com.netscape.certsrv.audit.IAuditor;
 import com.netscape.certsrv.authority.IAuthority;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.IArgBlock;
@@ -187,6 +188,15 @@ public interface ICMSEngine extends ISubsystem {
     public ILogger getLogger();
 
     /**
+     * Returns the auditor of the current server. The auditor can
+     * be used to audit critical informational or critical error
+     * messages.
+     *
+     * @return auditor
+     */
+    public IAuditor getAuditor();
+
+    /**
      * Returns the signed audit logger of the current server. This logger can
      * be used to log critical informational or critical error
      * messages.
diff --git a/base/common/src/com/netscape/certsrv/audit/Auditor.java b/base/common/src/com/netscape/certsrv/audit/Auditor.java
new file mode 100644
index 0000000000000000000000000000000000000000..f8fbf53e399150da9db68d22b857b6e2c9211f5e
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/audit/Auditor.java
@@ -0,0 +1,232 @@
+// --- 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) 2012 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.certsrv.audit;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.base.SessionContext;
+import com.netscape.certsrv.common.Constants;
+import com.netscape.certsrv.logging.ILogger;
+
+/**
+ * @author Endi S. Dewata
+ */
+public class Auditor implements IAuditor {
+
+    public final static Auditor auditor = new Auditor();
+
+    public final static String LOGGING_SIGNED_AUDIT_CONFIG_ROLE =
+            "LOGGING_SIGNED_AUDIT_CONFIG_ROLE_3";
+
+    public final static String SIGNED_AUDIT_SCOPE = "Scope";
+    public final static String SIGNED_AUDIT_OPERATION = "Operation";
+    public final static String SIGNED_AUDIT_RESOURCE = "Resource";
+    public final static String SIGNED_AUDIT_RULENAME = "RULENAME";
+    public final static String SIGNED_AUDIT_PASSWORD_VALUE = "********";
+    public final static String SIGNED_AUDIT_EMPTY_NAME_VALUE_PAIR = "Unknown";
+    public final static String SIGNED_AUDIT_NAME_VALUE_DELIMITER = ";;";
+    public final static String SIGNED_AUDIT_NAME_VALUE_PAIRS_DELIMITER = "+";
+
+    public ILogger signedAuditLogger = CMS.getSignedAuditLogger();
+
+    public static Auditor getAuditor() {
+        return auditor;
+    }
+
+    /**
+     * Signed Audit Parameters
+     *
+     * This method is inherited by all extended admin servlets and
+     * is called to extract parameters from the HttpServletRequest
+     * and return a string of name;;value pairs separated by a '+'
+     * if more than one name;;value pair exists.
+     * <P>
+     *
+     * @param request user request
+     * @return a delimited string of one or more delimited name/value pairs
+     */
+    public String auditParams(String scope, String type, String id, Map<String, String> params) {
+
+        // if no signed audit object exists, bail
+        if (signedAuditLogger == null) {
+            return null;
+        }
+
+        String parameters = SIGNED_AUDIT_EMPTY_NAME_VALUE_PAIR;
+        String value = null;
+
+        // always identify the scope of the request
+        if (scope != null) {
+            parameters = SIGNED_AUDIT_SCOPE
+                    + SIGNED_AUDIT_NAME_VALUE_DELIMITER
+                    + scope;
+        }
+
+        // identify the operation type of the request
+        if (type != null) {
+            parameters += SIGNED_AUDIT_NAME_VALUE_PAIRS_DELIMITER;
+
+            parameters += SIGNED_AUDIT_OPERATION
+                    + SIGNED_AUDIT_NAME_VALUE_DELIMITER
+                    + type;
+        }
+
+        // identify the resource type of the request
+        if (id != null) {
+            parameters += SIGNED_AUDIT_NAME_VALUE_PAIRS_DELIMITER;
+
+            parameters += SIGNED_AUDIT_RESOURCE
+                    + SIGNED_AUDIT_NAME_VALUE_DELIMITER
+                    + id;
+        }
+
+        if (params == null) return parameters;
+
+        // identify any remaining request parameters
+        Collection<String> names = params.keySet();
+
+        for (Iterator<String> i = names.iterator(); i.hasNext(); ) {
+            String name = i.next();
+
+            // skip "RULENAME" parameter
+            if (name.equals(SIGNED_AUDIT_RULENAME)) {
+                continue;
+            }
+
+            parameters += SIGNED_AUDIT_NAME_VALUE_PAIRS_DELIMITER;
+
+            value = params.get(name);
+            if (value != null) {
+                value = value.trim();
+
+                if (value.equals("")) {
+                    parameters += name
+                            + SIGNED_AUDIT_NAME_VALUE_DELIMITER
+                            + ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+                } else {
+                    //
+                    // To fix Blackflag Bug # 613800:
+                    //
+                    //     Check "com.netscape.certsrv.common.Constants" for
+                    //     case-insensitive "password", "pwd", and "passwd"
+                    //     name fields, and hide any password values:
+                    //
+                    /* "password" */if (name.equals(Constants.PASSWORDTYPE) ||
+                            name.equals(Constants.TYPE_PASSWORD) ||
+                            name.equals(Constants.PR_USER_PASSWORD) ||
+                            name.equals(Constants.PT_OLD_PASSWORD) ||
+                            name.equals(Constants.PT_NEW_PASSWORD) ||
+                            name.equals(Constants.PT_DIST_STORE) ||
+                            name.equals(Constants.PT_DIST_EMAIL) ||
+                            /* "pwd" */name.equals(Constants.PR_AUTH_ADMIN_PWD) ||
+                            // ignore this one  name.equals( Constants.PR_BINDPWD_PROMPT )        ||
+                            name.equals(Constants.PR_DIRECTORY_MANAGER_PWD) ||
+                            name.equals(Constants.PR_OLD_AGENT_PWD) ||
+                            name.equals(Constants.PR_AGENT_PWD) ||
+                            name.equals(Constants.PT_PUBLISH_PWD) ||
+                            /* "passwd" */name.equals(Constants.PR_BIND_PASSWD) ||
+                            name.equals(Constants.PR_BIND_PASSWD_AGAIN) ||
+                            name.equals(Constants.PR_TOKEN_PASSWD)) {
+
+                        // hide password value
+                        parameters += name
+                                    + SIGNED_AUDIT_NAME_VALUE_DELIMITER
+                                    + SIGNED_AUDIT_PASSWORD_VALUE;
+                    } else {
+                        // process normally
+                        parameters += name
+                                    + SIGNED_AUDIT_NAME_VALUE_DELIMITER
+                                    + value;
+                    }
+                }
+            } else {
+                parameters += name
+                        + SIGNED_AUDIT_NAME_VALUE_DELIMITER
+                        + ILogger.SIGNED_AUDIT_EMPTY_VALUE;
+            }
+        }
+
+        return parameters;
+    }
+
+    /**
+     * Signed Audit Log Subject ID
+     *
+     * This method is inherited by all extended "CMSServlet"s,
+     * and is called to obtain the "SubjectID" for
+     * a signed audit log message.
+     * <P>
+     *
+     * @return id string containing the signed audit log message SubjectID
+     */
+    public String auditSubjectID() {
+        // if no signed audit object exists, bail
+        if (signedAuditLogger == null) return null;
+
+        String subjectID = null;
+
+        // Initialize subjectID
+        SessionContext auditContext = SessionContext.getExistingContext();
+
+        if (auditContext != null) {
+            subjectID = (String)
+                    auditContext.get(SessionContext.USER_ID);
+
+            if (subjectID != null) {
+                subjectID = subjectID.trim();
+            } else {
+                subjectID = ILogger.NONROLEUSER;
+            }
+        } else {
+            subjectID = ILogger.UNIDENTIFIED;
+        }
+
+        return subjectID;
+    }
+
+    @Override
+    public void audit(String scope, String type, String id, String status) {
+        audit(scope, type, id, null, status);
+    }
+
+    @Override
+    public void audit(String scope, String type, String id, Map<String, String> params, String status) {
+
+        if (signedAuditLogger == null) return;
+
+        String subjectId = auditSubjectID();
+        String paramsString = auditParams(scope, type, id, params);
+
+        String message = CMS.getLogMessage(
+                LOGGING_SIGNED_AUDIT_CONFIG_ROLE,
+                subjectId,
+                status,
+                paramsString);
+
+        signedAuditLogger.log(
+                ILogger.EV_SIGNED_AUDIT,
+                null,
+                ILogger.S_SIGNED_AUDIT,
+                ILogger.LL_SECURITY,
+                message);
+    }
+}
diff --git a/base/common/src/com/netscape/certsrv/audit/IAuditor.java b/base/common/src/com/netscape/certsrv/audit/IAuditor.java
new file mode 100644
index 0000000000000000000000000000000000000000..110f1aa14d780fd8a5ae48ade6b90b8284da8952
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/audit/IAuditor.java
@@ -0,0 +1,37 @@
+// --- 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) 2012 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+package com.netscape.certsrv.audit;
+
+import java.util.Map;
+
+/**
+ * @author Endi S. Dewata
+ */
+public interface IAuditor {
+
+    /**
+     * Audit an operation.
+     */
+    public abstract void audit(String scope, String type, String id, String status);
+
+    /**
+     * Audit an operation with parameters.
+     */
+    public abstract void audit(String scope, String type, String id, Map<String, String> params, String status);
+}
\ No newline at end of file
diff --git a/base/common/src/com/netscape/cmscore/apps/CMSEngine.java b/base/common/src/com/netscape/cmscore/apps/CMSEngine.java
index 19fc5162b0f4ff43b1bec1ff6dc9004a2f6748ec..d104ebe7bbb98dc12e3a3582bfbe07cd0e210dd9 100644
--- a/base/common/src/com/netscape/cmscore/apps/CMSEngine.java
+++ b/base/common/src/com/netscape/cmscore/apps/CMSEngine.java
@@ -70,6 +70,8 @@ import com.netscape.certsrv.acls.IACL;
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.apps.ICMSEngine;
 import com.netscape.certsrv.apps.ICommandQueue;
+import com.netscape.certsrv.audit.Auditor;
+import com.netscape.certsrv.audit.IAuditor;
 import com.netscape.certsrv.authority.IAuthority;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.IArgBlock;
@@ -1513,6 +1515,10 @@ public class CMSEngine implements ICMSEngine {
         return Logger.getLogger();
     }
 
+    public IAuditor getAuditor() {
+        return Auditor.getAuditor();
+    }
+
     public ILogger getSignedAuditLogger() {
         return SignedAuditLogger.getLogger();
     }
diff --git a/base/common/test/com/netscape/certsrv/app/CMSEngineDefaultStub.java b/base/common/test/com/netscape/certsrv/app/CMSEngineDefaultStub.java
index cddd1205a7f6bd42ce751b92c174b7bb83792e3f..75212977f82323cb6b722d6f026b796ee9ad2f18 100644
--- a/base/common/test/com/netscape/certsrv/app/CMSEngineDefaultStub.java
+++ b/base/common/test/com/netscape/certsrv/app/CMSEngineDefaultStub.java
@@ -27,6 +27,7 @@ import com.netscape.certsrv.acls.EACLsException;
 import com.netscape.certsrv.acls.IACL;
 import com.netscape.certsrv.apps.ICMSEngine;
 import com.netscape.certsrv.apps.ICommandQueue;
+import com.netscape.certsrv.audit.IAuditor;
 import com.netscape.certsrv.authority.IAuthority;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.IArgBlock;
@@ -142,6 +143,10 @@ public class CMSEngineDefaultStub implements ICMSEngine {
         return null;
     }
 
+    public IAuditor getAuditor() {
+        return null;
+    }
+
     public ILogger getSignedAuditLogger() {
         return null;
     }
-- 
1.7.7.6

