All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sap.cloud.sdk.cloudplatform.auditlog.ScpCfAuditLog Maven / Gradle / Ivy

Go to download

Implementation of the Cloud platform abstraction for audit logging on the SAP Cloud Platform (Cloud Foundry).

The newest version!
/*
 * Copyright (c) 2020 SAP SE or an SAP affiliate company. All rights reserved.
 */

package com.sap.cloud.sdk.cloudplatform.auditlog;

import static com.sap.cloud.sdk.cloudplatform.auditlog.AuditLogUtils.attributesAsList;

import java.util.Map;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import org.slf4j.Logger;

import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.sap.cloud.sdk.cloudplatform.auditlog.exception.AuditLogAccessException;
import com.sap.cloud.sdk.cloudplatform.logging.CloudLoggerFactory;
import com.sap.xs.audit.api.AuditLogMessage;
import com.sap.xs.audit.api.TransactionalAuditLogMessage;
import com.sap.xs.audit.api.exception.AuditLogException;
import com.sap.xs.audit.api.exception.AuditLogNotAvailableException;
import com.sap.xs.audit.api.exception.AuditLogWriteException;
import com.sap.xs.audit.api.v2.AuditLogMessageFactory;
import com.sap.xs.audit.api.v2.AuditedDataSubject;
import com.sap.xs.audit.api.v2.AuditedObject;
import com.sap.xs.audit.api.v2.ConfigurationChangeAuditMessage;
import com.sap.xs.audit.api.v2.DataAccessAuditMessage;
import com.sap.xs.audit.api.v2.DataModificationAuditMessage;
import com.sap.xs.audit.api.v2.SecurityEventAuditMessage;
import com.sap.xs.audit.client.impl.v2.AuditLogMessageFactoryImpl;

