AMBARI-15241. Basic Operational Audit Logging. (Daniel Gergely via stoader)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/46a34ccd Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/46a34ccd Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/46a34ccd Branch: refs/heads/trunk Commit: 46a34ccdeeeeabe0ad4172e94a63c9b077e17861 Parents: b197a6f Author: Toader, Sebastian <[email protected]> Authored: Wed Mar 30 20:02:27 2016 +0200 Committer: Toader, Sebastian <[email protected]> Committed: Wed Mar 30 21:50:51 2016 +0200 ---------------------------------------------------------------------- ambari-project/pom.xml | 7 +- ambari-server/conf/unix/log4j.properties | 14 + ambari-server/conf/windows/log4j.properties | 14 + ambari-server/pom.xml | 6 +- ambari-server/src/main/conf/log4j.properties | 14 + .../actionmanager/ActionDBAccessorImpl.java | 125 +++++ .../ambari/server/api/services/BaseRequest.java | 16 +- .../ambari/server/api/services/BaseService.java | 24 +- .../server/api/services/LogoutService.java | 28 +- .../ambari/server/api/services/Request.java | 32 +- .../ambari/server/audit/AsyncAuditLogger.java | 101 ++++ .../apache/ambari/server/audit/AuditLogger.java | 39 ++ .../server/audit/AuditLoggerDefaultImpl.java | 77 +++ .../ambari/server/audit/AuditLoggerModule.java | 94 ++++ .../server/audit/event/AbstractAuditEvent.java | 148 ++++++ .../audit/event/AbstractUserAuditEvent.java | 92 ++++ .../event/AccessUnauthorizedAuditEvent.java | 97 ++++ .../ambari/server/audit/event/AuditEvent.java | 56 ++ .../server/audit/event/LoginAuditEvent.java | 126 +++++ .../server/audit/event/LogoutAuditEvent.java | 67 +++ .../audit/event/OperationStatusAuditEvent.java | 108 ++++ .../audit/event/TaskStatusAuditEvent.java | 148 ++++++ .../kerberos/AbstractKerberosAuditEvent.java | 87 ++++ .../ChangeSecurityStateKerberosAuditEvent.java | 118 +++++ .../CreateKeyTabKerberosAuditEvent.java | 110 ++++ .../CreatePrincipalKerberosAuditEvent.java | 73 +++ .../DestroyPrincipalKerberosAuditEvent.java | 80 +++ .../request/ActivateUserRequestAuditEvent.java | 101 ++++ .../request/AddAlertGroupRequestAuditEvent.java | 113 ++++ .../AddAlertTargetRequestAuditEvent.java | 167 ++++++ .../request/AddBlueprintRequestAuditEvent.java | 88 ++++ .../AddComponentToHostRequestAuditEvent.java | 98 ++++ .../request/AddCredentialRequestAuditEvent.java | 122 +++++ .../event/request/AddHostRequestAuditEvent.java | 86 ++++ .../request/AddRepositoryRequestAuditEvent.java | 134 +++++ .../AddRepositoryVersionRequestAuditEvent.java | 153 ++++++ .../request/AddRequestRequestAuditEvent.java | 98 ++++ .../request/AddUpgradeRequestAuditEvent.java | 111 ++++ .../AddUserToGroupRequestAuditEvent.java | 98 ++++ .../AddViewInstanceRequestAuditEvent.java | 134 +++++ .../request/AdminUserRequestAuditEvent.java | 101 ++++ .../BlueprintExportRequestAuditEvent.java | 72 +++ .../ChangeAlertGroupRequestAuditEvent.java | 113 ++++ .../ChangeAlertTargetRequestAuditEvent.java | 134 +++++ ...hangeRepositoryVersionRequestAuditEvent.java | 153 ++++++ .../ChangeViewInstanceRequestAuditEvent.java | 134 +++++ .../ClientConfigDownloadRequestAuditEvent.java | 100 ++++ .../ClusterNameChangeRequestAuditEvent.java | 91 ++++ ...ClusterPrivilegeChangeRequestAuditEvent.java | 126 +++++ .../ConfigurationChangeRequestAuditEvent.java | 101 ++++ .../request/CreateGroupRequestAuditEvent.java | 88 ++++ .../request/CreateUserRequestAuditEvent.java | 113 ++++ .../DeleteAlertGroupRequestAuditEvent.java | 86 ++++ .../DeleteAlertTargetRequestAuditEvent.java | 86 ++++ .../DeleteBlueprintRequestAuditEvent.java | 88 ++++ .../request/DeleteGroupRequestAuditEvent.java | 88 ++++ .../request/DeleteHostRequestAuditEvent.java | 88 ++++ ...eleteRepositoryVersionRequestAuditEvent.java | 110 ++++ .../request/DeleteServiceRequestAuditEvent.java | 88 ++++ .../request/DeleteUserRequestAuditEvent.java | 88 ++++ .../DeleteViewInstanceRequestAuditEvent.java | 110 ++++ .../MembershipChangeRequestAuditEvent.java | 108 ++++ .../PrivilegeChangeRequestAuditEvent.java | 113 ++++ .../RemoveUserFromGroupRequestAuditEvent.java | 98 ++++ .../StartOperationRequestAuditEvent.java | 126 +++++ .../UpdateRepositoryRequestAuditEvent.java | 134 +++++ .../UpdateUpgradeItemRequestAuditEvent.java | 111 ++++ .../UserPasswordChangeRequestAuditEvent.java | 88 ++++ .../ViewPrivilegeChangeRequestAuditEvent.java | 163 ++++++ .../server/audit/request/RequestAuditEvent.java | 161 ++++++ .../audit/request/RequestAuditEventCreator.java | 59 +++ .../audit/request/RequestAuditLogger.java | 36 ++ .../audit/request/RequestAuditLoggerImpl.java | 150 ++++++ .../eventcreator/AlertGroupEventCreator.java | 170 ++++++ .../eventcreator/AlertTargetEventCreator.java | 164 ++++++ .../eventcreator/BlueprintEventCreator.java | 109 ++++ .../BlueprintExportEventCreator.java | 94 ++++ .../eventcreator/ComponentEventCreator.java | 188 +++++++ .../ConfigurationChangeEventCreator.java | 150 ++++++ .../eventcreator/CredentialEventCreator.java | 111 ++++ .../eventcreator/DefaultEventCreator.java | 89 ++++ .../request/eventcreator/GroupEventCreator.java | 124 +++++ .../request/eventcreator/HostEventCreator.java | 167 ++++++ .../eventcreator/MemberEventCreator.java | 175 +++++++ .../eventcreator/PrivilegeEventCreator.java | 147 ++++++ .../RecommendationIgnoreEventCreator.java | 81 +++ .../eventcreator/RepositoryEventCreator.java | 132 +++++ .../RepositoryVersionEventCreator.java | 215 ++++++++ .../eventcreator/RequestEventCreator.java | 101 ++++ .../ServiceConfigDownloadEventCreator.java | 92 ++++ .../eventcreator/ServiceEventCreator.java | 179 +++++++ .../eventcreator/UnauthorizedEventCreator.java | 86 ++++ .../eventcreator/UpgradeEventCreator.java | 110 ++++ .../eventcreator/UpgradeItemEventCreator.java | 110 ++++ .../request/eventcreator/UserEventCreator.java | 211 ++++++++ .../ValidationIgnoreEventCreator.java | 81 +++ .../eventcreator/ViewInstanceEventCreator.java | 149 ++++++ .../eventcreator/ViewPrivilegeEventCreator.java | 145 ++++++ .../server/configuration/Configuration.java | 24 + .../ambari/server/controller/AmbariServer.java | 41 +- .../server/controller/ControllerModule.java | 1 - .../controller/internal/CalculatedStatus.java | 2 +- .../AmbariAuthenticationFilter.java | 160 ++++++ .../AmbariAuthorizationFilter.java | 43 +- .../authorization/AuthorizationHelper.java | 29 ++ .../authorization/PermissionHelper.java | 88 ++++ .../serveraction/AbstractServerAction.java | 12 + .../kerberos/CreateKeytabFilesServerAction.java | 189 +++---- .../kerberos/CreatePrincipalsServerAction.java | 154 +++--- .../kerberos/DestroyPrincipalsServerAction.java | 42 +- .../kerberos/FinalizeKerberosServerAction.java | 9 + .../ambari/server/utils/RequestUtils.java | 88 ++++ .../webapp/WEB-INF/spring-security.xml | 6 +- .../actionmanager/TestActionDBAccessorImpl.java | 4 + .../server/actionmanager/TestActionManager.java | 4 + .../server/agent/HeartbeatProcessorTest.java | 4 + .../server/api/services/BaseServiceTest.java | 27 + .../audit/AccessUnauthorizedAuditEventTest.java | 77 +++ .../server/audit/LoginAuditEventTest.java | 118 +++++ .../server/audit/LogoutAuditEventTest.java | 74 +++ .../audit/OperationStatusAuditEventTest.java | 74 +++ .../StartOperationRequestAuditEventTest.java | 79 +++ .../audit/request/AbstractBaseCreator.java | 45 ++ .../server/audit/request/AllGetCreator.java | 44 ++ .../audit/request/AllPostAndPutCreator.java | 45 ++ .../audit/request/DefaultEventCreatorTest.java | 515 +++++++++++++++++++ .../audit/request/PutHostComponentCreator.java | 44 ++ .../audit/request/RequestAuditLogModule.java | 40 ++ .../audit/request/RequestAuditLoggerTest.java | 153 ++++++ .../server/checks/UpgradeCheckOrderTest.java | 3 +- .../AmbariManagementControllerTest.java | 9 +- .../server/controller/KerberosHelperTest.java | 2 + .../notifications/DispatchFactoryTest.java | 3 +- .../server/orm/InMemoryDefaultTestModule.java | 4 + .../ambari/server/orm/JdbcPropertyTest.java | 6 +- .../AmbariAuthenticationFilterTest.java | 135 +++++ .../AmbariAuthorizationFilterTest.java | 24 + ...uthenticationProviderForDNWithSpaceTest.java | 4 +- .../AmbariLdapAuthenticationProviderTest.java | 4 +- .../AmbariLocalUserDetailsServiceTest.java | 4 +- .../authorization/LdapServerPropertiesTest.java | 4 +- .../kerberos/KerberosServerActionTest.java | 2 + .../UpdateKerberosConfigsServerActionTest.java | 2 + .../ambari/server/utils/RequestUtilsTest.java | 77 +++ 144 files changed, 12582 insertions(+), 225 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-project/pom.xml ---------------------------------------------------------------------- diff --git a/ambari-project/pom.xml b/ambari-project/pom.xml index b3d9ca2..21c5baf 100644 --- a/ambari-project/pom.xml +++ b/ambari-project/pom.xml @@ -407,7 +407,7 @@ <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> - <version>1.2.16</version> + <version>1.2.17</version> <exclusions> <exclusion> <groupId>com.sun.jdmk</groupId> @@ -432,6 +432,11 @@ </exclusions> </dependency> <dependency> + <groupId>log4j</groupId> + <artifactId>apache-log4j-extras</artifactId> + <version>1.2.17</version> + </dependency> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.10</version> http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/conf/unix/log4j.properties ---------------------------------------------------------------------- diff --git a/ambari-server/conf/unix/log4j.properties b/ambari-server/conf/unix/log4j.properties index ab3ea0b..3cb7fd0 100644 --- a/ambari-server/conf/unix/log4j.properties +++ b/ambari-server/conf/unix/log4j.properties @@ -24,6 +24,7 @@ ambari.log.file=ambari-server.log ambari.config-changes.file=ambari-config-changes.log ambari.alerts.file=ambari-alerts.log ambari.eclipselink.file=ambari-eclipselink.log +ambari.audit.file=ambari-audit.log ambari.dbcheck.file=ambari-server-check-database.log log4j.rootLogger=INFO,file @@ -70,6 +71,19 @@ log4j.appender.eclipselink.MaxBackupIndex=10 log4j.appender.eclipselink.layout=org.apache.log4j.PatternLayout log4j.appender.eclipselink.layout.ConversionPattern=%m%n +# Audit logging +log4j.logger.audit=INFO,audit +log4j.additivity.audit=false +log4j.appender.audit=org.apache.log4j.rolling.RollingFileAppender +log4j.appender.audit.rollingPolicy=org.apache.log4j.rolling.FixedWindowRollingPolicy +log4j.appender.audit.rollingPolicy.ActiveFileName=${ambari.log.dir}/${ambari.audit.file} +log4j.appender.audit.rollingPolicy.FileNamePattern=${ambari.log.dir}/${ambari.audit.file}-%i.log.gz +log4j.appender.audit.rollingPolicy.maxIndex=13 +log4j.appender.audit.triggeringPolicy=org.apache.log4j.rolling.SizeBasedTriggeringPolicy +log4j.appender.audit.triggeringPolicy.maxFileSize=50000000 +log4j.appender.audit.layout=org.apache.log4j.PatternLayout +log4j.appender.audit.layout.ConversionPattern=%m%n + log4j.logger.org.apache.hadoop.yarn.client=WARN log4j.logger.org.apache.slider.common.tools.SliderUtils=WARN log4j.logger.org.apache.ambari.server.security.authorization=WARN http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/conf/windows/log4j.properties ---------------------------------------------------------------------- diff --git a/ambari-server/conf/windows/log4j.properties b/ambari-server/conf/windows/log4j.properties index cc40f74..8beba68 100644 --- a/ambari-server/conf/windows/log4j.properties +++ b/ambari-server/conf/windows/log4j.properties @@ -23,6 +23,7 @@ ambari.log.file=ambari-server.log ambari.config-changes.file=ambari-config-changes.log ambari.alerts.file=ambari-alerts.log ambari.eclipselink.file=ambari-eclipselink.log +ambari.audit.file=ambari-audit.log ambari.dbcheck.file=ambari-server-check-database.log # Define the root logger to the system property "ambari.root.logger". @@ -94,3 +95,16 @@ log4j.appender.eclipselink.MaxFileSize=50MB log4j.appender.eclipselink.MaxBackupIndex=10 log4j.appender.eclipselink.layout=org.apache.log4j.PatternLayout log4j.appender.eclipselink.layout.ConversionPattern=%m%n + +# Audit logging +log4j.logger.audit=INFO,audit +log4j.additivity.audit=false +log4j.appender.audit=org.apache.log4j.rolling.RollingFileAppender +log4j.appender.audit.rollingPolicy=org.apache.log4j.rolling.FixedWindowRollingPolicy +log4j.appender.audit.rollingPolicy.ActiveFileName=${ambari.log.dir}\${ambari.audit.file} +log4j.appender.audit.rollingPolicy.FileNamePattern=${ambari.log.dir}\${ambari.audit.file}-%i.log.gz +log4j.appender.audit.rollingPolicy.maxIndex=13 +log4j.appender.audit.triggeringPolicy=org.apache.log4j.rolling.SizeBasedTriggeringPolicy +log4j.appender.audit.triggeringPolicy.maxFileSize=50000000 +log4j.appender.audit.layout=org.apache.log4j.PatternLayout +log4j.appender.audit.layout.ConversionPattern=%m%n http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/pom.xml ---------------------------------------------------------------------- diff --git a/ambari-server/pom.xml b/ambari-server/pom.xml index 07a315d..b36c4e1 100644 --- a/ambari-server/pom.xml +++ b/ambari-server/pom.xml @@ -1058,6 +1058,10 @@ <artifactId>log4j</artifactId> </dependency> <dependency> + <groupId>log4j</groupId> + <artifactId>apache-log4j-extras</artifactId> + </dependency> + <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>eclipselink</artifactId> </dependency> @@ -1277,7 +1281,7 @@ <groupId>c3p0</groupId> <artifactId>c3p0</artifactId> </exclusion> - </exclusions> + </exclusions> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/conf/log4j.properties ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/conf/log4j.properties b/ambari-server/src/main/conf/log4j.properties index 8e6652d..5021c77 100644 --- a/ambari-server/src/main/conf/log4j.properties +++ b/ambari-server/src/main/conf/log4j.properties @@ -23,6 +23,7 @@ ambari.log.file=ambari-server.log ambari.config-changes.file=ambari-config-changes.log ambari.alerts.file=ambari-alerts.log ambari.eclipselink.file=ambari-eclipselink.log +ambari.audit.file=ambari-audit.log ambari.dbcheck.file=ambari-server-check-database.log # Define the root logger to the system property "ambari.root.logger". @@ -95,3 +96,16 @@ log4j.appender.eclipselink.MaxBackupIndex=10 log4j.appender.eclipselink.layout=org.apache.log4j.PatternLayout log4j.appender.eclipselink.layout.ConversionPattern=%m%n +# Audit logging +log4j.logger.audit=INFO,audit +log4j.additivity.audit=false +log4j.appender.audit=org.apache.log4j.rolling.RollingFileAppender +log4j.appender.audit.rollingPolicy=org.apache.log4j.rolling.FixedWindowRollingPolicy +log4j.appender.audit.rollingPolicy.ActiveFileName=${ambari.log.dir}/${ambari.audit.file} +log4j.appender.audit.rollingPolicy.FileNamePattern=${ambari.log.dir}/${ambari.audit.file}-%i.log.gz +log4j.appender.audit.rollingPolicy.maxIndex=13 +log4j.appender.audit.triggeringPolicy=org.apache.log4j.rolling.SizeBasedTriggeringPolicy +log4j.appender.audit.triggeringPolicy.maxFileSize=50000000 +log4j.appender.audit.layout=org.apache.log4j.PatternLayout +log4j.appender.audit.layout.ConversionPattern=%m%n + http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java index a75a000..79d3470 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/actionmanager/ActionDBAccessorImpl.java @@ -23,8 +23,13 @@ import java.util.Collections; import java.util.Comparator; import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.TreeSet; import java.util.concurrent.TimeUnit; import org.apache.ambari.annotations.Experimental; @@ -35,7 +40,13 @@ import org.apache.ambari.annotations.TransactionalLock.LockType; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.agent.CommandReport; import org.apache.ambari.server.agent.ExecutionCommand; +import org.apache.ambari.server.api.services.ResultStatus; +import org.apache.ambari.server.audit.event.AuditEvent; +import org.apache.ambari.server.audit.AuditLogger; +import org.apache.ambari.server.audit.event.OperationStatusAuditEvent; +import org.apache.ambari.server.audit.event.TaskStatusAuditEvent; import org.apache.ambari.server.configuration.Configuration; +import org.apache.ambari.server.controller.internal.CalculatedStatus; import org.apache.ambari.server.events.HostRemovedEvent; import org.apache.ambari.server.events.publishers.AmbariEventPublisher; import org.apache.ambari.server.orm.dao.ClusterDAO; @@ -117,6 +128,22 @@ public class ActionDBAccessorImpl implements ActionDBAccessor { @Inject Configuration configuration; + @Inject + AuditLogger auditLogger; + + /** + * Caches to store current request and task statuses. + * It is used for avoiding audit log entry duplication + */ + private Map<Long, HostRoleStatus> temporaryStatusCache = new HashMap<Long, HostRoleStatus>(); + private Map<Long, HostRoleStatus> temporaryTaskStatusCache = new HashMap<Long, HostRoleStatus>(); + + /** + * Stores the host role command entities that are not completed for a request id + * It is used to calculate the summary state of the request for audit logging + */ + private Map<Long, Map<Long, HostRoleStatus>> tasksForRequest = new HashMap<>(); + private Cache<Long, HostRoleCommand> hostRoleCommandCache; private long cacheLimit; //may be exceeded to store tasks from one request @@ -198,6 +225,8 @@ public class ActionDBAccessorImpl implements ActionDBAccessor { + " requestId " + command.getRequestId() + " taskId " + command.getTaskId() + " stageId " + command.getStageId()); + + auditLog(command, requestId); } } @@ -219,6 +248,8 @@ public class ActionDBAccessorImpl implements ActionDBAccessor { for (HostRoleCommandEntity command : commands) { command.setStatus(command.isRetryAllowed() ? HostRoleStatus.HOLDING_TIMEDOUT : HostRoleStatus.TIMEDOUT); command.setEndTime(now); + + auditLog(command, requestId); } // no need to merge if there's nothing to merge @@ -448,6 +479,8 @@ public class ActionDBAccessorImpl implements ActionDBAccessor { for (HostRoleCommandEntity commandEntity : commandEntities) { CommandReport report = taskReports.get(commandEntity.getTaskId()); + boolean statusChanged = false; + switch (commandEntity.getStatus()) { case ABORTED: // We don't want to overwrite statuses for ABORTED tasks with @@ -467,6 +500,7 @@ public class ActionDBAccessorImpl implements ActionDBAccessor { } commandEntity.setStatus(status); + statusChanged = true; break; } @@ -485,6 +519,9 @@ public class ActionDBAccessorImpl implements ActionDBAccessor { long stageId = requestStageIds[1]; if (requestDAO.getLastStageId(requestId).equals(stageId)) { requestsToCheck.add(requestId); + if(statusChanged) { + auditLog(commandEntity, requestId); // wrong requestId !!! + } } } } @@ -542,6 +579,8 @@ public class ActionDBAccessorImpl implements ActionDBAccessor { } } command.setExitcode(report.getExitCode()); + + auditLog(command, requestId); } // no need to merge if there's nothing to merge @@ -607,6 +646,9 @@ public class ActionDBAccessorImpl implements ActionDBAccessor { entity.setLastAttemptTime(hostRoleCommand.getLastAttemptTime()); entity.setStatus(hostRoleCommand.getStatus()); entity.setAttemptCount(hostRoleCommand.getAttemptCount()); + + auditLog(entity, s.getRequestId()); + hostRoleCommandDAO.merge(entity); } else { throw new RuntimeException("HostRoleCommand is not persisted, cannot update:\n" + hostRoleCommand); @@ -745,6 +787,8 @@ public class ActionDBAccessorImpl implements ActionDBAccessor { // Because it expects -1, RetryActionMonitor.java also had to set it to -1. task.setStartTime(-1L); task.setEndTime(-1L); + + auditLog(task, task.getRequestId()); } // no need to merge if there's nothing to merge @@ -764,4 +808,85 @@ public class ActionDBAccessorImpl implements ActionDBAccessor { LOG.info("Invalidating HRC cache after receiveing {}", event); hostRoleCommandCache.invalidateAll(); } + + /** + * AuditLog operation status change + * @param requestId + */ + private void auditLog(HostRoleCommandEntity commandEntity, Long requestId) { + if(!auditLogger.isEnabled()) { + return; + } + + if(requestId != null) { + + HostRoleStatus calculatedStatus = calculateStatus(commandEntity, requestId); + + if (!temporaryStatusCache.containsKey(requestId) || temporaryStatusCache.get(requestId) != calculatedStatus) { + RequestEntity request = requestDAO.findByPK(requestId); + String context = request != null ? request.getRequestContext() : null; + AuditEvent auditEvent = OperationStatusAuditEvent.builder() + .withRequestId(String.valueOf(requestId)) + .withStatus(String.valueOf(calculatedStatus)) + .withRequestContext(context) + .withTimestamp(System.currentTimeMillis()) + .build(); + auditLogger.log(auditEvent); + + temporaryStatusCache.put(requestId, calculatedStatus); + } + } + logTask(commandEntity, requestId); + } + + /** + * Calculates summary status for the given request id for the new command entity status + * @param commandEntity + * @param requestId + * @return + */ + private HostRoleStatus calculateStatus(HostRoleCommandEntity commandEntity, Long requestId) { + if(!tasksForRequest.containsKey(requestId)) { + tasksForRequest.put(requestId, new HashMap<Long, HostRoleStatus>()); + } + + tasksForRequest.get(requestId).put(commandEntity.getTaskId(), commandEntity.getStatus()); + + HostRoleStatus calculatedStatus = CalculatedStatus.calculateSummaryStatusOfStage(CalculatedStatus.calculateStatusCounts(tasksForRequest.get(requestId).values()), tasksForRequest.get(requestId).size(), false); + + // if all task status is completed, we can remove it from the container + boolean hasInProgress = false; + for(HostRoleStatus hrcs : tasksForRequest.get(requestId).values()) { + if(!hrcs.isCompletedState()) { + hasInProgress = true; + break; + } + } + if(!hasInProgress) { + tasksForRequest.remove(requestId); + } + return calculatedStatus; + } + + /** + * Logs task status change + * @param commandEntity + * @param requestId + */ + private void logTask(HostRoleCommandEntity commandEntity, Long requestId) { + if(!temporaryTaskStatusCache.containsKey(commandEntity.getTaskId()) || temporaryTaskStatusCache.get(commandEntity.getTaskId()) != commandEntity.getStatus() ) { + AuditEvent taskEvent = TaskStatusAuditEvent.builder() + .withTaskId(String.valueOf(commandEntity.getTaskId())) + .withHostName(commandEntity.getHostName()) + .withOperation(commandEntity.getRoleCommand().toString() + " " + commandEntity.getRole().toString()) + .withDetails(commandEntity.getCommandDetail()) + .withStatus(commandEntity.getStatus().toString()) + .withRequestId(String.valueOf(requestId)) + .withTimestamp(System.currentTimeMillis()) + .build(); + + auditLogger.log(taskEvent); + temporaryTaskStatusCache.put(commandEntity.getTaskId(), commandEntity.getStatus()); + } + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseRequest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseRequest.java index a33e8a7..88b8170 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseRequest.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseRequest.java @@ -18,7 +18,6 @@ package org.apache.ambari.server.api.services; -import com.sun.jersey.spi.container.ContainerRequest; import org.apache.ambari.server.api.handlers.RequestHandler; import org.apache.ambari.server.api.predicate.InvalidQueryException; import org.apache.ambari.server.api.predicate.PredicateCompiler; @@ -33,8 +32,12 @@ import org.apache.ambari.server.controller.spi.PageRequest; import org.apache.ambari.server.controller.spi.Predicate; import org.apache.ambari.server.controller.spi.SortRequestProperty; import org.apache.ambari.server.controller.spi.TemporalInfo; +import org.apache.ambari.server.utils.RequestUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.UriInfo; import java.io.UnsupportedEncodingException; @@ -71,6 +74,11 @@ public abstract class BaseRequest implements Request { private RequestBody m_body; /** + * Remote address + */ + private String m_remoteAddress; + + /** * Query Predicate */ private Predicate m_predicate; @@ -121,6 +129,7 @@ public abstract class BaseRequest implements Request { m_uriInfo = uriInfo; m_resource = resource; m_body = body; + m_remoteAddress = RequestUtils.getRemoteAddress(); } @Override @@ -375,4 +384,9 @@ public abstract class BaseRequest implements Request { * @return the request handler */ protected abstract RequestHandler getRequestHandler(); + + @Override + public String getRemoteAddress() { + return m_remoteAddress; + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java index 7945599..2e5b920 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java @@ -27,6 +27,7 @@ import org.apache.ambari.server.api.services.parsers.RequestBodyParser; import org.apache.ambari.server.api.services.serializers.CsvSerializer; import org.apache.ambari.server.api.services.serializers.JsonSerializer; import org.apache.ambari.server.api.services.serializers.ResultSerializer; +import org.apache.ambari.server.audit.request.RequestAuditLogger; import org.apache.ambari.server.controller.spi.Resource; import org.apache.ambari.server.utils.RetryHelper; import org.eclipse.jetty.util.ajax.JSON; @@ -39,6 +40,8 @@ import java.util.Iterator; import java.util.Map; import java.util.Set; +import com.google.inject.Inject; + /** * Provides common functionality to all services. */ @@ -55,6 +58,11 @@ public abstract class BaseService { */ private ResultSerializer m_serializer = new JsonSerializer(); + protected static RequestAuditLogger requestAuditLogger; + + public static void init(RequestAuditLogger instance) { + requestAuditLogger = instance; + } /** * Requests are funneled through this method so that common logic can be executed. @@ -92,7 +100,12 @@ public abstract class BaseService { UriInfo uriInfo, Request.Type requestType, MediaType mediaType, ResourceInstance resource) { + // original request and initial result + RequestBody rb = new RequestBody(); + rb.setBody(body); + Request request = getRequestFactory().createRequest(headers, rb, uriInfo, requestType, resource); Result result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.OK)); + try { Set<RequestBody> requestBodySet = getBodyParser().parse(body); @@ -100,13 +113,22 @@ public abstract class BaseService { while (iterator.hasNext() && result.getStatus().getStatus().equals(ResultStatus.STATUS.OK)) { RequestBody requestBody = iterator.next(); - Request request = getRequestFactory().createRequest( + request = getRequestFactory().createRequest( headers, requestBody, uriInfo, requestType, resource); result = request.process(); + requestAuditLogger.log(request, result); + } + + if(requestBodySet.isEmpty() || !ResultStatus.STATUS.OK.equals(result.getStatus().getStatus())) { + requestAuditLogger.log(request, result); } } catch (BodyParseException e) { result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.BAD_REQUEST, e.getMessage())); + requestAuditLogger.log(request, result); + } catch (Throwable t) { + requestAuditLogger.log(request, new ResultImpl(new ResultStatus(ResultStatus.STATUS.SERVER_ERROR, t.getMessage()))); + throw t; } ResultSerializer serializer = mediaType == null ? getResultSerializer() : getResultSerializer(mediaType); http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/api/services/LogoutService.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/LogoutService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/LogoutService.java index df8faaa..3b449ca 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/LogoutService.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/LogoutService.java @@ -17,8 +17,6 @@ */ package org.apache.ambari.server.api.services; -import org.springframework.security.core.context.SecurityContextHolder; - import javax.servlet.http.HttpServletRequest; import javax.ws.rs.GET; import javax.ws.rs.Path; @@ -26,18 +24,44 @@ import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; +import org.apache.ambari.server.StaticallyInject; +import org.apache.ambari.server.audit.AuditLogger; +import org.apache.ambari.server.audit.event.LogoutAuditEvent; +import org.apache.ambari.server.security.authorization.AuthorizationHelper; +import org.apache.ambari.server.utils.RequestUtils; + +import com.google.inject.Inject; +import org.springframework.security.core.context.SecurityContextHolder; + /** * Service performing logout of current user */ +@StaticallyInject @Path("/logout") public class LogoutService { + @Inject + private static AuditLogger auditLogger; + @GET @Produces("text/plain") public Response performLogout(@Context HttpServletRequest servletRequest) { + auditLog(servletRequest); SecurityContextHolder.clearContext(); servletRequest.getSession().invalidate(); return Response.status(Response.Status.OK).build(); } + /** + * Creates and send and audit log event that the user has successfully logged out + * @param servletRequest + */ + private void auditLog(HttpServletRequest servletRequest) { + LogoutAuditEvent logoutEvent = LogoutAuditEvent.builder() + .withTimestamp(System.currentTimeMillis()) + .withRemoteIp(RequestUtils.getRemoteAddress(servletRequest)) + .withUserName(AuthorizationHelper.getAuthenticatedName()) + .build(); + auditLogger.log(logoutEvent); + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/api/services/Request.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/Request.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/Request.java index ff9b6c7..771875a 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/Request.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/Request.java @@ -37,7 +37,7 @@ public interface Request { /** * Enum of request types. */ - public enum Type { + enum Type { GET, POST, PUT, @@ -50,7 +50,7 @@ public interface Request { * * @return the result */ - public Result process(); + Result process(); /** * Obtain the resource definition which corresponds to the resource being operated on by the request. @@ -58,28 +58,28 @@ public interface Request { * * @return the associated {@link ResourceDefinition} */ - public ResourceInstance getResource(); + ResourceInstance getResource(); /** * Obtain the URI of this request. * * @return the request uri */ - public String getURI(); + String getURI(); /** * Obtain the http request type. Type is one of {@link Type}. * * @return the http request type */ - public Type getRequestType(); + Type getRequestType(); /** * Obtain the api version of the request. The api version is specified in the request URI. * * @return the api version of the request */ - public int getAPIVersion(); + int getAPIVersion(); /** * Obtain the query predicate that was built from the user provided predicate fields in the query string. @@ -88,7 +88,7 @@ public interface Request { * * @return the user defined predicate */ - public Predicate getQueryPredicate(); + Predicate getQueryPredicate(); /** * Obtain the partial response fields and associated temporal information which were provided @@ -96,39 +96,45 @@ public interface Request { * * @return map of partial response propertyId to temporal information */ - public Map<String, TemporalInfo> getFields(); + Map<String, TemporalInfo> getFields(); /** * Obtain the request body data. */ - public RequestBody getBody(); + RequestBody getBody(); /** * Obtain the http headers associated with the request. * * @return the http headers */ - public Map<String, List<String>> getHttpHeaders(); + Map<String, List<String>> getHttpHeaders(); /** * Obtain the pagination request information. * * @return the page request */ - public PageRequest getPageRequest(); + PageRequest getPageRequest(); /** * Obtain information to order the results by. * * @return the order request */ - public SortRequest getSortRequest(); + SortRequest getSortRequest(); /** * Obtain the renderer for the request. * * @return renderer instance */ - public Renderer getRenderer(); + Renderer getRenderer(); + + /** + * Returns the remote address for the request + * @return the remote address for the request + */ + String getRemoteAddress(); } http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/AsyncAuditLogger.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/AsyncAuditLogger.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/AsyncAuditLogger.java new file mode 100644 index 0000000..c520c8d --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/AsyncAuditLogger.java @@ -0,0 +1,101 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ambari.server.audit; + + +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.ambari.server.audit.event.AuditEvent; +import org.apache.ambari.server.configuration.Configuration; + +import com.google.common.eventbus.AsyncEventBus; +import com.google.common.eventbus.EventBus; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.name.Named; + +/** + * This is a wrapper for an audit log implementation that uses {@link EventBus} to make audit logging asynchronous + */ +@Singleton +class AsyncAuditLogger implements AuditLogger { + /** + * Name for guice injection + */ + final static String InnerLogger = "AsyncAuditLogger"; + + /** + * Event bus that holds audit event objects + */ + private EventBus eventBus; + + /** + * Indicates if audit log feature is enabled + */ + private final boolean isEnabled; + + /** + * Constructor. + * + * @param auditLogger the audit logger to use + */ + @Inject + public AsyncAuditLogger(@Named(InnerLogger) AuditLogger auditLogger, Configuration configuration) { + isEnabled = configuration.isAuditLogEnabled(); + if(isEnabled) { + eventBus = new AsyncEventBus("AuditLoggerEventBus", new ThreadPoolExecutor(0, 1, 5L, TimeUnit.MINUTES, + new LinkedBlockingQueue<Runnable>(configuration.getAuditLoggerCapacity()), new AuditLogThreadFactory(), + new ThreadPoolExecutor.CallerRunsPolicy())); + eventBus.register(auditLogger); + } + } + + @Override + public void log(AuditEvent event) { + if(isEnabled) { + eventBus.post(event); + } + } + + @Override + public boolean isEnabled() { + return isEnabled; + } + + /** + * A custom {@link ThreadFactory} for the threads that logs audit events + */ + private static final class AuditLogThreadFactory implements ThreadFactory { + + private static final AtomicInteger nextId = new AtomicInteger(1); + + /** + * {@inheritDoc} + */ + @Override + public Thread newThread(Runnable runnable) { + Thread thread = new Thread(runnable, "auditlog-" + nextId.getAndIncrement()); + thread.setDaemon(true); + return thread; + } + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLogger.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLogger.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLogger.java new file mode 100644 index 0000000..8c68e3e --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLogger.java @@ -0,0 +1,39 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ambari.server.audit; + +import org.apache.ambari.server.audit.event.AuditEvent; + +/** + * Interface to handle audit log events + */ +public interface AuditLogger { + + /** + * Logs audit log events + * @param event + */ + void log(final AuditEvent event); + + /** + * Returns if the feature is enabled + */ + boolean isEnabled(); + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLoggerDefaultImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLoggerDefaultImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLoggerDefaultImpl.java new file mode 100644 index 0000000..1cfb740 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLoggerDefaultImpl.java @@ -0,0 +1,77 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ambari.server.audit; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.apache.ambari.server.audit.event.AuditEvent; +import org.apache.ambari.server.configuration.Configuration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.eventbus.Subscribe; +import com.google.inject.Inject; +import com.google.inject.Singleton; + +/** + * Default audit logger implementation, logs messages into log file + */ +@Singleton +public class AuditLoggerDefaultImpl implements AuditLogger { + + private static final Logger LOG = LoggerFactory.getLogger("audit"); + + /** + * Indicates if audit log feature is enabled + */ + private final boolean isEnabled; + + private ThreadLocal<DateFormat> dateFormatThreadLocal = new ThreadLocal<>(); + + @Inject + public AuditLoggerDefaultImpl(Configuration configuration) { + isEnabled = configuration.isAuditLogEnabled(); + } + + /** + * {@inheritDoc} + */ + @Override + @Subscribe + public void log(AuditEvent event) { + if(!isEnabled) { + return; + } + + if(dateFormatThreadLocal.get() == null) { + //2016-03-11T10:42:36.376Z + dateFormatThreadLocal.set(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX")); + } + + Date date = new Date(event.getTimestamp()); + LOG.info("{}, {}", dateFormatThreadLocal.get().format(date), event.getAuditMessage()); + } + + @Override + public boolean isEnabled() { + return isEnabled; + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLoggerModule.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLoggerModule.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLoggerModule.java new file mode 100644 index 0000000..b20714b --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/AuditLoggerModule.java @@ -0,0 +1,94 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ambari.server.audit; + +import org.apache.ambari.server.audit.request.RequestAuditEventCreator; +import org.apache.ambari.server.audit.request.RequestAuditLogger; +import org.apache.ambari.server.audit.request.RequestAuditLoggerImpl; +import org.apache.ambari.server.audit.request.eventcreator.AlertGroupEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.AlertTargetEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.BlueprintEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.BlueprintExportEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.ComponentEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.ConfigurationChangeEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.CredentialEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.DefaultEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.GroupEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.HostEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.MemberEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.PrivilegeEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.RecommendationIgnoreEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.RepositoryEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.RepositoryVersionEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.RequestEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.ServiceConfigDownloadEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.ServiceEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.UnauthorizedEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.UpgradeEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.UpgradeItemEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.UserEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.ValidationIgnoreEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.ViewInstanceEventCreator; +import org.apache.ambari.server.audit.request.eventcreator.ViewPrivilegeEventCreator; + +import com.google.inject.AbstractModule; +import com.google.inject.multibindings.Multibinder; +import com.google.inject.name.Names; + +public class AuditLoggerModule extends AbstractModule { + + @Override + protected void configure() { + bind(AuditLogger.class).to(AsyncAuditLogger.class); + + // set AuditLoggerDefaultImpl to be used by AsyncAuditLogger + bind(AuditLogger.class).annotatedWith(Names.named(AsyncAuditLogger.InnerLogger)).to(AuditLoggerDefaultImpl.class); + + // binding for audit event creators + Multibinder<RequestAuditEventCreator> auditLogEventCreatorBinder = Multibinder.newSetBinder(binder(), RequestAuditEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(DefaultEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(ComponentEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(ServiceEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(UnauthorizedEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(ConfigurationChangeEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(UserEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(GroupEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(MemberEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(PrivilegeEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(BlueprintExportEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(ServiceConfigDownloadEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(BlueprintEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(ViewInstanceEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(ViewPrivilegeEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(RepositoryEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(RepositoryVersionEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(AlertGroupEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(AlertTargetEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(HostEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(UpgradeEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(UpgradeItemEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(RecommendationIgnoreEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(ValidationIgnoreEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(CredentialEventCreator.class); + auditLogEventCreatorBinder.addBinding().to(RequestEventCreator.class); + + bind(RequestAuditLogger.class).to(RequestAuditLoggerImpl.class); + + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AbstractAuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AbstractAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AbstractAuditEvent.java new file mode 100644 index 0000000..558b0ea --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AbstractAuditEvent.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ambari.server.audit.event; + +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; + +/** + * Base class for concrete audit event types. + */ +public abstract class AbstractAuditEvent implements AuditEvent { + + /** + * Timestamp for the audit event creation + */ + private final Long timestamp; + + /** + * Message to log + */ + private final String auditMessage; + + /** + * Base class for concrete audit event builders. + * + * @param <T> the type of the concrete audit event built by this builder + * @param <TBuilder> the type of the concrete audit event builder. + */ + protected static abstract class AbstractAuditEventBuilder<T extends AbstractAuditEvent, TBuilder extends AbstractAuditEventBuilder<T, TBuilder>> + implements AuditEventBuilder<T> { + + private Long timestamp; + private String auditMessage; + + + /** + * Creates a new audit event instance from this builder. + * + * @return the build audit event instance. + */ + protected abstract T newAuditEvent(); + + /** + * Appends details from this builder to the detailed description of the audit event. + * + * @param builder builder for the audit event details. + */ + protected abstract void buildAuditMessage(StringBuilder builder); + + + /** + * The timestamp of the audit event. + * + * @param timestamp + * @return + */ + public TBuilder withTimestamp(Long timestamp) { + this.timestamp = timestamp; + + return (TBuilder) this; + } + + /** + * {@inheritDoc} + */ + @Override + public final T build() { + final StringBuilder auditMessageBuilder = new StringBuilder(); + + buildAuditMessage(auditMessageBuilder); + auditMessage = auditMessageBuilder.toString(); + + return newAuditEvent(); + } + + } + + + protected AbstractAuditEvent() { + this.timestamp = null; + this.auditMessage = null; + } + + /** + * Constructor. Initializes fields using the provided builder. + * + * @param builder + */ + protected AbstractAuditEvent(AbstractAuditEventBuilder<?, ?> builder) { + timestamp = builder.timestamp; + auditMessage = builder.auditMessage; + } + + /** + * {@inheritDoc} + */ + @Override + public Long getTimestamp() { + return timestamp; + } + + + /** + * {@inheritDoc} + */ + @Override + public String getAuditMessage() { + return auditMessage; + } + + @Override + public final boolean equals(Object o) { + if (this == o) return true; + + if (!(o instanceof AbstractAuditEvent)) return false; + + AbstractAuditEvent that = (AbstractAuditEvent) o; + + return new EqualsBuilder() + .append(getTimestamp(), that.getTimestamp()) + .append(getAuditMessage(), that.getAuditMessage()) + .isEquals(); + } + + @Override + public final int hashCode() { + return new HashCodeBuilder(17, 37) + .append(getTimestamp()) + .append(getAuditMessage()) + .toHashCode(); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AbstractUserAuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AbstractUserAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AbstractUserAuditEvent.java new file mode 100644 index 0000000..a968a64 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AbstractUserAuditEvent.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ambari.server.audit.event; + +/** + * Base class for audit events which are result of user actions. It appends + * to audit event details the user name and remote ip of the host + * where user actions originates from. + */ +public abstract class AbstractUserAuditEvent extends AbstractAuditEvent { + + public static abstract class AbstractUserAuditEventBuilder<T extends AbstractUserAuditEvent, TBuilder extends AbstractUserAuditEventBuilder<T, TBuilder>> + extends AbstractAuditEventBuilder<T, TBuilder> { + + /** + * Name of the user started the operation + */ + private String userName; + + /** + * Ip of the user who started the operation. Note: remote ip might not be the original ip (proxies, routers can modify it) + */ + private String remoteIp; + + /** + * Appends to audit event details the user name and remote ip of the host + * where user actions originates from. + * + * @param builder builder for the audit message details. + */ + @Override + protected void buildAuditMessage(StringBuilder builder) { + builder + .append("User(") + .append(this.userName) + .append("), RemoteIp(") + .append(this.remoteIp) + .append(")"); + } + + /** + * Sets the user name of the user that initiated the audited action. + * + * @param userName + * @return the builder + */ + public TBuilder withUserName(String userName) { + this.userName = userName; + + return (TBuilder) this; + } + + /** + * Sets the remote ip where the user action originated from. + * + * @param ip + * @return the builder + */ + public TBuilder withRemoteIp(String ip) { + this.remoteIp = ip; + + return (TBuilder) this; + } + } + + protected AbstractUserAuditEvent() { + } + + /** + * {@inheritDoc} + */ + protected AbstractUserAuditEvent(AbstractUserAuditEventBuilder<?, ?> builder) { + super(builder); + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AccessUnauthorizedAuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AccessUnauthorizedAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AccessUnauthorizedAuditEvent.java new file mode 100644 index 0000000..b6e60e1 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AccessUnauthorizedAuditEvent.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ambari.server.audit.event; + +import javax.annotation.concurrent.Immutable; + +/** + * Access to given resource is not authorized. + */ +@Immutable +public class AccessUnauthorizedAuditEvent extends AbstractUserAuditEvent { + + public static class AccessUnauthorizedAuditEventBuilder + extends AbstractUserAuditEventBuilder<AccessUnauthorizedAuditEvent, AccessUnauthorizedAuditEventBuilder> { + + /** + * Name of http method (PUT, POST, DELETE, etc...) + */ + private String httpMethodName; + + /** + * The resource path that is tried to be accessed + */ + private String resourcePath; + + /** + * Appends to the aduit event detail the list of the privileges + * possessed by the principal requesting access to a resource. + * + * @param builder builder for the audit event details. + */ + @Override + protected void buildAuditMessage(StringBuilder builder) { + super.buildAuditMessage(builder); + + builder + .append(", Operation(") + .append(httpMethodName) + .append("), ResourcePath(") + .append(resourcePath) + .append("), Status(Failed), Reason(Access not authorized)"); + } + + public AccessUnauthorizedAuditEventBuilder withHttpMethodName(String httpMethodName) { + this.httpMethodName = httpMethodName; + return this; + } + + public AccessUnauthorizedAuditEventBuilder withResourcePath(String resourcePath) { + this.resourcePath = resourcePath; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + protected AccessUnauthorizedAuditEvent newAuditEvent() { + return new AccessUnauthorizedAuditEvent(this); + } + } + + private AccessUnauthorizedAuditEvent() { + } + + /** + * {@inheritDoc} + */ + private AccessUnauthorizedAuditEvent(AccessUnauthorizedAuditEventBuilder builder) { + super(builder); + } + + /** + * Returns an builder for {@link AccessUnauthorizedAuditEvent} + * + * @return a builder instance + */ + public static AccessUnauthorizedAuditEventBuilder builder() { + return new AccessUnauthorizedAuditEventBuilder(); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AuditEvent.java new file mode 100644 index 0000000..fc027c7 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/AuditEvent.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ambari.server.audit.event; + +/** + * Audit event that contains + * the details of an action/event + * that is subject to audit. + */ +public interface AuditEvent { + + /** + * Builder for {@link AuditEvent} + * + * @param <T> the type of the concrete audit event. + */ + interface AuditEventBuilder<T extends AuditEvent> { + /** + * Builds an audit event. + * + * @return audit event instance + */ + T build(); + } + + /** + * Returns the timestamp of the audit event. + * + * @return timestamp of the audit event. + */ + Long getTimestamp(); + + /** + * Returns the details of the audit event. + * + * @return detail of the audit event. + */ + String getAuditMessage(); + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LoginAuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LoginAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LoginAuditEvent.java new file mode 100644 index 0000000..223dd18 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LoginAuditEvent.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ambari.server.audit.event; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.annotation.concurrent.Immutable; + +import org.apache.commons.lang.StringUtils; + +/** + * Login audit event. + */ +@Immutable +public class LoginAuditEvent extends AbstractUserAuditEvent { + + public static class LoginAuditEventBuilder + extends AbstractUserAuditEventBuilder<LoginAuditEvent, LoginAuditEventBuilder> { + + private LoginAuditEventBuilder() { + } + + /** + * List of roles possessed by the principal requesting access to a resource. + * [ view name | cluster name | 'Ambari'] -> list of permissions + */ + private Map<String, List<String>> roles; + + /** + * Reason of failure, if it is not null, then the request status is consider as failed + */ + private String reasonOfFailure; + + /** + * {@inheritDoc} + */ + @Override + protected void buildAuditMessage(StringBuilder builder) { + super.buildAuditMessage(builder); + + builder.append(", Operation(User login), Roles(").append(System.lineSeparator()); + + if (roles != null && !roles.isEmpty()) { + List<String> lines = new LinkedList<>(); + for (Map.Entry<String, List<String>> entry : roles.entrySet()) { + lines.add(" " + entry.getKey() + ": " + StringUtils.join(entry.getValue(), ", ")); + } + builder.append(StringUtils.join(lines, System.lineSeparator())); + builder.append(System.lineSeparator()); + } + builder.append("), Status(") + .append(reasonOfFailure == null ? "Success" : "Failed"); + + if (reasonOfFailure != null) { + builder.append("), Reason(") + .append(reasonOfFailure); + } + builder.append(")"); + } + + /** + * Sets the list of roles possessed by the principal requesting access to a resource. + * + * @param roles + * @return this builder + */ + public LoginAuditEventBuilder withRoles(Map<String, List<String>> roles) { + this.roles = roles; + + return this; + } + + public LoginAuditEventBuilder withReasonOfFailure(String reasonOfFailure) { + this.reasonOfFailure = reasonOfFailure; + return this; + } + + /** + * {@inheritDoc} + */ + @Override + protected LoginAuditEvent newAuditEvent() { + return new LoginAuditEvent(this); + } + + } + + + private LoginAuditEvent() { + } + + /** + * {@inheritDoc} + */ + private LoginAuditEvent(LoginAuditEventBuilder builder) { + super(builder); + + } + + /** + * Returns an builder for {@link LoginAuditEvent} + * + * @return a builder instance + */ + public static LoginAuditEventBuilder builder() { + return new LoginAuditEventBuilder(); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LogoutAuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LogoutAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LogoutAuditEvent.java new file mode 100644 index 0000000..3ce8c31 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/LogoutAuditEvent.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ambari.server.audit.event; + +import javax.annotation.concurrent.Immutable; + +/** + * Logout audit event. + */ +@Immutable +public class LogoutAuditEvent extends AbstractUserAuditEvent { + public static class LogoutAuditEventBuilder + extends AbstractUserAuditEventBuilder<LogoutAuditEvent, LogoutAuditEventBuilder> { + + private LogoutAuditEventBuilder() { + } + + /** + * {@inheritDoc} + */ + @Override + protected void buildAuditMessage(StringBuilder builder) { + super.buildAuditMessage(builder); + builder.append(", Operation(Logout), Status(Success)"); + } + + @Override + protected LogoutAuditEvent newAuditEvent() { + return new LogoutAuditEvent(this); + } + } + + private LogoutAuditEvent() { + } + + /** + * {@inheritDoc} + */ + private LogoutAuditEvent(LogoutAuditEventBuilder builder) { + super(builder); + + } + + /** + * Returns an builder for {@link LogoutAuditEvent} + * + * @return a builder instance + */ + public static LogoutAuditEventBuilder builder() { + return new LogoutAuditEventBuilder(); + } +} http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/OperationStatusAuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/OperationStatusAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/OperationStatusAuditEvent.java new file mode 100644 index 0000000..319d772 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/OperationStatusAuditEvent.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ambari.server.audit.event; + + +import javax.annotation.concurrent.Immutable; + +/** + * Audit event for tracking operations + */ +@Immutable +public class OperationStatusAuditEvent extends AbstractAuditEvent { + + public static class OperationStatusAuditEventBuilder extends AbstractAuditEventBuilder<OperationStatusAuditEvent, OperationStatusAuditEventBuilder> { + + /** + * Request identifier + */ + private String requestId; + + /** + * Status of the whole request + */ + private String status; + + /** + * Name of the operation + */ + private String operation; + + private OperationStatusAuditEventBuilder() { + } + + @Override + protected OperationStatusAuditEvent newAuditEvent() { + return new OperationStatusAuditEvent(this); + } + + /** + * Builds and audit log message based on the member variables + * + * @param builder builder for the audit event details. + */ + @Override + protected void buildAuditMessage(StringBuilder builder) { + builder + .append("Operation(") + .append(this.operation) + .append("), Status(") + .append(this.status) + .append("), RequestId(") + .append(this.requestId) + .append(")"); + } + + + public OperationStatusAuditEventBuilder withStatus(String status) { + this.status = status; + return this; + } + + public OperationStatusAuditEventBuilder withRequestId(String requestId) { + this.requestId = requestId; + return this; + } + + public OperationStatusAuditEventBuilder withRequestContext(String operation) { + this.operation = operation; + return this; + } + } + + private OperationStatusAuditEvent() { + } + + /** + * {@inheritDoc} + */ + private OperationStatusAuditEvent(OperationStatusAuditEventBuilder builder) { + super(builder); + } + + /** + * Returns an builder for {@link OperationStatusAuditEvent} + * + * @return a builder instance + */ + public static OperationStatusAuditEventBuilder builder() { + return new OperationStatusAuditEventBuilder(); + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/TaskStatusAuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/TaskStatusAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/TaskStatusAuditEvent.java new file mode 100644 index 0000000..eaea058 --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/TaskStatusAuditEvent.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ambari.server.audit.event; + + +import javax.annotation.concurrent.Immutable; + +/** + * Audit event for tracking task status + */ +@Immutable +public class TaskStatusAuditEvent extends AbstractAuditEvent { + + public static class TaskStatusAuditEventBuilder extends AbstractAuditEventBuilder<TaskStatusAuditEvent, TaskStatusAuditEventBuilder> { + + /** + * Request identifier + */ + private String requestId; + + /** + * Task identifier + */ + private String taskId; + + /** + * Request identifier + */ + private String hostName; + + /** + * Status of the whole request + */ + private String status; + + /** + * Name of the operation + */ + private String operation; + + /** + * Task command details + */ + private String details; + + private TaskStatusAuditEventBuilder() { + } + + @Override + protected TaskStatusAuditEvent newAuditEvent() { + return new TaskStatusAuditEvent(this); + } + + /** + * Builds and audit log message based on the member variables + * + * @param builder builder for the audit event details. + */ + @Override + protected void buildAuditMessage(StringBuilder builder) { + builder + .append("Operation(") + .append(this.operation); + + if (details != null) { + builder.append("), Details(") + .append(this.details); + } + + builder.append("), Status(") + .append(this.status) + .append("), RequestId(") + .append(this.requestId) + .append("), TaskId(") + .append(this.taskId) + .append("), Hostname(") + .append(this.hostName) + .append(")"); + } + + + public TaskStatusAuditEventBuilder withStatus(String status) { + this.status = status; + return this; + } + + public TaskStatusAuditEventBuilder withRequestId(String requestId) { + this.requestId = requestId; + return this; + } + + public TaskStatusAuditEventBuilder withTaskId(String taskId) { + this.taskId = taskId; + return this; + } + + public TaskStatusAuditEventBuilder withHostName(String hostName) { + this.hostName = hostName; + return this; + } + + public TaskStatusAuditEventBuilder withOperation(String operation) { + this.operation = operation; + return this; + } + + public TaskStatusAuditEventBuilder withDetails(String details) { + this.details = details; + return this; + } + } + + private TaskStatusAuditEvent() { + } + + /** + * {@inheritDoc} + */ + private TaskStatusAuditEvent(TaskStatusAuditEventBuilder builder) { + super(builder); + } + + /** + * Returns an builder for {@link TaskStatusAuditEvent} + * + * @return a builder instance + */ + public static TaskStatusAuditEventBuilder builder() { + return new TaskStatusAuditEventBuilder(); + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/kerberos/AbstractKerberosAuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/kerberos/AbstractKerberosAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/kerberos/AbstractKerberosAuditEvent.java new file mode 100644 index 0000000..77c162c --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/kerberos/AbstractKerberosAuditEvent.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ambari.server.audit.event.kerberos; + + +import javax.annotation.concurrent.Immutable; + +import org.apache.ambari.server.audit.event.AbstractAuditEvent; + +/** + * Base class for kerberos audit events + */ +@Immutable +public class AbstractKerberosAuditEvent extends AbstractAuditEvent { + static abstract class AbstractKerberosAuditEventBuilder<T extends AbstractKerberosAuditEvent, TBuilder extends AbstractKerberosAuditEventBuilder<T, TBuilder>> + extends AbstractAuditEvent.AbstractAuditEventBuilder<T, TBuilder> { + + /** + * Description of the operation + */ + protected String operation; + + /** + * Reason of failure, if it is not null, then the request is considered as failed + */ + protected String reasonOfFailure; + + /** + * Builds and audit log message based on the member variables + * + * @param builder builder for the audit event details. + */ + @Override + protected void buildAuditMessage(StringBuilder builder) { + builder + .append("Operation(") + .append(operation); + + builder.append("), Status(") + .append(reasonOfFailure == null ? "Success" : "Failed"); + + if (reasonOfFailure != null) { + builder.append("), Reason of failure(") + .append(reasonOfFailure); + } + + builder.append(")"); + } + + public TBuilder withOperation(String operation) { + this.operation = operation; + return (TBuilder) this; + } + + public TBuilder withReasonOfFailure(String reasonOfFailure) { + this.reasonOfFailure = reasonOfFailure; + return (TBuilder) this; + } + } + + protected AbstractKerberosAuditEvent() { + } + + /** + * {@inheritDoc} + */ + protected AbstractKerberosAuditEvent(AbstractKerberosAuditEventBuilder<?, ?> builder) { + super(builder); + } + +} http://git-wip-us.apache.org/repos/asf/ambari/blob/46a34ccd/ambari-server/src/main/java/org/apache/ambari/server/audit/event/kerberos/ChangeSecurityStateKerberosAuditEvent.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/audit/event/kerberos/ChangeSecurityStateKerberosAuditEvent.java b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/kerberos/ChangeSecurityStateKerberosAuditEvent.java new file mode 100644 index 0000000..ffb7e8a --- /dev/null +++ b/ambari-server/src/main/java/org/apache/ambari/server/audit/event/kerberos/ChangeSecurityStateKerberosAuditEvent.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ambari.server.audit.event.kerberos; + +import javax.annotation.concurrent.Immutable; + +/** + * Audit event for kerberos security state change of components + */ +@Immutable +public class ChangeSecurityStateKerberosAuditEvent extends AbstractKerberosAuditEvent { + + public static class ChangeSecurityStateKerberosAuditEventBuilder extends AbstractKerberosAuditEventBuilder<ChangeSecurityStateKerberosAuditEvent, ChangeSecurityStateKerberosAuditEventBuilder> { + + /** + * Service name + */ + private String service; + + /** + * Component name + */ + private String component; + + /** + * Host name + */ + private String hostName; + + /** + * Security state + */ + private String state; + + private ChangeSecurityStateKerberosAuditEventBuilder() { + this.withOperation("Security state change"); + } + + @Override + protected void buildAuditMessage(StringBuilder builder) { + super.buildAuditMessage(builder); + + builder + .append(", Hostname(") + .append(hostName) + .append("), Service(") + .append(service) + .append("), Component(") + .append(component) + .append("), State(") + .append(state) + .append(")"); + } + + /** + * {@inheritDoc} + */ + @Override + protected ChangeSecurityStateKerberosAuditEvent newAuditEvent() { + return new ChangeSecurityStateKerberosAuditEvent(this); + } + + public ChangeSecurityStateKerberosAuditEventBuilder withService(String service) { + this.service = service; + return this; + } + + public ChangeSecurityStateKerberosAuditEventBuilder withComponent(String component) { + this.component = component; + return this; + } + + public ChangeSecurityStateKerberosAuditEventBuilder withHostName(String hostName) { + this.hostName = hostName; + return this; + } + + public ChangeSecurityStateKerberosAuditEventBuilder withState(String state) { + this.state = state; + return this; + } + } + + private ChangeSecurityStateKerberosAuditEvent() { + } + + /** + * {@inheritDoc} + */ + private ChangeSecurityStateKerberosAuditEvent(ChangeSecurityStateKerberosAuditEventBuilder builder) { + super(builder); + } + + /** + * Returns an builder for {@link ChangeSecurityStateKerberosAuditEvent} + * + * @return a builder instance + */ + public static ChangeSecurityStateKerberosAuditEventBuilder builder() { + return new ChangeSecurityStateKerberosAuditEventBuilder(); + } +}
