com.sap.cloud.yaas.servicesdk.auditbase.event.AuditEvent Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of service-sdk-audit-base Show documentation
Show all versions of service-sdk-audit-base Show documentation
Contains base utility classes for audit event logging
The newest version!
/*
* © 2017 SAP SE or an SAP affiliate company.
* All rights reserved.
* Please see http://www.sap.com/corporate-en/legal/copyright/index.epx for additional trademark information and
* notices.
*/
package com.sap.cloud.yaas.servicesdk.auditbase.event;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonValue;
import com.sap.cloud.yaas.servicesdk.auditbase.utils.AuditUtils;
import com.sap.cloud.yaas.servicesdk.auditbase.validation.Mandatory;
import com.sap.cloud.yaas.servicesdk.auditbase.validation.Validated;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.MDC;
import java.util.Date;
/**
* Base class for audit events.
*/
@Validated
public abstract class AuditEvent
{
/**
* Maps to name set in APP_NAME environment variable eg. wishlist.
*/
static final String APP_NAME = "APP_NAME";
/**
* Maps to version set in APP_API_VERSION environment variable eg. 4.
*/
static final String APP_API_VERSION = "APP_API_VERSION";
/**
* Maps to organization set in APP_YAAS_ORG environment variable eg. hybris.
*/
static final String APP_YAAS_ORG = "APP_YAAS_ORG";
/**
* Maps to environment set in REGION_ID environment variable eg. prod.
*/
static final String REGION_ID = "REGION_ID";
/**
* MDC key for the user id.
*/
static final String MDC_KEY_USER_ID = "userId";
/**
* MDC key for the user (deprecated but still supported).
*/
static final String MDC_KEY_USER = "user";
/**
* MDC key for the calling tenant.
*/
static final String MDC_KEY_TENANT = "tenant";
/**
* MDC key for the calling organization.
*/
static final String MDC_KEY_ORGANIZATION = "organization";
@Mandatory
@JsonProperty(value = "serviceBasePath")
private final String serviceBasePath;
@Mandatory
@JsonProperty(value = "serviceRegion")
private final String serviceRegion;
@Mandatory
@JsonProperty(value = "source")
private final String source;
@Mandatory
@JsonProperty(value = "sourceType")
private final SourceType sourceType;
@Mandatory
@JsonProperty(value = "time")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSX")
private final Date time;
@JsonProperty(value = "userId")
private final String userId;
/**
* Constructs a new audit event.
*
* @param serviceBasePath
* the base part of the URL used to call the service. Used to identify the service.
* @param serviceRegion
* the region where the service is deployed
* @param source
* the source
* @param sourceType
* the source type
* @param userId
* the user id
* @param time
* the timestamp
*/
protected AuditEvent(
final String serviceBasePath,
final String serviceRegion,
final String source,
final SourceType sourceType,
final String userId,
final Date time)
{
this.serviceBasePath = serviceBasePath;
this.serviceRegion = serviceRegion;
this.source = source;
this.sourceType = sourceType;
this.userId = userId;
this.time = time;
}
/**
* Returns the string representation of the type of the audit event. One of "configuration-changes",
* "personal-changes" or "security-events".
*
* @return the audit event type
*/
public abstract String getType();
/**
* Returns human readable information about an audit event excluding any personal data.
* Each property is in a new line.
*
* @return the information about this event, excluding personal data
*/
@Override
public String toString()
{
return String.format("audit event type: '%s', serviceBasePath: '%s', serviceRegion: '%s', source: '%s', sourceType: '%s'",
getType(),
getServiceBasePath(),
getServiceRegion(),
getSource(),
getSourceType());
}
/**
* See {@link AbstractAuditEventBuilder#serviceBasePath(String)}.
*
* @return the serviceBasePath
* the base part of the URL used to call the service. Used to identify the service.
*/
public String getServiceBasePath()
{
return serviceBasePath;
}
/**
* See {@link AbstractAuditEventBuilder#serviceRegion(String)}.
*
* @return the serviceRegion
* the region where the service that contains the configuration to change is running.
*/
public String getServiceRegion()
{
return serviceRegion;
}
/**
* See {@link AbstractAuditEventBuilder#source(String)}.
*
* @return the source
*/
public String getSource()
{
return source;
}
/**
* See {@link AbstractAuditEventBuilder#sourceType(SourceType)}.
*
* @return the type of the source
*/
public SourceType getSourceType()
{
return sourceType;
}
/**
* See {@link AbstractAuditEventBuilder#userId(String)}.
*
* @return the user id
*/
public String getUserId()
{
return userId;
}
/**
* See {@link AbstractAuditEventBuilder#time(Date)}.
*
* @return the timestamp
*/
public Date getTime()
{
return time;
}
/**
* The possible values of source type, see {@link AbstractAuditEventBuilder#sourceType(SourceType)}.
*/
public enum SourceType
{
/**
* The "tenant" source type.
*/
TENANT("tenant"),
/**
* The "organization" source type.
*/
ORGANIZATION("organization"),
/**
* The "account" source type.
*/
ACCOUNT("account");
private final String label;
SourceType(final String label)
{
this.label = label;
}
@JsonValue
public String getLabel()
{
return label;
}
@Override
public String toString()
{
return label;
}
}
/**
* Abstract builder for {@link AuditEvent}s.
*
* @param the concrete builder type
* @param the audit event type
*/
@SuppressWarnings("PMD.AvoidFieldNameMatchingMethodName")
public abstract static class AbstractAuditEventBuilder
{
private String serviceBasePath;
private String serviceRegion;
private String source;
private SourceType sourceType;
private String userId;
private Date time;
/**
* Creates the prepared {@link AuditEvent} of type {@link E}.
*
* @return the {@link AuditEvent}
*/
public abstract E build();
/**
* The 'service basepath' of the service that manages the object containing the
* personal data to change.
*
* The service basepath is the root part of the public URI used by the service
* registered in YaaS and which can uniquely identify the service (for example by
* name, organization and version)
*
* Example: /hybris/order/v1
*
* If not set it is derived from the "APP_YAAS_ORG", "APP_NAME" and "APP_VERSION" environment variable values,
* or null if not present.
*
* @param newServiceBasePath
* the new value for serviceBasepath
* @return {@code this}, for chaining
*/
public T serviceBasePath(final String newServiceBasePath)
{
if (newServiceBasePath != null)
{
this.serviceBasePath = newServiceBasePath;
}
return (T) this;
}
/**
* The region where the service that contains the configuration to change is running.
*
* Example: us
*
* If not set it is derived from the "REGION_ID" environment variable value, or null if not present.
*
* @param newServiceRegion
* the new value for serviceRegion
* @return {@code this}, for chaining
*/
public T serviceRegion(final String newServiceRegion)
{
if (newServiceRegion != null)
{
this.serviceRegion = newServiceRegion;
}
return (T) this;
}
/**
* User that has modified data contained in the object. By default,
* derived from the value of hybris-user-id header from Yaas proxy.
* Modified data includes:
*
* - modified personal data (see
* {@link PersonalDataChangeAuditEvent})
* - modified configuration data (see
* {@link ConfigurationChangeAuditEvent})
* - created a security event (see {@link SecurityAuditEvent})
*
* , e.g. "[email protected]".
*
* @param newUserId the user
* @return {@code this}, for chaining
*/
public T userId(final String newUserId)
{
if (newUserId != null)
{
userId = newUserId;
}
return (T) this;
}
/**
* The identifier of the owner of the object containing the personal
* data being changed.
*
* @param newSource the source
* @return {@code this}, for chaining
*/
public T source(final String newSource)
{
if (newSource != null)
{
this.source = newSource;
}
return (T) this;
}
/**
* The type of the owner of the object being changed (tenant,
* organization or account). For example: change of billing address of a
* customer will use 'tenant', change of the contact email for an
* organization will use 'organization', change of profile picture of a
* Yaas users will use 'account'.
*
* @param newSourceType the source type
* @return {@code this}, for chaining
*/
public T sourceType(final SourceType newSourceType)
{
if (newSourceType != null)
{
this.sourceType = newSourceType;
}
return (T) this;
}
/**
* Timestamp of the audit event. If not filled in, the time of request serialization will be used.
*
* @param newTime the time of the audit event occurring
* @return {@code this}, for chaining
*/
public T time(final Date newTime)
{
if (newTime != null)
{
this.time = newTime;
}
return (T) this;
}
protected String resolveServiceBasePath()
{
return serviceBasePath != null ? serviceBasePath : getDefaultServiceBasePath();
}
protected String resolveServiceRegion()
{
return serviceRegion != null ? serviceRegion : getDefaultServiceRegion();
}
protected String resolveSource()
{
return resolveSourceAndSourceType().getLeft();
}
protected SourceType resolveSourceType()
{
return resolveSourceAndSourceType().getRight();
}
protected String resolveUserId()
{
return resolveDefaultFromMDC(resolveDefaultFromMDC(userId, MDC_KEY_USER_ID), MDC_KEY_USER);
}
protected Date resolveTimestamp()
{
return time != null ? time : new Date();
}
/**
* The value derived from the "APP_YAAS_ORG", "APP_NAME" and "APP_VERSION"
* environment variable values, or null if one of them is not set.
*
* Example: /hybris/order/v1
*
* @return the /APP_YAAS_ORG/APP_NAME/APP_VERSION
*/
private String getDefaultServiceBasePath()
{
final String appName = AuditUtils.getProperty(APP_NAME, null);
final String appApiVersion = AuditUtils.getProperty(APP_API_VERSION, null);
final String appOrganization = AuditUtils.getProperty(APP_YAAS_ORG, null);
if (appName != null && appApiVersion != null && appOrganization != null)
{
return String.format("/%s/%s/%s", appOrganization, appName, appApiVersion);
}
return null;
}
/**
* The value derived from the "REGION_ID" environment variable value.
*/
private String getDefaultServiceRegion()
{
return AuditUtils.getProperty(REGION_ID, null);
}
private String resolveDefaultFromMDC(final String value, final String mdcKey)
{
return StringUtils.isNotEmpty(value) ? value : MDC.get(mdcKey);
}
private Pair resolveSourceAndSourceType()
{
if (StringUtils.isNotEmpty(source))
{
return Pair.of(source, sourceType);
}
else if (StringUtils.isNotEmpty(MDC.get(MDC_KEY_TENANT)))
{
return Pair.of(MDC.get(MDC_KEY_TENANT), SourceType.TENANT);
}
else if (StringUtils.isNotEmpty(MDC.get(MDC_KEY_ORGANIZATION)))
{
return Pair.of(MDC.get(MDC_KEY_ORGANIZATION), SourceType.ORGANIZATION);
}
else if (StringUtils.isNotEmpty(MDC.get("userId")))
{
return Pair.of(MDC.get("userId"), SourceType.ACCOUNT);
}
else if (StringUtils.isNotEmpty(MDC.get("user")))
{
return Pair.of(MDC.get("user"), SourceType.ACCOUNT);
}
return Pair.of(source, sourceType);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy