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

com.sap.cloud.yaas.servicesdk.auditbase.event.AuditEvent Maven / Gradle / Ivy

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