ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stoa...@apache.org
Subject [2/7] ambari git commit: AMBARI-15241. Basic Operational Audit Logging. (Daniel Gergely via stoader)
Date Wed, 30 Mar 2016 19:51:16 GMT
http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationFilter.java
new file mode 100644
index 0000000..5663ed2
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authentication/AmbariAuthenticationFilter.java
@@ -0,0 +1,160 @@
+/**
+ * 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.security.authentication;
+
+import java.io.IOException;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.AuditLogger;
+import org.apache.ambari.server.audit.event.LoginAuditEvent;
+import org.apache.ambari.server.security.AmbariEntryPoint;
+import org.apache.ambari.server.security.authorization.AuthorizationHelper;
+import org.apache.ambari.server.security.authorization.PermissionHelper;
+import org.apache.ambari.server.utils.RequestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.crypto.codec.Base64;
+import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
+
+/**
+ * The purpose of this class is to check whether authentication is successful or not,
+ * and make an audit event
+ */
+public class AmbariAuthenticationFilter extends BasicAuthenticationFilter {
+  private static final Logger LOG = LoggerFactory.getLogger(AmbariAuthenticationFilter.class);
+
+  /**
+   * Audit logger
+   */
+  private AuditLogger auditLogger;
+
+  private PermissionHelper permissionHelper;
+
+  public AmbariAuthenticationFilter() {
+    super();
+  }
+
+  public AmbariAuthenticationFilter(AuthenticationManager authenticationManager, AuditLogger auditLogger, PermissionHelper permissionHelper, AmbariEntryPoint ambariEntryPoint) {
+    super(authenticationManager, ambariEntryPoint);
+    this.auditLogger = auditLogger;
+    this.permissionHelper = permissionHelper;
+  }
+
+  /**
+   * Checks whether the authentication information is filled. If it is not, then a login failed audit event is logged
+   * @param req
+   * @param res
+   * @param chain
+   * @throws IOException
+   * @throws ServletException
+   */
+  @Override
+  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
+    HttpServletRequest request = (HttpServletRequest) req;
+    String header = request.getHeader("Authorization");
+    if (AuthorizationHelper.getAuthenticatedName() == null && (header == null || !header.startsWith("Basic "))) {
+      AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()
+        .withRemoteIp(RequestUtils.getRemoteAddress(request))
+        .withTimestamp(System.currentTimeMillis())
+        .withReasonOfFailure("Authentication required")
+        .withUserName(null)
+        .build();
+      auditLogger.log(loginFailedAuditEvent);
+    }
+    super.doFilter(req, res, chain);
+  }
+
+  /**
+   * If the authentication was successful, then an audit event is logged about the success
+   * @param request
+   * @param response
+   * @param authResult
+   * @throws IOException
+   */
+  @Override
+  protected void onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException {
+    AuditEvent loginSucceededAuditEvent = LoginAuditEvent.builder()
+      .withRemoteIp(RequestUtils.getRemoteAddress(request))
+      .withUserName(authResult.getName())
+      .withTimestamp(System.currentTimeMillis())
+      .withRoles(permissionHelper.getPermissionLabels(authResult))
+      .build();
+    auditLogger.log(loginSucceededAuditEvent);
+  }
+
+  /**
+   * In the case of invalid username or password, the authentication fails and it is logged
+   * @param request
+   * @param response
+   * @param authEx
+   * @throws IOException
+   */
+  @Override
+  protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx) throws IOException {
+    String header = request.getHeader("Authorization");
+    String username = null;
+    try {
+      String[] decodedAuth = decodeAuth(header, request);
+      username = decodedAuth[0];
+    } catch (Exception e) {
+      LOG.warn("Error occurred during decoding authorization header.",e);
+    }
+    AuditEvent loginFailedAuditEvent = LoginAuditEvent.builder()
+      .withRemoteIp(RequestUtils.getRemoteAddress(request))
+      .withTimestamp(System.currentTimeMillis())
+      .withReasonOfFailure("Invalid username/password combination")
+      .withUserName(username)
+      .build();
+    auditLogger.log(loginFailedAuditEvent);
+  }
+
+  /**
+   * Helper function to decode Authorization header
+   * @param header
+   * @param request
+   * @return
+   * @throws IOException
+   */
+  private String[] decodeAuth(String header, HttpServletRequest request) throws IOException {
+    byte[] base64Token = header.substring(6).getBytes("UTF-8");
+
+    byte[] decoded;
+    try {
+      decoded = Base64.decode(base64Token);
+    } catch (IllegalArgumentException ex) {
+      throw new BadCredentialsException("Failed to decode basic authentication token");
+    }
+
+    String token = new String(decoded, this.getCredentialsCharset(request));
+    int delim = token.indexOf(":");
+    if(delim == -1) {
+      throw new BadCredentialsException("Invalid basic authentication token");
+    } else {
+      return new String[]{token.substring(0, delim), token.substring(delim + 1)};
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
index 4be804d..96d6131 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AmbariAuthorizationFilter.java
@@ -19,10 +19,15 @@
 package org.apache.ambari.server.security.authorization;
 
 import com.google.inject.Inject;
+import org.apache.ambari.server.audit.event.AccessUnauthorizedAuditEvent;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.AuditLogger;
+import org.apache.ambari.server.audit.event.LoginAuditEvent;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.orm.entities.PermissionEntity;
 import org.apache.ambari.server.orm.entities.PrivilegeEntity;
 import org.apache.ambari.server.security.authorization.internal.InternalAuthenticationToken;
+import org.apache.ambari.server.utils.RequestUtils;
 import org.apache.ambari.server.view.ViewRegistry;
 import org.apache.commons.lang.StringUtils;
 import org.springframework.security.authentication.AnonymousAuthenticationToken;
@@ -90,6 +95,11 @@ public class AmbariAuthorizationFilter implements Filter {
   @Inject
   private Users users;
 
+  @Inject
+  private AuditLogger auditLogger;
+
+  @Inject PermissionHelper permissionHelper;
+
   /**
    * The realm to use for the basic http auth
    */
@@ -111,6 +121,8 @@ public class AmbariAuthorizationFilter implements Filter {
 
     Authentication authentication = context.getAuthentication();
 
+    AuditEvent auditEvent = null;
+
     //  If no explicit authenticated user is set, set it to the default user (if one is specified)
     if (authentication == null || authentication instanceof AnonymousAuthenticationToken) {
       Authentication defaultAuthentication = getDefaultAuthentication();
@@ -123,19 +135,26 @@ public class AmbariAuthorizationFilter implements Filter {
         !authentication.isAuthenticated()) {
       String token = httpRequest.getHeader(INTERNAL_TOKEN_HEADER);
       if (token != null) {
-        context.setAuthentication(new InternalAuthenticationToken(token));
+        InternalAuthenticationToken internalAuthenticationToken = new InternalAuthenticationToken(token);
+        context.setAuthentication(internalAuthenticationToken);
+        LoginAuditEvent loginAuditEvent = LoginAuditEvent.builder()
+          .withUserName(internalAuthenticationToken.getName())
+          .withRemoteIp(RequestUtils.getRemoteAddress(httpRequest))
+          .withRoles(permissionHelper.getPermissionLabels(authentication))
+          .withTimestamp(System.currentTimeMillis()).build();
+        auditLogger.log(loginAuditEvent);
       } else {
         // for view access, we should redirect to the Ambari login
         if (requestURI.matches(VIEWS_CONTEXT_ALL_PATTERN)) {
           String queryString = httpRequest.getQueryString();
           String requestedURL = queryString == null ? requestURI : (requestURI + '?' + queryString);
           String redirectURL = httpResponse.encodeRedirectURL(LOGIN_REDIRECT_BASE + requestedURL);
-
           httpResponse.sendRedirect(redirectURL);
-          return;
         } else {
           httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Authentication required");
+          httpResponse.flushBuffer();
         }
+        return;
       }
     } else if (!authorizationPerformedInternally(requestURI)) {
       boolean authorized = false;
@@ -188,6 +207,14 @@ public class AmbariAuthorizationFilter implements Filter {
       if (!authorized &&
           (!httpRequest.getMethod().equals("GET")
               || requestURI.matches(API_LDAP_SYNC_EVENTS_ALL_PATTERN))) {
+        auditEvent = AccessUnauthorizedAuditEvent.builder()
+          .withHttpMethodName(httpRequest.getMethod())
+          .withRemoteIp(RequestUtils.getRemoteAddress(httpRequest))
+          .withResourcePath(httpRequest.getRequestURI())
+          .withUserName(AuthorizationHelper.getAuthenticatedName())
+          .withTimestamp(System.currentTimeMillis())
+          .build();
+        auditLogger.log(auditEvent);
 
         httpResponse.setHeader("WWW-Authenticate", "Basic realm=\"" + realm + "\"");
         httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "You do not have permissions to access this resource.");
@@ -197,6 +224,16 @@ public class AmbariAuthorizationFilter implements Filter {
     }
     if (AuthorizationHelper.getAuthenticatedName() != null) {
       httpResponse.setHeader("User", AuthorizationHelper.getAuthenticatedName());
+      if (httpResponse.getStatus() == HttpServletResponse.SC_FORBIDDEN) {
+        auditEvent = AccessUnauthorizedAuditEvent.builder()
+          .withHttpMethodName(httpRequest.getMethod())
+          .withRemoteIp(RequestUtils.getRemoteAddress(httpRequest))
+          .withResourcePath(httpRequest.getRequestURI())
+          .withUserName(AuthorizationHelper.getAuthenticatedName())
+          .withTimestamp(System.currentTimeMillis())
+          .build();
+        auditLogger.log(auditEvent);
+      }
     }
     chain.doFilter(request, response);
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java
index 15ef8d0..4007c76 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/AuthorizationHelper.java
@@ -17,11 +17,17 @@
  */
 package org.apache.ambari.server.security.authorization;
 
+import com.google.common.collect.Lists;
 import com.google.inject.Singleton;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.orm.dao.ClusterDAO;
+import org.apache.ambari.server.orm.dao.ViewInstanceDAO;
 import org.apache.ambari.server.orm.entities.PermissionEntity;
 import org.apache.ambari.server.orm.entities.PrivilegeEntity;
 import org.apache.ambari.server.orm.entities.ResourceEntity;
 import org.apache.ambari.server.orm.entities.RoleAuthorizationEntity;
+import org.apache.ambari.server.state.Clusters;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.security.core.Authentication;
@@ -283,4 +289,27 @@ public class AuthorizationHelper {
 
     return loginAlias;
   }
+
+  /**
+   * Retrieve authorization names based on the details of the authenticated user
+   * @param authentication the authenticated user and associated access privileges
+   * @return human readable role authorizations
+   */
+  public static List<String> getAuthorizationNames(Authentication authentication) {
+    List<String> authorizationNames = Lists.newArrayList();
+    if (authentication.getAuthorities() != null) {
+      for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
+        AmbariGrantedAuthority ambariGrantedAuthority = (AmbariGrantedAuthority) grantedAuthority;
+
+        PrivilegeEntity privilegeEntity = ambariGrantedAuthority.getPrivilegeEntity();
+        Collection<RoleAuthorizationEntity> roleAuthorizationEntities =
+          privilegeEntity.getPermission().getAuthorizations();
+        for (RoleAuthorizationEntity entity : roleAuthorizationEntities) {
+          authorizationNames.add(entity.getAuthorizationName());
+        }
+      }
+    }
+    return authorizationNames;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/PermissionHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/PermissionHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/PermissionHelper.java
new file mode 100644
index 0000000..ecf2d7a
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/security/authorization/PermissionHelper.java
@@ -0,0 +1,88 @@
+/*
+ * 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.security.authorization;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ambari.server.orm.dao.ClusterDAO;
+import org.apache.ambari.server.orm.dao.ViewInstanceDAO;
+import org.apache.ambari.server.orm.entities.PrivilegeEntity;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+@Singleton
+public class PermissionHelper {
+
+  private final static Logger LOG = LoggerFactory.getLogger(PermissionHelper.class);
+
+  @Inject
+  private ClusterDAO clusterDAO;
+
+  @Inject
+  private ViewInstanceDAO viewInstanceDAO;
+
+  /**
+   * Retrieve permission labels based on the details of the authenticated user
+   * @param authentication the authenticated user and associated access privileges
+   * @return human-readable permissions
+   */
+  public Map<String,List<String>> getPermissionLabels(Authentication authentication) {
+    Map<String,List<String>> permissionLabels = new HashMap<>();
+    if (authentication.getAuthorities() != null) {
+      for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
+        AmbariGrantedAuthority ambariGrantedAuthority = (AmbariGrantedAuthority) grantedAuthority;
+
+        PrivilegeEntity privilegeEntity = ambariGrantedAuthority.getPrivilegeEntity();
+
+        String key = null;
+        try {
+          switch(privilegeEntity.getResource().getResourceType().getName()) {
+            case "CLUSTER":
+              key = clusterDAO.findByResourceId(privilegeEntity.getResource().getId()).getClusterName();
+              break;
+            case "AMBARI":
+              key = "Ambari";
+              break;
+            default:
+              key = viewInstanceDAO.findByResourceId(privilegeEntity.getResource().getId()).getLabel();
+              break;
+          }
+        } catch (Throwable ignored) {
+          LOG.warn("Error occurred when cluster or view is searched based on resource id", ignored);
+        }
+
+        if(key != null) {
+          if(!permissionLabels.containsKey(key)) {
+            permissionLabels.put(key, new LinkedList<String>());
+          }
+          permissionLabels.get(key).add(privilegeEntity.getPermission().getPermissionLabel());
+        }
+      }
+    }
+    return permissionLabels;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/AbstractServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/AbstractServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/AbstractServerAction.java
index 33191bf..ca4a92c 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/AbstractServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/AbstractServerAction.java
@@ -24,11 +24,16 @@ import org.apache.ambari.server.actionmanager.HostRoleCommand;
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
 import org.apache.ambari.server.agent.CommandReport;
 import org.apache.ambari.server.agent.ExecutionCommand;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.AuditLogger;
 import org.apache.ambari.server.utils.StageUtils;
 
 import java.util.Collections;
 import java.util.Map;
 
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+
 /**
  * AbstractServerActionImpl is an abstract implementation of a ServerAction.
  * <p/>
@@ -52,6 +57,9 @@ public abstract class AbstractServerAction implements ServerAction {
    */
   protected ActionLog actionLog = new ActionLog();
 
+  @Inject
+  private AuditLogger auditLogger;
+
   @Override
   public ExecutionCommand getExecutionCommand() {
     return this.executionCommand;
@@ -175,4 +183,8 @@ public abstract class AbstractServerAction implements ServerAction {
     return getConfigurations().get(configurationName);
   }
 
+  protected void auditLog(AuditEvent ae) {
+    auditLogger.log(ae);
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java
index 81dae0e..8c728db 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreateKeytabFilesServerAction.java
@@ -22,6 +22,7 @@ import com.google.inject.Inject;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
 import org.apache.ambari.server.agent.CommandReport;
+import org.apache.ambari.server.audit.event.kerberos.CreateKeyTabKerberosAuditEvent;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.KerberosHelper;
 import org.apache.ambari.server.orm.dao.HostDAO;
@@ -148,51 +149,55 @@ public class CreateKeytabFilesServerAction extends KerberosServerAction {
                                           Map<String, String> kerberosConfiguration,
                                           Map<String, Object> requestSharedDataContext)
       throws AmbariException {
+
+
+    CreateKeyTabKerberosAuditEvent.CreateKeyTabKerberosAuditEventBuilder auditEventBuilder = CreateKeyTabKerberosAuditEvent.builder().withTimestamp(System.currentTimeMillis());
     CommandReport commandReport = null;
+    String message = null;
+    try {
+      if (identityRecord != null) {
+        String dataDirectory = getDataDirectoryPath();
 
-    if (identityRecord != null) {
-      String message;
-      String dataDirectory = getDataDirectoryPath();
-
-      if (operationHandler == null) {
-        message = String.format("Failed to create keytab file for %s, missing KerberosOperationHandler", evaluatedPrincipal);
-        actionLog.writeStdErr(message);
-        LOG.error(message);
-        commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
-      } else if (dataDirectory == null) {
-        message = "The data directory has not been set. Generated keytab files can not be stored.";
-        LOG.error(message);
-        commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
-      } else {
-        Map<String, String> principalPasswordMap = getPrincipalPasswordMap(requestSharedDataContext);
-        Map<String, Integer> principalKeyNumberMap = getPrincipalKeyNumberMap(requestSharedDataContext);
-
-        String hostName = identityRecord.get(KerberosIdentityDataFileReader.HOSTNAME);
-        String keytabFilePath = identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_PATH);
-
-        if ((hostName != null) && !hostName.isEmpty() && (keytabFilePath != null) && !keytabFilePath.isEmpty()) {
-          Set<String> visitedPrincipalKeys = visitedIdentities.get(evaluatedPrincipal);
-          String visitationKey = String.format("%s|%s", hostName, keytabFilePath);
-
-          if ((visitedPrincipalKeys == null) || !visitedPrincipalKeys.contains(visitationKey)) {
-            // Look up the current evaluatedPrincipal's password.
-            // If found create the keytab file, else try to find it in the cache.
-            String password = principalPasswordMap.get(evaluatedPrincipal);
-            Integer keyNumber = principalKeyNumberMap.get(evaluatedPrincipal);
-
-            message = String.format("Creating keytab file for %s on host %s", evaluatedPrincipal, hostName);
-            LOG.info(message);
-            actionLog.writeStdOut(message);
-
-            // Determine where to store the keytab file.  It should go into a host-specific
-            // directory under the previously determined data directory.
-            File hostDirectory = new File(dataDirectory, hostName);
-
-            // Ensure the host directory exists...
-            if (!hostDirectory.exists() && hostDirectory.mkdirs()) {
-              // Make sure only Ambari has access to this directory.
-              ensureAmbariOnlyAccess(hostDirectory);
-            }
+        if (operationHandler == null) {
+          message = String.format("Failed to create keytab file for %s, missing KerberosOperationHandler", evaluatedPrincipal);
+          actionLog.writeStdErr(message);
+          LOG.error(message);
+          commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
+        } else if (dataDirectory == null) {
+          message = "The data directory has not been set. Generated keytab files can not be stored.";
+          LOG.error(message);
+          commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
+        } else {
+          Map<String, String> principalPasswordMap = getPrincipalPasswordMap(requestSharedDataContext);
+          Map<String, Integer> principalKeyNumberMap = getPrincipalKeyNumberMap(requestSharedDataContext);
+
+          String hostName = identityRecord.get(KerberosIdentityDataFileReader.HOSTNAME);
+          String keytabFilePath = identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_PATH);
+
+          if ((hostName != null) && !hostName.isEmpty() && (keytabFilePath != null) && !keytabFilePath.isEmpty()) {
+            Set<String> visitedPrincipalKeys = visitedIdentities.get(evaluatedPrincipal);
+            String visitationKey = String.format("%s|%s", hostName, keytabFilePath);
+
+            if ((visitedPrincipalKeys == null) || !visitedPrincipalKeys.contains(visitationKey)) {
+              // Look up the current evaluatedPrincipal's password.
+              // If found create the keytab file, else try to find it in the cache.
+              String password = principalPasswordMap.get(evaluatedPrincipal);
+              Integer keyNumber = principalKeyNumberMap.get(evaluatedPrincipal);
+
+              message = String.format("Creating keytab file for %s on host %s", evaluatedPrincipal, hostName);
+              LOG.info(message);
+              actionLog.writeStdOut(message);
+              auditEventBuilder.withPrincipal(evaluatedPrincipal).withHostName(hostName).withKeyTabFilePath(keytabFilePath);
+
+              // Determine where to store the keytab file.  It should go into a host-specific
+              // directory under the previously determined data directory.
+              File hostDirectory = new File(dataDirectory, hostName);
+
+              // Ensure the host directory exists...
+              if (!hostDirectory.exists() && hostDirectory.mkdirs()) {
+                // Make sure only Ambari has access to this directory.
+                ensureAmbariOnlyAccess(hostDirectory);
+              }
 
             if (hostDirectory.exists()) {
               File destinationKeytabFile = new File(hostDirectory, DigestUtils.sha1Hex(keytabFilePath));
@@ -217,71 +222,79 @@ public class CreateKeytabFilesServerAction extends KerberosServerAction {
                   KerberosPrincipalEntity principalEntity = kerberosPrincipalDAO.find(evaluatedPrincipal);
                   String cachedKeytabPath = (principalEntity == null) ? null : principalEntity.getCachedKeytabPath();
 
-                  if (cachedKeytabPath == null) {
-                    message = String.format("Failed to create keytab for %s, missing cached file", evaluatedPrincipal);
-                    actionLog.writeStdErr(message);
-                    LOG.error(message);
-                    commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
-                  } else {
-                    try {
-                      operationHandler.createKeytabFile(new File(cachedKeytabPath), destinationKeytabFile);
-                    } catch (KerberosOperationException e) {
-                      message = String.format("Failed to create keytab file for %s - %s", evaluatedPrincipal, e.getMessage());
+                    if (cachedKeytabPath == null) {
+                      message = String.format("Failed to create keytab for %s, missing cached file", evaluatedPrincipal);
                       actionLog.writeStdErr(message);
-                      LOG.error(message, e);
+                      LOG.error(message);
                       commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
+                    } else {
+                      try {
+                        operationHandler.createKeytabFile(new File(cachedKeytabPath), destinationKeytabFile);
+                      } catch (KerberosOperationException e) {
+                        message = String.format("Failed to create keytab file for %s - %s", evaluatedPrincipal, e.getMessage());
+                        actionLog.writeStdErr(message);
+                        LOG.error(message, e);
+                        commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
+                      }
                     }
                   }
-                }
-              } else {
-                boolean canCache = ("true".equalsIgnoreCase(identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_IS_CACHABLE)));
-
-                Keytab keytab = createKeytab(evaluatedPrincipal, password, keyNumber, operationHandler, visitedPrincipalKeys != null, canCache, actionLog);
+                } else {
+                  boolean canCache = ("true".equalsIgnoreCase(identityRecord.get(KerberosIdentityDataFileReader.KEYTAB_FILE_IS_CACHABLE)));
 
-                if (keytab != null) {
-                  try {
-                    if (operationHandler.createKeytabFile(keytab, destinationKeytabFile)) {
-                      ensureAmbariOnlyAccess(destinationKeytabFile);
+                  Keytab keytab = createKeytab(evaluatedPrincipal, password, keyNumber, operationHandler, visitedPrincipalKeys != null, canCache, actionLog);
 
-                      message = String.format("Successfully created keytab file for %s at %s", evaluatedPrincipal, destinationKeytabFile.getAbsolutePath());
-                      LOG.debug(message);
-                    } else {
-                      message = String.format("Failed to create keytab file for %s at %s", evaluatedPrincipal, destinationKeytabFile.getAbsolutePath());
+                  if (keytab != null) {
+                    try {
+                      if (operationHandler.createKeytabFile(keytab, destinationKeytabFile)) {
+                        ensureAmbariOnlyAccess(destinationKeytabFile);
+
+                        message = String.format("Successfully created keytab file for %s at %s", evaluatedPrincipal, destinationKeytabFile.getAbsolutePath());
+                        LOG.debug(message);
+                        auditEventBuilder.withPrincipal(evaluatedPrincipal).withHostName(hostName).withKeyTabFilePath(destinationKeytabFile.getAbsolutePath());
+                      } else {
+                        message = String.format("Failed to create keytab file for %s at %s", evaluatedPrincipal, destinationKeytabFile.getAbsolutePath());
+                        actionLog.writeStdErr(message);
+                        LOG.error(message);
+                        commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
+                      }
+                    } catch (KerberosOperationException e) {
+                      message = String.format("Failed to create keytab file for %s - %s", evaluatedPrincipal, e.getMessage());
                       actionLog.writeStdErr(message);
-                      LOG.error(message);
+                      LOG.error(message, e);
                       commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
                     }
-                  } catch (KerberosOperationException e) {
-                    message = String.format("Failed to create keytab file for %s - %s", evaluatedPrincipal, e.getMessage());
-                    actionLog.writeStdErr(message);
-                    LOG.error(message, e);
+                  } else {
                     commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
                   }
-                } else {
-                  commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
-                }
 
-                if (visitedPrincipalKeys == null) {
-                  visitedPrincipalKeys = new HashSet<String>();
-                  visitedIdentities.put(evaluatedPrincipal, visitedPrincipalKeys);
-                }
+                  if (visitedPrincipalKeys == null) {
+                    visitedPrincipalKeys = new HashSet<String>();
+                    visitedIdentities.put(evaluatedPrincipal, visitedPrincipalKeys);
+                  }
 
-                visitedPrincipalKeys.add(visitationKey);
+                  visitedPrincipalKeys.add(visitationKey);
+                }
+              } else {
+                message = String.format("Failed to create keytab file for %s, the container directory does not exist: %s",
+                  evaluatedPrincipal, hostDirectory.getAbsolutePath());
+                actionLog.writeStdErr(message);
+                LOG.error(message);
+                commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
               }
             } else {
-              message = String.format("Failed to create keytab file for %s, the container directory does not exist: %s",
-                  evaluatedPrincipal, hostDirectory.getAbsolutePath());
-              actionLog.writeStdErr(message);
-              LOG.error(message);
-              commandReport = createCommandReport(1, HostRoleStatus.FAILED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
+              LOG.debug(String.format("Skipping previously processed keytab for %s on host %s", evaluatedPrincipal, hostName));
             }
-          } else {
-            LOG.debug(String.format("Skipping previously processed keytab for %s on host %s", evaluatedPrincipal, hostName));
           }
         }
       }
+    } finally {
+      if(commandReport != null && HostRoleStatus.FAILED.toString().equals(commandReport.getStatus())) {
+        auditEventBuilder.withReasonOfFailure(message == null ? "Unknown error" : message);
+      }
+      if(commandReport != null || auditEventBuilder.hasPrincipal()) {
+        auditLog(auditEventBuilder.build());
+      }
     }
-
     return commandReport;
   }
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java
index 8009ae1..03a181e 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/CreatePrincipalsServerAction.java
@@ -22,6 +22,7 @@ import com.google.inject.Inject;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
 import org.apache.ambari.server.agent.CommandReport;
+import org.apache.ambari.server.audit.event.kerberos.CreatePrincipalKerberosAuditEvent;
 import org.apache.ambari.server.orm.dao.KerberosPrincipalDAO;
 import org.apache.ambari.server.orm.dao.KerberosPrincipalHostDAO;
 import org.apache.ambari.server.orm.entities.KerberosPrincipalEntity;
@@ -173,92 +174,103 @@ public class CreatePrincipalsServerAction extends KerberosServerAction {
                                                Map<String, String> kerberosConfiguration,
                                                KerberosOperationHandler kerberosOperationHandler,
                                                ActionLog actionLog) {
+    CreatePrincipalKerberosAuditEvent.CreatePrincipalKerberosAuditEventBuilder auditEventBuilder = CreatePrincipalKerberosAuditEvent.builder()
+      .withTimestamp(System.currentTimeMillis())
+      .withPrincipal(principal);
     CreatePrincipalResult result = null;
+    String message = null;
+    try {
 
-    String message = String.format("Creating principal, %s", principal);
-    LOG.info(message);
-    if (actionLog != null) {
-      actionLog.writeStdOut(message);
-    }
-
-    Integer length;
-    Integer minLowercaseLetters;
-    Integer minUppercaseLetters;
-    Integer minDigits;
-    Integer minPunctuation;
-    Integer minWhitespace;
-
-    if (kerberosConfiguration == null) {
-      length = null;
-      minLowercaseLetters = null;
-      minUppercaseLetters = null;
-      minDigits = null;
-      minPunctuation = null;
-      minWhitespace = null;
-    } else {
-      length = toInt(kerberosConfiguration.get("password_length"));
-      minLowercaseLetters = toInt(kerberosConfiguration.get("password_min_lowercase_letters"));
-      minUppercaseLetters = toInt(kerberosConfiguration.get("password_min_uppercase_letters"));
-      minDigits = toInt(kerberosConfiguration.get("password_min_digits"));
-      minPunctuation = toInt(kerberosConfiguration.get("password_min_punctuation"));
-      minWhitespace = toInt(kerberosConfiguration.get("password_min_whitespace"));
-    }
-
-    String password = securePasswordHelper.createSecurePassword(length, minLowercaseLetters, minUppercaseLetters, minDigits, minPunctuation, minWhitespace);
+      message = String.format("Creating principal, %s", principal);
+      LOG.info(message);
+      if (actionLog != null) {
+        actionLog.writeStdOut(message);
+      }
 
-    try {
+      Integer length;
+      Integer minLowercaseLetters;
+      Integer minUppercaseLetters;
+      Integer minDigits;
+      Integer minPunctuation;
+      Integer minWhitespace;
+
+      if (kerberosConfiguration == null) {
+        length = null;
+        minLowercaseLetters = null;
+        minUppercaseLetters = null;
+        minDigits = null;
+        minPunctuation = null;
+        minWhitespace = null;
+      } else {
+        length = toInt(kerberosConfiguration.get("password_length"));
+        minLowercaseLetters = toInt(kerberosConfiguration.get("password_min_lowercase_letters"));
+        minUppercaseLetters = toInt(kerberosConfiguration.get("password_min_uppercase_letters"));
+        minDigits = toInt(kerberosConfiguration.get("password_min_digits"));
+        minPunctuation = toInt(kerberosConfiguration.get("password_min_punctuation"));
+        minWhitespace = toInt(kerberosConfiguration.get("password_min_whitespace"));
+      }
 
-      if (kerberosOperationHandler.principalExists(principal)) {
-        // Create a new password since we need to know what it is.
-        // A new password/key would have been generated after exporting the keytab anyways.
-        message = String.format("Principal, %s, already exists, setting new password", principal);
-        LOG.warn(message);
-        if (actionLog != null) {
-          actionLog.writeStdOut(message);
-        }
+      String password = securePasswordHelper.createSecurePassword(length, minLowercaseLetters, minUppercaseLetters, minDigits, minPunctuation, minWhitespace);
 
-        Integer keyNumber = kerberosOperationHandler.setPrincipalPassword(principal, password);
+      try {
 
-        if (keyNumber != null) {
-          result = new CreatePrincipalResult(principal, password, keyNumber);
-          message = String.format("Successfully set password for %s", principal);
-          LOG.debug(message);
-        } else {
-          message = String.format("Failed to set password for %s - unknown reason", principal);
-          LOG.error(message);
+        if (kerberosOperationHandler.principalExists(principal)) {
+          // Create a new password since we need to know what it is.
+          // A new password/key would have been generated after exporting the keytab anyways.
+          message = String.format("Principal, %s, already exists, setting new password", principal);
+          LOG.warn(message);
           if (actionLog != null) {
-            actionLog.writeStdErr(message);
+            actionLog.writeStdOut(message);
           }
-        }
-      } else {
-        message = String.format("Creating new principal, %s", principal);
-        LOG.debug(message);
 
-        Integer keyNumber = kerberosOperationHandler.createPrincipal(principal, password, isServicePrincipal);
-
-        if (keyNumber != null) {
-          result = new CreatePrincipalResult(principal, password, keyNumber);
-          message = String.format("Successfully created new principal, %s", principal);
-          LOG.debug(message);
+          Integer keyNumber = kerberosOperationHandler.setPrincipalPassword(principal, password);
+
+          if (keyNumber != null) {
+            result = new CreatePrincipalResult(principal, password, keyNumber);
+            message = String.format("Successfully set password for %s", principal);
+            LOG.debug(message);
+          } else {
+            message = String.format("Failed to set password for %s - unknown reason", principal);
+            LOG.error(message);
+            if (actionLog != null) {
+              actionLog.writeStdErr(message);
+            }
+          }
         } else {
-          message = String.format("Failed to create principal, %s - unknown reason", principal);
-          LOG.error(message);
-          if (actionLog != null) {
-            actionLog.writeStdErr(message);
+          message = String.format("Creating new principal, %s", principal);
+          LOG.debug(message);
+
+          Integer keyNumber = kerberosOperationHandler.createPrincipal(principal, password, isServicePrincipal);
+
+          if (keyNumber != null) {
+            result = new CreatePrincipalResult(principal, password, keyNumber);
+            message = String.format("Successfully created new principal, %s", principal);
+            LOG.debug(message);
+          } else {
+            message = String.format("Failed to create principal, %s - unknown reason", principal);
+            LOG.error(message);
+            if (actionLog != null) {
+              actionLog.writeStdErr(message);
+            }
           }
         }
-      }
 
-      if (!kerberosPrincipalDAO.exists(principal)) {
-        kerberosPrincipalDAO.create(principal, isServicePrincipal);
-      }
+        if (!kerberosPrincipalDAO.exists(principal)) {
+          kerberosPrincipalDAO.create(principal, isServicePrincipal);
+        }
 
-    } catch (KerberosOperationException e) {
-      message = String.format("Failed to create principal, %s - %s", principal, e.getMessage());
-      LOG.error(message, e);
-      if (actionLog != null) {
-        actionLog.writeStdErr(message);
+      } catch (KerberosOperationException e) {
+        message = String.format("Failed to create principal, %s - %s", principal, e.getMessage());
+        LOG.error(message, e);
+        if (actionLog != null) {
+          actionLog.writeStdErr(message);
+        }
+      }
+    } finally {
+      if(result == null) {
+        auditEventBuilder.withReasonOfFailure(message == null ? "Unknown error" : message);
       }
+      auditLog(auditEventBuilder.build());
     }
 
     return result;

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java
index c2d8f6a..95dd7a3 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/DestroyPrincipalsServerAction.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.serveraction.kerberos;
 import com.google.inject.Inject;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.agent.CommandReport;
+import org.apache.ambari.server.audit.event.kerberos.DestroyPrincipalKerberosAuditEvent;
 import org.apache.ambari.server.controller.KerberosHelper;
 import org.apache.ambari.server.orm.dao.KerberosPrincipalDAO;
 import org.apache.ambari.server.orm.entities.KerberosPrincipalEntity;
@@ -90,22 +91,28 @@ public class DestroyPrincipalsServerAction extends KerberosServerAction {
     String message = String.format("Destroying identity, %s", evaluatedPrincipal);
     LOG.info(message);
     actionLog.writeStdOut(message);
+    DestroyPrincipalKerberosAuditEvent.DestroyPrincipalKerberosAuditEventBuilder auditEventBuilder = DestroyPrincipalKerberosAuditEvent.builder()
+      .withTimestamp(System.currentTimeMillis())
+      .withPrincipal(evaluatedPrincipal);
 
     try {
-      operationHandler.removePrincipal(evaluatedPrincipal);
-    } catch (KerberosOperationException e) {
-      message = String.format("Failed to remove identity for %s from the KDC - %s", evaluatedPrincipal, e.getMessage());
-      LOG.warn(message);
-      actionLog.writeStdErr(message);
-    }
 
-    try {
-      KerberosPrincipalEntity principalEntity = kerberosPrincipalDAO.find(evaluatedPrincipal);
+      try {
+        operationHandler.removePrincipal(evaluatedPrincipal);
+      } catch (KerberosOperationException e) {
+        message = String.format("Failed to remove identity for %s from the KDC - %s", evaluatedPrincipal, e.getMessage());
+        LOG.warn(message);
+        actionLog.writeStdErr(message);
+        auditEventBuilder.withReasonOfFailure(message);
+      }
 
-      if(principalEntity != null) {
-        String cachedKeytabPath = principalEntity.getCachedKeytabPath();
+      try {
+        KerberosPrincipalEntity principalEntity = kerberosPrincipalDAO.find(evaluatedPrincipal);
 
-        kerberosPrincipalDAO.remove(principalEntity);
+        if (principalEntity != null) {
+          String cachedKeytabPath = principalEntity.getCachedKeytabPath();
+
+          kerberosPrincipalDAO.remove(principalEntity);
 
         // If a cached  keytabs file exists for this principal, delete it.
         if (cachedKeytabPath != null) {
@@ -125,11 +132,14 @@ public class DestroyPrincipalsServerAction extends KerberosServerAction {
           }
         }
       }
-    }
-    catch (Throwable t) {
-      message = String.format("Failed to remove identity for %s from the Ambari database - %s", evaluatedPrincipal, t.getMessage());
-      LOG.warn(message);
-      actionLog.writeStdErr(message);
+    } catch (Throwable t) {
+        message = String.format("Failed to remove identity for %s from the Ambari database - %s", evaluatedPrincipal, t.getMessage());
+        LOG.warn(message);
+        actionLog.writeStdErr(message);
+        auditEventBuilder.withReasonOfFailure(message);
+      }
+    } finally {
+      auditLog(auditEventBuilder.build());
     }
 
     // There is no reason to fail this task if an identity was not removed. The cluster will work

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java
index c710b8e..922cadb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.serveraction.kerberos;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.actionmanager.HostRoleStatus;
 import org.apache.ambari.server.agent.CommandReport;
+import org.apache.ambari.server.audit.event.kerberos.ChangeSecurityStateKerberosAuditEvent;
 import org.apache.ambari.server.state.Cluster;
 import org.apache.ambari.server.state.Host;
 import org.apache.ambari.server.state.SecurityState;
@@ -91,6 +92,14 @@ public class FinalizeKerberosServerAction extends KerberosServerAction {
             actionLog.writeStdOut(message);
 
             sch.setSecurityState(sch.getDesiredSecurityState());
+            ChangeSecurityStateKerberosAuditEvent auditEvent = ChangeSecurityStateKerberosAuditEvent.builder()
+              .withTimestamp(System.currentTimeMillis())
+              .withService(sch.getServiceName())
+              .withComponent(sch.getServiceComponentName())
+              .withHostName(sch.getHostName())
+              .withState(sch.getDesiredSecurityState().toString())
+              .build();
+            auditLog(auditEvent);
           }
         }
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/utils/RequestUtils.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/utils/RequestUtils.java b/ambari-server/src/main/java/org/apache/ambari/server/utils/RequestUtils.java
new file mode 100644
index 0000000..0ac782f
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/utils/RequestUtils.java
@@ -0,0 +1,88 @@
+/**
+ * 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.utils;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.Arrays;
+import java.util.Set;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.ambari.server.api.services.Request;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+/**
+ * The purpose of this helper is to get remote address from an HTTP request
+ */
+public class RequestUtils {
+
+  private static Set<String> headersToCheck= ImmutableSet.copyOf(Arrays.asList(
+    "X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR"));
+
+  /**
+   * Returns remote address
+   * @param request contains the details of http request
+   * @return
+   */
+  public static String getRemoteAddress(HttpServletRequest request) {
+    String ip = null;
+    for (String header : headersToCheck) {
+      ip = request.getHeader(header);
+      if (!isRemoteAddressUnknown(ip)) {
+        break;
+      }
+    }
+    if (isRemoteAddressUnknown(ip)) {
+      ip = request.getRemoteAddr();
+    }
+    return ip;
+  }
+
+  /**
+   * Returns remote address by using {@link HttpServletRequest} from {@link RequestContextHolder}
+   * @return
+   */
+  public static String getRemoteAddress() {
+
+    if(hasValidRequest()) {
+      return getRemoteAddress(((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest());
+    }
+
+    return null;
+  }
+
+  /**
+   * Checks whether ip address is null, empty or unknown
+   * @param ip
+   * @return
+   */
+  private static boolean isRemoteAddressUnknown(String ip) {
+    return ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip);
+  }
+
+  /**
+   * Checks if RequestContextHolder contains a valid HTTP request
+   * @return
+   */
+  private static boolean hasValidRequest() {
+    return RequestContextHolder.getRequestAttributes() != null &&
+      RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes &&
+      ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest() != null;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml b/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml
index 8b44b94..01243ef 100644
--- a/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml
+++ b/ambari-server/src/main/resources/webapp/WEB-INF/spring-security.xml
@@ -25,7 +25,7 @@
   <http use-expressions="true"
         disable-url-rewriting="true" entry-point-ref="ambariEntryPoint">
     <intercept-url pattern="/**" access="isAuthenticated()"/>
-    <custom-filter ref="basicFilter" position="BASIC_AUTH_FILTER"/>
+    <custom-filter ref="ambariAuthenticationFilter" position="BASIC_AUTH_FILTER"/>
     <custom-filter ref="ambariJwtAuthenticationFilter" after="BASIC_AUTH_FILTER" />
     <custom-filter ref="ambariAuthorizationFilter" before="FILTER_SECURITY_INTERCEPTOR"/>
   </http>
@@ -47,8 +47,10 @@
   <beans:bean id="ambariEntryPoint" class="org.apache.ambari.server.security.AmbariEntryPoint">
   </beans:bean>
 
-  <beans:bean id="basicFilter" class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
+  <beans:bean id="ambariAuthenticationFilter" class="org.apache.ambari.server.security.authentication.AmbariAuthenticationFilter">
     <beans:constructor-arg ref="authenticationManager"/>
+    <beans:constructor-arg ref="auditLogger"/>
+    <beans:constructor-arg ref="permissionHelper"/>
     <beans:constructor-arg ref="ambariEntryPoint"/>
   </beans:bean>
 </beans:beans>

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionDBAccessorImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionDBAccessorImpl.java b/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionDBAccessorImpl.java
index f88cf8e..50021c2 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionDBAccessorImpl.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionDBAccessorImpl.java
@@ -35,6 +35,7 @@ import org.apache.ambari.server.agent.ActionQueue;
 import org.apache.ambari.server.agent.CommandReport;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
 import org.apache.ambari.server.api.services.BaseRequest;
+import org.apache.ambari.server.audit.AuditLogger;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.HostsMap;
 import org.apache.ambari.server.controller.internal.RequestResourceFilter;
@@ -50,6 +51,7 @@ import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostStartEvent;
 import org.apache.ambari.server.utils.StageUtils;
+import org.easymock.EasyMock;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -124,6 +126,8 @@ public class TestActionDBAccessorImpl {
         new HostsMap((String) null), injector.getInstance(UnitOfWork.class),
 
 		injector.getInstance(RequestFactory.class), null, null);
+
+    EasyMock.replay(injector.getInstance(AuditLogger.class));
   }
 
   @After

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionManager.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionManager.java b/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionManager.java
index d7d08b1..baee0d8 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionManager.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/actionmanager/TestActionManager.java
@@ -37,6 +37,7 @@ import org.apache.ambari.server.Role;
 import org.apache.ambari.server.RoleCommand;
 import org.apache.ambari.server.agent.ActionQueue;
 import org.apache.ambari.server.agent.CommandReport;
+import org.apache.ambari.server.audit.AuditLogger;
 import org.apache.ambari.server.controller.HostsMap;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
 import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
@@ -44,6 +45,7 @@ import org.apache.ambari.server.state.Clusters;
 import org.apache.ambari.server.state.StackId;
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostStartEvent;
 import org.apache.ambari.server.utils.StageUtils;
+import org.easymock.EasyMock;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
@@ -79,6 +81,8 @@ public class TestActionManager {
     StackId stackId = new StackId("HDP-0.1");
     clusters.addCluster(clusterName, stackId);
     unitOfWork = injector.getInstance(UnitOfWork.class);
+
+    EasyMock.replay(injector.getInstance(AuditLogger.class));
   }
 
   @After

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/test/java/org/apache/ambari/server/agent/HeartbeatProcessorTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/agent/HeartbeatProcessorTest.java b/ambari-server/src/test/java/org/apache/ambari/server/agent/HeartbeatProcessorTest.java
index 7f3d763..bdbb9ab 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/agent/HeartbeatProcessorTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/agent/HeartbeatProcessorTest.java
@@ -38,6 +38,7 @@ import org.apache.ambari.server.actionmanager.RequestFactory;
 import org.apache.ambari.server.actionmanager.Stage;
 import org.apache.ambari.server.actionmanager.StageFactory;
 import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.audit.AuditLogger;
 import org.apache.ambari.server.configuration.Configuration;
 import org.apache.ambari.server.controller.HostsMap;
 import org.apache.ambari.server.orm.GuiceJpaInitializer;
@@ -62,6 +63,7 @@ import org.apache.ambari.server.state.svccomphost.ServiceComponentHostInstallEve
 import org.apache.ambari.server.state.svccomphost.ServiceComponentHostUpgradeEvent;
 import org.apache.ambari.server.utils.EventBusSynchronizer;
 import org.apache.ambari.server.utils.StageUtils;
+import org.easymock.EasyMock;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -134,6 +136,8 @@ public class HeartbeatProcessorTest {
     clusters = injector.getInstance(Clusters.class);
     injector.injectMembers(this);
     unitOfWork = injector.getInstance(UnitOfWork.class);
+
+    EasyMock.replay(injector.getInstance(AuditLogger.class));
   }
 
   @After

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/test/java/org/apache/ambari/server/api/services/BaseServiceTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/BaseServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/BaseServiceTest.java
index 19eeffb..26eb705 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/BaseServiceTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/BaseServiceTest.java
@@ -22,8 +22,16 @@ import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.parsers.BodyParseException;
 import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
 import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.audit.request.RequestAuditLogger;
 import org.easymock.Capture;
+import org.easymock.EasyMock;
+import org.easymock.EasyMockRunner;
+import org.easymock.Mock;
+import org.easymock.MockType;
+import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.Response;
@@ -45,6 +53,7 @@ import static org.junit.Assert.assertEquals;
 /**
  * Base class for service unit tests.
  */
+@RunWith(EasyMockRunner.class)
 public abstract class BaseServiceTest {
 
   protected ResourceInstance resourceInstance = createNiceMock(ResourceInstance.class);
@@ -88,6 +97,14 @@ public abstract class BaseServiceTest {
     return serializer;
   }
 
+  @Mock(type = MockType.NICE)
+  public RequestAuditLogger requestAuditLogger;
+
+  @Before
+  public void before() throws Exception {
+    BaseService.init(requestAuditLogger);
+  }
+
   @Test
   public void testService() throws Exception {
     List<ServiceTestInvocation> listTestInvocations = getTestInvocations();
@@ -121,6 +138,7 @@ public abstract class BaseServiceTest {
   }
 
   protected void assertCreateRequest(ServiceTestInvocation testMethod) {
+    addExpectForInitialRequest(testMethod);
     expect(requestFactory.createRequest(httpHeaders, requestBody, uriInfo,
         testMethod.getRequestType(), resourceInstance)).andReturn(request);
   }
@@ -128,6 +146,8 @@ public abstract class BaseServiceTest {
 
 
   private void testMethod_bodyParseException(ServiceTestInvocation testMethod) throws Exception {
+    addExpectForInitialRequest(testMethod);
+
     Capture<Result> resultCapture = new Capture<Result>();
     BodyParseException e = new BodyParseException("TEST MSG");
     expect(bodyParser.parse(testMethod.getBody())).andThrow(e);
@@ -173,6 +193,13 @@ public abstract class BaseServiceTest {
     reset(resourceInstance, requestFactory, request, result, requestBody, bodyParser, status, serializer);
   }
 
+  private void addExpectForInitialRequest(ServiceTestInvocation testMethod) {
+    RequestBody rb = new RequestBody();
+    rb.setBody("body");
+    expect(requestFactory.createRequest(EasyMock.eq(httpHeaders), EasyMock.anyObject(RequestBody.class), EasyMock.eq(uriInfo),
+      EasyMock.eq(testMethod.getRequestType()), EasyMock.eq(resourceInstance))).andReturn(request);
+  }
+
   public static class ServiceTestInvocation {
     private Request.Type m_type;
     private BaseService m_instance;

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/test/java/org/apache/ambari/server/audit/AccessUnauthorizedAuditEventTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/audit/AccessUnauthorizedAuditEventTest.java b/ambari-server/src/test/java/org/apache/ambari/server/audit/AccessUnauthorizedAuditEventTest.java
new file mode 100644
index 0000000..70e4b64
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/audit/AccessUnauthorizedAuditEventTest.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
+ *
+ * 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;
+
+import org.apache.ambari.server.audit.event.AccessUnauthorizedAuditEvent;
+import org.junit.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+public class AccessUnauthorizedAuditEventTest {
+
+  @Test
+  public void testAuditMessage() throws Exception {
+    // Given
+    String testUserName = "USER1";
+    String testRemoteIp = "127.0.0.1";
+    String testHttpMethod = "GET";
+    String testResourcePath = "/api/v1/hosts";
+
+    AccessUnauthorizedAuditEvent evnt = AccessUnauthorizedAuditEvent.builder()
+      .withTimestamp(System.currentTimeMillis())
+      .withRemoteIp(testRemoteIp)
+      .withUserName(testUserName)
+      .withHttpMethodName(testHttpMethod)
+      .withResourcePath(testResourcePath)
+      .build();
+
+    // When
+    String actualAuditMessage = evnt.getAuditMessage();
+
+    // Then
+    String expectedAuditMessage = String.format("User(%s), RemoteIp(%s), Operation(%s), ResourcePath(%s), Status(Failed), Reason(Access not authorized)", testUserName, testRemoteIp, testHttpMethod, testResourcePath);
+
+    assertThat(actualAuditMessage, equalTo(expectedAuditMessage));
+  }
+
+
+  @Test
+  public void testTimestamp() throws Exception {
+    // Given
+    long testTimestamp = System.currentTimeMillis();
+    AccessUnauthorizedAuditEvent evnt = AccessUnauthorizedAuditEvent.builder()
+      .withTimestamp(testTimestamp)
+      .build();
+
+    // When
+    long actualTimestamp = evnt.getTimestamp();
+
+    // Then
+    assertThat(actualTimestamp, equalTo(testTimestamp));
+
+  }
+
+  @Test
+  public void testEquals() throws Exception {
+    EqualsVerifier.forClass(AccessUnauthorizedAuditEvent.class)
+      .verify();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/test/java/org/apache/ambari/server/audit/LoginAuditEventTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/audit/LoginAuditEventTest.java b/ambari-server/src/test/java/org/apache/ambari/server/audit/LoginAuditEventTest.java
new file mode 100644
index 0000000..a146176
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/audit/LoginAuditEventTest.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;
+
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ambari.server.audit.event.LoginAuditEvent;
+import org.junit.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+public class LoginAuditEventTest {
+
+  @Test
+  public void testAuditMessage() throws Exception {
+    // Given
+    String testUserName = "USER1";
+    String testRemoteIp = "127.0.0.1";
+
+    Map<String, List<String>> roles = new HashMap<>();
+    roles.put("a", Arrays.asList("r1", "r2", "r3"));
+
+    LoginAuditEvent evnt = LoginAuditEvent.builder()
+      .withTimestamp(System.currentTimeMillis())
+      .withRemoteIp(testRemoteIp)
+      .withUserName(testUserName)
+      .withRoles(roles)
+      .build();
+
+    // When
+    String actualAuditMessage = evnt.getAuditMessage();
+
+    String roleMessage = System.lineSeparator() + "    a: r1, r2, r3" + System.lineSeparator();
+
+    // Then
+    String expectedAuditMessage = String.format("User(%s), RemoteIp(%s), Operation(User login), Roles(%s), Status(Success)",
+      testUserName, testRemoteIp, roleMessage);
+
+    assertThat(actualAuditMessage, equalTo(expectedAuditMessage));
+
+  }
+
+  @Test
+  public void testFailedAuditMessage() throws Exception {
+    // Given
+    String testUserName = "USER1";
+    String testRemoteIp = "127.0.0.1";
+    String reason = "Bad credentials";
+
+    Map<String, List<String>> roles = new HashMap<>();
+    roles.put("a", Arrays.asList("r1", "r2", "r3"));
+
+    LoginAuditEvent evnt = LoginAuditEvent.builder()
+      .withTimestamp(System.currentTimeMillis())
+      .withRemoteIp(testRemoteIp)
+      .withUserName(testUserName)
+      .withRoles(roles)
+      .withReasonOfFailure(reason)
+      .build();
+
+    // When
+    String actualAuditMessage = evnt.getAuditMessage();
+
+    String roleMessage = System.lineSeparator() + "    a: r1, r2, r3" + System.lineSeparator();
+
+    // Then
+    String expectedAuditMessage = String.format("User(%s), RemoteIp(%s), Operation(User login), Roles(%s), Status(Failed), Reason(%s)",
+      testUserName, testRemoteIp, roleMessage, reason);
+
+    assertThat(actualAuditMessage, equalTo(expectedAuditMessage));
+
+  }
+
+  @Test
+  public void testTimestamp() throws Exception {
+    // Given
+    long testTimestamp = System.currentTimeMillis();
+    LoginAuditEvent evnt = LoginAuditEvent.builder()
+      .withTimestamp(testTimestamp)
+      .build();
+
+    // When
+    long actualTimestamp = evnt.getTimestamp();
+
+    // Then
+    assertThat(actualTimestamp, equalTo(testTimestamp));
+
+  }
+
+  @Test
+  public void testEquals() throws Exception {
+    EqualsVerifier.forClass(LoginAuditEvent.class)
+      .verify();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/test/java/org/apache/ambari/server/audit/LogoutAuditEventTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/audit/LogoutAuditEventTest.java b/ambari-server/src/test/java/org/apache/ambari/server/audit/LogoutAuditEventTest.java
new file mode 100644
index 0000000..7fb6fef
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/audit/LogoutAuditEventTest.java
@@ -0,0 +1,74 @@
+/**
+ * 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;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+import org.apache.ambari.server.audit.event.LogoutAuditEvent;
+import org.junit.Test;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+public class LogoutAuditEventTest {
+
+  @Test
+  public void testAuditMessage() throws Exception {
+    // Given
+    String testUserName = "USER1";
+    String testRemoteIp = "127.0.0.1";
+
+    LogoutAuditEvent evnt = LogoutAuditEvent.builder()
+      .withTimestamp(System.currentTimeMillis())
+      .withRemoteIp(testRemoteIp)
+      .withUserName(testUserName)
+      .build();
+
+    // When
+    String actualAuditMessage = evnt.getAuditMessage();
+
+    // Then
+    String expectedAuditMessage = String.format("User(%s), RemoteIp(%s), Operation(Logout), Status(Success)",
+      testUserName, testRemoteIp);
+
+    assertThat(actualAuditMessage, equalTo(expectedAuditMessage));
+
+  }
+
+  @Test
+  public void testTimestamp() throws Exception {
+    // Given
+    long testTimestamp = System.currentTimeMillis();
+    LogoutAuditEvent evnt = LogoutAuditEvent.builder()
+      .withTimestamp(testTimestamp)
+      .build();
+
+    // When
+    long actualTimestamp = evnt.getTimestamp();
+
+    // Then
+    assertThat(actualTimestamp, equalTo(testTimestamp));
+
+  }
+
+  @Test
+  public void testEquals() throws Exception {
+    EqualsVerifier.forClass(LogoutAuditEvent.class)
+      .verify();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/test/java/org/apache/ambari/server/audit/OperationStatusAuditEventTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/audit/OperationStatusAuditEventTest.java b/ambari-server/src/test/java/org/apache/ambari/server/audit/OperationStatusAuditEventTest.java
new file mode 100644
index 0000000..0d2e710
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/audit/OperationStatusAuditEventTest.java
@@ -0,0 +1,74 @@
+/**
+ * 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;
+
+import org.apache.ambari.server.audit.event.OperationStatusAuditEvent;
+import org.junit.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+public class OperationStatusAuditEventTest {
+
+  @Test
+  public void testAuditMessage() throws Exception {
+    // Given
+    Long testRequestId = 100L;
+    String testStatus = "IN PROGRESS";
+
+    OperationStatusAuditEvent evnt = OperationStatusAuditEvent.builder()
+      .withTimestamp(System.currentTimeMillis())
+      .withRequestId(testRequestId.toString())
+      .withStatus(testStatus)
+      .withRequestContext("Start Service")
+      .build();
+
+    // When
+    String actualAuditMessage = evnt.getAuditMessage();
+
+    // Then
+    String expectedAuditMessage = String.format("Operation(Start Service), Status(%s), RequestId(%s)", testStatus, testRequestId);
+
+    assertThat(actualAuditMessage, equalTo(expectedAuditMessage));
+  }
+
+  @Test
+  public void testTimestamp() throws Exception {
+    // Given
+    long testTimestamp = System.currentTimeMillis();
+    OperationStatusAuditEvent evnt = OperationStatusAuditEvent.builder()
+      .withTimestamp(testTimestamp)
+      .build();
+
+    // When
+    long actualTimestamp = evnt.getTimestamp();
+
+    // Then
+    assertThat(actualTimestamp, equalTo(testTimestamp));
+
+  }
+
+  @Test
+  public void testEquals() throws Exception {
+    EqualsVerifier.forClass(OperationStatusAuditEvent.class)
+      .verify();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/test/java/org/apache/ambari/server/audit/StartOperationRequestAuditEventTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/audit/StartOperationRequestAuditEventTest.java b/ambari-server/src/test/java/org/apache/ambari/server/audit/StartOperationRequestAuditEventTest.java
new file mode 100644
index 0000000..a2097d5
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/audit/StartOperationRequestAuditEventTest.java
@@ -0,0 +1,79 @@
+/**
+ * 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;
+
+import org.apache.ambari.server.audit.event.LoginAuditEvent;
+import org.apache.ambari.server.audit.event.request.StartOperationRequestAuditEvent;
+import org.junit.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+
+import static org.hamcrest.core.IsEqual.equalTo;
+import static org.junit.Assert.assertThat;
+
+public class StartOperationRequestAuditEventTest {
+
+  @Test
+  public void testAuditMessage() throws Exception {
+    // Given
+    String testUserName = "USER1";
+    String testRemoteIp = "127.0.0.1";
+    String testRequestDetails = "{ \"key\": \"value\"}";
+    Long testRequestId = 100L;
+
+    StartOperationRequestAuditEvent evnt = StartOperationRequestAuditEvent.builder()
+      .withTimestamp(System.currentTimeMillis())
+      .withRemoteIp(testRemoteIp)
+      .withUserName(testUserName)
+      .withOperation(testRequestDetails)
+      .withRequestId(testRequestId.toString())
+      .build();
+
+    // When
+    String actualAuditMessage = evnt.getAuditMessage();
+
+    // Then
+    String expectedAuditMessage = String.format("User(%s), RemoteIp(%s), Operation(%s), RequestId(%d), Status(Successfully queued)", testUserName, testRemoteIp, testRequestDetails, testRequestId);
+
+    assertThat(actualAuditMessage, equalTo(expectedAuditMessage));
+
+  }
+
+  @Test
+  public void testTimestamp() throws Exception {
+    // Given
+    long testTimestamp = System.currentTimeMillis();
+    StartOperationRequestAuditEvent evnt = StartOperationRequestAuditEvent.builder()
+      .withTimestamp(testTimestamp)
+      .build();
+
+    // When
+    long actualTimestamp = evnt.getTimestamp();
+
+    // Then
+    assertThat(actualTimestamp, equalTo(testTimestamp));
+
+  }
+
+
+  @Test
+  public void testEquals() throws Exception {
+    EqualsVerifier.forClass(LoginAuditEvent.class)
+      .verify();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/test/java/org/apache/ambari/server/audit/request/AbstractBaseCreator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/audit/request/AbstractBaseCreator.java b/ambari-server/src/test/java/org/apache/ambari/server/audit/request/AbstractBaseCreator.java
new file mode 100644
index 0000000..02ecb00
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/audit/request/AbstractBaseCreator.java
@@ -0,0 +1,45 @@
+/**
+ * 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.request;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.audit.event.AuditEvent;
+
+public abstract class AbstractBaseCreator implements RequestAuditEventCreator {
+
+  public String getPrefix() {
+    return this.getClass().getName();
+  }
+
+  @Override
+  public AuditEvent createAuditEvent(final Request request, final Result result) {
+    return new AuditEvent() {
+      @Override
+      public Long getTimestamp() {
+        return System.currentTimeMillis();
+      }
+
+      @Override
+      public String getAuditMessage() {
+        return getPrefix() + " " + String.format("%s %s %s %s %s", request.getRequestType(), request.getURI(), result.getStatus().getStatusCode(), result.getStatus().getStatus(), result.getStatus().getMessage());
+      }
+    };
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/test/java/org/apache/ambari/server/audit/request/AllGetCreator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/audit/request/AllGetCreator.java b/ambari-server/src/test/java/org/apache/ambari/server/audit/request/AllGetCreator.java
new file mode 100644
index 0000000..b40e036
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/audit/request/AllGetCreator.java
@@ -0,0 +1,44 @@
+/**
+ * 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.request;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.controller.spi.Resource;
+
+public class AllGetCreator extends AbstractBaseCreator {
+
+  @Override
+  public Set<Request.Type> getRequestTypes() {
+    return Collections.singleton(Request.Type.GET);
+  }
+
+  @Override
+  public Set<Resource.Type> getResourceTypes() {
+    return null;
+  }
+
+  @Override
+  public Set<ResultStatus.STATUS> getResultStatuses() {
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/test/java/org/apache/ambari/server/audit/request/AllPostAndPutCreator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/audit/request/AllPostAndPutCreator.java b/ambari-server/src/test/java/org/apache/ambari/server/audit/request/AllPostAndPutCreator.java
new file mode 100644
index 0000000..45aa1df
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/audit/request/AllPostAndPutCreator.java
@@ -0,0 +1,45 @@
+/**
+ * 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.request;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.controller.spi.Resource;
+
+public class AllPostAndPutCreator extends AbstractBaseCreator {
+
+  @Override
+  public Set<Request.Type> getRequestTypes() {
+    return new HashSet<Request.Type>(Arrays.asList(Request.Type.POST, Request.Type.PUT));
+  }
+
+  @Override
+  public Set<Resource.Type> getResourceTypes() {
+    return null;
+  }
+
+  @Override
+  public Set<ResultStatus.STATUS> getResultStatuses() {
+    return null;
+  }
+}


Mime
View raw message