>From e5031fe071e15eba2a3894f664abb09570f3a60f Mon Sep 17 00:00:00 2001
From: Ade Lee <alee@redhat.com>
Date: Wed, 28 Aug 2013 00:49:05 -0400
Subject: [PATCH 146/147] Add audit logging to profile interface

This patch adds initial audit logging to the Profile interface.
A more complete review of audit logging will probably be done for
Common Criteria testing.
---
 .../netscape/certsrv/profile/PolicyConstraint.java |  42 ++
 .../certsrv/profile/PolicyConstraintValue.java     |  37 ++
 .../netscape/certsrv/profile/PolicyDefault.java    |  48 ++
 .../netscape/certsrv/profile/ProfileAttribute.java |  37 ++
 .../com/netscape/certsrv/profile/ProfileInput.java |  55 +++
 .../netscape/certsrv/profile/ProfileOutput.java    |  49 ++
 .../netscape/certsrv/profile/ProfilePolicy.java    |  37 ++
 .../com/netscape/certsrv/property/Descriptor.java  |  43 ++
 .../cms/servlet/profile/ProfileService.java        | 549 ++++++++++++++++-----
 9 files changed, 784 insertions(+), 113 deletions(-)

diff --git a/base/common/src/com/netscape/certsrv/profile/PolicyConstraint.java b/base/common/src/com/netscape/certsrv/profile/PolicyConstraint.java
index a0f4e9defcb71eb24b930ce275dbc4bd1f41bd4f..ab46ecd14e87019c025b87c40cfb8e537cf461eb 100644
--- a/base/common/src/com/netscape/certsrv/profile/PolicyConstraint.java
+++ b/base/common/src/com/netscape/certsrv/profile/PolicyConstraint.java
@@ -81,4 +81,46 @@ public class PolicyConstraint {
         this.constraints = constraints;
     }
 
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((classId == null) ? 0 : classId.hashCode());
+        result = prime * result + ((constraints == null) ? 0 : constraints.hashCode());
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        result = prime * result + ((text == null) ? 0 : text.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;
+        PolicyConstraint other = (PolicyConstraint) obj;
+        if (classId == null) {
+            if (other.classId != null)
+                return false;
+        } else if (!classId.equals(other.classId))
+            return false;
+        if (constraints == null) {
+            if (other.constraints != null)
+                return false;
+        } else if (!constraints.equals(other.constraints))
+            return false;
+        if (name == null) {
+            if (other.name != null)
+                return false;
+        } else if (!name.equals(other.name))
+            return false;
+        if (text == null) {
+            if (other.text != null)
+                return false;
+        } else if (!text.equals(other.text))
+            return false;
+        return true;
+    }
 }
diff --git a/base/common/src/com/netscape/certsrv/profile/PolicyConstraintValue.java b/base/common/src/com/netscape/certsrv/profile/PolicyConstraintValue.java
index a16b4c59d67741ebb23d8c451a368172f087f74b..162b706bb0c1cd7dc85daa88cea5e2f8c521ace0 100644
--- a/base/common/src/com/netscape/certsrv/profile/PolicyConstraintValue.java
+++ b/base/common/src/com/netscape/certsrv/profile/PolicyConstraintValue.java
@@ -70,4 +70,41 @@ public class PolicyConstraintValue {
     public void setValue(String value) {
         this.value = value;
     }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((descriptor == null) ? 0 : descriptor.hashCode());
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        result = prime * result + ((value == null) ? 0 : value.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;
+        PolicyConstraintValue other = (PolicyConstraintValue) obj;
+        if (descriptor == null) {
+            if (other.descriptor != null)
+                return false;
+        } else if (!descriptor.equals(other.descriptor))
+            return false;
+        if (name == null) {
+            if (other.name != null)
+                return false;
+        } else if (!name.equals(other.name))
+            return false;
+        if (value == null) {
+            if (other.value != null)
+                return false;
+        } else if (!value.equals(other.value))
+            return false;
+        return true;
+    }
 }
diff --git a/base/common/src/com/netscape/certsrv/profile/PolicyDefault.java b/base/common/src/com/netscape/certsrv/profile/PolicyDefault.java
index f92242cc18c068dae841e1a86b10793216187167..5b1943147c3801c15de759959c8f3a7234c59f40 100644
--- a/base/common/src/com/netscape/certsrv/profile/PolicyDefault.java
+++ b/base/common/src/com/netscape/certsrv/profile/PolicyDefault.java
@@ -92,4 +92,52 @@ public class PolicyDefault {
         this.params = params;
     }
 
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((attributes == null) ? 0 : attributes.hashCode());
+        result = prime * result + ((classId == null) ? 0 : classId.hashCode());
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        result = prime * result + ((params == null) ? 0 : params.hashCode());
+        result = prime * result + ((text == null) ? 0 : text.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;
+        PolicyDefault other = (PolicyDefault) obj;
+        if (attributes == null) {
+            if (other.attributes != null)
+                return false;
+        } else if (!attributes.equals(other.attributes))
+            return false;
+        if (classId == null) {
+            if (other.classId != null)
+                return false;
+        } else if (!classId.equals(other.classId))
+            return false;
+        if (name == null) {
+            if (other.name != null)
+                return false;
+        } else if (!name.equals(other.name))
+            return false;
+        if (params == null) {
+            if (other.params != null)
+                return false;
+        } else if (!params.equals(other.params))
+            return false;
+        if (text == null) {
+            if (other.text != null)
+                return false;
+        } else if (!text.equals(other.text))
+            return false;
+        return true;
+    }
 }
