You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by st...@apache.org on 2016/03/30 21:51:18 UTC

[4/7] ambari git commit: AMBARI-15241. Basic Operational Audit Logging. (Daniel Gergely via stoader)

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/request/RequestAuditEvent.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/RequestAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/RequestAuditEvent.java
new file mode 100644
index 0000000..200ecfa
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/RequestAuditEvent.java
@@ -0,0 +1,161 @@
+/*
+ * 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 org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.audit.event.AbstractUserAuditEvent;
+
+/**
+ * Base class for start operation audit events.
+ */
+public class RequestAuditEvent extends AbstractUserAuditEvent {
+
+  public static class RequestAuditEventBuilder<T extends RequestAuditEvent, TBuilder extends RequestAuditEventBuilder<T, TBuilder>> extends AbstractUserAuditEventBuilder<T, TBuilder> {
+
+    /**
+     * Request type (PUT, POST, DELETE, etc...)
+     */
+    private Request.Type requestType;
+
+    /**
+     * Result status, that contains http statuses (OK, ACCEPTED, FORBIDDEN, etc...)
+     */
+    private ResultStatus resultStatus;
+
+    /**
+     * The url that is called
+     */
+    private String url;
+
+    /**
+     * Description of the operation
+     */
+    private String operation;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected T newAuditEvent() {
+      return (T) new RequestAuditEvent(this);
+    }
+
+    /**
+     * Appends to the event the details of the incoming request.
+     *
+     * @param builder builder for the audit event details.
+     */
+    @Override
+    protected void buildAuditMessage(StringBuilder builder) {
+      super.buildAuditMessage(builder);
+      if (operation != null) {
+        builder
+          .append(", Operation(")
+          .append(operation)
+          .append(")");
+      }
+      builder
+        .append(", RequestType(")
+        .append(requestType)
+        .append("), ")
+        .append("url(")
+        .append(url)
+        .append("), ResultStatus(")
+        .append(resultStatus.getStatusCode())
+        .append(" ")
+        .append(resultStatus.getStatus())
+        .append(")");
+
+      if (resultStatus.isErrorState()) {
+        builder.append(", Reason(")
+          .append(resultStatus.getMessage())
+          .append(")");
+      }
+    }
+
+    /**
+     * Sets the request type to be added to the audit event.
+     *
+     * @param requestType request type to be added to the audit event.
+     * @return this builder
+     */
+    public TBuilder withRequestType(Request.Type requestType) {
+      this.requestType = requestType;
+
+      return (TBuilder) this;
+    }
+
+    /**
+     * Sets the url to be added to the audit event.
+     *
+     * @param url url to be added to the audit event.
+     * @return this builder
+     */
+    public TBuilder withUrl(String url) {
+      this.url = url;
+
+      return (TBuilder) this;
+    }
+
+    /**
+     * Sets the result status to be added to the audit event.
+     *
+     * @param resultStatus result status to be added to the audit event.
+     * @return this builder
+     */
+    public TBuilder withResultStatus(ResultStatus resultStatus) {
+      this.resultStatus = resultStatus;
+
+      return (TBuilder) this;
+    }
+
+    /**
+     * Sets the operation to be added to the audit event.
+     *
+     * @param operation operation to be added to the audit event.
+     * @return this builder
+     */
+    public TBuilder withOperation(String operation) {
+      this.operation = operation;
+
+      return (TBuilder) this;
+    }
+  }
+
+  protected RequestAuditEvent() {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  protected RequestAuditEvent(RequestAuditEventBuilder<?, ?> builder) {
+    super(builder);
+  }
+
+  /**
+   * Returns an builder for {@link RequestAuditEvent}
+   *
+   * @return a builder instance
+   */
+  public static RequestAuditEventBuilder<?, ?> builder() {
+    return new RequestAuditEventBuilder();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/request/RequestAuditEventCreator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/RequestAuditEventCreator.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/RequestAuditEventCreator.java
new file mode 100644
index 0000000..ccb39de
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/RequestAuditEventCreator.java
@@ -0,0 +1,59 @@
+/*
+ * 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.Set;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.controller.spi.Resource;
+
+/**
+ * This interface must be implemented by the plugins for the request audit logger
+ * in order to make custom {@link AuditEvent}s based on {@link org.apache.ambari.server.api.services.Request.Type}s
+ * and {@link org.apache.ambari.server.controller.spi.Resource.Type}
+ */
+public interface RequestAuditEventCreator {
+
+  /**
+   * @return the set of {@link org.apache.ambari.server.api.services.Request.Type}s that are handled by this creator
+   */
+  Set<Request.Type> getRequestTypes();
+
+  /**
+   * @return the {@link org.apache.ambari.server.controller.spi.Resource.Type}s that is handled by this creator
+   */
+  Set<Resource.Type> getResourceTypes();
+
+  /**
+   * @return the {@link ResultStatus}es that is handled by this creator
+   */
+  Set<ResultStatus.STATUS> getResultStatuses();
+
+  /**
+   * Creates and {@link AuditEvent}
+   * @param request HTTP request object
+   * @param result HTTP result object
+   * @return an {@link AuditEvent}
+   */
+  AuditEvent createAuditEvent(Request request, Result result);
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/request/RequestAuditLogger.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/RequestAuditLogger.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/RequestAuditLogger.java
new file mode 100644
index 0000000..c132139
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/RequestAuditLogger.java
@@ -0,0 +1,36 @@
+/*
+ * 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 org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.Result;
+
+/**
+ * Audit logger interface for logging requests
+ */
+public interface RequestAuditLogger {
+
+  /**
+   * Logs an audit event based on the http request and result
+   * @param request
+   * @param result
+   */
+  void log(Request request, Result result);
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/request/RequestAuditLoggerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/RequestAuditLoggerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/RequestAuditLoggerImpl.java
new file mode 100644
index 0000000..56efd18
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/RequestAuditLoggerImpl.java
@@ -0,0 +1,150 @@
+/*
+ * 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.Set;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.audit.AuditLogger;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.controller.spi.Resource;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * The purpose of this class is to create audit log entries for the HTTP requests
+ */
+@Singleton
+public class RequestAuditLoggerImpl implements RequestAuditLogger {
+
+  /**
+   * Priorities for searching the proper creator
+   */
+  private static final int REQUEST_TYPE_PRIORITY = 1;
+  private static final int RESULT_STATUS_PRIORITY = 2;
+  private static final int RESOURCE_TYPE_PRIORITY = 4;
+
+  /**
+   * Container for the {@link RequestAuditEventCreator}
+   */
+  private Set<RequestAuditEventCreator> creators;
+
+  /**
+   * Audit logger that receives {@link AuditEvent}s and does the actual logging
+   */
+  private AuditLogger auditLogger;
+
+  /**
+   * Injecting dependencies through the constructor
+   * @param auditLogger Audit Logger
+   * @param creatorSet Set of plugins that are registered for requests
+   */
+  @Inject
+  public RequestAuditLoggerImpl(AuditLogger auditLogger, Set<RequestAuditEventCreator> creatorSet) {
+    this.auditLogger = auditLogger;
+    this.creators = creatorSet;
+  }
+
+  /**
+   * Finds the proper creator, then creates and logs and {@link AuditEvent}
+   * @param request
+   * @param result
+   */
+  @Override
+  public void log(Request request, Result result) {
+    if(!auditLogger.isEnabled()) {
+      return;
+    }
+
+    Resource.Type resourceType = request.getResource().getResourceDefinition().getType();
+    Request.Type requestType = request.getRequestType();
+    ResultStatus resultStatus = result.getStatus();
+
+    RequestAuditEventCreator creator = selectCreator(resourceType, resultStatus, requestType);
+    if (creator != null) {
+      AuditEvent ae = creator.createAuditEvent(request, result);
+      if (ae != null) {
+        auditLogger.log(ae);
+      }
+    }
+  }
+
+  /**
+   * Select the proper creator. Priority order: resourceType > resultStatus > requestType
+   * The most matching creator is returned
+   * If there is no creator found, then null is returned.
+   * @param resourceType
+   * @param requestType
+   * @param resultStatus
+   * @return
+   */
+  private RequestAuditEventCreator selectCreator(Resource.Type resourceType, ResultStatus resultStatus, Request.Type requestType) {
+
+    RequestAuditEventCreator selected = null;
+    Integer priority = -1;
+
+    for (RequestAuditEventCreator creator : creators) {
+      Integer creatorPriority = getPriority(creator, resourceType, resultStatus, requestType);
+      if (creatorPriority != null && priority < creatorPriority) {
+        priority = creatorPriority;
+        selected = creator;
+      }
+    }
+    return selected;
+  }
+
+  /**
+   * Calculates the creator priority for the actual resouce type, result status and request type
+   * @param creator
+   * @param resourceType
+   * @param resultStatus
+   * @param requestType
+   * @return
+   */
+  private Integer getPriority(RequestAuditEventCreator creator, Resource.Type resourceType, ResultStatus resultStatus, Request.Type requestType) {
+    Integer priority = 0;
+
+    if (isIncompatible(creator, resourceType, resultStatus, requestType)) {
+      return null;
+    }
+
+    priority += creator.getRequestTypes() != null && creator.getRequestTypes().contains(requestType) ? REQUEST_TYPE_PRIORITY : 0;
+    priority += creator.getResultStatuses() != null && creator.getResultStatuses().contains(resultStatus.getStatus()) ? RESULT_STATUS_PRIORITY : 0;
+    priority += creator.getResourceTypes() != null && creator.getResourceTypes().contains(resourceType) ? RESOURCE_TYPE_PRIORITY : 0;
+    return priority;
+  }
+
+  /**
+   * Checks if the creator is a possible candidate for creating audit log event for the request
+   * @param creator
+   * @param resourceType
+   * @param resultStatus
+   * @param requestType
+   * @return
+   */
+  private boolean isIncompatible(RequestAuditEventCreator creator, Resource.Type resourceType, ResultStatus resultStatus, Request.Type requestType) {
+    return creator.getRequestTypes() != null && !creator.getRequestTypes().contains(requestType) ||
+      creator.getResultStatuses() != null && !creator.getResultStatuses().contains(resultStatus.getStatus()) ||
+      creator.getResourceTypes() != null && !creator.getResourceTypes().contains(resourceType);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/AlertGroupEventCreator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/AlertGroupEventCreator.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/AlertGroupEventCreator.java
new file mode 100644
index 0000000..103fd4d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/AlertGroupEventCreator.java
@@ -0,0 +1,170 @@
+/*
+ * 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.eventcreator;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.event.request.AddAlertGroupRequestAuditEvent;
+import org.apache.ambari.server.audit.event.request.ChangeAlertGroupRequestAuditEvent;
+import org.apache.ambari.server.audit.event.request.DeleteAlertGroupRequestAuditEvent;
+import org.apache.ambari.server.audit.request.RequestAuditEventCreator;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * This creator handles alert group requests
+ * For resource type {@link Resource.Type#AlertGroup}
+ * and request types {@link Request.Type#POST}, {@link Request.Type#PUT} and {@link Request.Type#DELETE}
+ */
+public class AlertGroupEventCreator implements RequestAuditEventCreator {
+
+  /**
+   * Set of {@link Request.Type}s that are handled by this plugin
+   */
+  private Set<Request.Type> requestTypes = ImmutableSet.<Request.Type>builder().add(Request.Type.PUT, Request.Type.POST, Request.Type.DELETE).build();
+
+  /**
+   * Set of {@link Resource.Type}s that are handled by this plugin
+   */
+  private Set<Resource.Type> resourceTypes = ImmutableSet.<Resource.Type>builder().add(Resource.Type.AlertGroup).build();
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Request.Type> getRequestTypes() {
+    return requestTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Resource.Type> getResourceTypes() {
+    return resourceTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<ResultStatus.STATUS> getResultStatuses() {
+    return null;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public AuditEvent createAuditEvent(Request request, Result result) {
+    String username = ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
+
+    switch (request.getRequestType()) {
+      case POST:
+        return AddAlertGroupRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withName(getName(request))
+          .withDefinitionIds(getDefinitionIds(request))
+          .withNotificationIds(getNotificationIds(request))
+          .build();
+      case PUT:
+        return ChangeAlertGroupRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withName(getName(request))
+          .withDefinitionIds(getDefinitionIds(request))
+          .withNotificationIds(getNotificationIds(request))
+          .build();
+      case DELETE:
+        return DeleteAlertGroupRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withId(request.getResource().getKeyValueMap().get(Resource.Type.AlertGroup))
+          .build();
+      default:
+        return null;
+    }
+  }
+
+  /**
+   * Returns the alert group name from the request
+   * @param request
+   * @return
+   */
+  private String getName(Request request) {
+    if (!request.getBody().getNamedPropertySets().isEmpty()) {
+      return String.valueOf(request.getBody().getNamedPropertySets().iterator().next().getProperties().get(PropertyHelper.getPropertyId("AlertGroup", "name")));
+    }
+    return null;
+  }
+
+  /**
+   * Returns definition ids from the request
+   * @param request
+   * @return
+   */
+  private List<String> getDefinitionIds(Request request) {
+    if (!request.getBody().getNamedPropertySets().isEmpty()) {
+      List<String> list = (List<String>) request.getBody().getNamedPropertySets().iterator().next().getProperties().get(PropertyHelper.getPropertyId("AlertGroup", "definitions"));
+      if (list != null) {
+        return list;
+      }
+    }
+    return Collections.emptyList();
+  }
+
+  /**
+   * Returns notification ids from the request
+   * @param request
+   * @return
+   */
+  private List<String> getNotificationIds(Request request) {
+    if (!request.getBody().getNamedPropertySets().isEmpty()) {
+      List<String> list = (List<String>) request.getBody().getNamedPropertySets().iterator().next().getProperties().get(PropertyHelper.getPropertyId("AlertGroup", "targets"));
+      if (list != null) {
+        return list;
+      }
+    }
+    return Collections.emptyList();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/AlertTargetEventCreator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/AlertTargetEventCreator.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/AlertTargetEventCreator.java
new file mode 100644
index 0000000..29a241e
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/AlertTargetEventCreator.java
@@ -0,0 +1,164 @@
+/*
+ * 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.eventcreator;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.event.request.AddAlertTargetRequestAuditEvent;
+import org.apache.ambari.server.audit.event.request.ChangeAlertTargetRequestAuditEvent;
+import org.apache.ambari.server.audit.event.request.DeleteAlertTargetRequestAuditEvent;
+import org.apache.ambari.server.audit.request.RequestAuditEventCreator;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * This creator handles alert target requests
+ * For resource type {@link Resource.Type#AlertTarget}
+ * and request types {@link Request.Type#POST}, {@link Request.Type#PUT} and {@link Request.Type#DELETE}
+ */
+public class AlertTargetEventCreator implements RequestAuditEventCreator {
+
+  /**
+   * Set of {@link Request.Type}s that are handled by this plugin
+   */
+  private Set<Request.Type> requestTypes = ImmutableSet.<Request.Type>builder().add(Request.Type.PUT, Request.Type.POST, Request.Type.DELETE).build();
+
+  /**
+   * Set of {@link Resource.Type}s that are handled by this plugin
+   */
+  private Set<Resource.Type> resourceTypes = ImmutableSet.<Resource.Type>builder().add(Resource.Type.AlertTarget).build();
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Request.Type> getRequestTypes() {
+    return requestTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Resource.Type> getResourceTypes() {
+    return resourceTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<ResultStatus.STATUS> getResultStatuses() {
+    return null;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public AuditEvent createAuditEvent(Request request, Result result) {
+    String username = ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
+
+    switch (request.getRequestType()) {
+      case POST:
+        return AddAlertTargetRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withName(getProperty(request, "name"))
+          .withDescription(getProperty(request, "description"))
+          .withAlertStates(getPropertyList(request, "alert_states"))
+          .withGroupIds(getPropertyList(request, "groups"))
+          .withNotificationType(getProperty(request, "notification_type"))
+          .withEmailFrom(getProperty(request, "properties/mail.smtp.from"))
+          .withEmailRecipients(getPropertyList(request, "properties/ambari.dispatch.recipients"))
+          .build();
+      case PUT:
+        return ChangeAlertTargetRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withName(getProperty(request, "name"))
+          .withDescription(getProperty(request, "description"))
+          .withAlertStates(getPropertyList(request, "alert_states"))
+          .withGroupIds(getPropertyList(request, "groups"))
+          .withNotificationType(getProperty(request, "notification_type"))
+          .withEmailFrom(getProperty(request, "properties/mail.smtp.from"))
+          .withEmailRecipients(getPropertyList(request, "properties/ambari.dispatch.recipients"))
+          .build();
+      case DELETE:
+        return DeleteAlertTargetRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withId(request.getResource().getKeyValueMap().get(Resource.Type.AlertTarget))
+          .build();
+      default:
+        return null;
+    }
+  }
+
+  /**
+   * Returns a property list from the request, named by the parameter propertyName
+   * @param request
+   * @param propertyName
+   * @return
+   */
+  private List<String> getPropertyList(Request request, String propertyName) {
+    if (!request.getBody().getNamedPropertySets().isEmpty()) {
+      List<String> list = (List<String>) request.getBody().getNamedPropertySets().iterator().next().getProperties().get(PropertyHelper.getPropertyId("AlertTarget", propertyName));
+      if (list != null) {
+        return list;
+      }
+    }
+    return Collections.emptyList();
+  }
+
+  /**
+   * Returns a property from the request, named by the parameter propertyName
+   * @param request
+   * @param propertyName
+   * @return
+   */
+  private String getProperty(Request request, String propertyName) {
+    if (!request.getBody().getPropertySets().isEmpty()) {
+      return String.valueOf(request.getBody().getPropertySets().iterator().next().get(PropertyHelper.getPropertyId("AlertTarget", propertyName)));
+    }
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/BlueprintEventCreator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/BlueprintEventCreator.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/BlueprintEventCreator.java
new file mode 100644
index 0000000..bdd6dbe
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/BlueprintEventCreator.java
@@ -0,0 +1,109 @@
+/*
+ * 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.eventcreator;
+
+import java.util.Set;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.event.request.AddBlueprintRequestAuditEvent;
+import org.apache.ambari.server.audit.event.request.DeleteBlueprintRequestAuditEvent;
+import org.apache.ambari.server.audit.request.RequestAuditEventCreator;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * This creator handles blueprint add and remove requests
+ * For resource type {@link Resource.Type#Blueprint}
+ * and request types {@link Request.Type#POST} and {@link Request.Type#POST}
+ */
+public class BlueprintEventCreator implements RequestAuditEventCreator {
+
+  /**
+   * Set of {@link Request.Type}s that are handled by this plugin
+   */
+  private Set<Request.Type> requestTypes = ImmutableSet.<Request.Type>builder().add(Request.Type.POST, Request.Type.DELETE).build();
+
+  /**
+   * Set of {@link Resource.Type}s that are handled by this plugin
+   */
+  private Set<Resource.Type> resourceTypes = ImmutableSet.<Resource.Type>builder().add(Resource.Type.Blueprint).build();
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Request.Type> getRequestTypes() {
+    return requestTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Resource.Type> getResourceTypes() {
+    return resourceTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<ResultStatus.STATUS> getResultStatuses() {
+    return null;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public AuditEvent createAuditEvent(Request request, Result result) {
+    String username = ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
+
+    switch (request.getRequestType()) {
+      case POST:
+        return AddBlueprintRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withBlueprintName(request.getResource().getKeyValueMap().get(Resource.Type.Blueprint))
+          .build();
+      case DELETE:
+        return DeleteBlueprintRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withBlueprintName(request.getResource().getKeyValueMap().get(Resource.Type.Blueprint))
+          .build();
+      default:
+        return null;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/BlueprintExportEventCreator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/BlueprintExportEventCreator.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/BlueprintExportEventCreator.java
new file mode 100644
index 0000000..1416021
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/BlueprintExportEventCreator.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
+ *
+ * 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.eventcreator;
+
+import java.util.Set;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.event.request.BlueprintExportRequestAuditEvent;
+import org.apache.ambari.server.audit.request.RequestAuditEventCreator;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * This creator handles blueprint export requests
+ * For resource type {@link Resource.Type#Cluster}
+ * and request types {@link Request.Type#GET}
+ */
+public class BlueprintExportEventCreator implements RequestAuditEventCreator {
+
+  /**
+   * Set of {@link Request.Type}s that are handled by this plugin
+   */
+  private Set<Request.Type> requestTypes = ImmutableSet.<Request.Type>builder().add(Request.Type.GET).build();
+
+  /**
+   * Set of {@link Resource.Type}s that are handled by this plugin
+   */
+  private Set<Resource.Type> resourceTypes = ImmutableSet.<Resource.Type>builder().add(Resource.Type.Cluster).build();
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Request.Type> getRequestTypes() {
+    return requestTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Resource.Type> getResourceTypes() {
+    return resourceTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<ResultStatus.STATUS> getResultStatuses() {
+    return null;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public AuditEvent createAuditEvent(Request request, Result result) {
+    String username = ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
+    if (!request.getURI().contains("format=blueprint")) {
+      return null;
+    }
+    return BlueprintExportRequestAuditEvent.builder()
+      .withTimestamp(System.currentTimeMillis())
+      .withRequestType(request.getRequestType())
+      .withResultStatus(result.getStatus())
+      .withUrl(request.getURI())
+      .withRemoteIp(request.getRemoteAddress())
+      .withUserName(username)
+      .build();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/ComponentEventCreator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/ComponentEventCreator.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/ComponentEventCreator.java
new file mode 100644
index 0000000..8034d24
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/ComponentEventCreator.java
@@ -0,0 +1,188 @@
+/*
+ * 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.eventcreator;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.event.request.StartOperationRequestAuditEvent;
+import org.apache.ambari.server.audit.request.RequestAuditEventCreator;
+import org.apache.ambari.server.controller.internal.RequestOperationLevel;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * This creator handles operation requests (start, stop, install, etc)
+ * For resource type {@link org.apache.ambari.server.controller.spi.Resource.Type#HostComponent}
+ * and request types {@link org.apache.ambari.server.api.services.Request.Type#POST}, {@link org.apache.ambari.server.api.services.Request.Type#PUT} and {@link org.apache.ambari.server.api.services.Request.Type#DELETE}
+ */
+public class ComponentEventCreator implements RequestAuditEventCreator {
+
+  /**
+   * Set of {@link Request.Type}s that are handled by this plugin
+   */
+  private Set<Request.Type> requestTypes = ImmutableSet.<Request.Type>builder().add(Request.Type.PUT, Request.Type.POST, Request.Type.DELETE).build();
+
+  /**
+   * Set of {@link Resource.Type}s that are handled by this plugin
+   */
+  private Set<Resource.Type> resourceTypes = ImmutableSet.<Resource.Type>builder().add(Resource.Type.HostComponent).build();
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Request.Type> getRequestTypes() {
+    return requestTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Resource.Type> getResourceTypes() {
+    return resourceTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<ResultStatus.STATUS> getResultStatuses() {
+    // null makes this default
+    return null;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public AuditEvent createAuditEvent(Request request, Result result) {
+    String username = ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
+
+    String operation = getOperation(request);
+
+    Long requestId = null;
+    if (containsRequestId(result)) {
+      requestId = getRequestId(result);
+    }
+
+    StartOperationRequestAuditEvent.StartOperationAuditEventBuilder auditEventBuilder = StartOperationRequestAuditEvent.builder()
+      .withOperation(operation)
+      .withUserName(username)
+      .withRemoteIp(request.getRemoteAddress())
+      .withTimestamp(System.currentTimeMillis())
+      .withRequestId(String.valueOf(requestId));
+
+    if (result.getStatus().isErrorState()) {
+      auditEventBuilder.withReasonOfFailure(result.getStatus().getMessage());
+    }
+
+    return auditEventBuilder.build();
+  }
+
+  /**
+   * Generates operation name based on the request. It checks the operation level, the host name, the service name, the status
+   * and whether this is a maintenance mode switch change.
+   * @param request
+   * @return
+   */
+  private String getOperation(Request request) {
+    if (request.getRequestType() == Request.Type.DELETE) {
+      return "Delete component " + request.getResource().getKeyValueMap().get(Resource.Type.HostComponent);
+    }
+
+    if (request.getBody().getRequestInfoProperties().containsKey(RequestOperationLevel.OPERATION_LEVEL_ID)) {
+      String operation = "";
+      switch (request.getBody().getRequestInfoProperties().get(RequestOperationLevel.OPERATION_LEVEL_ID)) {
+        case "CLUSTER":
+          for (Map<String, Object> map : request.getBody().getPropertySets()) {
+            if (map.containsKey(PropertyHelper.getPropertyId("HostRoles", "cluster_name"))) {
+              operation = String.valueOf(map.get(PropertyHelper.getPropertyId("HostRoles", "state"))) + ": all services"
+                + " on all hosts"
+                + (request.getBody().getQueryString().length() > 0 ? " that matches " + request.getBody().getQueryString() : "")
+                + " (" + request.getBody().getRequestInfoProperties().get(RequestOperationLevel.OPERATION_CLUSTER_ID) + ")";
+              break;
+            }
+          }
+          break;
+        case "HOST":
+          for (Map<String, Object> map : request.getBody().getPropertySets()) {
+            if (map.containsKey(PropertyHelper.getPropertyId("HostRoles", "cluster_name"))) {
+              String query = request.getBody().getRequestInfoProperties().get("query");
+              operation = String.valueOf(map.get(PropertyHelper.getPropertyId("HostRoles", "state"))) + ": " + query.substring(query.indexOf("(") + 1, query.length() - 1)
+                + " on " + request.getBody().getRequestInfoProperties().get("operation_level/host_names")
+                + " (" + request.getBody().getRequestInfoProperties().get(RequestOperationLevel.OPERATION_CLUSTER_ID) + ")";
+              break;
+            }
+          }
+          break;
+        case "HOST_COMPONENT":
+          for (Map<String, Object> map : request.getBody().getPropertySets()) {
+            if (map.containsKey(PropertyHelper.getPropertyId("HostRoles", "component_name"))) {
+              operation = String.valueOf(map.get(PropertyHelper.getPropertyId("HostRoles", "state"))) + ": " + String.valueOf(map.get(PropertyHelper.getPropertyId("HostRoles", "component_name")))
+                + "/" + request.getBody().getRequestInfoProperties().get(RequestOperationLevel.OPERATION_SERVICE_ID)
+                + " on " + request.getBody().getRequestInfoProperties().get("operation_level/host_name")
+                + " (" + request.getBody().getRequestInfoProperties().get(RequestOperationLevel.OPERATION_CLUSTER_ID) + ")";
+              break;
+            }
+          }
+          break;
+      }
+      return operation;
+    }
+
+    for (Map<String, Object> map : request.getBody().getPropertySets()) {
+      if (map.containsKey(PropertyHelper.getPropertyId("HostRoles", "maintenance_state"))) {
+        return "Turn " + map.get(PropertyHelper.getPropertyId("HostRoles", "maintenance_state")) + " Maintenance Mode for " + map.get(PropertyHelper.getPropertyId("HostRoles", "component_name"));
+      }
+    }
+
+    return null;
+  }
+
+  /**
+   * Returns request id from the result
+   * @param result
+   * @return
+   */
+  private Long getRequestId(Result result) {
+    return (Long) result.getResultTree().getChild("request").getObject().getPropertiesMap().get("Requests").get("id");
+  }
+
+  /**
+   * Checks if request id can be found in the result
+   * @param result
+   * @return
+   */
+  private boolean containsRequestId(Result result) {
+    return result.getResultTree().getChild("request") != null
+      && result.getResultTree().getChild("request").getObject() != null
+      && result.getResultTree().getChild("request").getObject().getPropertiesMap().get("Requests") != null
+      && result.getResultTree().getChild("request").getObject().getPropertiesMap().get("Requests").get("id") != null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/ConfigurationChangeEventCreator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/ConfigurationChangeEventCreator.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/ConfigurationChangeEventCreator.java
new file mode 100644
index 0000000..7e58893
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/ConfigurationChangeEventCreator.java
@@ -0,0 +1,150 @@
+/*
+ * 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.eventcreator;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.event.request.ClusterNameChangeRequestAuditEvent;
+import org.apache.ambari.server.audit.event.request.ConfigurationChangeRequestAuditEvent;
+import org.apache.ambari.server.audit.request.RequestAuditEventCreator;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * This creator handles operation requests (start, stop, install, etc)
+ * For resource type {@link Resource.Type#HostComponent}
+ * and request types {@link Request.Type#POST}, {@link Request.Type#PUT} and {@link Request.Type#DELETE}
+ */
+public class ConfigurationChangeEventCreator implements RequestAuditEventCreator {
+
+  /**
+   * Set of {@link Request.Type}s that are handled by this plugin
+   */
+  private Set<Request.Type> requestTypes = ImmutableSet.<Request.Type>builder().add(Request.Type.PUT, Request.Type.POST, Request.Type.DELETE).build();
+
+  /**
+   * Set of {@link Resource.Type}s that are handled by this plugin
+   */
+  private Set<Resource.Type> resourceTypes = ImmutableSet.<Resource.Type>builder().add(Resource.Type.Cluster).build();
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Request.Type> getRequestTypes() {
+    return requestTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Resource.Type> getResourceTypes() {
+    return resourceTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<ResultStatus.STATUS> getResultStatuses() {
+    return null;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public AuditEvent createAuditEvent(Request request, Result result) {
+    String username = ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
+
+    if (!request.getBody().getPropertySets().isEmpty()) {
+      Map<String, Object> map = request.getBody().getPropertySets().iterator().next();
+      if (map.size() == 1 && map.containsKey(PropertyHelper.getPropertyId("Clusters", "cluster_name"))) {
+        String newName = String.valueOf(map.get(PropertyHelper.getPropertyId("Clusters", "cluster_name")));
+        String oldName = request.getResource().getKeyValueMap().get(Resource.Type.Cluster);
+        return ClusterNameChangeRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withOldName(oldName)
+          .withNewName(newName)
+          .build();
+      }
+    }
+
+    return ConfigurationChangeRequestAuditEvent.builder()
+      .withTimestamp(System.currentTimeMillis())
+      .withRequestType(request.getRequestType())
+      .withResultStatus(result.getStatus())
+      .withUrl(request.getURI())
+      .withRemoteIp(request.getRemoteAddress())
+      .withUserName(username)
+      .withVersionNote(getServiceConfigVersionNote(result))
+      .withVersionNumber(getServiceConfigVersion(result))
+      .build();
+  }
+
+  /**
+   * Returns service configuration version from the result
+   * @param result
+   * @return
+   */
+  private String getServiceConfigVersion(Result result) {
+    Map<String, Object> map = getServiceConfigMap(result);
+    return map == null ? null : String.valueOf(map.get("service_config_version"));
+  }
+
+  /**
+   * Returns service configurationv ersion note from the result
+   * @param result
+   * @return
+   */
+  private String getServiceConfigVersionNote(Result result) {
+    Map<String, Object> map = getServiceConfigMap(result);
+    return map == null ? null : String.valueOf(map.get("service_config_version_note"));
+  }
+
+  /**
+   * Returns service configuration map from the result. This map contains version number and version info
+   * @param result
+   * @return
+   */
+  private Map<String, Object> getServiceConfigMap(Result result) {
+    if (result.getResultTree().getChild("resources") != null &&
+      !result.getResultTree().getChild("resources").getChildren().isEmpty() &&
+      result.getResultTree().getChild("resources").getChildren().iterator().next().getObject() != null) {
+      return result.getResultTree().getChild("resources").getChildren().iterator().next().getObject().getPropertiesMap().get("");
+    }
+    return null;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/CredentialEventCreator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/CredentialEventCreator.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/CredentialEventCreator.java
new file mode 100644
index 0000000..3b1f462
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/CredentialEventCreator.java
@@ -0,0 +1,111 @@
+/*
+ * 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.eventcreator;
+
+import java.util.Set;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.event.request.AddCredentialRequestAuditEvent;
+import org.apache.ambari.server.audit.request.RequestAuditEventCreator;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * This creator handles crednetial requests
+ * For resource type {@link Resource.Type#Upgrade}
+ * and request types {@link Request.Type#POST}
+ */
+public class CredentialEventCreator implements RequestAuditEventCreator {
+
+  /**
+   * Set of {@link Request.Type}s that are handled by this plugin
+   */
+  private Set<Request.Type> requestTypes = ImmutableSet.<Request.Type>builder().add(Request.Type.POST).build();
+
+  /**
+   * Set of {@link Resource.Type}s that are handled by this plugin
+   */
+  private Set<Resource.Type> resourceTypes = ImmutableSet.<Resource.Type>builder().add(Resource.Type.Credential).build();
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Request.Type> getRequestTypes() {
+    return requestTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Resource.Type> getResourceTypes() {
+    return resourceTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<ResultStatus.STATUS> getResultStatuses() {
+    return null;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public AuditEvent createAuditEvent(Request request, Result result) {
+    String username = ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
+
+    return AddCredentialRequestAuditEvent.builder()
+      .withTimestamp(System.currentTimeMillis())
+      .withRequestType(request.getRequestType())
+      .withResultStatus(result.getStatus())
+      .withUrl(request.getURI())
+      .withRemoteIp(request.getRemoteAddress())
+      .withUserName(username)
+      .withClusterName(getProperty(request, "cluster_name"))
+      .withType(getProperty(request, "type"))
+      .withAlias(getProperty(request, "alias"))
+      .withPrincipal(getProperty(request, "principal"))
+      .build();
+
+  }
+
+  /**
+   * Returns a property from the resquest
+   * @param request
+   * @param propertyName
+   * @return
+   */
+  private String getProperty(Request request, String propertyName) {
+    if (!request.getBody().getPropertySets().isEmpty()) {
+      return String.valueOf(request.getBody().getPropertySets().iterator().next().get(PropertyHelper.getPropertyId("Credential", propertyName)));
+    }
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/DefaultEventCreator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/DefaultEventCreator.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/DefaultEventCreator.java
new file mode 100644
index 0000000..d0f57f2
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/DefaultEventCreator.java
@@ -0,0 +1,89 @@
+/**
+ * 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.eventcreator;
+
+import java.util.EnumSet;
+import java.util.Set;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.request.RequestAuditEvent;
+import org.apache.ambari.server.audit.request.RequestAuditEventCreator;
+import org.apache.ambari.server.audit.request.RequestAuditLogger;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Default creator for {@link RequestAuditLogger}
+ */
+public class DefaultEventCreator implements RequestAuditEventCreator {
+
+  /**
+   * Set of {@link org.apache.ambari.server.api.services.Request.Type}s that are handled by this plugin
+   * In this case all {@link Request.Type}s are listed, except {@link Request.Type#GET}
+   */
+  private Set<Request.Type> requestTypes = ImmutableSet.<Request.Type>builder().addAll(EnumSet.complementOf(EnumSet.of(Request.Type.GET))).build();
+
+
+  /** {@inheritDoc} */
+  @Override
+  public Set<Request.Type> getRequestTypes() {
+    return requestTypes;
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public Set<Resource.Type> getResourceTypes() {
+    // null makes this default
+    return null;
+  }
+
+  /** {@inheritDoc} */
+  @Override
+  public Set<ResultStatus.STATUS> getResultStatuses() {
+    // null makes this default
+    return null;
+  }
+
+  /**
+   * Creates a simple {@link AuditEvent} with the details of request and response
+   * @param request HTTP request object
+   * @param result HTTP result object
+   * @return
+   */
+  @Override
+  public AuditEvent createAuditEvent(final Request request, final Result result) {
+    String username = ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
+
+    return RequestAuditEvent.builder()
+      .withTimestamp(System.currentTimeMillis())
+      .withUserName(username)
+      .withRemoteIp(request.getRemoteAddress())
+      .withRequestType(request.getRequestType())
+      .withUrl(request.getURI())
+      .withResultStatus(result.getStatus())
+      .build();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/GroupEventCreator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/GroupEventCreator.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/GroupEventCreator.java
new file mode 100644
index 0000000..d926d94
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/GroupEventCreator.java
@@ -0,0 +1,124 @@
+/*
+ * 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.eventcreator;
+
+import java.util.Set;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.event.request.CreateGroupRequestAuditEvent;
+import org.apache.ambari.server.audit.event.request.DeleteGroupRequestAuditEvent;
+import org.apache.ambari.server.audit.request.RequestAuditEventCreator;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * This creator handles group requests
+ * For resource type {@link Resource.Type#Group}
+ * and request types {@link Request.Type#POST} and {@link Request.Type#DELETE}
+ */
+public class GroupEventCreator implements RequestAuditEventCreator {
+
+  /**
+   * Set of {@link Request.Type}s that are handled by this plugin
+   */
+  private Set<Request.Type> requestTypes = ImmutableSet.<Request.Type>builder().add(Request.Type.POST, Request.Type.DELETE).build();
+
+  /**
+   * Set of {@link Resource.Type}s that are handled by this plugin
+   */
+  private Set<Resource.Type> resourceTypes = ImmutableSet.<Resource.Type>builder().add(Resource.Type.Group).build();
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Request.Type> getRequestTypes() {
+    return requestTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Resource.Type> getResourceTypes() {
+    return resourceTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<ResultStatus.STATUS> getResultStatuses() {
+    return null;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public AuditEvent createAuditEvent(Request request, Result result) {
+    String username = ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
+
+    switch (request.getRequestType()) {
+      case POST:
+        return CreateGroupRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withGroupName(getGroupName(request))
+          .build();
+      case DELETE:
+        return DeleteGroupRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withGroupName(request.getResource().getKeyValueMap().get(Resource.Type.Group))
+          .build();
+      default:
+        break;
+    }
+    return null;
+  }
+
+  /**
+   * Returns group name from request
+   * @param request
+   * @return
+   */
+  private String getGroupName(Request request) {
+    if (!request.getBody().getPropertySets().isEmpty()) {
+      return String.valueOf(request.getBody().getPropertySets().iterator().next().get(PropertyHelper.getPropertyId("Groups", "group_name")));
+    }
+    return null;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/HostEventCreator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/HostEventCreator.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/HostEventCreator.java
new file mode 100644
index 0000000..910280d
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/HostEventCreator.java
@@ -0,0 +1,167 @@
+/*
+ * 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.eventcreator;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.event.request.AddComponentToHostRequestAuditEvent;
+import org.apache.ambari.server.audit.event.request.AddHostRequestAuditEvent;
+import org.apache.ambari.server.audit.event.request.DeleteHostRequestAuditEvent;
+import org.apache.ambari.server.audit.request.RequestAuditEventCreator;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * This creator handles host requests (add, delete, add component)
+ * For resource type {@link Resource.Type#HostComponent}
+ * and request types {@link Request.Type#POST}, {@link Request.Type#DELETE} and {@link Request.Type#QUERY_POST}
+ */
+public class HostEventCreator implements RequestAuditEventCreator {
+
+  /**
+   * Set of {@link Request.Type}s that are handled by this plugin
+   */
+  private Set<Request.Type> requestTypes = ImmutableSet.<Request.Type>builder().add(Request.Type.QUERY_POST, Request.Type.POST, Request.Type.DELETE).build();
+
+  /**
+   * Set of {@link Resource.Type}s that are handled by this plugin
+   */
+  private Set<Resource.Type> resourceTypes = ImmutableSet.<Resource.Type>builder().add(Resource.Type.Host).build();
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Request.Type> getRequestTypes() {
+    return requestTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Resource.Type> getResourceTypes() {
+    return resourceTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<ResultStatus.STATUS> getResultStatuses() {
+    // null makes this default
+    return null;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public AuditEvent createAuditEvent(Request request, Result result) {
+    String username = ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
+
+    switch (request.getRequestType()) {
+      case DELETE:
+        return DeleteHostRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withHostName(request.getResource().getKeyValueMap().get(Resource.Type.Host))
+          .build();
+      case POST:
+        return AddHostRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withHostName(getHostName(request))
+          .build();
+      case QUERY_POST:
+        return AddComponentToHostRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withHostName(getHostNameFromQuery(request))
+          .withComponent(getHostComponent(request))
+          .build();
+      default:
+        return null;
+    }
+  }
+
+  /**
+   * Returns hostname from the request
+   * @param request
+   * @return
+   */
+  private String getHostName(Request request) {
+    if (!request.getBody().getNamedPropertySets().isEmpty()) {
+      return String.valueOf(request.getBody().getNamedPropertySets().iterator().next().getProperties().get(PropertyHelper.getPropertyId("Hosts", "host_name")));
+    }
+    return null;
+  }
+
+  /**
+   * Returns component name from the request
+   * @param request
+   * @return
+   */
+  private String getHostComponent(Request request) {
+    if (!request.getBody().getNamedPropertySets().isEmpty()) {
+      Set<Map<String, String>> set = (Set<Map<String, String>>) request.getBody().getNamedPropertySets().iterator().next().getProperties().get("host_components");
+      if (set != null && !set.isEmpty()) {
+        return set.iterator().next().get(PropertyHelper.getPropertyId("HostRoles", "component_name"));
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Returns hostname from the query string of the request
+   * @param request
+   * @return
+   */
+  private String getHostNameFromQuery(Request request) {
+    final String key = PropertyHelper.getPropertyId("Hosts", "host_name");
+    if (request.getBody().getQueryString().contains(key)) {
+      String q = request.getBody().getQueryString();
+      int startIndex = q.indexOf(key) + key.length() + 1;
+      int endIndex = q.indexOf("&", startIndex) == -1 ? q.length() : q.indexOf("&", startIndex);
+      return q.substring(startIndex, endIndex);
+    }
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/MemberEventCreator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/MemberEventCreator.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/MemberEventCreator.java
new file mode 100644
index 0000000..a3c3164
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/MemberEventCreator.java
@@ -0,0 +1,175 @@
+/*
+ * 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.eventcreator;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.event.request.AddUserToGroupRequestAuditEvent;
+import org.apache.ambari.server.audit.event.request.MembershipChangeRequestAuditEvent;
+import org.apache.ambari.server.audit.event.request.RemoveUserFromGroupRequestAuditEvent;
+import org.apache.ambari.server.audit.request.RequestAuditEventCreator;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * This creator handles member requests
+ * For resource type {@link Resource.Type#Member}
+ * and request types {@link Request.Type#POST}, {@link Request.Type#PUT} and {@link Request.Type#DELETE}
+ */
+public class MemberEventCreator implements RequestAuditEventCreator {
+
+  /**
+   * Set of {@link Request.Type}s that are handled by this plugin
+   */
+  private Set<Request.Type> requestTypes = ImmutableSet.<Request.Type>builder().add(Request.Type.PUT, Request.Type.POST, Request.Type.DELETE).build();
+
+  /**
+   * Set of {@link Resource.Type}s that are handled by this plugin
+   */
+  private Set<Resource.Type> resourceTypes = ImmutableSet.<Resource.Type>builder().add(Resource.Type.Member).build();
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Request.Type> getRequestTypes() {
+    return requestTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Resource.Type> getResourceTypes() {
+    return resourceTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<ResultStatus.STATUS> getResultStatuses() {
+    return null;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public AuditEvent createAuditEvent(Request request, Result result) {
+    String username = ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
+
+    switch (request.getRequestType()) {
+      case POST:
+        return AddUserToGroupRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withAffectedUserName(getUserName(request))
+          .withGroupName(getGroupName(request))
+          .build();
+      case DELETE:
+        return RemoveUserFromGroupRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withAffectedUserName(getUserName(request))
+          .withGroupName(getGroupName(request))
+          .build();
+      case PUT:
+        return MembershipChangeRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withGroupName(getGroupNameForPut(request))
+          .withUserNameList(getUsers(request))
+          .build();
+      default:
+        return null;
+    }
+  }
+
+  /**
+   * Returns users from the request
+   * @param request
+   * @return
+   */
+  private List<String> getUsers(Request request) {
+    List<String> users = new LinkedList<String>();
+
+    for (Map<String, Object> propertyMap : request.getBody().getPropertySets()) {
+      String userName = String.valueOf(propertyMap.get(PropertyHelper.getPropertyId("MemberInfo", "user_name")));
+      users.add(userName);
+    }
+    return users;
+  }
+
+  /**
+   * Returns target group name from the request. This is called when PUT request type is used.
+   * @param request
+   * @return
+   */
+  private String getGroupNameForPut(Request request) {
+
+    for (Map<String, Object> propertyMap : request.getBody().getPropertySets()) {
+      return String.valueOf(propertyMap.get(PropertyHelper.getPropertyId("MemberInfo", "group_name")));
+    }
+    return null;
+  }
+
+  /**
+   * Returns username from the request
+   * @param request
+   * @return
+   */
+  private String getUserName(Request request) {
+    return request.getResource().getKeyValueMap().get(Resource.Type.Member);
+  }
+
+  /**
+   * Returns groupname from the request
+   * @param request
+   * @return
+   */
+  private String getGroupName(Request request) {
+    return request.getResource().getKeyValueMap().get(Resource.Type.Group);
+  }
+
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/PrivilegeEventCreator.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/PrivilegeEventCreator.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/PrivilegeEventCreator.java
new file mode 100644
index 0000000..bdc7b59
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/request/eventcreator/PrivilegeEventCreator.java
@@ -0,0 +1,147 @@
+/*
+ * 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.eventcreator;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.audit.event.AuditEvent;
+import org.apache.ambari.server.audit.event.request.ClusterPrivilegeChangeRequestAuditEvent;
+import org.apache.ambari.server.audit.event.request.PrivilegeChangeRequestAuditEvent;
+import org.apache.ambari.server.audit.request.RequestAuditEventCreator;
+import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * This creator handles privilege requests
+ * For resource type {@link Resource.Type#ClusterPrivilege}
+ * and request types {@link Request.Type#POST}, {@link Request.Type#PUT}
+ */
+public class PrivilegeEventCreator implements RequestAuditEventCreator {
+
+  /**
+   * Set of {@link Request.Type}s that are handled by this plugin
+   */
+  private Set<Request.Type> requestTypes = ImmutableSet.<Request.Type>builder().add(Request.Type.PUT, Request.Type.POST).build();
+
+  /**
+   * Set of {@link Resource.Type}s that are handled by this plugin
+   */
+  private Set<Resource.Type> resourceTypes = ImmutableSet.<Resource.Type>builder().add(Resource.Type.ClusterPrivilege).build();
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Request.Type> getRequestTypes() {
+    return requestTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<Resource.Type> getResourceTypes() {
+    return resourceTypes;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Set<ResultStatus.STATUS> getResultStatuses() {
+    return null;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public AuditEvent createAuditEvent(Request request, Result result) {
+    String username = ((User) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
+
+    Map<String, List<String>> users = getEntities(request, "USER");
+    Map<String, List<String>> groups = getEntities(request, "GROUP");
+
+    switch (request.getRequestType()) {
+      case PUT:
+        return ClusterPrivilegeChangeRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withUsers(users)
+          .withGroups(groups)
+          .build();
+      case POST:
+        String role = users.isEmpty() ? (groups.isEmpty() ? null : groups.keySet().iterator().next()) : users.keySet().iterator().next();
+        return PrivilegeChangeRequestAuditEvent.builder()
+          .withTimestamp(System.currentTimeMillis())
+          .withRequestType(request.getRequestType())
+          .withResultStatus(result.getStatus())
+          .withUrl(request.getURI())
+          .withRemoteIp(request.getRemoteAddress())
+          .withUserName(username)
+          .withRole(role)
+          .withGroup(groups.get(role) == null ? null : groups.get(role).get(0))
+          .withUser(users.get(role) == null ? null : users.get(role).get(0))
+          .withOperation((users.isEmpty() ? (groups.isEmpty() ? "" : "Group ") : "User ") + "role change")
+          .build();
+      default:
+        return null;
+    }
+  }
+
+  /**
+   * Assembles entities from the request. The result can contain users or groups based on the value of type parameter
+   * @param request
+   * @param type
+   * @return a map of role -> [user|group] names
+   */
+  private Map<String, List<String>> getEntities(final Request request, final String type) {
+    Map<String, List<String>> entities = new HashMap<String, List<String>>();
+
+    for (Map<String, Object> propertyMap : request.getBody().getPropertySets()) {
+      String ptype = String.valueOf(propertyMap.get(PropertyHelper.getPropertyId("PrivilegeInfo", "principal_type")));
+      if (type.equals(ptype)) {
+        String role = String.valueOf(propertyMap.get(PropertyHelper.getPropertyId("PrivilegeInfo", "permission_name")));
+        String name = String.valueOf(propertyMap.get(PropertyHelper.getPropertyId("PrivilegeInfo", "principal_name")));
+        if (!entities.containsKey(role)) {
+          entities.put(role, new LinkedList<String>());
+        }
+
+        entities.get(role).add(name);
+      }
+    }
+    return entities;
+  }
+
+}