/*
* Copyright (c) 2012 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.api.service.impl.resource;
import java.io.*;
import java.util.List;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import com.emc.storageos.security.audit.AuditLogManager;
import com.emc.storageos.security.audit.AuditLogRequest;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.api.service.impl.resource.utils.AuditLogRetriever;
import com.emc.storageos.api.service.impl.resource.utils.MarshallingExcetion;
import com.emc.storageos.db.client.TimeSeriesMetadata;
import com.emc.storageos.security.authorization.CheckPermission;
import com.emc.storageos.security.authorization.Role;
import com.emc.storageos.svcs.errorhandling.resources.APIException;
/**
* Audit log resource implementation
*/
@Path("/audit")
public class AuditService extends ResourceService {
final private Logger _logger = LoggerFactory.getLogger(AuditService.class);
private AuditLogRetriever _auditlogRetriever;
/**
* formats to be used to parse supported time bucket strings
*/
public static final String HOUR_BUCKET_TIME_FORMAT = "yyyy-MM-dd'T'HH";
public static final String MINUTE_BUCKET_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm";
public static final String BAD_TIMEBUCKET_MSG = "Error: time_bucket parameter format supplied is not valid.\n"
+ "Acceptable formats: yyyy-MM-dd'T'HH , yyyy-MM-dd'T'HH:mm";
/**
* getter
*/
public AuditLogRetriever getAuditLogRetriever() {
return _auditlogRetriever;
}
/**
* setter
*/
public void setAuditLogRetriever(AuditLogRetriever auditlogRetriever) {
_auditlogRetriever = auditlogRetriever;
}
/**
* Retrieves the bulk auditlogs and alerts in a specified time bucket (minute
* or hour).
*
* @param timeBucket Time bucket for retrieval of auditlogs. Acceptable
* formats are: yyyy-MM-dd'T'HH for hour bucket,
* yyyy-MM-dd'T'HH:mm for minute bucket
* @param language Lanuage for the auditlog description. "en_US" by default
* @brief Show audit logs for time period
* @return Output stream of auditlogs or an error status.
*/
public Response getAuditLogs( final String timeBucket, final String language, HttpHeaders header) {
return getAuditLogs(timeBucket, language, null, null, null, null, null, null, header);
}
/**
* Retrieves the bulk auditlogs and alerts based on passed request paramters
* or hour).
*
* @param timeBucket Time bucket for retrieval of auditlogs. Acceptable
* formats are: yyyy-MM-dd'T'HH for hour bucket,
* yyyy-MM-dd'T'HH:mm for minute bucket
* @param startTimeStr Overrided if timeBucket specified .start time for retieval of auditlogs.
* formats are: yyyy-MM-dd'T'HH
* @param endTimeStr Override if timeBucket specified .end time for retieval of auditlogs.
* formats are: yyyy-MM-dd'T'HH
* @param svcType service type for retrieval of auditlogs
* @param user the user of auditlogs to retrieve
* @param result the result of auditlogs to retrieve
* @param keyword the containing keyword of auditlog to retrive
* @param language Lanuage for the auditlog description. "en_US" by default
* @brief Show audit logs for time period with specified paramters
* @return Output stream of auditlogs or an error status.
*/
@GET
@Path("/logs")
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN })
@CheckPermission(roles = { Role.SYSTEM_AUDITOR })
public Response getAuditLogs(
@QueryParam("time_bucket") final String timeBucket,
@QueryParam("start") final String startTimeStr,
@QueryParam("end") final String endTimeStr,
@QueryParam("service_type") final String svcType,
@QueryParam("user") final String user,
@QueryParam("result") final String result,
@QueryParam("keyword") final String keyword,
@QueryParam("language") @DefaultValue("en_US") final String language,
@Context HttpHeaders header) {
MediaType mType = MediaType.APPLICATION_XML_TYPE;
List<MediaType> mTypes = header.getAcceptableMediaTypes();
if (mTypes != null) {
for (MediaType media : mTypes) {
if (media.equals(MediaType.APPLICATION_JSON_TYPE)
|| media.equals(MediaType.TEXT_PLAIN_TYPE)) {
mType = media;
break;
}
}
}
_logger.info("mtype is :{}",mType);
DateTime startTime, endTime;
if (timeBucket != null && !timeBucket.isEmpty()) {
startTime = getDataTime(timeBucket,HOUR_BUCKET_TIME_FORMAT);
if (startTime != null ) {
endTime = startTime.plusMinutes(59);
}else {
startTime = getDataTime(timeBucket,MINUTE_BUCKET_TIME_FORMAT);
if (startTime != null) {
endTime = startTime.plusSeconds(59);
}else {
throw APIException.badRequests.invalidTimeBucket(timeBucket);
}
}
}else {
startTime = getDataTime(startTimeStr, HOUR_BUCKET_TIME_FORMAT);
if (startTime == null) {
throw APIException.badRequests.invalidDate(startTimeStr, HOUR_BUCKET_TIME_FORMAT);
}
endTime = getDataTime(endTimeStr, HOUR_BUCKET_TIME_FORMAT);
if (endTime == null) {
throw APIException.badRequests.invalidDate(endTimeStr, HOUR_BUCKET_TIME_FORMAT);
}
validateDataTimePair(startTime,endTime);
}
validateResultValue(result);
String auditResult = null;
if (result != null){
auditResult = (result.equalsIgnoreCase("S") ? AuditLogManager.AUDITLOG_SUCCESS : AuditLogManager.AUDITLOG_FAILURE);
}
AuditLogRequest auditLogRequest = new AuditLogRequest.Builder().serviceType(svcType)
.user(user).result(auditResult).keyword(keyword).lang(language).timeBucket(timeBucket)
.start(startTime).end(endTime).build();
return Response.ok(getStreamOutput(auditLogRequest, mType), mType).build();
}
/**
* Return an output stream object as http response entity so that the client
* could stream potentially large response.
*
* @param auditLogRequest - the auditLogRequest containing query paramter to filter out when retrieve auditlogs.
* @param type - media type of the response.
* @return - the stream object from which client retrieves response message
* body.
*/
private StreamingOutput getStreamOutput(final AuditLogRequest auditLogRequest,final MediaType type) {
return new StreamingOutput() {
@Override
public void write(OutputStream outputStream) {
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(outputStream));
try {
if (_auditlogRetriever == null) {
throw APIException.internalServerErrors.noAuditLogRetriever();
}
_auditlogRetriever.getBulkAuditLogs(auditLogRequest, type, out);
} catch (MarshallingExcetion e) {
_logger.error("retrieving event error", e);
} finally {
try {
out.close();
} catch (IOException e) {
_logger.error("stream close error", e);
}
}
}
};
}
private DateTime getDataTime(String timeStr,String timeFormatStr) {
DateTimeFormatter timeFormatter = DateTimeFormat.forPattern(
timeFormatStr).withZoneUTC();
if ((timeStr == null) || timeStr.length() != timeFormatStr.length() - 2) {
return null;
}
try{
return timeFormatter.parseDateTime(timeStr);
}catch (IllegalArgumentException e){
throw APIException.badRequests.invalidTimeBucket(timeStr, e);
}
}
private void validateDataTimePair(DateTime start,DateTime end) {
if ((start != null) && (end != null)) {
if (end.isBefore(start.toInstant())) {
throw APIException.badRequests.endTimeBeforeStartTime(start.toString(), end.toString());
}
}
}
private void validateResultValue( String result) {
if (result != null) {
if (!result.equalsIgnoreCase("S") && !result.equalsIgnoreCase("F")){
throw APIException.badRequests.parameterIsNotValid("result");
}
}
}
}