/**
 * Implementation of audit logging that uses the Cloud Foundry (HANA XS) library. The cloudplatform library is very
 * limited, so audit data is filled in on a best effort basis.
 * 

* Important: For performance reasons, consider to only use the audit log for logging of events such as: *

    *
  • security relevant events, *
  • read access to sensitive personal data, *
  • changes to configuration data, *
  • and changes to personal data. *
*/ public class ScpCfAuditLog implements AuditLog { private static final Logger logger = CloudLoggerFactory.getLogger(ScpCfAuditLog.class); private static final String ACTION_BEGINNING = "[BEGINNING] "; private static final String ACTION_COMPLETED = "[COMPLETED] "; private static final String ACTION_FAILED = "[FAILED] "; private static AuditLogMessageFactory getAuditLogMessageFactory() throws AuditLogAccessException { try { return new AuditLogMessageFactoryImpl(); } catch( final AuditLogException e ) { throw new AuditLogAccessException("Failed to instantiate AuditLogMessageFactoryImpl.", e); } } private final AuditLogMessageFactory auditLogMessageFactory; /** * Creates a new instance using the default {@link AuditLogMessageFactoryImpl}. * * @throws AuditLogAccessException * If there is an issue while instantiating the {@link AuditLogMessageFactoryImpl}. */ ScpCfAuditLog() throws AuditLogAccessException { this(getAuditLogMessageFactory()); } ScpCfAuditLog( @Nonnull final AuditLogMessageFactory auditLogMessageFactory ) { this.auditLogMessageFactory = auditLogMessageFactory; } /** * {@inheritDoc} */ @Override public void logSecurityEventBeginning( @Nonnull final AccessRequester initiator, final String message ) { logSecurityEvent(true, initiator, message, null); } /** * {@inheritDoc} */ @Override public void logSecurityEvent( @Nonnull final AccessRequester initiator, @Nullable final String message, @Nullable final Throwable throwable ) { logSecurityEvent(false, initiator, message, throwable); } private void logSecurityEvent( final boolean isBeginning, @Nonnull final AccessRequester initiator, @Nullable final String message, @Nullable final Throwable throwable ) { final SecurityEventAuditMessage auditLogEntry = auditLogMessageFactory.createSecurityEventAuditMessage(); fillCommonAttributes(auditLogEntry, initiator); auditLogEntry.setIp(initiator.getIpAddress().orElse(null)); final StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(throwable == null ? (isBeginning ? ACTION_BEGINNING : ACTION_COMPLETED) : ACTION_FAILED); if( !Strings.isNullOrEmpty(message) ) { stringBuilder.append(message); } if( throwable != null ) { stringBuilder.append(System.lineSeparator()); stringBuilder.append(throwable.getMessage()); stringBuilder.append(System.lineSeparator()); stringBuilder.append(Throwables.getStackTraceAsString(throwable)); stringBuilder.append(System.lineSeparator()); } auditLogEntry.setData(stringBuilder.toString()); logNonTransactional(auditLogEntry); } /** * {@inheritDoc} * * @deprecated Use * {@link #logConfigChangeBeginning(AccessRequester, AuditedDataObject, AccessedAttribute, AccessedAttribute...)} * instead. */ @Deprecated @Override public void logConfigChangeBeginning( @Nonnull final AccessRequester initiator, @Nonnull final AuditedDataObject object, @Nullable final Iterable attributesAffected ) { logConfigChange(true, initiator, object, attributesAffected, null); } /** * {@inheritDoc} */ @Override public void logConfigChangeBeginning( @Nonnull final AccessRequester initiator, @Nonnull final AuditedDataObject object, @Nonnull final AccessedAttribute attributeAffected, @Nullable final AccessedAttribute... attributesAffected ) { logConfigChange(true, initiator, object, attributesAsList(attributeAffected, attributesAffected), null); } /** * {@inheritDoc} * * @deprecated Use * {@link #logConfigChange(AccessRequester, AuditedDataObject, Throwable, AccessedAttribute, AccessedAttribute...)} * instead. */ @Deprecated @Override public void logConfigChange( @Nonnull final AccessRequester initiator, @Nonnull final AuditedDataObject object, @Nullable final Iterable attributesAffected, @Nullable final Throwable error ) { logConfigChange(false, initiator, object, attributesAffected, error); } /** * {@inheritDoc} */ @Override public void logConfigChange( @Nonnull final AccessRequester initiator, @Nonnull final AuditedDataObject object, @Nullable final Throwable error, @Nonnull final AccessedAttribute attributeAffected, @Nullable final AccessedAttribute... attributesAffected ) { logConfigChange(false, initiator, object, attributesAsList(attributeAffected, attributesAffected), error); } private void logConfigChange( final boolean isBeginning, @Nonnull final AccessRequester initiator, @Nonnull final AuditedDataObject object, @Nullable final Iterable attributesAffected, @Nullable final Throwable error ) { final ConfigurationChangeAuditMessage auditLogEntry = auditLogMessageFactory.createConfigurationChangeAuditMessage(); fillCommonAttributes(auditLogEntry, initiator); auditLogEntry.setObject(convertAuditedObject(object)); if( attributesAffected != null ) { for( final AccessedAttribute attribute : attributesAffected ) { auditLogEntry.addValue( attribute.getIdentifier(), String.valueOf(attribute.getOldValue()), String.valueOf(attribute.getNewValue())); } } logTransactional(auditLogEntry, isBeginning, error); } /** * {@inheritDoc} * * @deprecated Use * {@link #logDataReadAttempt(AccessRequester, AuditedDataObject, com.sap.cloud.sdk.cloudplatform.auditlog.AuditedDataSubject, AccessedAttribute, AccessedAttribute...)} * instead. */ @Deprecated @Override public void logDataReadAttempt( @Nonnull final AccessRequester initiator, @Nonnull final AuditedDataObject object, @Nonnull final com.sap.cloud.sdk.cloudplatform.auditlog.AuditedDataSubject subject, @Nullable final Iterable attributesAffected ) { logDataRead(true, initiator, object, subject, attributesAffected, null); } /** * {@inheritDoc} */ @Override public void logDataReadAttempt( @Nonnull final AccessRequester initiator, @Nonnull final AuditedDataObject object, @Nonnull final com.sap.cloud.sdk.cloudplatform.auditlog.AuditedDataSubject subject, @Nonnull final AccessedAttribute attributeAffected, @Nullable final AccessedAttribute... attributesAffected ) { logDataRead(true, initiator, object, subject, attributesAsList(attributeAffected, attributesAffected), null); } /** * {@inheritDoc} * * @deprecated Use * {@link #logDataRead(AccessRequester, AuditedDataObject, com.sap.cloud.sdk.cloudplatform.auditlog.AuditedDataSubject, Throwable, AccessedAttribute, AccessedAttribute...)} * instead. */ @Deprecated @Override public void logDataRead( @Nonnull final AccessRequester initiator, @Nonnull final AuditedDataObject object, @Nonnull final com.sap.cloud.sdk.cloudplatform.auditlog.AuditedDataSubject subject, @Nullable final Iterable attributesAffected, @Nullable final Throwable error ) { logDataRead(false, initiator, object, subject, attributesAffected, error); } /** * {@inheritDoc} */ @Override public void logDataRead( @Nonnull final AccessRequester initiator, @Nonnull final AuditedDataObject object, @Nonnull final com.sap.cloud.sdk.cloudplatform.auditlog.AuditedDataSubject subject, @Nullable final Throwable error, @Nonnull final AccessedAttribute attributeAffected, @Nullable final AccessedAttribute... attributesAffected ) { logDataRead(false, initiator, object, subject, attributesAsList(attributeAffected, attributesAffected), error); } private void logDataRead( final boolean isBeginning, @Nonnull final AccessRequester initiator, @Nonnull final AuditedDataObject object, @Nonnull final com.sap.cloud.sdk.cloudplatform.auditlog.AuditedDataSubject subject, @Nullable final Iterable attributesAffected, @Nullable final Throwable error ) { final DataAccessAuditMessage auditLogEntry = auditLogMessageFactory.createDataAccessAuditMessage(); fillCommonAttributes(auditLogEntry, initiator); auditLogEntry.setChannel(initiator.getChannel().orElse(null)); auditLogEntry.setObject(convertAuditedObject(object)); auditLogEntry.setDataSubject(convertAuditedSubject(subject)); if( attributesAffected != null ) { for( final AccessedAttribute attribute : attributesAffected ) { auditLogEntry.addAttribute(attribute.getIdentifier(), attribute.isOperationSuccessful()); } } logNonTransactional(auditLogEntry); } /** * {@inheritDoc} * * @deprecated Use * {@link #logDataWriteAttempt(AccessRequester, AuditedDataObject, com.sap.cloud.sdk.cloudplatform.auditlog.AuditedDataSubject, AccessedAttribute, AccessedAttribute...)} * instead. */ @Deprecated @Override public void logDataWriteAttempt( @Nonnull final AccessRequester initiator, @Nonnull final AuditedDataObject object, @Nonnull final com.sap.cloud.sdk.cloudplatform.auditlog.AuditedDataSubject subject, @Nullable final Iterable attributesAffected ) { logDataWrite(true, initiator, object, subject, attributesAffected, null); } /** * {@inheritDoc} */ @Override public void logDataWriteAttempt( @Nonnull final AccessRequester initiator, @Nonnull final AuditedDataObject object, @Nonnull final com.sap.cloud.sdk.cloudplatform.auditlog.AuditedDataSubject subject, @Nonnull final AccessedAttribute attributeAffected, @Nullable final AccessedAttribute... attributesAffected ) { logDataWrite(true, initiator, object, subject, attributesAsList(attributeAffected, attributesAffected), null); } /** * {@inheritDoc} * * @deprecated Use * {@link #logDataWrite(AccessRequester, AuditedDataObject, com.sap.cloud.sdk.cloudplatform.auditlog.AuditedDataSubject, Throwable, AccessedAttribute, AccessedAttribute...)} * instead. */ @Deprecated @Override public void logDataWrite( @Nonnull final AccessRequester initiator, @Nonnull final AuditedDataObject object, @Nonnull final com.sap.cloud.sdk.cloudplatform.auditlog.AuditedDataSubject subject, @Nullable final Iterable attributesAffected, @Nullable final Throwable error ) { logDataWrite(false, initiator, object, subject, attributesAffected, error); } /** * {@inheritDoc} */ @Override public void logDataWrite( @Nonnull final AccessRequester initiator, @Nonnull final AuditedDataObject object, @Nonnull final com.sap.cloud.sdk.cloudplatform.auditlog.AuditedDataSubject subject, @Nullable final Throwable error, @Nonnull final AccessedAttribute attributeAffected, @Nullable final AccessedAttribute... attributesAffected ) { logDataWrite(false, initiator, object, subject, attributesAsList(attributeAffected, attributesAffected), error); } private void logDataWrite( final boolean isBeginning, @Nonnull final AccessRequester initiator, @Nonnull final AuditedDataObject object, @Nonnull final com.sap.cloud.sdk.cloudplatform.auditlog.AuditedDataSubject subject, @Nullable final Iterable attributesAffected, @Nullable final Throwable error ) { final DataModificationAuditMessage auditLogEntry; auditLogEntry = auditLogMessageFactory.createDataModificationAuditMessage(); fillCommonAttributes(auditLogEntry, initiator); auditLogEntry.setObject(convertAuditedObject(object)); auditLogEntry.setDataSubject(convertAuditedSubject(subject)); if( attributesAffected != null ) { for( final AccessedAttribute attribute : attributesAffected ) { auditLogEntry.addAttribute( attribute.getIdentifier(), String.valueOf(attribute.getOldValue()), String.valueOf(attribute.getNewValue())); } } logTransactional(auditLogEntry, isBeginning, error); } private void fillCommonAttributes( @Nonnull final AuditLogMessage auditLogEntry, @Nonnull final AccessRequester initiator ) { auditLogEntry.setUser(initiator.getUserId().orElse(null)); auditLogEntry.setTenant(initiator.getTenantId().orElse(null)); } private void logNonTransactional( @Nonnull final AuditLogMessage auditLogEntry ) { try { auditLogEntry.log(); } catch( final AuditLogNotAvailableException | AuditLogWriteException e ) { logger.error("Unable to write audit log entry. Entry contents: [" + auditLogEntry + "].", e); } } private void logTransactional( @Nonnull final TransactionalAuditLogMessage auditLogEntry, final boolean isBeginning, @Nullable final Throwable error ) { try { if( isBeginning ) { auditLogEntry.logPrepare(); } else { if( error == null ) { auditLogEntry.logSuccess(); } else { auditLogEntry.logFailure(); } } } catch( final AuditLogNotAvailableException | AuditLogWriteException e ) { logger.error("Unable to write audit log entry. Entry contents: [" + auditLogEntry + "].", e); } } private AuditedObject convertAuditedObject( @Nonnull final AuditedDataObject sdkObject ) { final AuditedObject converted = auditLogMessageFactory.createAuditedObject(); converted.setType(sdkObject.getType()); for( final Map.Entry identifier : sdkObject.getAllIdentifiers().entrySet() ) { converted.addIdentifier(identifier.getKey(), identifier.getValue()); } return converted; } private AuditedDataSubject convertAuditedSubject( @Nonnull final com.sap.cloud.sdk.cloudplatform.auditlog.AuditedDataSubject sdkSubject ) { final AuditedDataSubject converted = auditLogMessageFactory.createAuditedDataSubject(); converted.setType(sdkSubject.getType()); converted.setRole(sdkSubject.getRole()); for( final Map.Entry identifier : sdkSubject.getAllIdentifiers().entrySet() ) { converted.addIdentifier(identifier.getKey(), identifier.getValue()); } return converted; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy