AMBARI-15241. Basic Operational Audit Logging. (Daniel Gergely via stoader)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/46a34ccd
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/46a34ccd
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/46a34ccd

Branch: refs/heads/trunk
Commit: 46a34ccdeeeeabe0ad4172e94a63c9b077e17861
Parents: b197a6f
Author: Toader, Sebastian <[email protected]>
Authored: Wed Mar 30 20:02:27 2016 +0200
Committer: Toader, Sebastian <[email protected]>
Committed: Wed Mar 30 21:50:51 2016 +0200

----------------------------------------------------------------------
 ambari-project/pom.xml                          |   7 +-
 ambari-server/conf/unix/log4j.properties        |  14 +
 ambari-server/conf/windows/log4j.properties     |  14 +
 ambari-server/pom.xml                           |   6 +-
 ambari-server/src/main/conf/log4j.properties    |  14 +
 .../actionmanager/ActionDBAccessorImpl.java     | 125 +++++
 .../ambari/server/api/services/BaseRequest.java |  16 +-
 .../ambari/server/api/services/BaseService.java |  24 +-
 .../server/api/services/LogoutService.java      |  28 +-
 .../ambari/server/api/services/Request.java     |  32 +-
 .../ambari/server/audit/AsyncAuditLogger.java   | 101 ++++
 .../apache/ambari/server/audit/AuditLogger.java |  39 ++
 .../server/audit/AuditLoggerDefaultImpl.java    |  77 +++
 .../ambari/server/audit/AuditLoggerModule.java  |  94 ++++
 .../server/audit/event/AbstractAuditEvent.java  | 148 ++++++
 .../audit/event/AbstractUserAuditEvent.java     |  92 ++++
 .../event/AccessUnauthorizedAuditEvent.java     |  97 ++++
 .../ambari/server/audit/event/AuditEvent.java   |  56 ++
 .../server/audit/event/LoginAuditEvent.java     | 126 +++++
 .../server/audit/event/LogoutAuditEvent.java    |  67 +++
 .../audit/event/OperationStatusAuditEvent.java  | 108 ++++
 .../audit/event/TaskStatusAuditEvent.java       | 148 ++++++
 .../kerberos/AbstractKerberosAuditEvent.java    |  87 ++++
 .../ChangeSecurityStateKerberosAuditEvent.java  | 118 +++++
 .../CreateKeyTabKerberosAuditEvent.java         | 110 ++++
 .../CreatePrincipalKerberosAuditEvent.java      |  73 +++
 .../DestroyPrincipalKerberosAuditEvent.java     |  80 +++
 .../request/ActivateUserRequestAuditEvent.java  | 101 ++++
 .../request/AddAlertGroupRequestAuditEvent.java | 113 ++++
 .../AddAlertTargetRequestAuditEvent.java        | 167 ++++++
 .../request/AddBlueprintRequestAuditEvent.java  |  88 ++++
 .../AddComponentToHostRequestAuditEvent.java    |  98 ++++
 .../request/AddCredentialRequestAuditEvent.java | 122 +++++
 .../event/request/AddHostRequestAuditEvent.java |  86 ++++
 .../request/AddRepositoryRequestAuditEvent.java | 134 +++++
 .../AddRepositoryVersionRequestAuditEvent.java  | 153 ++++++
 .../request/AddRequestRequestAuditEvent.java    |  98 ++++
 .../request/AddUpgradeRequestAuditEvent.java    | 111 ++++
 .../AddUserToGroupRequestAuditEvent.java        |  98 ++++
 .../AddViewInstanceRequestAuditEvent.java       | 134 +++++
 .../request/AdminUserRequestAuditEvent.java     | 101 ++++
 .../BlueprintExportRequestAuditEvent.java       |  72 +++
 .../ChangeAlertGroupRequestAuditEvent.java      | 113 ++++
 .../ChangeAlertTargetRequestAuditEvent.java     | 134 +++++
 ...hangeRepositoryVersionRequestAuditEvent.java | 153 ++++++
 .../ChangeViewInstanceRequestAuditEvent.java    | 134 +++++
 .../ClientConfigDownloadRequestAuditEvent.java  | 100 ++++
 .../ClusterNameChangeRequestAuditEvent.java     |  91 ++++
 ...ClusterPrivilegeChangeRequestAuditEvent.java | 126 +++++
 .../ConfigurationChangeRequestAuditEvent.java   | 101 ++++
 .../request/CreateGroupRequestAuditEvent.java   |  88 ++++
 .../request/CreateUserRequestAuditEvent.java    | 113 ++++
 .../DeleteAlertGroupRequestAuditEvent.java      |  86 ++++
 .../DeleteAlertTargetRequestAuditEvent.java     |  86 ++++
 .../DeleteBlueprintRequestAuditEvent.java       |  88 ++++
 .../request/DeleteGroupRequestAuditEvent.java   |  88 ++++
 .../request/DeleteHostRequestAuditEvent.java    |  88 ++++
 ...eleteRepositoryVersionRequestAuditEvent.java | 110 ++++
 .../request/DeleteServiceRequestAuditEvent.java |  88 ++++
 .../request/DeleteUserRequestAuditEvent.java    |  88 ++++
 .../DeleteViewInstanceRequestAuditEvent.java    | 110 ++++
 .../MembershipChangeRequestAuditEvent.java      | 108 ++++
 .../PrivilegeChangeRequestAuditEvent.java       | 113 ++++
 .../RemoveUserFromGroupRequestAuditEvent.java   |  98 ++++
 .../StartOperationRequestAuditEvent.java        | 126 +++++
 .../UpdateRepositoryRequestAuditEvent.java      | 134 +++++
 .../UpdateUpgradeItemRequestAuditEvent.java     | 111 ++++
 .../UserPasswordChangeRequestAuditEvent.java    |  88 ++++
 .../ViewPrivilegeChangeRequestAuditEvent.java   | 163 ++++++
 .../server/audit/request/RequestAuditEvent.java | 161 ++++++
 .../audit/request/RequestAuditEventCreator.java |  59 +++
 .../audit/request/RequestAuditLogger.java       |  36 ++
 .../audit/request/RequestAuditLoggerImpl.java   | 150 ++++++
 .../eventcreator/AlertGroupEventCreator.java    | 170 ++++++
 .../eventcreator/AlertTargetEventCreator.java   | 164 ++++++
 .../eventcreator/BlueprintEventCreator.java     | 109 ++++
 .../BlueprintExportEventCreator.java            |  94 ++++
 .../eventcreator/ComponentEventCreator.java     | 188 +++++++
 .../ConfigurationChangeEventCreator.java        | 150 ++++++
 .../eventcreator/CredentialEventCreator.java    | 111 ++++
 .../eventcreator/DefaultEventCreator.java       |  89 ++++
 .../request/eventcreator/GroupEventCreator.java | 124 +++++
 .../request/eventcreator/HostEventCreator.java  | 167 ++++++
 .../eventcreator/MemberEventCreator.java        | 175 +++++++
 .../eventcreator/PrivilegeEventCreator.java     | 147 ++++++
 .../RecommendationIgnoreEventCreator.java       |  81 +++
 .../eventcreator/RepositoryEventCreator.java    | 132 +++++
 .../RepositoryVersionEventCreator.java          | 215 ++++++++
 .../eventcreator/RequestEventCreator.java       | 101 ++++
 .../ServiceConfigDownloadEventCreator.java      |  92 ++++
 .../eventcreator/ServiceEventCreator.java       | 179 +++++++
 .../eventcreator/UnauthorizedEventCreator.java  |  86 ++++
 .../eventcreator/UpgradeEventCreator.java       | 110 ++++
 .../eventcreator/UpgradeItemEventCreator.java   | 110 ++++
 .../request/eventcreator/UserEventCreator.java  | 211 ++++++++
 .../ValidationIgnoreEventCreator.java           |  81 +++
 .../eventcreator/ViewInstanceEventCreator.java  | 149 ++++++
 .../eventcreator/ViewPrivilegeEventCreator.java | 145 ++++++
 .../server/configuration/Configuration.java     |  24 +
 .../ambari/server/controller/AmbariServer.java  |  41 +-
 .../server/controller/ControllerModule.java     |   1 -
 .../controller/internal/CalculatedStatus.java   |   2 +-
 .../AmbariAuthenticationFilter.java             | 160 ++++++
 .../AmbariAuthorizationFilter.java              |  43 +-
 .../authorization/AuthorizationHelper.java      |  29 ++
 .../authorization/PermissionHelper.java         |  88 ++++
 .../serveraction/AbstractServerAction.java      |  12 +
 .../kerberos/CreateKeytabFilesServerAction.java | 189 +++----
 .../kerberos/CreatePrincipalsServerAction.java  | 154 +++---
 .../kerberos/DestroyPrincipalsServerAction.java |  42 +-
 .../kerberos/FinalizeKerberosServerAction.java  |   9 +
 .../ambari/server/utils/RequestUtils.java       |  88 ++++
 .../webapp/WEB-INF/spring-security.xml          |   6 +-
 .../actionmanager/TestActionDBAccessorImpl.java |   4 +
 .../server/actionmanager/TestActionManager.java |   4 +
 .../server/agent/HeartbeatProcessorTest.java    |   4 +
 .../server/api/services/BaseServiceTest.java    |  27 +
 .../audit/AccessUnauthorizedAuditEventTest.java |  77 +++
 .../server/audit/LoginAuditEventTest.java       | 118 +++++
 .../server/audit/LogoutAuditEventTest.java      |  74 +++
 .../audit/OperationStatusAuditEventTest.java    |  74 +++
 .../StartOperationRequestAuditEventTest.java    |  79 +++
 .../audit/request/AbstractBaseCreator.java      |  45 ++
 .../server/audit/request/AllGetCreator.java     |  44 ++
 .../audit/request/AllPostAndPutCreator.java     |  45 ++
 .../audit/request/DefaultEventCreatorTest.java  | 515 +++++++++++++++++++
 .../audit/request/PutHostComponentCreator.java  |  44 ++
 .../audit/request/RequestAuditLogModule.java    |  40 ++
 .../audit/request/RequestAuditLoggerTest.java   | 153 ++++++
 .../server/checks/UpgradeCheckOrderTest.java    |   3 +-
 .../AmbariManagementControllerTest.java         |   9 +-
 .../server/controller/KerberosHelperTest.java   |   2 +
 .../notifications/DispatchFactoryTest.java      |   3 +-
 .../server/orm/InMemoryDefaultTestModule.java   |   4 +
 .../ambari/server/orm/JdbcPropertyTest.java     |   6 +-
 .../AmbariAuthenticationFilterTest.java         | 135 +++++
 .../AmbariAuthorizationFilterTest.java          |  24 +
 ...uthenticationProviderForDNWithSpaceTest.java |   4 +-
 .../AmbariLdapAuthenticationProviderTest.java   |   4 +-
 .../AmbariLocalUserDetailsServiceTest.java      |   4 +-
 .../authorization/LdapServerPropertiesTest.java |   4 +-
 .../kerberos/KerberosServerActionTest.java      |   2 +
 .../UpdateKerberosConfigsServerActionTest.java  |   2 +
 .../ambari/server/utils/RequestUtilsTest.java   |  77 +++
 144 files changed, 12582 insertions(+), 225 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-project/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-project/pom.xml b/ambari-project/pom.xml