diff --git a/base/common/src/com/netscape/certsrv/profile/ProfileAttribute.java b/base/common/src/com/netscape/certsrv/profile/ProfileAttribute.java
index 9c889bb8a1881a241f0d079c66f51385e9427cec..c3549424c8468af4976d893b96db1f21a48d35a6 100644
--- a/base/common/src/com/netscape/certsrv/profile/ProfileAttribute.java
+++ b/base/common/src/com/netscape/certsrv/profile/ProfileAttribute.java
@@ -77,4 +77,41 @@ public class ProfileAttribute {
         return "PolicyAttribute [name=" + name + ", value=" + value + ", descriptor=" + descriptor + "]";
     }
 
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((descriptor == null) ? 0 : descriptor.hashCode());
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        result = prime * result + ((value == null) ? 0 : value.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;
+        ProfileAttribute other = (ProfileAttribute) obj;
+        if (descriptor == null) {
+            if (other.descriptor != null)
+                return false;
+        } else if (!descriptor.equals(other.descriptor))
+            return false;
+        if (name == null) {
+            if (other.name != null)
+                return false;
+        } else if (!name.equals(other.name))
+            return false;
+        if (value == null) {
+            if (other.value != null)
+                return false;
+        } else if (!value.equals(other.value))
+            return false;
+        return true;
+    }
+
 }
diff --git a/base/common/src/com/netscape/certsrv/profile/ProfileInput.java b/base/common/src/com/netscape/certsrv/profile/ProfileInput.java
index a9b9507cbbaffe6cd49d1f902188ff8002f85020..2826f50d8bd7f36a1ad8cb3e6352984c1ef68a5f 100644
--- a/base/common/src/com/netscape/certsrv/profile/ProfileInput.java
+++ b/base/common/src/com/netscape/certsrv/profile/ProfileInput.java
@@ -129,4 +129,59 @@ public class ProfileInput {
         configAttrs.clear();
     }
 
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((attrs == null) ? 0 : attrs.hashCode());
+        result = prime * result + ((classId == null) ? 0 : classId.hashCode());
+        result = prime * result + ((configAttrs == null) ? 0 : configAttrs.hashCode());
+        result = prime * result + ((id == null) ? 0 : id.hashCode());
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        result = prime * result + ((text == null) ? 0 : text.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;
+        ProfileInput other = (ProfileInput) obj;
+        if (attrs == null) {
+            if (other.attrs != null)
+                return false;
+        } else if (!attrs.equals(other.attrs))
+            return false;
+        if (classId == null) {
+            if (other.classId != null)
+                return false;
+        } else if (!classId.equals(other.classId))
+            return false;
+        if (configAttrs == null) {
+            if (other.configAttrs != null)
+                return false;
+        } else if (!configAttrs.equals(other.configAttrs))
+            return false;
+        if (id == null) {
+            if (other.id != null)
+                return false;
+        } else if (!id.equals(other.id))
+            return false;
+        if (name == null) {
+            if (other.name != null)
+                return false;
+        } else if (!name.equals(other.name))
+            return false;
+        if (text == null) {
+            if (other.text != null)
+                return false;
+        } else if (!text.equals(other.text))
+            return false;
+        return true;
+    }
+
 }
diff --git a/base/common/src/com/netscape/certsrv/profile/ProfileOutput.java b/base/common/src/com/netscape/certsrv/profile/ProfileOutput.java
index 759b65ce72cbe250a672b4c780d615c3cca10c50..f12b647877fd4590efbe1f0347764b4fc635a59d 100644
--- a/base/common/src/com/netscape/certsrv/profile/ProfileOutput.java
+++ b/base/common/src/com/netscape/certsrv/profile/ProfileOutput.java
@@ -118,4 +118,53 @@ public class ProfileOutput {
         attrs.clear();
     }
 
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((attrs == null) ? 0 : attrs.hashCode());
+        result = prime * result + ((classId == null) ? 0 : classId.hashCode());
+        result = prime * result + ((id == null) ? 0 : id.hashCode());
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        result = prime * result + ((text == null) ? 0 : text.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;
+        ProfileOutput other = (ProfileOutput) obj;
+        if (attrs == null) {
+            if (other.attrs != null)
+                return false;
+        } else if (!attrs.equals(other.attrs))
+            return false;
+        if (classId == null) {
+            if (other.classId != null)
+                return false;
+        } else if (!classId.equals(other.classId))
+            return false;
+        if (id == null) {
+            if (other.id != null)
+                return false;
+        } else if (!id.equals(other.id))
+            return false;
+        if (name == null) {
+            if (other.name != null)
+                return false;
+        } else if (!name.equals(other.name))
+            return false;
+        if (text == null) {
+            if (other.text != null)
+                return false;
+        } else if (!text.equals(other.text))
+            return false;
+        return true;
+    }
+
 }
diff --git a/base/common/src/com/netscape/certsrv/profile/ProfilePolicy.java b/base/common/src/com/netscape/certsrv/profile/ProfilePolicy.java
index d5f84f188b17ff59e36d122c13aa8f90994a206a..4ea0f1abbad64c67c2022041f547ac3185a79384 100644
--- a/base/common/src/com/netscape/certsrv/profile/ProfilePolicy.java
+++ b/base/common/src/com/netscape/certsrv/profile/ProfilePolicy.java
@@ -79,4 +79,41 @@ public class ProfilePolicy {
         return null;
     }
 
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((constraint == null) ? 0 : constraint.hashCode());
+        result = prime * result + ((def == null) ? 0 : def.hashCode());
+        result = prime * result + ((id == null) ? 0 : id.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;
+        ProfilePolicy other = (ProfilePolicy) obj;
+        if (constraint == null) {
+            if (other.constraint != null)
+                return false;
+        } else if (!constraint.equals(other.constraint))
+            return false;
+        if (def == null) {
+            if (other.def != null)
+                return false;
+        } else if (!def.equals(other.def))
+            return false;
+        if (id == null) {
+            if (other.id != null)
+                return false;
+        } else if (!id.equals(other.id))
+            return false;
+        return true;
+    }
+
 }
