/* * Copyright (c) 2008-2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.security.audit; // Logger imports import java.net.URI; import java.util.Arrays; import java.util.List; import java.util.Enumeration; import com.emc.storageos.coordinator.client.model.Site; import com.emc.storageos.coordinator.client.model.SiteState; import com.emc.storageos.coordinator.client.service.CoordinatorClient; import com.emc.storageos.coordinator.client.service.DrUtil; import com.emc.storageos.db.client.DbClient; import com.emc.storageos.db.client.impl.DbClientImpl; import com.emc.storageos.db.client.model.AuditLog; import com.emc.storageos.db.client.model.AuditLogTimeSeries; import com.emc.storageos.db.exceptions.DatabaseException; import com.emc.storageos.model.property.PropertyInfo; import com.emc.storageos.services.OperationTypeEnum; import org.apache.log4j.Logger; import java.util.Locale; import java.util.ResourceBundle; /** * AuditLogManager is used to store system auditlogs to the Cassandra database. */ public class AuditLogManager { final private org.slf4j.Logger _log = org.slf4j.LoggerFactory .getLogger(AuditLogManager.class); private static final String PRODUCT_ID = "ViPR 1.0"; public static final String AUDITLOG_SUCCESS = "SUCCESS"; public static final String AUDITLOG_FAILURE = "FAILURE"; public static final String AUDITOP_BEGIN = "BEGIN"; public static final String AUDITOP_MULTI_BEGIN = "MULTI_BEGIN"; public static final String AUDITOP_END = "END"; // Site in these states should enable recording auditlog private static final List<SiteState> ENABLE_AUDITLOG_SITESTATES = Arrays.asList(SiteState.ACTIVE, SiteState.STANDBY_FAILING_OVER, SiteState.STANDBY_SWITCHING_OVER, SiteState.ACTIVE_SWITCHING_OVER); private static final String SYSLOG_ENALBE="system_syslog_enable"; // auditlog version, to compatible with the possible changes in the future. public static final String AUDITLOG_VERSION = "1"; // A reference to the database client. private DbClient _dbClient; private CoordinatorClient _coordinator; // The logger. private static org.slf4j.Logger s_logger = org.slf4j.LoggerFactory.getLogger(AuditLogManager.class); private static Logger logger = Logger.getLogger("AuditLog"); private DrUtil drUtil; /** * Default constructor. */ public AuditLogManager() { super(); } /** * Setter for the data base client. * * @param dbClient Reference to a database client. */ public void setDbClient(DbClient dbClient) { _dbClient = dbClient; } /** * Setter for the data base client. * * @param dbClient Reference to a database client. */ public void setCoordinator(CoordinatorClient coordinator) { _coordinator = coordinator; drUtil = new DrUtil(_coordinator); } /** * Called to record auditlogs in the database. * * @param events references to recordable auditlogs. */ public void recordAuditLogs(RecordableAuditLog... auditlogs) { if (!shouldRecordAuditLog()) { s_logger.info("Ignore audit log on standby site"); return; } AuditLog dbAuditLogs[] = new AuditLog[auditlogs.length]; int i = 0; for (RecordableAuditLog auditlog : auditlogs) { AuditLog dbAuditlog = AuditLogUtils.convertToAuditLog(auditlog); dbAuditLogs[i++] = dbAuditlog; AuditLog auditSyslog = dbAuditlog; PropertyInfo propInfo = _coordinator.getPropertyInfo(); if (propInfo.getProperty(SYSLOG_ENALBE).equalsIgnoreCase("true")) { Locale locale = new Locale("en", "US"); ResourceBundle resb = ResourceBundle.getBundle("SDSAuditlogRes", locale); AuditLogUtils.resetDesc(auditSyslog,resb); logger.info("audit log is " + dbAuditlog.getServiceType() + " " + dbAuditlog.getUserId() + " " + dbAuditlog.getOperationalStatus() + " " + dbAuditlog.getDescription()); } } // Now insert the events into the database. try { _dbClient.start(); String bucketId = _dbClient.insertTimeSeries(AuditLogTimeSeries.class, dbAuditLogs); s_logger.info("AuditLog(s) persisted into Cassandra with bucketId/rowId : {}", bucketId); } catch (DatabaseException e) { s_logger.error("Error inserting auditlogs into the database", e); throw e; } } /** * Record auditlog for the completed operations * * @param tenantId tenant URI * @param userId user URI * @param serviceType service type (e.g. CoS, Block etc.) * @param auditType audit event type (e.g. Create_COS|TEANT etc.) * @param timestamp time that the audit event happened * @param operationalStatus result of the audit event * @param operationStage * a) For sync operation, it should be null; * b) For async operation, it should be "BEGIN" or "END"; * It is used as sub part of description Id. * The description Id which will be replaced with the * concrete description and parameters after fetching from db. * @param descparams the parameters for the description. */ public void recordAuditLog(URI tenantId, URI userId, String serviceType, OperationTypeEnum auditType, long timestamp, String operationalStatus, String operationStage, Object... descparams) { // Description Id which will be replaced with the concrete description and parameters after fetching from db. // Formatted description: "<auditlog version>|<description id>|<param1>|<param2>|..." // The formatted description will be persistent in cassandra db. During query, it // will be replaced with the real description in specific language. StringBuilder s = new StringBuilder(AUDITLOG_VERSION); s.append("|"); s.append(auditType.toString()); if (operationStage != null) { s.append("_"); s.append(operationStage); } if (operationalStatus.equals(AUDITLOG_FAILURE)) { s.append("_"); s.append(operationalStatus); } for (int i = 0; i < descparams.length; i++) { s.append("|"); if (descparams[i] != null && !descparams[i].toString().isEmpty()) { s.append(descparams[i].toString()); } else { s.append("null"); } } RecordableAuditLog auditlog = new RecordableAuditLog(PRODUCT_ID, tenantId, userId, serviceType, auditType, timestamp, s.toString(), operationalStatus); try { recordAuditLogs(auditlog); } catch (Exception ex) { _log.error("Failed to record auditlog. Auditlog description id: {}", auditType.toString(), ex); } } private boolean shouldRecordAuditLog() { Site site = drUtil.getLocalSite(); return ENABLE_AUDITLOG_SITESTATES.contains(site.getState()); } }