index b3d9ca2..21c5baf 100644
--- a/ambari-project/pom.xml
+++ b/ambari-project/pom.xml
@@ -407,7 +407,7 @@
       <dependency>
         <groupId>log4j</groupId>
         <artifactId>log4j</artifactId>
-        <version>1.2.16</version>
+        <version>1.2.17</version>
         <exclusions>
           <exclusion>
             <groupId>com.sun.jdmk</groupId>
@@ -432,6 +432,11 @@
         </exclusions>
       </dependency>
       <dependency>
+        <groupId>log4j</groupId>
+        <artifactId>apache-log4j-extras</artifactId>
+        <version>1.2.17</version>
+      </dependency>
+      <dependency>
         <groupId>junit</groupId>
         <artifactId>junit</artifactId>
         <version>4.10</version>

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/conf/unix/log4j.properties
----------------------------------------------------------------------
diff --git a/ambari-server/conf/unix/log4j.properties 
b/ambari-server/conf/unix/log4j.properties
index ab3ea0b..3cb7fd0 100644
--- a/ambari-server/conf/unix/log4j.properties
+++ b/ambari-server/conf/unix/log4j.properties
@@ -24,6 +24,7 @@ ambari.log.file=ambari-server.log
 ambari.config-changes.file=ambari-config-changes.log
 ambari.alerts.file=ambari-alerts.log
 ambari.eclipselink.file=ambari-eclipselink.log
+ambari.audit.file=ambari-audit.log
 ambari.dbcheck.file=ambari-server-check-database.log
 
 log4j.rootLogger=INFO,file
@@ -70,6 +71,19 @@ log4j.appender.eclipselink.MaxBackupIndex=10
 log4j.appender.eclipselink.layout=org.apache.log4j.PatternLayout
 log4j.appender.eclipselink.layout.ConversionPattern=%m%n
 
+# Audit logging
+log4j.logger.audit=INFO,audit
+log4j.additivity.audit=false
+log4j.appender.audit=org.apache.log4j.rolling.RollingFileAppender
+log4j.appender.audit.rollingPolicy=org.apache.log4j.rolling.FixedWindowRollingPolicy
+log4j.appender.audit.rollingPolicy.ActiveFileName=${ambari.log.dir}/${ambari.audit.file}
+log4j.appender.audit.rollingPolicy.FileNamePattern=${ambari.log.dir}/${ambari.audit.file}-%i.log.gz
+log4j.appender.audit.rollingPolicy.maxIndex=13
+log4j.appender.audit.triggeringPolicy=org.apache.log4j.rolling.SizeBasedTriggeringPolicy
+log4j.appender.audit.triggeringPolicy.maxFileSize=50000000
+log4j.appender.audit.layout=org.apache.log4j.PatternLayout
+log4j.appender.audit.layout.ConversionPattern=%m%n
+
 log4j.logger.org.apache.hadoop.yarn.client=WARN
 log4j.logger.org.apache.slider.common.tools.SliderUtils=WARN
 log4j.logger.org.apache.ambari.server.security.authorization=WARN

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/conf/windows/log4j.properties
----------------------------------------------------------------------
diff --git a/ambari-server/conf/windows/log4j.properties 
b/ambari-server/conf/windows/log4j.properties
index cc40f74..8beba68 100644
--- a/ambari-server/conf/windows/log4j.properties
+++ b/ambari-server/conf/windows/log4j.properties
@@ -23,6 +23,7 @@ ambari.log.file=ambari-server.log
 ambari.config-changes.file=ambari-config-changes.log
 ambari.alerts.file=ambari-alerts.log
 ambari.eclipselink.file=ambari-eclipselink.log
+ambari.audit.file=ambari-audit.log
 ambari.dbcheck.file=ambari-server-check-database.log
 
 # Define the root logger to the system property "ambari.root.logger".
@@ -94,3 +95,16 @@ log4j.appender.eclipselink.MaxFileSize=50MB
 log4j.appender.eclipselink.MaxBackupIndex=10
 log4j.appender.eclipselink.layout=org.apache.log4j.PatternLayout
 log4j.appender.eclipselink.layout.ConversionPattern=%m%n
+
+# Audit logging
+log4j.logger.audit=INFO,audit
+log4j.additivity.audit=false
+log4j.appender.audit=org.apache.log4j.rolling.RollingFileAppender
+log4j.appender.audit.rollingPolicy=org.apache.log4j.rolling.FixedWindowRollingPolicy
+log4j.appender.audit.rollingPolicy.ActiveFileName=${ambari.log.dir}\${ambari.audit.file}
+log4j.appender.audit.rollingPolicy.FileNamePattern=${ambari.log.dir}\${ambari.audit.file}-%i.log.gz
+log4j.appender.audit.rollingPolicy.maxIndex=13
+log4j.appender.audit.triggeringPolicy=org.apache.log4j.rolling.SizeBasedTriggeringPolicy
+log4j.appender.audit.triggeringPolicy.maxFileSize=50000000
+log4j.appender.audit.layout=org.apache.log4j.PatternLayout
+log4j.appender.audit.layout.ConversionPattern=%m%n

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-server/pom.xml b/ambari-server/pom.xml
index 07a315d..b36c4e1 100644
--- a/ambari-server/pom.xml
+++ b/ambari-server/pom.xml
@@ -1058,6 +1058,10 @@
       <artifactId>log4j</artifactId>
     </dependency>
     <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>apache-log4j-extras</artifactId>
+    </dependency>
+    <dependency>
       <groupId>org.eclipse.persistence</groupId>
       <artifactId>eclipselink</artifactId>
     </dependency>