diff --git a/base/common/src/com/netscape/certsrv/property/Descriptor.java b/base/common/src/com/netscape/certsrv/property/Descriptor.java
index f5069d0461479b9e27e4d30e87f8c5ea43daff0d..63e1544669ec3853847c07b23ebecba825db47de 100644
--- a/base/common/src/com/netscape/certsrv/property/Descriptor.java
+++ b/base/common/src/com/netscape/certsrv/property/Descriptor.java
@@ -115,4 +115,47 @@ public class Descriptor implements IDescriptor {
         return "Descriptor [mSyntax=" + mSyntax + ", mConstraint=" + mConstraint + ", mDescription=" + mDescription
                 + ", mDef=" + mDef + "]";
     }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((mConstraint == null) ? 0 : mConstraint.hashCode());
+        result = prime * result + ((mDef == null) ? 0 : mDef.hashCode());
+        result = prime * result + ((mDescription == null) ? 0 : mDescription.hashCode());
+        result = prime * result + ((mSyntax == null) ? 0 : mSyntax.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;
+        Descriptor other = (Descriptor) obj;
+        if (mConstraint == null) {
+            if (other.mConstraint != null)
+                return false;
+        } else if (!mConstraint.equals(other.mConstraint))
+            return false;
+        if (mDef == null) {
+            if (other.mDef != null)
+                return false;
+        } else if (!mDef.equals(other.mDef))
+            return false;
+        if (mDescription == null) {
+            if (other.mDescription != null)
+                return false;
+        } else if (!mDescription.equals(other.mDescription))
+            return false;
+        if (mSyntax == null) {
+            if (other.mSyntax != null)
+                return false;
+        } else if (!mSyntax.equals(other.mSyntax))
+            return false;
+        return true;
+    }
 }
diff --git a/base/common/src/com/netscape/cms/servlet/profile/ProfileService.java b/base/common/src/com/netscape/cms/servlet/profile/ProfileService.java
index d4b23d95c0c59e430fd61564164d47e353ab8b0b..09a9a1c23d76d73d55ab8d60a45fc25b0c9b9241 100644
--- a/base/common/src/com/netscape/cms/servlet/profile/ProfileService.java
+++ b/base/common/src/com/netscape/cms/servlet/profile/ProfileService.java
@@ -32,6 +32,7 @@ import java.util.Vector;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.core.UriBuilder;
 
+import org.apache.commons.lang.StringUtils;
 import org.jboss.resteasy.plugins.providers.atom.Link;
 
 import com.netscape.certsrv.apps.CMS;
@@ -41,6 +42,9 @@ import com.netscape.certsrv.base.IConfigStore;
 import com.netscape.certsrv.base.PKIException;
 import com.netscape.certsrv.base.UnauthorizedException;
 import com.netscape.certsrv.common.NameValuePairs;
+import com.netscape.certsrv.common.OpDef;
+import com.netscape.certsrv.common.ScopeDef;
+import com.netscape.certsrv.logging.ILogger;
 import com.netscape.certsrv.profile.EProfileException;
 import com.netscape.certsrv.profile.IProfile;
 import com.netscape.certsrv.profile.IProfileEx;
