
com.sap.cloud.sdk.cloudplatform.auditlog.ScpCfAuditLog Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of auditlog-scp-cf Show documentation
Show all versions of auditlog-scp-cf Show documentation
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