@@ -1277,7 +1281,7 @@
           <groupId>c3p0</groupId>
           <artifactId>c3p0</artifactId>
         </exclusion>
-      </exclusions>      
+      </exclusions>
     </dependency>
     <dependency>
       <groupId>org.quartz-scheduler</groupId>

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/conf/log4j.properties
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/conf/log4j.properties 
b/ambari-server/src/main/conf/log4j.properties
index 8e6652d..5021c77 100644
--- a/ambari-server/src/main/conf/log4j.properties
+++ b/ambari-server/src/main/conf/log4j.properties
@@ -23,6 +23,7 @@ ambari.log.file=ambari-server.log
 ambari.config-changes.file=ambari-config-changes.log
 ambari.alerts.file=ambari-alerts.log
 ambari.eclipselink.file=ambari-eclipselink.log
+ambari.audit.file=ambari-audit.log
 ambari.dbcheck.file=ambari-server-check-database.log
 
 # Define the root logger to the system property "ambari.root.logger".
@@ -95,3 +96,16 @@ log4j.appender.eclipselink.MaxBackupIndex=10
 log4j.appender.eclipselink.layout=org.apache.log4j.PatternLayout
 log4j.appender.eclipselink.layout.ConversionPattern=%m%n
 
+# Audit logging
+log4j.logger.audit=INFO,audit
+log4j.additivity.audit=false
+log4j.appender.audit=org.apache.log4j.rolling.RollingFileAppender
+log4j.appender.audit.rollingPolicy=org.apache.log4j.rolling.FixedWindowRollingPolicy
+log4j.appender.audit.rollingPolicy.ActiveFileName=${ambari.log.dir}/${ambari.audit.file}
+log4j.appender.audit.rollingPolicy.FileNamePattern=${ambari.log.dir}/${ambari.audit.file}-%i.log.gz
+log4j.appender.audit.rollingPolicy.maxIndex=13
+log4j.appender.audit.triggeringPolicy=org.apache.log4j.rolling.SizeBasedTriggeringPolicy
+log4j.appender.audit.triggeringPolicy.maxFileSize=50000000
+log4j.appender.audit.layout=org.apache.log4j.PatternLayout
+log4j.appender.audit.layout.ConversionPattern=%m%n
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java
index a75a000..79d3470 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java
@@ -23,8 +23,13 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.EnumSet;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.ambari.annotations.Experimental;
@@ -35,7 +40,13 @@ import 
org.apache.ambari.annotations.TransactionalLock.LockType;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.agent.CommandReport;
 import org.apache.ambari.server.agent.ExecutionCommand;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.AuditLogger;
+import org.apache.ambari.server.audit.event.OperationStatusAuditEvent;
+import org.apache.ambari.server.audit.event.TaskStatusAuditEvent;
 import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.controller.internal.CalculatedStatus;
 import org.apache.ambari.server.events.HostRemovedEvent;
 import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
 import org.apache.ambari.server.orm.dao.ClusterDAO;
@@ -117,6 +128,22 @@ public class ActionDBAccessorImpl implements 
ActionDBAccessor {
   @Inject
   Configuration configuration;
 
+  @Inject
+  AuditLogger auditLogger;
+
+  /**
+   * Caches to store current request and task statuses.
+   * It is used for avoiding audit log entry duplication
+   */
+  private Map<Long, HostRoleStatus> temporaryStatusCache = new HashMap<Long, 
HostRoleStatus>();
+  private Map<Long, HostRoleStatus> temporaryTaskStatusCache = new 
HashMap<Long, HostRoleStatus>();
+
+  /**
+   * Stores the host role command entities that are not completed for a 
request id
+   * It is used to calculate the summary state of the request for audit logging
+   */
+  private Map<Long, Map<Long, HostRoleStatus>> tasksForRequest = new 
HashMap<>();
+
   private Cache<Long, HostRoleCommand> hostRoleCommandCache;
   private long cacheLimit; //may be exceeded to store tasks from one request
 
@@ -198,6 +225,8 @@ public class ActionDBAccessorImpl implements 
ActionDBAccessor {
             + " requestId " + command.getRequestId()
             + " taskId " + command.getTaskId()
             + " stageId " + command.getStageId());
+
+        auditLog(command, requestId);
       }
     }
 
@@ -219,6 +248,8 @@ public class ActionDBAccessorImpl implements 
ActionDBAccessor {
     for (HostRoleCommandEntity command : commands) {
       command.setStatus(command.isRetryAllowed() ? 
HostRoleStatus.HOLDING_TIMEDOUT : HostRoleStatus.TIMEDOUT);
       command.setEndTime(now);
+
+      auditLog(command, requestId);
     }
 
     // no need to merge if there's nothing to merge
@@ -448,6 +479,8 @@ public class ActionDBAccessorImpl implements 
ActionDBAccessor {
     for (HostRoleCommandEntity commandEntity : commandEntities) {
       CommandReport report = taskReports.get(commandEntity.getTaskId());
 
+      boolean statusChanged = false;
+
       switch (commandEntity.getStatus()) {
         case ABORTED:
           // We don't want to overwrite statuses for ABORTED tasks with
@@ -467,6 +500,7 @@ public class ActionDBAccessorImpl implements 
ActionDBAccessor {
           }
 
           commandEntity.setStatus(status);
+          statusChanged = true;
           break;
       }
 
@@ -485,6 +519,9 @@ public class ActionDBAccessorImpl implements 
ActionDBAccessor {
         long stageId = requestStageIds[1];
         if (requestDAO.getLastStageId(requestId).equals(stageId)) {
           requestsToCheck.add(requestId);
+          if(statusChanged) {
+            auditLog(commandEntity, requestId); // wrong requestId !!!
+          }
         }
       }
     }
@@ -542,6 +579,8 @@ public class ActionDBAccessorImpl implements 
ActionDBAccessor {
         }
       }
       command.setExitcode(report.getExitCode());
+
+      auditLog(command, requestId);
     }
 
     // no need to merge if there's nothing to merge
