/** * Copyright (c) Codice Foundation * <p/> * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, either version 3 of the * License, or any later version. * <p/> * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. A copy of the GNU Lesser General Public License * is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package org.codice.ddf.catalog.security.logging; import java.util.Map; import java.util.stream.Collectors; import org.apache.commons.lang.StringUtils; import ddf.catalog.content.data.ContentItem; import ddf.catalog.content.operation.CreateStorageRequest; import ddf.catalog.content.operation.CreateStorageResponse; import ddf.catalog.content.operation.UpdateStorageRequest; import ddf.catalog.content.operation.UpdateStorageResponse; import ddf.catalog.content.plugin.PostCreateStoragePlugin; import ddf.catalog.content.plugin.PostUpdateStoragePlugin; import ddf.catalog.content.plugin.PreCreateStoragePlugin; import ddf.catalog.content.plugin.PreUpdateStoragePlugin; import ddf.catalog.data.Metacard; import ddf.catalog.data.Result; import ddf.catalog.operation.CreateRequest; import ddf.catalog.operation.CreateResponse; import ddf.catalog.operation.DeleteRequest; import ddf.catalog.operation.DeleteResponse; import ddf.catalog.operation.Query; import ddf.catalog.operation.QueryRequest; import ddf.catalog.operation.QueryResponse; import ddf.catalog.operation.Request; import ddf.catalog.operation.ResourceRequest; import ddf.catalog.operation.ResourceResponse; import ddf.catalog.operation.Response; import ddf.catalog.operation.Update; import ddf.catalog.operation.UpdateRequest; import ddf.catalog.operation.UpdateResponse; import ddf.catalog.operation.impl.QueryImpl; import ddf.catalog.plugin.PluginExecutionException; import ddf.catalog.plugin.PostFederatedQueryPlugin; import ddf.catalog.plugin.PostIngestPlugin; import ddf.catalog.plugin.PostQueryPlugin; import ddf.catalog.plugin.PostResourcePlugin; import ddf.catalog.plugin.PreFederatedQueryPlugin; import ddf.catalog.plugin.PreIngestPlugin; import ddf.catalog.plugin.PreQueryPlugin; import ddf.catalog.plugin.PreResourcePlugin; import ddf.catalog.plugin.StopProcessingException; import ddf.catalog.source.Source; import ddf.catalog.util.impl.Requests; import ddf.security.common.audit.SecurityLogger; /** * Logs the current operation being performed to the security logger. */ public class SecurityLoggingPlugin implements PreIngestPlugin, PostIngestPlugin, PreQueryPlugin, PostQueryPlugin, PreFederatedQueryPlugin, PostFederatedQueryPlugin, PreResourcePlugin, PostResourcePlugin, PreCreateStoragePlugin, PreUpdateStoragePlugin, PostCreateStoragePlugin, PostUpdateStoragePlugin { @Override public CreateRequest process(CreateRequest input) throws PluginExecutionException, StopProcessingException { String additional = input.getMetacards() .stream() .map(Metacard::getId) .collect(Collectors.joining(",", "Creating metacards: ", "")); logOperation(CatalogOperationType.INGEST_REQUEST, input, additional); return input; } @Override public UpdateRequest process(UpdateRequest input) throws PluginExecutionException, StopProcessingException { String additional = input.getUpdates() .stream() .map(Map.Entry::getValue) .map(Metacard::getId) .collect(Collectors.joining(",", "Updating metacards: ", "")); logOperation(CatalogOperationType.UPDATE_REQUEST, input, additional); return input; } @Override public DeleteRequest process(DeleteRequest input) throws PluginExecutionException, StopProcessingException { String additional = "Deleting: " + input.getAttributeName(); additional += " with values: " + StringUtils.join(input.getAttributeValues(), ","); logOperation(CatalogOperationType.DELETE_REQUEST, input, additional); return input; } @Override public QueryRequest process(QueryRequest input) throws PluginExecutionException, StopProcessingException { String additional = ""; Query query = input.getQuery(); if (query instanceof QueryImpl) { additional = ((QueryImpl) query).getFilter() .toString(); } logOperation(CatalogOperationType.QUERY_REQUEST, input, additional); return input; } @Override public ResourceRequest process(ResourceRequest input) throws PluginExecutionException, StopProcessingException { String additional = "Request resource: " + input.getAttributeName() + " with value " + input.getAttributeValue(); logOperation(CatalogOperationType.RESOURCE_REQUEST, input, additional); return input; } @Override public CreateResponse process(CreateResponse input) throws PluginExecutionException { String additional = input.getCreatedMetacards() .stream() .map(Metacard::getId) .collect(Collectors.joining(",", "Created metacards: ", "")); logOperation(CatalogOperationType.INGEST_RESPONSE, input, additional); return input; } @Override public UpdateResponse process(UpdateResponse input) throws PluginExecutionException { String additional = input.getUpdatedMetacards() .stream() .map(Update::getNewMetacard) .map(Metacard::getId) .collect(Collectors.joining(",", "Updated metacards: ", "")); logOperation(CatalogOperationType.UPDATE_RESPONSE, input, additional); return input; } @Override public DeleteResponse process(DeleteResponse input) throws PluginExecutionException { String additional = input.getDeletedMetacards() .stream() .map(Metacard::getId) .collect(Collectors.joining(",", "Deleted metacards: ", "")); logOperation(CatalogOperationType.DELETE_RESPONSE, input, additional); return input; } @Override public QueryResponse process(QueryResponse input) throws PluginExecutionException, StopProcessingException { String addtional = input.getResults() .stream() .map(Result::getMetacard) .map(Metacard::getId) .collect(Collectors.joining(",", "Queried metacards: ", "")); logOperation(CatalogOperationType.QUERY_RESPONSE, input, addtional); return input; } @Override public ResourceResponse process(ResourceResponse input) throws PluginExecutionException, StopProcessingException { String addtional = "Return resource: " + input.getResource() .getName(); logOperation(CatalogOperationType.RESOURCE_RESPONSE, input, addtional); return input; } @Override public QueryRequest process(Source source, QueryRequest input) throws PluginExecutionException, StopProcessingException { String additional = ""; Query query = input.getQuery(); if (query instanceof QueryImpl) { additional = ((QueryImpl) query).getFilter() .toString() + " for source " + source.getId(); } logOperation(CatalogOperationType.QUERY_REQUEST, input, additional); return input; } @Override public CreateStorageRequest process(CreateStorageRequest input) throws PluginExecutionException { String additional = input.getContentItems() .stream() .map(ContentItem::getMetacard) .map(Metacard::getId) .collect(Collectors.joining(",", "Creating products: ", "")); logOperation(CatalogOperationType.INGEST_REQUEST, input, additional); return input; } @Override public UpdateStorageRequest process(UpdateStorageRequest input) throws PluginExecutionException { String additional = input.getContentItems() .stream() .map(ContentItem::getMetacard) .map(Metacard::getId) .collect(Collectors.joining(",", "Updating products: ", "")); logOperation(CatalogOperationType.UPDATE_REQUEST, input, additional); return input; } @Override public CreateStorageResponse process(CreateStorageResponse input) throws PluginExecutionException { String additional = input.getCreatedContentItems() .stream() .map(ContentItem::getMetacard) .map(Metacard::getId) .collect(Collectors.joining(",", "Created product: ", "")); logOperation(CatalogOperationType.INGEST_RESPONSE, input, additional); return input; } @Override public UpdateStorageResponse process(UpdateStorageResponse input) throws PluginExecutionException { String additional = input.getUpdatedContentItems() .stream() .map(ContentItem::getMetacard) .map(Metacard::getId) .collect(Collectors.joining(",", "Updated products: ", "")); logOperation(CatalogOperationType.UPDATE_RESPONSE, input, additional); return input; } private void logOperation(CatalogOperationType operationType, Request request, String additionalInfo) { if (Requests.isLocal(request)) { SecurityLogger.audit("Performing {} operation {} on catalog.", operationType, additionalInfo); } else { SecurityLogger.audit("Performing {} operation {} on {}", operationType, additionalInfo, request.getStoreIds()); } } private void logOperation(CatalogOperationType operationType, Response response, String additionalInfo) { if (Requests.isLocal(response.getRequest())) { SecurityLogger.audit("Receiving results of {} operation {} on catalog.", operationType, additionalInfo); } else { SecurityLogger.audit("Receiving results of {} operation {} on {}", operationType, additionalInfo, response.getRequest() .getStoreIds()); } } private enum CatalogOperationType { INGEST_REQUEST, UPDATE_REQUEST, DELETE_REQUEST, QUERY_REQUEST, RESOURCE_REQUEST, INGEST_RESPONSE, UPDATE_RESPONSE, DELETE_RESPONSE, QUERY_RESPONSE, RESOURCE_RESPONSE } }