@@ -76,6 +80,11 @@ public class ProfileService extends PKIService implements ProfileResource {
     private IPluginRegistry registry = (IPluginRegistry) CMS.getSubsystem(CMS.SUBSYSTEM_REGISTRY);
     private IConfigStore cs = CMS.getConfigStore().getSubStore("profile");
 
+    private final static String LOGGING_SIGNED_AUDIT_CERT_PROFILE_APPROVAL =
+            "LOGGING_SIGNED_AUDIT_CERT_PROFILE_APPROVAL_4";
+    private final static String LOGGING_SIGNED_AUDIT_CONFIG_CERT_PROFILE =
+            "LOGGING_SIGNED_AUDIT_CONFIG_CERT_PROFILE_3";
+
     public ProfileDataInfos listProfiles() {
         List<ProfileDataInfo> list = new ArrayList<ProfileDataInfo>();
         ProfileDataInfos infos = new ProfileDataInfos();
@@ -85,10 +94,10 @@ public class ProfileService extends PKIService implements ProfileResource {
             return null;
         }
 
-        PKIPrincipal principal = (PKIPrincipal)servletRequest.getUserPrincipal();
+        PKIPrincipal principal = (PKIPrincipal) servletRequest.getUserPrincipal();
         if ((principal != null) &&
-            (principal.hasRole("Certificate Manager Agents") ||
-             principal.hasRole("Certificate Manager Administrators"))) {
+                (principal.hasRole("Certificate Manager Agents") ||
+                principal.hasRole("Certificate Manager Administrators"))) {
             visibleOnly = false;
         }
         Enumeration<String> profileIds = ps.getProfileIds();
@@ -120,10 +129,10 @@ public class ProfileService extends PKIService implements ProfileResource {
             return null;
         }
 
-        PKIPrincipal principal = (PKIPrincipal)servletRequest.getUserPrincipal();
+        PKIPrincipal principal = (PKIPrincipal) servletRequest.getUserPrincipal();
         if ((principal != null) &&
-            (principal.hasRole("Certificate Manager Agents") ||
-             principal.hasRole("Certificate Manager Administrators"))) {
+                (principal.hasRole("Certificate Manager Agents") ||
+                principal.hasRole("Certificate Manager Administrators"))) {
             visibleOnly = false;
         }
 
@@ -197,18 +206,10 @@ public class ProfileService extends PKIService implements ProfileResource {
 
         Enumeration<String> inputIds = profile.getProfileInputIds();
         if (inputIds != null) {
-            IConfigStore inputStore = profile.getConfigStore().getSubStore("input");
             while (inputIds.hasMoreElements()) {
-                String inputId = inputIds.nextElement();
-                IProfileInput profileInput = profile.getProfileInput(inputId);
-
-                if (profileInput == null) {
+                ProfileInput input = createProfileInput(profile, inputIds.nextElement());
+                if (input == null)
                     continue;
-                }
-
-                String classId = inputStore.getString(inputId + ".class_id");
-
-                ProfileInput input = new ProfileInput(profileInput, inputId, classId, getLocale());
                 data.addProfileInput(input);
             }
         }
@@ -216,18 +217,10 @@ public class ProfileService extends PKIService implements ProfileResource {
         // profile outputs
         Enumeration<String> outputIds = profile.getProfileOutputIds();
         if (outputIds != null) {
-            IConfigStore outputStore = profile.getConfigStore().getSubStore("output");
             while (outputIds.hasMoreElements()) {
-                String outputId = outputIds.nextElement();
-                IProfileOutput profileOutput = profile.getProfileOutput(outputId);
-
-                if (profileOutput == null) {
+                ProfileOutput output = createProfileOutput(profile, outputIds.nextElement());
+                if (output == null)
                     continue;
-                }
-
-                String classId = outputStore.getString(outputId + ".class_id");
-
-                ProfileOutput output = new ProfileOutput(profileOutput, outputId, classId, getLocale());
                 data.addProfileOutput(output);
             }
         }
@@ -238,22 +231,12 @@ public class ProfileService extends PKIService implements ProfileResource {
             while (policySetIds.hasMoreElements()) {
                 Vector<ProfilePolicy> pset = new Vector<ProfilePolicy>();
                 String policySetId = policySetIds.nextElement();
-                Enumeration<com.netscape.cms.profile.common.ProfilePolicy> policies =
-                        profile.getProfilePolicies(policySetId);
-                if (policies != null) {
-                    while (policies.hasMoreElements()) {
-                        com.netscape.cms.profile.common.ProfilePolicy policy = policies.nextElement();
-                        IConfigStore policyStore = profile.getConfigStore().getSubStore(
-                                "policyset." + policySetId + "." + policy.getId());
-                        ProfilePolicy p = new ProfilePolicy();
-                        String constraintClassId = policyStore.getString("constraint.class_id");
-                        p.setConstraint(PolicyConstraintFactory.create(getLocale(), policy.getConstraint(), constraintClassId));
-                        String defaultClassId = policyStore.getString("default.class_id");
-                        p.setDef(PolicyDefaultFactory.create(getLocale(), policy.getDefault(), defaultClassId));
-                        p.setId(policy.getId());
-                        pset.add(p);
-                    }
+                Enumeration<String> policyIds = profile.getProfilePolicyIds(policySetId);
+                while (policyIds.hasMoreElements()) {
+                    String policyId = policyIds.nextElement();
+                    pset.add(createProfilePolicy(profile, policySetId, policyId));
                 }
+
                 if (!pset.isEmpty()) {
                     data.addProfilePolicySet(policySetId, pset);
                 }
@@ -268,6 +251,42 @@ public class ProfileService extends PKIService implements ProfileResource {
         return data;
     }
 
+    public ProfilePolicy createProfilePolicy(IProfile profile, String setId, String policyId) throws EBaseException {
+        IProfilePolicy policy = profile.getProfilePolicy(setId, policyId);
+        IConfigStore policyStore = profile.getConfigStore().getSubStore(
+                "policyset." + setId + "." + policy.getId());
+
+        ProfilePolicy p = new ProfilePolicy();
+        String constraintClassId = policyStore.getString("constraint.class_id");
+        p.setConstraint(PolicyConstraintFactory.create(getLocale(), policy.getConstraint(), constraintClassId));
+        String defaultClassId = policyStore.getString("default.class_id");
+        p.setDef(PolicyDefaultFactory.create(getLocale(), policy.getDefault(), defaultClassId));
+        p.setId(policy.getId());
+        return p;
+    }
+
+    public ProfileInput createProfileInput(IProfile profile, String inputId) throws EBaseException {
+        IProfileInput profileInput = profile.getProfileInput(inputId);
+        if (profileInput == null)
+            return null;
+
+        IConfigStore inputStore = profile.getConfigStore().getSubStore("input");
+        String classId = inputStore.getString(inputId + ".class_id");
+
+        return new ProfileInput(profileInput, inputId, classId, getLocale());
+    }
+
+    public ProfileOutput createProfileOutput(IProfile profile, String outputId) throws EBaseException {
+        IProfileOutput profileOutput = profile.getProfileOutput(outputId);
+        if (profileOutput == null)
+            return null;
+
+        IConfigStore outputStore = profile.getConfigStore().getSubStore("output");
+        String classId = outputStore.getString(outputId + ".class_id");
+
+        return new ProfileOutput(profileOutput, outputId, classId, getLocale());
+    }
+
     public ProfileDataInfo createProfileDataInfo(String profileId, boolean visibleOnly) throws EBaseException {
 
         if (profileId == null) {
@@ -307,6 +326,11 @@ public class ProfileService extends PKIService implements ProfileResource {
             throw new PKIException("Error modifying profile state.  Profile Service not available");
         }
 
+        if (profileId == null) {
+            CMS.debug("modifyProfileState: invalid request. profileId is null");
+            throw new BadRequestException("Invalid ProfileId");
+        }
+
         Principal principal = servletRequest.getUserPrincipal();
 
         switch (action) {
@@ -316,9 +340,11 @@ public class ProfileService extends PKIService implements ProfileResource {
             }
             try {
                 ps.enableProfile(profileId, principal.getName());
+                auditProfileChangeState(profileId, "approve", ILogger.SUCCESS);
             } catch (EProfileException e) {
                 CMS.debug("modifyProfileState: error enabling profile. " + e);
                 e.printStackTrace();
+                auditProfileChangeState(profileId, "approve", ILogger.FAILURE);
                 throw new PKIException("Error enabling profile");
             }
             break;
@@ -332,25 +358,28 @@ public class ProfileService extends PKIService implements ProfileResource {
                     if (ps.getProfileEnableBy(profileId).equals(userid)) {
                         ps.disableProfile(profileId);
                     } else {
-                        // audit log messages
+                        auditProfileChangeState(profileId, "disapprove", ILogger.FAILURE);
                         throw new UnauthorizedException(
                                 "Profile can only be disabled by the agent that enabled it");
                     }
                 } else {
                     ps.disableProfile(profileId);
+                    auditProfileChangeState(profileId, "disapprove", ILogger.SUCCESS);
                 }
             } catch (EProfileException e) {
                 CMS.debug("modifyProfileState: Error disabling profile: " + e);
                 e.printStackTrace();
+                auditProfileChangeState(profileId, "disapprove", ILogger.FAILURE);
                 throw new PKIException("Error disabling profile");
             }
             break;
         default:
+            auditProfileChangeState(profileId, "invalid", ILogger.FAILURE);
             throw new BadRequestException("Invalid operation");
         }
     }
 
-    public void createProfile(ProfileData data){
+    public void createProfile(ProfileData data) {
         if (ps == null) {
             CMS.debug("createProfile: ps is null");
             throw new PKIException("Error creating profile.  Profile Service not available");
@@ -358,11 +387,18 @@ public class ProfileService extends PKIService implements ProfileResource {
 
         IProfile profile = null;
         String profileId = data.getId();
+        Map<String, String> auditParams = new LinkedHashMap<String, String>();
         try {
             profile = ps.getProfile(profileId);
             if (profile != null) {
                 throw new BadRequestException("Profile already exists");
             }
+
+            auditParams.put("class_id", data.getClassId());
+            auditParams.put("name", data.getName());
+            auditParams.put("description", data.getDescription());
+            auditParams.put("visible", Boolean.toString(data.isVisible()));
+
             String config = CMS.getConfigStore().getString("instanceRoot") + "/ca/profiles/ca/" +
                     profileId + ".cfg";
             File configFile = new File(config);
@@ -370,7 +406,7 @@ public class ProfileService extends PKIService implements ProfileResource {
             IPluginInfo info = registry.getPluginInfo("profile", data.getClassId());
 
             profile = ps.createProfile(profileId, data.getClassId(), info.getClassName(), config);
-            profile.setName(getLocale(),data.getName());
+            profile.setName(getLocale(), data.getName());
             profile.setDescription(getLocale(), data.getDescription());
             profile.setVisible(data.isVisible());
             profile.getConfigStore().commit(false);
@@ -381,16 +417,31 @@ public class ProfileService extends PKIService implements ProfileResource {
                 // policies, inputs and outputs with defaults
                 ((IProfileEx) profile).populate();
             }
+
+            auditProfileChange(
+                    ScopeDef.SC_PROFILE_RULES,
+                    OpDef.OP_ADD,
+                    profileId,
+                    ILogger.SUCCESS,
+                    auditParams);
         } catch (EBaseException | IOException e) {
             CMS.debug("createProfile: error in creating profile: " + e);
             e.printStackTrace();
+
+            auditProfileChange(
+                    ScopeDef.SC_PROFILE_RULES,
+                    OpDef.OP_ADD,
+                    profileId,
+                    ILogger.FAILURE,
+                    auditParams);
+
             throw new PKIException("Error in creating profile");
         }
 
         changeProfileData(data, profile);
     }
 
-    public void modifyProfile(String profileId, ProfileData data){
+    public void modifyProfile(String profileId, ProfileData data) {
         if (ps == null) {
             CMS.debug("modifyProfile: ps is null");
             throw new PKIException("Error modifying profile.  Profile Service not available");
@@ -429,7 +480,7 @@ public class ProfileService extends PKIService implements ProfileResource {
             auditParams.put("authenticatorId", data.getAuthenticatorId());
         }
 
-        if (differs(profile.getAuthzAcl(),data.getAuthzAcl())) {
+        if (differs(profile.getAuthzAcl(), data.getAuthzAcl())) {
             profile.setAuthzAcl(data.getAuthzAcl());
             auditParams.put("authzAcl", data.getAuthzAcl());
         }
@@ -439,48 +490,46 @@ public class ProfileService extends PKIService implements ProfileResource {
             auditParams.put("description", data.getDescription());
         }
 
-        if (differs(profile.getId(),data.getId())) {
+        if (differs(profile.getId(), data.getId())) {
             profile.setId(data.getId());
             auditParams.put("id", data.getId());
         }
 
-        if (differs(profile.getName(getLocale()),data.getName())) {
-            profile.setName(getLocale(),data.getName());
+        if (differs(profile.getName(getLocale()), data.getName())) {
+            profile.setName(getLocale(), data.getName());
             auditParams.put("name", data.getName());
         }
 
         // TODO renewal is a string in Profile, should be changed
-        if (differs(profile.isRenewal(),Boolean.toString(data.isRenewal()))) {
+        if (differs(profile.isRenewal(), Boolean.toString(data.isRenewal()))) {
             profile.setRenewal(data.isRenewal());
             auditParams.put("renewal", Boolean.toString(data.isRenewal()));
         }
 
-        if (! profile.isVisible() == data.isVisible()) {
+        if (!profile.isVisible() == data.isVisible()) {
             profile.setVisible(data.isVisible());
             auditParams.put("visible", Boolean.toString(data.isVisible()));
         }
 
         // TODO xmloutput is a string in Profile, should be changed
-        if (differs(profile.isXmlOutput(),Boolean.toString(data.isXMLOutput()))) {
+        if (differs(profile.isXmlOutput(), Boolean.toString(data.isXMLOutput()))) {
             profile.setXMLOutput(data.isXMLOutput());
             auditParams.put("xmloutput", Boolean.toString(data.isXMLOutput()));
         }
 
-        // add audit log for auditParams
+        if (!auditParams.isEmpty()) {
+            auditProfileChange(
+                    ScopeDef.SC_PROFILE_RULES,
+                    OpDef.OP_MODIFY,
+                    profileId,
+                    ILogger.SUCCESS,
+                    auditParams);
+        }
 
         try {
             populateProfileInputs(data, profile);
-
-            // add audit log for profile inputs
-
             populateProfileOutputs(data, profile);
-
-            // add audit log for profile outputs
-
             populateProfilePolicies(data, profile);
-
-            // add audit log for profile policies
-
             profile.getConfigStore().commit(false);
         } catch (EBaseException e) {
             CMS.debug("changeProfileData: Error changing profile inputs/outputs/policies: " + e);
@@ -502,75 +551,310 @@ public class ProfileService extends PKIService implements ProfileResource {
         return false;
     }
 
-    private void populateProfilePolicies(ProfileData data, IProfile profile) throws EProfileException, EPropertyException {
-        profile.deleteAllProfilePolicies();
-        for (Map.Entry<String,List<ProfilePolicy>> policySet:
-            data.getPolicySets().entrySet()) {
+    private void populateProfilePolicies(ProfileData data, IProfile profile) throws EBaseException {
+        // get list of changes for auditing
+        List<String> auditAdd = new ArrayList<String>();
+        List<String> auditModify = new ArrayList<String>();
+
+        Enumeration<String> existingSetIds = profile.getProfilePolicySetIds();
+        Map<String, ProfilePolicy> existingPolicies = new LinkedHashMap<String, ProfilePolicy>();
+        while (existingSetIds.hasMoreElements()) {
+            String setId = existingSetIds.nextElement();
+            Enumeration<String> policyIds = profile.getProfilePolicyIds(setId);
+            while (policyIds.hasMoreElements()) {
+                String policyId = policyIds.nextElement();
+                existingPolicies.put(
+                        setId + ":" + policyId,
+                        createProfilePolicy(profile, setId, policyId));
+            }
+        }
+
+        for (Map.Entry<String, List<ProfilePolicy>> policySet : data.getPolicySets().entrySet()) {
             String setId = policySet.getKey();
-            for (ProfilePolicy policy: policySet.getValue()) {
-                PolicyDefault def = policy.getDef();
-                PolicyConstraint con = policy.getConstraint();
-
-                // create policy using defaults for PolicyDefault and PolicyConstraint
-                IProfilePolicy p = profile.createProfilePolicy(setId, policy.getId(),
-                        def.getClassId(), con.getClassId());
-
-                // change specific elements to match incoming data for PolicyDefault
-                IConfigStore pstore = profile.getConfigStore().getSubStore(
-                        "policyset." + setId + "." + policy.getId());
-                if (!def.getName().isEmpty()) {
-                    pstore.putString("default.name", def.getName());
-                }
-                /*if (!def.getText().isEmpty()) {
-                    pstore.putString("default.description", def.getText());
-                }*/
-                for (ProfileParameter param: def.getParams()) {
-                    if (!param.getValue().isEmpty()) {
-                        p.getDefault().setConfig(param.getName(), param.getValue());
+            for (ProfilePolicy policy : policySet.getValue()) {
+                String id = setId + ":" + policy.getId();
+                if (!existingPolicies.containsKey(id)) {
+                    auditAdd.add(id);
+                } else {
+                    if (!policy.equals(existingPolicies.get(id))) {
+                        auditModify.add(id);
                     }
                 }
+                existingPolicies.remove(id);
+            }
+        }
 
-                // change specific elements to match incoming data for PolicyConstraint
-                if (!con.getName().isEmpty()) {
-                    pstore.putString("constraint.name", con.getName());
-                }
-                /*if (!con.getText().isEmpty()) {
-                    pstore.putString("constraint.description", con.getText());
-                }*/
-                for (PolicyConstraintValue pcv : con.getConstraints()) {
-                    if (!pcv.getValue().isEmpty()) {
-                        p.getConstraint().setConfig(pcv.getName(), pcv.getValue());
+        List<String> auditDelete = new ArrayList<String>(existingPolicies.keySet());
+
+        //perform actions
+        try {
+            profile.deleteAllProfilePolicies();
+            for (Map.Entry<String, List<ProfilePolicy>> policySet : data.getPolicySets().entrySet()) {
+                String setId = policySet.getKey();
+                for (ProfilePolicy policy : policySet.getValue()) {
+                    PolicyDefault def = policy.getDef();
+                    PolicyConstraint con = policy.getConstraint();
+
+                    // create policy using defaults for PolicyDefault and PolicyConstraint
+                    IProfilePolicy p = profile.createProfilePolicy(setId, policy.getId(),
+                            def.getClassId(), con.getClassId());
+
+                    // change specific elements to match incoming data for PolicyDefault
+                    IConfigStore pstore = profile.getConfigStore().getSubStore(
+                            "policyset." + setId + "." + policy.getId());
+                    if (!def.getName().isEmpty()) {
+                        pstore.putString("default.name", def.getName());
+                    }
+                    /*if (!def.getText().isEmpty()) {
+                        pstore.putString("default.description", def.getText());
+                    }*/
+                    for (ProfileParameter param : def.getParams()) {
+                        if (!param.getValue().isEmpty()) {
+                            p.getDefault().setConfig(param.getName(), param.getValue());
+                        }
+                    }
+
+                    // change specific elements to match incoming data for PolicyConstraint
+                    if (!con.getName().isEmpty()) {
+                        pstore.putString("constraint.name", con.getName());
+                    }
+                    /*if (!con.getText().isEmpty()) {
+                        pstore.putString("constraint.description", con.getText());
+                    }*/
+                    for (PolicyConstraintValue pcv : con.getConstraints()) {
+                        if (!pcv.getValue().isEmpty()) {
+                            p.getConstraint().setConfig(pcv.getName(), pcv.getValue());
+                        }
                     }
                 }
             }
+
+            if (!auditDelete.isEmpty()) {
+                Map<String, String> auditParams = new LinkedHashMap<String, String>();
+                auditParams.put("inputs", StringUtils.join(auditDelete, ","));
+                auditProfileChange(
+                        ScopeDef.SC_PROFILE_POLICIES,
+                        OpDef.OP_DELETE,
+                        profile.getId(),
+                        ILogger.SUCCESS,
+                        auditParams);
+            }
+
+            if (!auditAdd.isEmpty()) {
+                Map<String, String> auditParams = new LinkedHashMap<String, String>();
+                auditParams.put("inputs", StringUtils.join(auditAdd, ","));
+                auditProfileChange(
+                        ScopeDef.SC_PROFILE_POLICIES,
+                        OpDef.OP_ADD,
+                        profile.getId(),
+                        ILogger.SUCCESS,
+                        auditParams);
+            }
+
+            if (!auditModify.isEmpty()) {
+                Map<String, String> auditParams = new LinkedHashMap<String, String>();
+                auditParams.put("inputs", StringUtils.join(auditModify, ","));
+                auditProfileChange(
+                        ScopeDef.SC_PROFILE_POLICIES,
+                        OpDef.OP_MODIFY,
+                        profile.getId(),
+                        ILogger.SUCCESS,
+                        auditParams);
+            }
+        } catch (EProfileException | EPropertyException e) {
+            Map<String, String> auditParams = new LinkedHashMap<String, String>();
+            auditParams.put("added", StringUtils.join(auditAdd, ","));
+            auditParams.put("deleted", StringUtils.join(auditDelete, ","));
+            auditParams.put("modified", StringUtils.join(auditModify, ","));
+            auditProfileChange(
+                    ScopeDef.SC_PROFILE_POLICIES,
+                    OpDef.OP_MODIFY,
+                    profile.getId(),
+                    ILogger.FAILURE,
+                    auditParams);
+            throw e;
         }
     }
 
-    private void populateProfileOutputs(ProfileData data, IProfile profile) throws EProfileException {
-        profile.deleteAllProfileOutputs();
+    private void populateProfileOutputs(ProfileData data, IProfile profile) throws EBaseException {
+        // get list of changes for auditing
+        List<String> auditAdd = new ArrayList<String>();
+        List<String> auditModify = new ArrayList<String>();
+
+        Enumeration<String> existingIds = profile.getProfileOutputIds();
+        Map<String, ProfileOutput> existingOutputs = new LinkedHashMap<String, ProfileOutput>();
+        while (existingIds.hasMoreElements()) {
+            String id = existingIds.nextElement();
+            ProfileOutput output = createProfileOutput(profile, id);
+            if (output == null)
+                continue;
+            existingOutputs.put(id, output);
+        }
+
         List<ProfileOutput> outputs = data.getOutputs();
-        for (ProfileOutput output: outputs) {
+        for (ProfileOutput output : outputs) {
             String id = output.getId();
-            String classId = output.getClassId();
+            if (!existingOutputs.containsKey(id)) {
+                auditAdd.add(id);
+            } else {
+                if (!output.equals(existingOutputs.get(id))) {
+                    auditModify.add(id);
+                }
+                existingOutputs.remove(id);
+            }
+        }
+        List<String> auditDelete = new ArrayList<String>(existingOutputs.keySet());
 
-            NameValuePairs nvp = new NameValuePairs();
-            // TODO - add a field for params in ProfileOuput
-            // No current examples
-            profile.createProfileOutput(id, classId, nvp);
+        // perform operations
+
+        try {
+            profile.deleteAllProfileOutputs();
+            for (ProfileOutput output : outputs) {
+                String id = output.getId();
+                String classId = output.getClassId();
+
+                NameValuePairs nvp = new NameValuePairs();
+                // TODO - add a field for params in ProfileOuput
+                // No current examples
+                profile.createProfileOutput(id, classId, nvp);
+            }
+
+            if (!auditDelete.isEmpty()) {
+                Map<String, String> auditParams = new LinkedHashMap<String, String>();
+                auditParams.put("outputs", StringUtils.join(auditDelete, ","));
+                auditProfileChange(
+                        ScopeDef.SC_PROFILE_OUTPUT,
+                        OpDef.OP_DELETE,
+                        profile.getId(),
+                        ILogger.SUCCESS,
+                        auditParams);
+            }
+
+            if (!auditAdd.isEmpty()) {
+                Map<String, String> auditParams = new LinkedHashMap<String, String>();
+                auditParams.put("outputs", StringUtils.join(auditAdd, ","));
+                auditProfileChange(
+                        ScopeDef.SC_PROFILE_OUTPUT,
+                        OpDef.OP_ADD,
+                        profile.getId(),
+                        ILogger.SUCCESS,
+                        auditParams);
+            }
+
+            if (!auditModify.isEmpty()) {
+                Map<String, String> auditParams = new LinkedHashMap<String, String>();
+                auditParams.put("outputs", StringUtils.join(auditModify, ","));
+                auditProfileChange(
+                        ScopeDef.SC_PROFILE_OUTPUT,
+                        OpDef.OP_MODIFY,
+                        profile.getId(),
+                        ILogger.SUCCESS,
+                        auditParams);
+            }
+        } catch (EProfileException e) {
+            Map<String, String> auditParams = new LinkedHashMap<String, String>();
+
+            auditParams.put("added", StringUtils.join(auditAdd, ","));
+            auditParams.put("deleted", StringUtils.join(auditDelete, ","));
+            auditParams.put("modified", StringUtils.join(auditModify, ","));
+            auditProfileChange(
+                    ScopeDef.SC_PROFILE_OUTPUT,
+                    OpDef.OP_MODIFY,
+                    profile.getId(),
+                    ILogger.FAILURE,
+                    auditParams);
+            throw e;
         }
     }
 
-    private void populateProfileInputs(ProfileData data, IProfile profile) throws EProfileException {
-        profile.deleteAllProfileInputs();
-       List<ProfileInput> inputs = data.getInputs();
-        for (ProfileInput input: inputs) {
+    private void populateProfileInputs(ProfileData data, IProfile profile) throws EBaseException {
+        // get list of changes for auditing
+        List<String> auditAdd = new ArrayList<String>();
+        List<String> auditModify = new ArrayList<String>();
+        Enumeration<String> existingIds = profile.getProfileInputIds();
+        Map<String, ProfileInput> existingInputs = new LinkedHashMap<String, ProfileInput>();
+
+        while (existingIds.hasMoreElements()) {
+            String id = existingIds.nextElement();
+            ProfileInput input = createProfileInput(profile, id);
+            if (input == null)
+                continue;
+            existingInputs.put(id, input);
+        }
+
+        List<ProfileInput> inputs = data.getInputs();
+        for (ProfileInput input : inputs) {
             String id = input.getId();
-            String classId = input.getClassId();
+            if (!existingInputs.containsKey(id)) {
+                auditAdd.add(id);
+            } else {
+                if (!input.equals(existingInputs.get(id))) {
+                    auditModify.add(id);
+                }
+                existingInputs.remove(id);
+            }
+        }
+        List<String> auditDelete = new ArrayList<String>(existingInputs.keySet());
 
-            NameValuePairs nvp = new NameValuePairs();
-            // TODO - add a field for params in ProfileInput.
-            // an example of this is DomainController.cfg
-            profile.createProfileInput(id, classId, nvp);
+        try {
+            // perform the operations
+            profile.deleteAllProfileInputs();
+
+            for (ProfileInput input : inputs) {
+                String id = input.getId();
+                String classId = input.getClassId();
+
+                NameValuePairs nvp = new NameValuePairs();
+                // TODO - add a field for params in ProfileInput.
+                // an example of this is DomainController.cfg
+                profile.createProfileInput(id, classId, nvp);
+            }
+
+            if (!auditDelete.isEmpty()) {
+                Map<String, String> auditParams = new LinkedHashMap<String, String>();
+                auditParams.put("inputs", StringUtils.join(auditDelete, ","));
+                auditProfileChange(
+                        ScopeDef.SC_PROFILE_INPUT,
+                        OpDef.OP_DELETE,
+                        profile.getId(),
+                        ILogger.SUCCESS,
+                        auditParams);
+            }
+
+            if (!auditAdd.isEmpty()) {
+                Map<String, String> auditParams = new LinkedHashMap<String, String>();
+                auditParams.put("inputs", StringUtils.join(auditAdd, ","));
+                auditProfileChange(
+                        ScopeDef.SC_PROFILE_INPUT,
+                        OpDef.OP_ADD,
+                        profile.getId(),
+                        ILogger.SUCCESS,
+                        auditParams);
+            }
+
+            if (!auditModify.isEmpty()) {
+                Map<String, String> auditParams = new LinkedHashMap<String, String>();
+                auditParams.put("inputs", StringUtils.join(auditModify, ","));
+                auditProfileChange(
+                        ScopeDef.SC_PROFILE_INPUT,
+                        OpDef.OP_MODIFY,
+                        profile.getId(),
+                        ILogger.SUCCESS,
+                        auditParams);
+            }
+        } catch (EProfileException e) {
+            Map<String, String> auditParams = new LinkedHashMap<String, String>();
+
+            auditParams.put("added", StringUtils.join(auditAdd, ","));
+            auditParams.put("deleted", StringUtils.join(auditDelete, ","));
+            auditParams.put("modified", StringUtils.join(auditModify, ","));
+            auditProfileChange(
+                    ScopeDef.SC_PROFILE_INPUT,
+                    OpDef.OP_MODIFY,
+                    profile.getId(),
+                    ILogger.FAILURE,
+                    auditParams);
+            throw e;
         }
     }
 
@@ -589,6 +873,13 @@ public class ProfileService extends PKIService implements ProfileResource {
 
             if (ps.isProfileEnable(profileId)) {
                 CMS.debug("Delete profile not permitted.  Profile must be disabled first.");
+                auditProfileChange(
+                        ScopeDef.SC_PROFILE_RULES,
+                        OpDef.OP_DELETE,
+                        profileId,
+                        ILogger.FAILURE,
+                        null);
+
                 throw new BadRequestException("Cannot delete profile `" + profileId +
                         "`.  Profile must be disabled first.");
             }
@@ -596,12 +887,44 @@ public class ProfileService extends PKIService implements ProfileResource {
             String configFile = CMS.getConfigStore().getString("profile." + profileId + ".config");
 
             ps.deleteProfile(profileId, configFile);
+
+            auditProfileChange(
+                    ScopeDef.SC_PROFILE_RULES,
+                    OpDef.OP_DELETE,
+                    profileId,
+                    ILogger.FAILURE,
+                    null);
         } catch (EBaseException e) {
             CMS.debug("deleteProfile: error in deleting profile `" + profileId + "`: " + e);
             e.printStackTrace();
+
+            auditProfileChange(
+                    ScopeDef.SC_PROFILE_RULES,
+                    OpDef.OP_DELETE,
+                    profileId,
+                    ILogger.FAILURE,
+                    null);
+
             throw new PKIException("Error deleting profile.");
         }
+    }
 
+    public void auditProfileChangeState(String profileId, String op, String status) {
+        String msg = CMS.getLogMessage(
+                LOGGING_SIGNED_AUDIT_CERT_PROFILE_APPROVAL,
+                auditor.getSubjectID(),
+                status,
+                profileId,
+                op);
+        auditor.log(msg);
+    }
 
+    public void auditProfileChange(String scope, String type, String id, String status, Map<String, String> params) {
+        String msg = CMS.getLogMessage(
+                LOGGING_SIGNED_AUDIT_CONFIG_CERT_PROFILE,
+                auditor.getSubjectID(),
+                status,
+                auditor.getParamString(scope, type, id, params));
+        auditor.log(msg);
     }
 }
-- 
1.8.1.4