@@ -607,6 +646,9 @@ public class ActionDBAccessorImpl implements 
ActionDBAccessor {
       entity.setLastAttemptTime(hostRoleCommand.getLastAttemptTime());
       entity.setStatus(hostRoleCommand.getStatus());
       entity.setAttemptCount(hostRoleCommand.getAttemptCount());
+
+      auditLog(entity, s.getRequestId());
+
       hostRoleCommandDAO.merge(entity);
     } else {
       throw new RuntimeException("HostRoleCommand is not persisted, cannot 
update:\n" + hostRoleCommand);
@@ -745,6 +787,8 @@ public class ActionDBAccessorImpl implements 
ActionDBAccessor {
       // Because it expects -1, RetryActionMonitor.java also had to set it to 
-1.
       task.setStartTime(-1L);
       task.setEndTime(-1L);
+
+      auditLog(task, task.getRequestId());
     }
 
     // no need to merge if there's nothing to merge
@@ -764,4 +808,85 @@ public class ActionDBAccessorImpl implements 
ActionDBAccessor {
     LOG.info("Invalidating HRC cache after receiveing {}", event);
     hostRoleCommandCache.invalidateAll();
   }
+
+  /**
+   * AuditLog operation status change
+   * @param requestId
+   */
+  private void auditLog(HostRoleCommandEntity commandEntity, Long requestId) {
+    if(!auditLogger.isEnabled()) {
+      return;
+    }
+
+    if(requestId != null) {
+
+      HostRoleStatus calculatedStatus = calculateStatus(commandEntity, 
requestId);
+
+      if (!temporaryStatusCache.containsKey(requestId) || 
temporaryStatusCache.get(requestId) != calculatedStatus) {
+        RequestEntity request = requestDAO.findByPK(requestId);
+        String context = request != null ? request.getRequestContext() : null;
+        AuditEvent auditEvent = OperationStatusAuditEvent.builder()
+          .withRequestId(String.valueOf(requestId))
+          .withStatus(String.valueOf(calculatedStatus))
+          .withRequestContext(context)
+          .withTimestamp(System.currentTimeMillis())
+          .build();
+        auditLogger.log(auditEvent);
+
+        temporaryStatusCache.put(requestId, calculatedStatus);
+      }
+    }
+    logTask(commandEntity, requestId);
+  }
+
+  /**
+   * Calculates summary status for the given request id for the new command 
entity status
+   * @param commandEntity
+   * @param requestId
+   * @return
+   */
+  private HostRoleStatus calculateStatus(HostRoleCommandEntity commandEntity, 
Long requestId) {
+    if(!tasksForRequest.containsKey(requestId)) {
+      tasksForRequest.put(requestId, new HashMap<Long, HostRoleStatus>());
+    }
+
+    tasksForRequest.get(requestId).put(commandEntity.getTaskId(), 
commandEntity.getStatus());
+
+    HostRoleStatus calculatedStatus = 
CalculatedStatus.calculateSummaryStatusOfStage(CalculatedStatus.calculateStatusCounts(tasksForRequest.get(requestId).values()),
 tasksForRequest.get(requestId).size(), false);
+
+    // if all task status is completed, we can remove it from the container
+    boolean hasInProgress = false;
+    for(HostRoleStatus hrcs : tasksForRequest.get(requestId).values()) {
+      if(!hrcs.isCompletedState()) {
+        hasInProgress = true;
+        break;
+      }
+    }
+    if(!hasInProgress) {
+      tasksForRequest.remove(requestId);
+    }
+    return calculatedStatus;
+  }
+
+  /**
+   * Logs task status change
+   * @param commandEntity
+   * @param requestId
+   */
+  private void logTask(HostRoleCommandEntity commandEntity, Long requestId) {
+    if(!temporaryTaskStatusCache.containsKey(commandEntity.getTaskId()) || 
temporaryTaskStatusCache.get(commandEntity.getTaskId()) != 
commandEntity.getStatus() ) {
+      AuditEvent taskEvent = TaskStatusAuditEvent.builder()
+        .withTaskId(String.valueOf(commandEntity.getTaskId()))
+        .withHostName(commandEntity.getHostName())
+        .withOperation(commandEntity.getRoleCommand().toString() + " " + 
commandEntity.getRole().toString())
+        .withDetails(commandEntity.getCommandDetail())
+        .withStatus(commandEntity.getStatus().toString())
+        .withRequestId(String.valueOf(requestId))
+        .withTimestamp(System.currentTimeMillis())
+        .build();
+
+      auditLogger.log(taskEvent);
+      temporaryTaskStatusCache.put(commandEntity.getTaskId(), 
commandEntity.getStatus());
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseRequest.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseRequest.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseRequest.java
index a33e8a7..88b8170 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseRequest.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseRequest.java
@@ -18,7 +18,6 @@
 
 package org.apache.ambari.server.api.services;
 
-import com.sun.jersey.spi.container.ContainerRequest;
 import org.apache.ambari.server.api.handlers.RequestHandler;
 import org.apache.ambari.server.api.predicate.InvalidQueryException;
 import org.apache.ambari.server.api.predicate.PredicateCompiler;
@@ -33,8 +32,12 @@ import org.apache.ambari.server.controller.spi.PageRequest;
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.SortRequestProperty;
 import org.apache.ambari.server.controller.spi.TemporalInfo;
+import org.apache.ambari.server.utils.RequestUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.UriInfo;
 import java.io.UnsupportedEncodingException;
@@ -71,6 +74,11 @@ public abstract class BaseRequest implements Request {
   private RequestBody m_body;
 
   /**
+   * Remote address
+   */
+  private String m_remoteAddress;
+
+  /**
    * Query Predicate
    */
   private Predicate m_predicate;
@@ -121,6 +129,7 @@ public abstract class BaseRequest implements Request {
     m_uriInfo     = uriInfo;
     m_resource    = resource;
     m_body        = body;
+    m_remoteAddress  = RequestUtils.getRemoteAddress();
   }
 
   @Override
@@ -375,4 +384,9 @@ public abstract class BaseRequest implements Request {
    * @return  the request handler
    */
   protected abstract RequestHandler getRequestHandler();
+
+  @Override
+  public String getRemoteAddress() {
+    return m_remoteAddress;
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
index 7945599..2e5b920 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
@@ -27,6 +27,7 @@ import 
org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.CsvSerializer;
 import org.apache.ambari.server.api.services.serializers.JsonSerializer;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.audit.request.RequestAuditLogger;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.utils.RetryHelper;
 import org.eclipse.jetty.util.ajax.JSON;
@@ -39,6 +40,8 @@ import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 
+import com.google.inject.Inject;
+
 /**
  * Provides common functionality to all services.
  */
@@ -55,6 +58,11 @@ public abstract class BaseService {
    */
   private ResultSerializer m_serializer = new JsonSerializer();
 
+  protected static RequestAuditLogger requestAuditLogger;
+
+  public static void init(RequestAuditLogger instance) {
+    requestAuditLogger = instance;
+  }
 
   /**
    * Requests are funneled through this method so that common logic can be 
executed.
@@ -92,7 +100,12 @@ public abstract class BaseService {
                                    UriInfo uriInfo, Request.Type requestType,
                                    MediaType mediaType, ResourceInstance 
resource) {
 
+    // original request and initial result
+    RequestBody rb = new RequestBody();
+    rb.setBody(body);
+    Request request = getRequestFactory().createRequest(headers, rb, uriInfo, 
requestType, resource);
     Result result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.OK));
+
     try {
       Set<RequestBody> requestBodySet = getBodyParser().parse(body);
 
@@ -100,13 +113,22 @@ public abstract class BaseService {
       while (iterator.hasNext() && 
result.getStatus().getStatus().equals(ResultStatus.STATUS.OK)) {
         RequestBody requestBody = iterator.next();
 
-        Request request = getRequestFactory().createRequest(
+        request = getRequestFactory().createRequest(
             headers, requestBody, uriInfo, requestType, resource);
 
         result  = request.process();
+        requestAuditLogger.log(request, result);
+      }
+
+      if(requestBodySet.isEmpty() || 
!ResultStatus.STATUS.OK.equals(result.getStatus().getStatus())) {
+        requestAuditLogger.log(request, result);
       }
     } catch (BodyParseException e) {
       result =  new ResultImpl(new 
ResultStatus(ResultStatus.STATUS.BAD_REQUEST, e.getMessage()));
+      requestAuditLogger.log(request, result);
+    } catch (Throwable t) {
+      requestAuditLogger.log(request, new ResultImpl(new 
ResultStatus(ResultStatus.STATUS.SERVER_ERROR, t.getMessage())));
+      throw t;
     }
 
     ResultSerializer serializer = mediaType == null ? getResultSerializer() : 
getResultSerializer(mediaType);

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/api/services/LogoutService.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/LogoutService.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/LogoutService.java
index df8faaa..3b449ca 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/LogoutService.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/LogoutService.java
@@ -17,8 +17,6 @@
  */
 package org.apache.ambari.server.api.services;
 
-import org.springframework.security.core.context.SecurityContextHolder;
-
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
@@ -26,18 +24,44 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Response;
 
+import org.apache.ambari.server.StaticallyInject;
+import org.apache.ambari.server.audit.AuditLogger;
+import org.apache.ambari.server.audit.event.LogoutAuditEvent;
+import org.apache.ambari.server.security.authorization.AuthorizationHelper;
+import org.apache.ambari.server.utils.RequestUtils;
+
+import com.google.inject.Inject;
+import org.springframework.security.core.context.SecurityContextHolder;
+
 /**
  * Service performing logout of current user
  */
+@StaticallyInject
 @Path("/logout")
 public class LogoutService {
 
+  @Inject
+  private static AuditLogger auditLogger;
+
   @GET
   @Produces("text/plain")
   public Response performLogout(@Context HttpServletRequest servletRequest) {
+    auditLog(servletRequest);
     SecurityContextHolder.clearContext();
     servletRequest.getSession().invalidate();
     return Response.status(Response.Status.OK).build();
   }
 
+  /**
+   * Creates and send and audit log event that the user has successfully 
logged out
+   * @param servletRequest
+   */
+  private void auditLog(HttpServletRequest servletRequest) {
+    LogoutAuditEvent logoutEvent = LogoutAuditEvent.builder()
+      .withTimestamp(System.currentTimeMillis())
+      .withRemoteIp(RequestUtils.getRemoteAddress(servletRequest))
+      .withUserName(AuthorizationHelper.getAuthenticatedName())
+      .build();
+    auditLogger.log(logoutEvent);
+  }
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/api/services/Request.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/Request.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/Request.java
index ff9b6c7..771875a 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/api/services/Request.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/api/services/Request.java
@@ -37,7 +37,7 @@ public interface Request {
   /**
    * Enum of request types.
    */
-  public enum Type {
+  enum Type {
     GET,
     POST,
     PUT,
@@ -50,7 +50,7 @@ public interface Request {
    *
    * @return the result
    */
-  public Result process();
+  Result process();
 
   /**
    * Obtain the resource definition which corresponds to the resource being 
operated on by the request.
@@ -58,28 +58,28 @@ public interface Request {
    *
    * @return the associated {@link ResourceDefinition}
    */
-  public ResourceInstance getResource();
+  ResourceInstance getResource();
 
   /**
    * Obtain the URI of this request.
    *
    * @return the request uri
    */
-  public String getURI();
+  String getURI();
 
   /**
    * Obtain the http request type.  Type is one of {@link Type}.
    *
    * @return the http request type
    */
-  public Type getRequestType();
+  Type getRequestType();
 
   /**
    * Obtain the api version of the request.  The api version is specified in 
the request URI.
    *
    * @return the api version of the request
    */
-  public int getAPIVersion();
+  int getAPIVersion();
 
   /**
    * Obtain the query predicate that was built from the user provided 
predicate fields in the query string.
@@ -88,7 +88,7 @@ public interface Request {
    *
    * @return the user defined predicate
    */
-  public Predicate getQueryPredicate();
+  Predicate getQueryPredicate();
 
   /**
    * Obtain the partial response fields and associated temporal information 
which were provided
@@ -96,39 +96,45 @@ public interface Request {
    *
    * @return map of partial response propertyId to temporal information
    */
-  public Map<String, TemporalInfo> getFields();
+  Map<String, TemporalInfo> getFields();
 
   /**
    * Obtain the request body data.
    */
-  public RequestBody getBody();
+  RequestBody getBody();
 
   /**
    * Obtain the http headers associated with the request.
    *
    * @return the http headers
    */
-  public Map<String, List<String>> getHttpHeaders();
+  Map<String, List<String>> getHttpHeaders();
 
   /**
    * Obtain the pagination request information.
    *
    * @return the page request
    */
-  public PageRequest getPageRequest();
+  PageRequest getPageRequest();
 
   /**
    * Obtain information to order the results by.
    *
    * @return the order request
    */
-  public SortRequest getSortRequest();
+  SortRequest getSortRequest();
 
   /**
    * Obtain the renderer for the request.
    *
    * @return renderer instance
    */
-  public Renderer getRenderer();
+  Renderer getRenderer();
+
+  /**
+   * Returns the remote address for the request
+   * @return the remote address for the request
+   */
+  String getRemoteAddress();
 
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/AsyncAuditLogger.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/audit/AsyncAuditLogger.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/AsyncAuditLogger.java
new file mode 100644
index 0000000..c520c8d
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/AsyncAuditLogger.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.audit;
+
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.configuration.Configuration;
+
+import com.google.common.eventbus.AsyncEventBus;
+import com.google.common.eventbus.EventBus;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+
+/**
+ * This is a wrapper for an audit log implementation that uses {@link 
EventBus} to make audit logging asynchronous
+ */
+@Singleton
+class AsyncAuditLogger implements AuditLogger {
+  /**
+   * Name for guice injection
+   */
+  final static String InnerLogger = "AsyncAuditLogger";
+
+  /**
+   * Event bus that holds audit event objects
+   */
+  private EventBus eventBus;
+
+  /**
+   * Indicates if audit log feature is enabled
+   */
+  private final boolean isEnabled;
+
+  /**
+   * Constructor.
+   *
+   * @param auditLogger the audit logger to use
+   */
+  @Inject
+  public AsyncAuditLogger(@Named(InnerLogger) AuditLogger auditLogger, 
Configuration configuration) {
+    isEnabled = configuration.isAuditLogEnabled();
+    if(isEnabled) {
+      eventBus = new AsyncEventBus("AuditLoggerEventBus", new 
ThreadPoolExecutor(0, 1, 5L, TimeUnit.MINUTES,
+        new 
LinkedBlockingQueue<Runnable>(configuration.getAuditLoggerCapacity()), new 
AuditLogThreadFactory(),
+        new ThreadPoolExecutor.CallerRunsPolicy()));
+      eventBus.register(auditLogger);
+    }
+  }
+
+  @Override
+  public void log(AuditEvent event) {
+    if(isEnabled) {
+      eventBus.post(event);
+    }
+  }
+
+  @Override
+  public boolean isEnabled() {
+    return isEnabled;
+  }
+
+  /**
+   * A custom {@link ThreadFactory} for the threads that logs audit events
+   */
+  private static final class AuditLogThreadFactory implements ThreadFactory {
+
+    private static final AtomicInteger nextId = new AtomicInteger(1);
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Thread newThread(Runnable runnable) {
+      Thread thread = new Thread(runnable, "auditlog-" + 
nextId.getAndIncrement());
+      thread.setDaemon(true);
+      return thread;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLogger.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLogger.java 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLogger.java
new file mode 100644
index 0000000..8c68e3e
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLogger.java
@@ -0,0 +1,39 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.audit;
+
+import org.apache.ambari.server.audit.event.AuditEvent;
+
+/**
+ * Interface to handle audit log events
+ */
+public interface AuditLogger {
+
+  /**
+   * Logs audit log events
+   * @param event
+   */
+  void log(final AuditEvent event);
+
+  /**
+   * Returns if the feature is enabled
+   */
+  boolean isEnabled();
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLoggerDefaultImpl.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLoggerDefaultImpl.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLoggerDefaultImpl.java
new file mode 100644
index 0000000..1cfb740
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLoggerDefaultImpl.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.audit;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.configuration.Configuration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * Default audit logger implementation, logs messages into log file
+ */
+@Singleton
+public class AuditLoggerDefaultImpl implements AuditLogger {
+
+  private static final Logger LOG = LoggerFactory.getLogger("audit");
+
+  /**
+   * Indicates if audit log feature is enabled
+   */
+  private final boolean isEnabled;
+
+  private ThreadLocal<DateFormat> dateFormatThreadLocal = new ThreadLocal<>();
+
+  @Inject
+  public AuditLoggerDefaultImpl(Configuration configuration) {
+    isEnabled = configuration.isAuditLogEnabled();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  @Subscribe
+  public void log(AuditEvent event) {
+    if(!isEnabled) {
+      return;
+    }
+
+    if(dateFormatThreadLocal.get() == null) {
+      //2016-03-11T10:42:36.376Z
+      dateFormatThreadLocal.set(new 
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX"));
+    }
+
+    Date date = new Date(event.getTimestamp());
+    LOG.info("{}, {}", dateFormatThreadLocal.get().format(date), 
event.getAuditMessage());
+  }
+
+  @Override
+  public boolean isEnabled() {
+    return isEnabled;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLoggerModule.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLoggerModule.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLoggerModule.java
new file mode 100644
index 0000000..b20714b
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLoggerModule.java
@@ -0,0 +1,94 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.audit;
+
+import org.apache.ambari.server.audit.request.RequestAuditEventCreator;
+import org.apache.ambari.server.audit.request.RequestAuditLogger;
+import org.apache.ambari.server.audit.request.RequestAuditLoggerImpl;
+import 
org.apache.ambari.server.audit.request.eventcreator.AlertGroupEventCreator;
+import 
org.apache.ambari.server.audit.request.eventcreator.AlertTargetEventCreator;
+import 
org.apache.ambari.server.audit.request.eventcreator.BlueprintEventCreator;
+import 
org.apache.ambari.server.audit.request.eventcreator.BlueprintExportEventCreator;
+import 
org.apache.ambari.server.audit.request.eventcreator.ComponentEventCreator;
+import 
org.apache.ambari.server.audit.request.eventcreator.ConfigurationChangeEventCreator;
+import 
org.apache.ambari.server.audit.request.eventcreator.CredentialEventCreator;
+import org.apache.ambari.server.audit.request.eventcreator.DefaultEventCreator;
+import org.apache.ambari.server.audit.request.eventcreator.GroupEventCreator;
+import org.apache.ambari.server.audit.request.eventcreator.HostEventCreator;
+import org.apache.ambari.server.audit.request.eventcreator.MemberEventCreator;
+import 
org.apache.ambari.server.audit.request.eventcreator.PrivilegeEventCreator;
+import 
org.apache.ambari.server.audit.request.eventcreator.RecommendationIgnoreEventCreator;
+import 
org.apache.ambari.server.audit.request.eventcreator.RepositoryEventCreator;
+import 
org.apache.ambari.server.audit.request.eventcreator.RepositoryVersionEventCreator;
+import org.apache.ambari.server.audit.request.eventcreator.RequestEventCreator;
+import 
org.apache.ambari.server.audit.request.eventcreator.ServiceConfigDownloadEventCreator;
+import org.apache.ambari.server.audit.request.eventcreator.ServiceEventCreator;
+import 
org.apache.ambari.server.audit.request.eventcreator.UnauthorizedEventCreator;
+import org.apache.ambari.server.audit.request.eventcreator.UpgradeEventCreator;
+import 
org.apache.ambari.server.audit.request.eventcreator.UpgradeItemEventCreator;
+import org.apache.ambari.server.audit.request.eventcreator.UserEventCreator;
+import 
org.apache.ambari.server.audit.request.eventcreator.ValidationIgnoreEventCreator;
+import 
org.apache.ambari.server.audit.request.eventcreator.ViewInstanceEventCreator;
+import 
org.apache.ambari.server.audit.request.eventcreator.ViewPrivilegeEventCreator;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.name.Names;
+
+public class AuditLoggerModule extends AbstractModule {
+
+  @Override
+  protected void configure() {
+    bind(AuditLogger.class).to(AsyncAuditLogger.class);
+
+    // set AuditLoggerDefaultImpl to be used by AsyncAuditLogger
+    
bind(AuditLogger.class).annotatedWith(Names.named(AsyncAuditLogger.InnerLogger)).to(AuditLoggerDefaultImpl.class);
+
+    // binding for audit event creators
+    Multibinder<RequestAuditEventCreator> auditLogEventCreatorBinder = 
Multibinder.newSetBinder(binder(), RequestAuditEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(DefaultEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(ComponentEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(ServiceEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(UnauthorizedEventCreator.class);
+    
auditLogEventCreatorBinder.addBinding().to(ConfigurationChangeEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(UserEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(GroupEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(MemberEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(PrivilegeEventCreator.class);
+    
auditLogEventCreatorBinder.addBinding().to(BlueprintExportEventCreator.class);
+    
auditLogEventCreatorBinder.addBinding().to(ServiceConfigDownloadEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(BlueprintEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(ViewInstanceEventCreator.class);
+    
auditLogEventCreatorBinder.addBinding().to(ViewPrivilegeEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(RepositoryEventCreator.class);
+    
auditLogEventCreatorBinder.addBinding().to(RepositoryVersionEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(AlertGroupEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(AlertTargetEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(HostEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(UpgradeEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(UpgradeItemEventCreator.class);
+    
auditLogEventCreatorBinder.addBinding().to(RecommendationIgnoreEventCreator.class);
+    
auditLogEventCreatorBinder.addBinding().to(ValidationIgnoreEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(CredentialEventCreator.class);
+    auditLogEventCreatorBinder.addBinding().to(RequestEventCreator.class);
+
+    bind(RequestAuditLogger.class).to(RequestAuditLoggerImpl.class);
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AbstractAuditEvent.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AbstractAuditEvent.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AbstractAuditEvent.java
new file mode 100644
index 0000000..558b0ea
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AbstractAuditEvent.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.audit.event;
+
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+
+/**
+ * Base class for concrete audit event types.
+ */
+public abstract class AbstractAuditEvent implements AuditEvent {
+
+  /**
+   * Timestamp for the audit event creation
+   */
+  private final Long timestamp;
+
+  /**
+   * Message to log
+   */
+  private final String auditMessage;
+
+  /**
+   * Base class for concrete audit event builders.
+   *
+   * @param <T>        the type of the concrete audit event built by this 
builder
+   * @param <TBuilder> the type of the concrete audit event builder.
+   */
+  protected static abstract class AbstractAuditEventBuilder<T extends 
AbstractAuditEvent, TBuilder extends AbstractAuditEventBuilder<T, TBuilder>>
+    implements AuditEventBuilder<T> {
+
+    private Long timestamp;
+    private String auditMessage;
+
+
+    /**
+     * Creates a new audit event instance from this builder.
+     *
+     * @return the build audit event instance.
+     */
+    protected abstract T newAuditEvent();
+
+    /**
+     * Appends details from this builder to the detailed description of the 
audit event.
+     *
+     * @param builder builder for the audit event details.
+     */
+    protected abstract void buildAuditMessage(StringBuilder builder);
+
+
+    /**
+     * The timestamp of the audit event.
+     *
+     * @param timestamp
+     * @return
+     */
+    public TBuilder withTimestamp(Long timestamp) {
+      this.timestamp = timestamp;
+
+      return (TBuilder) this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public final T build() {
+      final StringBuilder auditMessageBuilder = new StringBuilder();
+
+      buildAuditMessage(auditMessageBuilder);
+      auditMessage = auditMessageBuilder.toString();
+
+      return newAuditEvent();
+    }
+
+  }
+
+
+  protected AbstractAuditEvent() {
+    this.timestamp = null;
+    this.auditMessage = null;
+  }
+
+  /**
+   * Constructor. Initializes fields using the provided builder.
+   *
+   * @param builder
+   */
+  protected AbstractAuditEvent(AbstractAuditEventBuilder<?, ?> builder) {
+    timestamp = builder.timestamp;
+    auditMessage = builder.auditMessage;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Long getTimestamp() {
+    return timestamp;
+  }
+
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public String getAuditMessage() {
+    return auditMessage;
+  }
+
+  @Override
+  public final boolean equals(Object o) {
+    if (this == o) return true;
+
+    if (!(o instanceof AbstractAuditEvent)) return false;
+
+    AbstractAuditEvent that = (AbstractAuditEvent) o;
+
+    return new EqualsBuilder()
+      .append(getTimestamp(), that.getTimestamp())
+      .append(getAuditMessage(), that.getAuditMessage())
+      .isEquals();
+  }
+
+  @Override
+  public final int hashCode() {
+    return new HashCodeBuilder(17, 37)
+      .append(getTimestamp())
+      .append(getAuditMessage())
+      .toHashCode();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AbstractUserAuditEvent.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AbstractUserAuditEvent.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AbstractUserAuditEvent.java
new file mode 100644
index 0000000..a968a64
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AbstractUserAuditEvent.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.audit.event;
+
+/**
+ * Base class for audit events which are result of user actions. It appends
+ * to audit event details the user name and remote ip of the host
+ * where user actions originates from.
+ */
+public abstract class AbstractUserAuditEvent extends AbstractAuditEvent {
+
+  public static abstract class AbstractUserAuditEventBuilder<T extends 
AbstractUserAuditEvent, TBuilder extends AbstractUserAuditEventBuilder<T, 
TBuilder>>
+    extends AbstractAuditEventBuilder<T, TBuilder> {
+
+    /**
+     * Name of the user started the operation
+     */
+    private String userName;
+
+    /**
+     * Ip of the user who started the operation. Note: remote ip might not be 
the original ip (proxies, routers can modify it)
+     */
+    private String remoteIp;
+
+    /**
+     * Appends to audit event details the user name and remote ip of the host
+     * where user actions originates from.
+     *
+     * @param builder builder for the audit message details.
+     */
+    @Override
+    protected void buildAuditMessage(StringBuilder builder) {
+      builder
+        .append("User(")
+        .append(this.userName)
+        .append("), RemoteIp(")
+        .append(this.remoteIp)
+        .append(")");
+    }
+
+    /**
+     * Sets the user name of the user that initiated the audited action.
+     *
+     * @param userName
+     * @return the builder
+     */
+    public TBuilder withUserName(String userName) {
+      this.userName = userName;
+
+      return (TBuilder) this;
+    }
+
+    /**
+     * Sets the remote ip where the user action originated from.
+     *
+     * @param ip
+     * @return the builder
+     */
+    public TBuilder withRemoteIp(String ip) {
+      this.remoteIp = ip;
+
+      return (TBuilder) this;
+    }
+  }
+
+  protected AbstractUserAuditEvent() {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  protected AbstractUserAuditEvent(AbstractUserAuditEventBuilder<?, ?> 
builder) {
+    super(builder);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AccessUnauthorizedAuditEvent.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AccessUnauthorizedAuditEvent.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AccessUnauthorizedAuditEvent.java
new file mode 100644
index 0000000..b6e60e1
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AccessUnauthorizedAuditEvent.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.audit.event;
+
+import javax.annotation.concurrent.Immutable;
+
+/**
+ * Access to given resource is not authorized.
+ */
+@Immutable
+public class AccessUnauthorizedAuditEvent extends AbstractUserAuditEvent {
+
+  public static class AccessUnauthorizedAuditEventBuilder
+    extends AbstractUserAuditEventBuilder<AccessUnauthorizedAuditEvent, 
AccessUnauthorizedAuditEventBuilder> {
+
+    /**
+     * Name of http method (PUT, POST, DELETE, etc...)
+     */
+    private String httpMethodName;
+
+    /**
+     * The resource path that is tried to be accessed
+     */
+    private String resourcePath;
+
+    /**
+     * Appends to the aduit event detail the list of the privileges
+     * possessed by the principal requesting access to a resource.
+     *
+     * @param builder builder for the audit event details.
+     */
+    @Override
+    protected void buildAuditMessage(StringBuilder builder) {
+      super.buildAuditMessage(builder);
+
+      builder
+        .append(", Operation(")
+        .append(httpMethodName)
+        .append("), ResourcePath(")
+        .append(resourcePath)
+        .append("), Status(Failed), Reason(Access not authorized)");
+    }
+
+    public AccessUnauthorizedAuditEventBuilder withHttpMethodName(String 
httpMethodName) {
+      this.httpMethodName = httpMethodName;
+      return this;
+    }
+
+    public AccessUnauthorizedAuditEventBuilder withResourcePath(String 
resourcePath) {
+      this.resourcePath = resourcePath;
+      return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected AccessUnauthorizedAuditEvent newAuditEvent() {
+      return new AccessUnauthorizedAuditEvent(this);
+    }
+  }
+
+  private AccessUnauthorizedAuditEvent() {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  private AccessUnauthorizedAuditEvent(AccessUnauthorizedAuditEventBuilder 
builder) {
+    super(builder);
+  }
+
+  /**
+   * Returns an builder for {@link AccessUnauthorizedAuditEvent}
+   *
+   * @return a builder instance
+   */
+  public static AccessUnauthorizedAuditEventBuilder builder() {
+    return new AccessUnauthorizedAuditEventBuilder();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AuditEvent.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AuditEvent.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AuditEvent.java
new file mode 100644
index 0000000..fc027c7
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AuditEvent.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.audit.event;
+
+/**
+ * Audit event that contains
+ * the details of an action/event
+ * that is subject to audit.
+ */
+public interface AuditEvent {
+
+  /**
+   * Builder for {@link AuditEvent}
+   *
+   * @param <T> the type of the concrete audit event.
+   */
+  interface AuditEventBuilder<T extends AuditEvent> {
+    /**
+     * Builds an audit event.
+     *
+     * @return audit event instance
+     */
+    T build();
+  }
+
+  /**
+   * Returns the timestamp of the audit event.
+   *
+   * @return timestamp of the audit event.
+   */
+  Long getTimestamp();
+
+  /**
+   * Returns the details of the audit event.
+   *
+   * @return detail of the audit event.
+   */
+  String getAuditMessage();
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LoginAuditEvent.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LoginAuditEvent.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LoginAuditEvent.java
new file mode 100644
index 0000000..223dd18
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LoginAuditEvent.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.audit.event;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.concurrent.Immutable;
+
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * Login audit event.
+ */
+@Immutable
+public class LoginAuditEvent extends AbstractUserAuditEvent {
+
+  public static class LoginAuditEventBuilder
+    extends AbstractUserAuditEventBuilder<LoginAuditEvent, 
LoginAuditEventBuilder> {
+
+    private LoginAuditEventBuilder() {
+    }
+
+    /**
+     * List of roles possessed by the principal requesting access to a 
resource.
+     * [ view name | cluster name | 'Ambari'] -> list of permissions
+     */
+    private Map<String, List<String>> roles;
+
+    /**
+     * Reason of failure, if it is not null, then the request status is 
consider as failed
+     */
+    private String reasonOfFailure;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void buildAuditMessage(StringBuilder builder) {
+      super.buildAuditMessage(builder);
+
+      builder.append(", Operation(User login), 
Roles(").append(System.lineSeparator());
+
+      if (roles != null && !roles.isEmpty()) {
+        List<String> lines = new LinkedList<>();
+        for (Map.Entry<String, List<String>> entry : roles.entrySet()) {
+          lines.add("    " + entry.getKey() + ": " + 
StringUtils.join(entry.getValue(), ", "));
+        }
+        builder.append(StringUtils.join(lines, System.lineSeparator()));
+        builder.append(System.lineSeparator());
+      }
+      builder.append("), Status(")
+        .append(reasonOfFailure == null ? "Success" : "Failed");
+
+      if (reasonOfFailure != null) {
+        builder.append("), Reason(")
+          .append(reasonOfFailure);
+      }
+      builder.append(")");
+    }
+
+    /**
+     * Sets the list of roles possessed by the principal requesting access to 
a resource.
+     *
+     * @param roles
+     * @return this builder
+     */
+    public LoginAuditEventBuilder withRoles(Map<String, List<String>> roles) {
+      this.roles = roles;
+
+      return this;
+    }
+
+    public LoginAuditEventBuilder withReasonOfFailure(String reasonOfFailure) {
+      this.reasonOfFailure = reasonOfFailure;
+      return this;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected LoginAuditEvent newAuditEvent() {
+      return new LoginAuditEvent(this);
+    }
+
+  }
+
+
+  private LoginAuditEvent() {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  private LoginAuditEvent(LoginAuditEventBuilder builder) {
+    super(builder);
+
+  }
+
+  /**
+   * Returns an builder for {@link LoginAuditEvent}
+   *
+   * @return a builder instance
+   */
+  public static LoginAuditEventBuilder builder() {
+    return new LoginAuditEventBuilder();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LogoutAuditEvent.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LogoutAuditEvent.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LogoutAuditEvent.java
new file mode 100644
index 0000000..3ce8c31
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LogoutAuditEvent.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.server.audit.event;
+
+import javax.annotation.concurrent.Immutable;
+
+/**
+ * Logout audit event.
+ */
+@Immutable
+public class LogoutAuditEvent extends AbstractUserAuditEvent {
+  public static class LogoutAuditEventBuilder
+    extends AbstractUserAuditEventBuilder<LogoutAuditEvent, 
LogoutAuditEventBuilder> {
+
+    private LogoutAuditEventBuilder() {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void buildAuditMessage(StringBuilder builder) {
+      super.buildAuditMessage(builder);
+      builder.append(", Operation(Logout), Status(Success)");
+    }
+
+    @Override
+    protected LogoutAuditEvent newAuditEvent() {
+      return new LogoutAuditEvent(this);
+    }
+  }
+
+  private LogoutAuditEvent() {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  private LogoutAuditEvent(LogoutAuditEventBuilder builder) {
+    super(builder);
+
+  }
+
+  /**
+   * Returns an builder for {@link LogoutAuditEvent}
+   *
+   * @return a builder instance
+   */
+  public static LogoutAuditEventBuilder builder() {
+    return new LogoutAuditEventBuilder();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/OperationStatusAuditEvent.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/OperationStatusAuditEvent.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/OperationStatusAuditEvent.java
new file mode 100644
index 0000000..319d772
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/OperationStatusAuditEvent.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.audit.event;
+
+
+import javax.annotation.concurrent.Immutable;
+
+/**
+ * Audit event for tracking operations
+ */
+@Immutable
+public class OperationStatusAuditEvent extends AbstractAuditEvent {
+
+  public static class OperationStatusAuditEventBuilder extends 
AbstractAuditEventBuilder<OperationStatusAuditEvent, 
OperationStatusAuditEventBuilder> {
+
+    /**
+     * Request identifier
+     */
+    private String requestId;
+
+    /**
+     * Status of the whole request
+     */
+    private String status;
+
+    /**
+     * Name of the operation
+     */
+    private String operation;
+
+    private OperationStatusAuditEventBuilder() {
+    }
+
+    @Override
+    protected OperationStatusAuditEvent newAuditEvent() {
+      return new OperationStatusAuditEvent(this);
+    }
+
+    /**
+     * Builds and audit log message based on the member variables
+     *
+     * @param builder builder for the audit event details.
+     */
+    @Override
+    protected void buildAuditMessage(StringBuilder builder) {
+      builder
+        .append("Operation(")
+        .append(this.operation)
+        .append("), Status(")
+        .append(this.status)
+        .append("), RequestId(")
+        .append(this.requestId)
+        .append(")");
+    }
+
+
+    public OperationStatusAuditEventBuilder withStatus(String status) {
+      this.status = status;
+      return this;
+    }
+
+    public OperationStatusAuditEventBuilder withRequestId(String requestId) {
+      this.requestId = requestId;
+      return this;
+    }
+
+    public OperationStatusAuditEventBuilder withRequestContext(String 
operation) {
+      this.operation = operation;
+      return this;
+    }
+  }
+
+  private OperationStatusAuditEvent() {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  private OperationStatusAuditEvent(OperationStatusAuditEventBuilder builder) {
+    super(builder);
+  }
+
+  /**
+   * Returns an builder for {@link OperationStatusAuditEvent}
+   *
+   * @return a builder instance
+   */
+  public static OperationStatusAuditEventBuilder builder() {
+    return new OperationStatusAuditEventBuilder();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/TaskStatusAuditEvent.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/TaskStatusAuditEvent.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/TaskStatusAuditEvent.java
new file mode 100644
index 0000000..eaea058
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/TaskStatusAuditEvent.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.audit.event;
+
+
+import javax.annotation.concurrent.Immutable;
+
+/**
+ * Audit event for tracking task status
+ */
+@Immutable
+public class TaskStatusAuditEvent extends AbstractAuditEvent {
+
+  public static class TaskStatusAuditEventBuilder extends 
AbstractAuditEventBuilder<TaskStatusAuditEvent, TaskStatusAuditEventBuilder> {
+
+    /**
+     * Request identifier
+     */
+    private String requestId;
+
+    /**
+     * Task identifier
+     */
+    private String taskId;
+
+    /**
+     * Request identifier
+     */
+    private String hostName;
+
+    /**
+     * Status of the whole request
+     */
+    private String status;
+
+    /**
+     * Name of the operation
+     */
+    private String operation;
+
+    /**
+     * Task command details
+     */
+    private String details;
+
+    private TaskStatusAuditEventBuilder() {
+    }
+
+    @Override
+    protected TaskStatusAuditEvent newAuditEvent() {
+      return new TaskStatusAuditEvent(this);
+    }
+
+    /**
+     * Builds and audit log message based on the member variables
+     *
+     * @param builder builder for the audit event details.
+     */
+    @Override
+    protected void buildAuditMessage(StringBuilder builder) {
+      builder
+        .append("Operation(")
+        .append(this.operation);
+
+      if (details != null) {
+        builder.append("), Details(")
+          .append(this.details);
+      }
+
+      builder.append("), Status(")
+        .append(this.status)
+        .append("), RequestId(")
+        .append(this.requestId)
+        .append("), TaskId(")
+        .append(this.taskId)
+        .append("), Hostname(")
+        .append(this.hostName)
+        .append(")");
+    }
+
+
+    public TaskStatusAuditEventBuilder withStatus(String status) {
+      this.status = status;
+      return this;
+    }
+
+    public TaskStatusAuditEventBuilder withRequestId(String requestId) {
+      this.requestId = requestId;
+      return this;
+    }
+
+    public TaskStatusAuditEventBuilder withTaskId(String taskId) {
+      this.taskId = taskId;
+      return this;
+    }
+
+    public TaskStatusAuditEventBuilder withHostName(String hostName) {
+      this.hostName = hostName;
+      return this;
+    }
+
+    public TaskStatusAuditEventBuilder withOperation(String operation) {
+      this.operation = operation;
+      return this;
+    }
+
+    public TaskStatusAuditEventBuilder withDetails(String details) {
+      this.details = details;
+      return this;
+    }
+  }
+
+  private TaskStatusAuditEvent() {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  private TaskStatusAuditEvent(TaskStatusAuditEventBuilder builder) {
+    super(builder);
+  }
+
+  /**
+   * Returns an builder for {@link TaskStatusAuditEvent}
+   *
+   * @return a builder instance
+   */
+  public static TaskStatusAuditEventBuilder builder() {
+    return new TaskStatusAuditEventBuilder();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/kerberos/AbstractKerberosAuditEvent.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/kerberos/AbstractKerberosAuditEvent.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/kerberos/AbstractKerberosAuditEvent.java
new file mode 100644
index 0000000..77c162c
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/kerberos/AbstractKerberosAuditEvent.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.audit.event.kerberos;
+
+
+import javax.annotation.concurrent.Immutable;
+
+import org.apache.ambari.server.audit.event.AbstractAuditEvent;
+
+/**
+ * Base class for kerberos audit events
+ */
+@Immutable
+public class AbstractKerberosAuditEvent extends AbstractAuditEvent {
+  static abstract class AbstractKerberosAuditEventBuilder<T extends 
AbstractKerberosAuditEvent, TBuilder extends 
AbstractKerberosAuditEventBuilder<T, TBuilder>>
+    extends AbstractAuditEvent.AbstractAuditEventBuilder<T, TBuilder> {
+
+    /**
+     * Description of the operation
+     */
+    protected String operation;
+
+    /**
+     * Reason of failure, if it is not null, then the request is considered as 
failed
+     */
+    protected String reasonOfFailure;
+
+    /**
+     * Builds and audit log message based on the member variables
+     *
+     * @param builder builder for the audit event details.
+     */
+    @Override
+    protected void buildAuditMessage(StringBuilder builder) {
+      builder
+        .append("Operation(")
+        .append(operation);
+
+      builder.append("), Status(")
+        .append(reasonOfFailure == null ? "Success" : "Failed");
+
+      if (reasonOfFailure != null) {
+        builder.append("), Reason of failure(")
+          .append(reasonOfFailure);
+      }
+
+      builder.append(")");
+    }
+
+    public TBuilder withOperation(String operation) {
+      this.operation = operation;
+      return (TBuilder) this;
+    }
+
+    public TBuilder withReasonOfFailure(String reasonOfFailure) {
+      this.reasonOfFailure = reasonOfFailure;
+      return (TBuilder) this;
+    }
+  }
+
+  protected AbstractKerberosAuditEvent() {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  protected AbstractKerberosAuditEvent(AbstractKerberosAuditEventBuilder<?, ?> 
builder) {
+    super(builder);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/kerberos/ChangeSecurityStateKerberosAuditEvent.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/kerberos/ChangeSecurityStateKerberosAuditEvent.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/kerberos/ChangeSecurityStateKerberosAuditEvent.java
new file mode 100644
index 0000000..ffb7e8a
--- /dev/null
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/kerberos/ChangeSecurityStateKerberosAuditEvent.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ambari.server.audit.event.kerberos;
+
+import javax.annotation.concurrent.Immutable;
+
+/**
+ * Audit event for kerberos security state change of components
+ */
+@Immutable
+public class ChangeSecurityStateKerberosAuditEvent extends 
AbstractKerberosAuditEvent {
+
+  public static class ChangeSecurityStateKerberosAuditEventBuilder extends 
AbstractKerberosAuditEventBuilder<ChangeSecurityStateKerberosAuditEvent, 
ChangeSecurityStateKerberosAuditEventBuilder> {
+
+    /**
+     * Service name
+     */
+    private String service;
+
+    /**
+     * Component name
+     */
+    private String component;
+
+    /**
+     * Host name
+     */
+    private String hostName;
+
+    /**
+     * Security state
+     */
+    private String state;
+
+    private ChangeSecurityStateKerberosAuditEventBuilder() {
+      this.withOperation("Security state change");
+    }
+
+    @Override
+    protected void buildAuditMessage(StringBuilder builder) {
+      super.buildAuditMessage(builder);
+
+      builder
+        .append(", Hostname(")
+        .append(hostName)
+        .append("), Service(")
+        .append(service)
+        .append("), Component(")
+        .append(component)
+        .append("), State(")
+        .append(state)
+        .append(")");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected ChangeSecurityStateKerberosAuditEvent newAuditEvent() {
+      return new ChangeSecurityStateKerberosAuditEvent(this);
+    }
+
+    public ChangeSecurityStateKerberosAuditEventBuilder withService(String 
service) {
+      this.service = service;
+      return this;
+    }
+
+    public ChangeSecurityStateKerberosAuditEventBuilder withComponent(String 
component) {
+      this.component = component;
+      return this;
+    }
+
+    public ChangeSecurityStateKerberosAuditEventBuilder withHostName(String 
hostName) {
+      this.hostName = hostName;
+      return this;
+    }
+
+    public ChangeSecurityStateKerberosAuditEventBuilder withState(String 
state) {
+      this.state = state;
+      return this;
+    }
+  }
+
+  private ChangeSecurityStateKerberosAuditEvent() {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  private 
ChangeSecurityStateKerberosAuditEvent(ChangeSecurityStateKerberosAuditEventBuilder
 builder) {
+    super(builder);
+  }
+
+  /**
+   * Returns an builder for {@link ChangeSecurityStateKerberosAuditEvent}
+   *
+   * @return a builder instance
+   */
+  public static ChangeSecurityStateKerberosAuditEventBuilder builder() {
+    return new ChangeSecurityStateKerberosAuditEventBuilder();
+  }
+}

Reply via email to