/*******************************************************************************
* Copyright 2010-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
******************************************************************************/
package com.amazonaws.services.cloudtrail.processinglibrary.serializer;
import com.amazonaws.services.cloudtrail.processinglibrary.model.CloudTrailEvent;
import com.amazonaws.services.cloudtrail.processinglibrary.model.CloudTrailEventData;
import com.amazonaws.services.cloudtrail.processinglibrary.model.CloudTrailEventMetadata;
import com.amazonaws.services.cloudtrail.processinglibrary.model.internal.*;
import com.amazonaws.services.cloudtrail.processinglibrary.model.internal.OnBehalfOf;
import com.amazonaws.services.cloudtrail.processinglibrary.model.internal.UserIdentity;
import com.amazonaws.services.cloudtrail.processinglibrary.utils.LibraryUtils;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.IOException;
import java.text.ParseException;
import java.util.*;
/**
* Abstract base class for Event Serializer implementations.
*/
public abstract class AbstractEventSerializer implements EventSerializer {
private static final Log logger = LogFactory.getLog(AbstractEventSerializer.class);
private static final String RECORDS = "Records";
private static final double SUPPORTED_EVENT_VERSION = 1.08d;
/**
* A Jackson JSON Parser object.
*/
private JsonParser jsonParser;
/**
* Construct an AbstractEventSerializer object
*
* @param jsonParser a Jackson
* JsonParser object to
* use for interpreting JSON objects.
* @throws IOException under no conditions.
*/
public AbstractEventSerializer(JsonParser jsonParser) throws IOException {
this.jsonParser = jsonParser;
}
/**
* An abstract class that returns an
* {@link CloudTrailEventMetadata} object.
*
* @param charStart the character count at which to begin reading event data.
* @param charEnd the character count at which to stop reading event data.
* @return the event metadata.
*/
public abstract CloudTrailEventMetadata getMetadata(int charStart, int charEnd);
/**
* Read the header of an AWS CloudTrail log.
*
* @throws JsonParseException if the log could not be parsed.
* @throws IOException if the log could not be opened or accessed.
*/
protected void readArrayHeader() throws IOException {
if (jsonParser.nextToken() != JsonToken.START_OBJECT) {
throw new JsonParseException("Not a Json object", jsonParser.getCurrentLocation());
}
jsonParser.nextToken();
if (!jsonParser.getText().equals(RECORDS)) {
throw new JsonParseException("Not a CloudTrail log", jsonParser.getCurrentLocation());
}
if (jsonParser.nextToken() != JsonToken.START_ARRAY) {
throw new JsonParseException("Not a CloudTrail log", jsonParser.getCurrentLocation());
}
}
/**
* Indicates whether the CloudTrail log has more events to read.
*
* @return true
if the log contains more events; false
otherwise.
* @throws IOException if the log could not be opened or accessed.
*/
public boolean hasNextEvent() throws IOException {
/* In Fasterxml parser, hasNextEvent will consume next token. So do not call it multiple times. */
JsonToken nextToken = jsonParser.nextToken();
return nextToken == JsonToken.START_OBJECT || nextToken == JsonToken.START_ARRAY;
}
/**
* Close the JSON parser object used to read the CloudTrail log.
*
* @throws IOException if the log could not be opened or accessed.
*/
public void close() throws IOException {
jsonParser.close();
}
/**
* Get the next event from the CloudTrail log and parse it.
*
* @return a {@link CloudTrailEvent} that represents the
* parsed event.
* @throws IOException if the event could not be parsed.
*/
public CloudTrailEvent getNextEvent() throws IOException {
CloudTrailEventData eventData = new CloudTrailEventData();
String key;
/* Get next CloudTrailEvent event from log file. When failed to parse a event,
* IOException will be thrown. In this case, the charEnd index the place we
* encountered parsing error. */
// return the starting location of the current token; that is, position of the first character
// from input that starts the current token
int charStart = (int) jsonParser.getTokenLocation().getCharOffset();
while(jsonParser.nextToken() != JsonToken.END_OBJECT) {
key = jsonParser.getCurrentName();
switch (key) {
case "eventVersion":
String eventVersion = jsonParser.nextTextValue();
if (Double.parseDouble(eventVersion) > SUPPORTED_EVENT_VERSION) {
logger.debug(String.format("EventVersion %s is not supported by CloudTrail.", eventVersion));
}
eventData.add(key, eventVersion);
break;
case "userIdentity":
this.parseUserIdentity(eventData);
break;
case "eventTime":
eventData.add(CloudTrailEventField.eventTime.name(), convertToDate(jsonParser.nextTextValue()));
break;
case "eventID":
eventData.add(key, convertToUUID(jsonParser.nextTextValue()));
break;
case "readOnly":
this.parseReadOnly(eventData);
break;
case "resources":
this.parseResources(eventData);
break;
case "managementEvent":
this.parseManagementEvent(eventData);
break;
case "insightDetails":
this.parseInsightDetails(eventData);
break;
case "addendum":
this.parseAddendum(eventData);
break;
case "tlsDetails":
this.parseTlsDetails(eventData);
break;
default:
eventData.add(key, parseDefaultValue(key));
break;
}
}
this.setAccountId(eventData);
// event's last character position in the log file.
int charEnd = (int) jsonParser.getTokenLocation().getCharOffset();
CloudTrailEventMetadata metaData = getMetadata(charStart, charEnd);
return new CloudTrailEvent(eventData, metaData);
}
/**
* Set AccountId in CloudTrailEventData top level from either recipientAccountID or from UserIdentity.
* If recipientAccountID exists then recipientAccountID is set to accountID; otherwise, accountID is retrieved
* from UserIdentity.
*
* There are 2 places accountID would appear in UserIdentity: first is the UserIdentity top level filed
* and the second place is accountID inside SessionIssuer. If accountID exists in the top level field, then it is
* set to accountID; otherwise, accountID is retrieved from SessionIssuer.
*
* If all 3 places cannot find accountID, then accountID is not set.
*
* @param eventData the event data to set.
*/
private void setAccountId(CloudTrailEventData eventData) {
if (eventData.getRecipientAccountId() != null) {
eventData.add("accountId", eventData.getRecipientAccountId());
return;
}
if (eventData.getUserIdentity() != null &&
eventData.getUserIdentity().getAccountId() != null) {
eventData.add("accountId", eventData.getUserIdentity().getAccountId());
return;
}
if (eventData.getUserIdentity() != null &&
eventData.getUserIdentity().getAccountId() == null &&
eventData.getUserIdentity().getSessionContext() != null &&
eventData.getUserIdentity().getSessionContext().getSessionIssuer() != null &&
eventData.getUserIdentity().getSessionContext().getSessionIssuer().getAccountId() != null) {
eventData.add("accountId", eventData.getUserIdentity().getSessionContext().getSessionIssuer().getAccountId());
}
}
/**
* Parses the {@link CloudTrailDataStore.UserIdentity} in CloudTrailEventData
*
* @param eventData {@link CloudTrailEventData} needs to parse.
* @throws IOException
*/
private void parseUserIdentity(CloudTrailEventData eventData) throws IOException {
JsonToken nextToken = jsonParser.nextToken();
if (nextToken == JsonToken.VALUE_NULL) {
eventData.add(CloudTrailEventField.userIdentity.name(), null);
return;
}
if (nextToken != JsonToken.START_OBJECT) {
throw new JsonParseException("Not a UserIdentity object", jsonParser.getCurrentLocation());
}
UserIdentity userIdentity = new UserIdentity();
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
String key = jsonParser.getCurrentName();
switch (key) {
case "type":
userIdentity.add(CloudTrailEventField.type.name(), jsonParser.nextTextValue());
break;
case "principalId":
userIdentity.add(CloudTrailEventField.principalId.name(), jsonParser.nextTextValue());
break;
case "arn":
userIdentity.add(CloudTrailEventField.arn.name(), jsonParser.nextTextValue());
break;
case "accountId":
userIdentity.add(CloudTrailEventField.accountId.name(), jsonParser.nextTextValue());
break;
case "accessKeyId":
userIdentity.add(CloudTrailEventField.accessKeyId.name(), jsonParser.nextTextValue());
break;
case "userName":
userIdentity.add(CloudTrailEventField.userName.name(), jsonParser.nextTextValue());
break;
case "sessionContext":
this.parseSessionContext(userIdentity);
break;
case "invokedBy":
userIdentity.add(CloudTrailEventField.invokedBy.name(), jsonParser.nextTextValue());
break;
case "identityProvider":
userIdentity.add(CloudTrailEventField.identityProvider.name(), jsonParser.nextTextValue());
break;
case "credentialId":
userIdentity.add(CloudTrailEventField.credentialId.name(), jsonParser.nextTextValue());
break;
case "onBehalfOf":
this.parseOnBehalfOf(userIdentity);
break;
default:
userIdentity.add(key, parseDefaultValue(key));
break;
}
}
eventData.add(CloudTrailEventField.userIdentity.name(), userIdentity);
}
private void parseOnBehalfOf(UserIdentity userIdentity) throws IOException{
if (jsonParser.nextToken() != JsonToken.START_OBJECT) {
throw new JsonParseException("Not a SessionContext object", jsonParser.getCurrentLocation());
}
OnBehalfOf onBehalfOf = new OnBehalfOf();
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
String key = jsonParser.getCurrentName();
switch (key) {
case "userId":
onBehalfOf.add(CloudTrailEventField.onBehalfOfUserId.name(), jsonParser.nextTextValue());
break;
case "identityStoreArn":
onBehalfOf.add(CloudTrailEventField.onBehalfOfIdentityStoreArn.name(), jsonParser.nextTextValue());
break;
default:
onBehalfOf.add(key, parseDefaultValue(key));
break;
}
userIdentity.add(CloudTrailEventField.onBehalfOf.name(), onBehalfOf);
}
}
/**
* Parses the {@link SessionContext} object.
*
* @param userIdentity the {@link UserIdentity}
* @throws IOException
* @throws JsonParseException
*/
private void parseSessionContext(UserIdentity userIdentity) throws IOException {
if (jsonParser.nextToken() != JsonToken.START_OBJECT) {
throw new JsonParseException("Not a SessionContext object", jsonParser.getCurrentLocation());
}
SessionContext sessionContext = new SessionContext();
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
String key = jsonParser.getCurrentName();
switch (key) {
case "attributes":
sessionContext.add(CloudTrailEventField.attributes.name(), parseAttributes());
break;
case "sessionIssuer":
sessionContext.add(CloudTrailEventField.sessionIssuer.name(), parseSessionIssuer(sessionContext));
break;
case "webIdFederationData":
sessionContext.add(CloudTrailEventField.webIdFederationData.name(), parseWebIdentitySessionContext(sessionContext));
break;
default:
sessionContext.add(key, parseDefaultValue(key));
break;
}
}
userIdentity.add(CloudTrailEventField.sessionContext.name(), sessionContext);
}
/**
* Parses the {@link InsightDetails} in CloudTrailEventData
*
* @param eventData {@link CloudTrailEventData} needs to parse.
* @throws IOException
*/
private void parseInsightDetails(CloudTrailEventData eventData) throws IOException {
JsonToken nextToken = jsonParser.nextToken();
if (nextToken == JsonToken.VALUE_NULL) {
eventData.add(CloudTrailEventField.insightDetails.name(), null);
return;
}
if (nextToken != JsonToken.START_OBJECT) {
throw new JsonParseException("Not a InsightDetails object", jsonParser.getCurrentLocation());
}
InsightDetails insightDetails = new InsightDetails();
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
String key = jsonParser.getCurrentName();
switch (key) {
case "eventName":
insightDetails.add(CloudTrailEventField.eventName.name(), jsonParser.nextTextValue());
break;
case "eventSource":
insightDetails.add(CloudTrailEventField.eventSource.name(), jsonParser.nextTextValue());
break;
case "insightType":
insightDetails.add(CloudTrailEventField.insightType.name(), jsonParser.nextTextValue());
break;
case "state":
insightDetails.add(CloudTrailEventField.state.name(), jsonParser.nextTextValue());
break;
case "insightContext":
this.parseInsightContext(insightDetails);
break;
case "errorCode":
insightDetails.add(CloudTrailEventField.errorCode.name(), jsonParser.nextTextValue());
break;
default:
insightDetails.add(key, parseDefaultValue(key));
break;
}
}
eventData.add(CloudTrailEventField.insightDetails.name(), insightDetails);
}
/**
* Parses the {@link InsightContext} object.
*
* @param insightDetails the {@link InsightDetails}
* @throws IOException
* @throws JsonParseException
*/
private void parseInsightContext(InsightDetails insightDetails) throws IOException {
if (jsonParser.nextToken() != JsonToken.START_OBJECT) {
throw new JsonParseException("Not a InsightContext object", jsonParser.getCurrentLocation());
}
InsightContext insightContext = new InsightContext();
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
String key = jsonParser.getCurrentName();
switch (key) {
case "statistics":
this.parseInsightStatistics(insightContext);
break;
case "attributions":
this.parseInsightAttributionsList(insightContext);
break;
default:
insightContext.add(key, parseDefaultValue(key));
}
}
insightDetails.add(CloudTrailEventField.insightContext.name(), insightContext);
}
/**
* Parses the {@link InsightStatistics} object.
*
* @param insightContext the {@link InsightContext}
* @throws IOException
* @throws JsonParseException
*/
private void parseInsightStatistics(InsightContext insightContext) throws IOException {
if (jsonParser.nextToken() != JsonToken.START_OBJECT) {
throw new JsonParseException("Not a InsightStatistics object", jsonParser.getCurrentLocation());
}
InsightStatistics insightStatistics = new InsightStatistics();
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
String key = jsonParser.getCurrentName();
switch (key) {
case "insightDuration":
insightStatistics.add(key, Integer.valueOf(jsonParser.getValueAsInt()));
break;
case "baselineDuration":
insightStatistics.add(key, Integer.valueOf(jsonParser.getValueAsInt()));
break;
case "baseline":
insightStatistics.add(key, parseAttributesWithDoubleValues());
break;
case "insight":
insightStatistics.add(key, parseAttributesWithDoubleValues());
break;
default:
insightStatistics.add(key, parseDefaultValue(key));
break;
}
}
insightContext.add(CloudTrailEventField.statistics.name(), insightStatistics);
}
/**
* Parses a list of {@link InsightAttributions} objects.
*
* @param insightContext the {@link InsightContext}
* @throws IOException
* @throws JsonParseException
*/
private void parseInsightAttributionsList(InsightContext insightContext) throws IOException {
if (jsonParser.nextToken() != JsonToken.START_ARRAY) {
throw new JsonParseException("Not a InsightAttributions list", jsonParser.getCurrentLocation());
}
List insightAttributionsList = new ArrayList<>();
while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
insightAttributionsList.add(parseInsightAttributions());
}
insightContext.add(CloudTrailEventField.attributions.name(), insightAttributionsList);
}
/**
* Parses an {@link InsightAttributions} object.
*
* @return a single {@link InsightAttributions}
* @throws IOException
* @throws JsonParseException
*/
private InsightAttributions parseInsightAttributions() throws IOException {
if (jsonParser.getCurrentToken() != JsonToken.START_OBJECT) {
throw new JsonParseException("Not a InsightAttributions object", jsonParser.getCurrentLocation());
}
InsightAttributions insightAttributions = new InsightAttributions();
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
String key = jsonParser.getCurrentName();
switch (key) {
case "attribute":
insightAttributions.add(CloudTrailEventField.attribute.name(), jsonParser.nextTextValue());
break;
case "baseline":
insightAttributions.add(CloudTrailEventField.baseline.name(), parseAttributeValueList());
break;
case "insight":
insightAttributions.add(CloudTrailEventField.insight.name(), parseAttributeValueList());
break;
default:
insightAttributions.add(key, parseDefaultValue(key));
}
}
return insightAttributions;
}
/**
* Parses a list of {@link AttributeValue} objects.
*
* @return list of {@link AttributeValue}
* @throws IOException
* @throws JsonParseException
*/
private List parseAttributeValueList() throws IOException {
if (jsonParser.nextToken() != JsonToken.START_ARRAY) {
throw new JsonParseException("Not a InsightAttributions list", jsonParser.getCurrentLocation());
}
List attributeValues = new ArrayList<>();
while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
attributeValues.add(parseAttributeValue());
}
return attributeValues;
}
/**
* Parses a single {@link AttributeValue} object.
*
* @return a single {@link AttributeValue}, which contains the string value of the attribute, and the average number of
* occurrences.
* @throws IOException
* @throws JsonParseException
*/
private AttributeValue parseAttributeValue() throws IOException {
if (jsonParser.getCurrentToken() != JsonToken.START_OBJECT) {
throw new JsonParseException("Not a InsightAttributions object", jsonParser.getCurrentLocation());
}
AttributeValue attributeValue = new AttributeValue();
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
String key = jsonParser.getCurrentName();
switch (key) {
case "value":
attributeValue.add(CloudTrailEventField.value.name(), jsonParser.nextTextValue());
break;
case "average":
attributeValue.add(CloudTrailEventField.average.name(), Double.valueOf(jsonParser.getValueAsDouble()));
break;
default:
attributeValue.add(key, parseDefaultValue(key));
}
}
return attributeValue;
}
/**
* Parses the {@link WebIdentitySessionContext} object.
*
* @param sessionContext {@link SessionContext}
* @return the web identity session context
* @throws IOException
*/
private WebIdentitySessionContext parseWebIdentitySessionContext(SessionContext sessionContext) throws IOException {
if (jsonParser.nextToken() != JsonToken.START_OBJECT) {
throw new JsonParseException("Not a WebIdentitySessionContext object", jsonParser.getCurrentLocation());
}
WebIdentitySessionContext webIdFederationData = new WebIdentitySessionContext();
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
String key = jsonParser.getCurrentName();
switch (key) {
case "attributes":
webIdFederationData.add(CloudTrailEventField.attributes.name(), parseAttributes());
break;
case "federatedProvider":
webIdFederationData.add(CloudTrailEventField.federatedProvider.name(), jsonParser.nextTextValue());
break;
default:
webIdFederationData.add(key, parseDefaultValue(key));
break;
}
}
return webIdFederationData;
}
/**
* Parses the {@link SessionContext} object.
* This runs only if the session is running with role-based or federated access permissions
* (in other words, temporary credentials in IAM).
*
* @param sessionContext
* @return the session issuer object.
* @throws IOException
*/
private SessionIssuer parseSessionIssuer(SessionContext sessionContext) throws IOException {
if (jsonParser.nextToken() != JsonToken.START_OBJECT) {
throw new JsonParseException("Not a SessionIssuer object", jsonParser.getCurrentLocation());
}
SessionIssuer sessionIssuer = new SessionIssuer();
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
String key = jsonParser.getCurrentName();
switch (key) {
case "type":
sessionIssuer.add(CloudTrailEventField.type.name(), this.jsonParser.nextTextValue());
break;
case "principalId":
sessionIssuer.add(CloudTrailEventField.principalId.name(), this.jsonParser.nextTextValue());
break;
case "arn":
sessionIssuer.add(CloudTrailEventField.arn.name(), this.jsonParser.nextTextValue());
break;
case "accountId":
sessionIssuer.add(CloudTrailEventField.accountId.name(), this.jsonParser.nextTextValue());
break;
case "userName":
sessionIssuer.add(CloudTrailEventField.userName.name(), this.jsonParser.nextTextValue());
break;
default:
sessionIssuer.add(key, this.parseDefaultValue(key));
break;
}
}
return sessionIssuer;
}
/**
* Parses the event readOnly attribute.
*
* @param eventData
*
* @throws JsonParseException
* @throws IOException
*/
private void parseReadOnly(CloudTrailEventData eventData) throws IOException {
jsonParser.nextToken();
Boolean readOnly = null;
if (jsonParser.getCurrentToken() != JsonToken.VALUE_NULL) {
readOnly = jsonParser.getBooleanValue();
}
eventData.add(CloudTrailEventField.readOnly.name(), readOnly);
}
/**
* Parses the event managementEvent attribute.
* @param eventData the interesting {@link CloudTrailEventData}
* @throws IOException
*/
private void parseManagementEvent(CloudTrailEventData eventData) throws IOException {
jsonParser.nextToken();
Boolean managementEvent = null;
if (jsonParser.getCurrentToken() != JsonToken.VALUE_NULL) {
managementEvent = jsonParser.getBooleanValue();
}
eventData.add(CloudTrailEventField.managementEvent.name(), managementEvent);
}
/**
* Parses a list of Resource.
*
* @param eventData the resources belong to
* @throws IOException
*/
private void parseResources(CloudTrailEventData eventData) throws IOException {
JsonToken nextToken = jsonParser.nextToken();
if (nextToken == JsonToken.VALUE_NULL) {
eventData.add(CloudTrailEventField.resources.name(), null);
return;
}
if (nextToken != JsonToken.START_ARRAY) {
throw new JsonParseException("Not a list of resources object", jsonParser.getCurrentLocation());
}
List resources = new ArrayList();
while (jsonParser.nextToken() != JsonToken.END_ARRAY) {
resources.add(parseResource());
}
eventData.add(CloudTrailEventField.resources.name(), resources);
}
/**
* Parses a single Resource.
*
* @return a single resource
* @throws IOException
*/
private Resource parseResource() throws IOException {
//current token is ready consumed by parseResources
if (jsonParser.getCurrentToken() != JsonToken.START_OBJECT) {
throw new JsonParseException("Not a Resource object", jsonParser.getCurrentLocation());
}
Resource resource = new Resource();
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
String key = jsonParser.getCurrentName();
switch (key) {
default:
resource.add(key, parseDefaultValue(key));
break;
}
}
return resource;
}
/**
* Parses the {@link Addendum} in CloudTrailEventData
*
* @param eventData {@link CloudTrailEventData} must parse.
* @throws IOException
*/
private void parseAddendum(CloudTrailEventData eventData) throws IOException {
JsonToken nextToken = jsonParser.nextToken();
if (nextToken == JsonToken.VALUE_NULL) {
eventData.add(CloudTrailEventField.addendum.name(), null);
return;
}
if (nextToken != JsonToken.START_OBJECT) {
throw new JsonParseException("Not an Addendum object", jsonParser.getCurrentLocation());
}
Addendum addendum = new Addendum();
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
String key = jsonParser.getCurrentName();
switch (key) {
case "reason":
addendum.add(CloudTrailEventField.reason.name(), jsonParser.nextTextValue());
break;
case "updatedFields":
addendum.add(CloudTrailEventField.updatedFields.name(), jsonParser.nextTextValue());
break;
case "originalRequestID":
addendum.add(CloudTrailEventField.originalRequestID.name(), jsonParser.nextTextValue());
break;
case "originalEventID":
addendum.add(CloudTrailEventField.originalEventID.name(), jsonParser.nextTextValue());
break;
default:
addendum.add(key, parseDefaultValue(key));
break;
}
}
eventData.add(CloudTrailEventField.addendum.name(), addendum);
}
private void parseTlsDetails(CloudTrailEventData eventData) throws IOException {
JsonToken nextToken = jsonParser.nextToken();
if (nextToken == JsonToken.VALUE_NULL) {
eventData.add(CloudTrailEventField.tlsDetails.name(), null);
return;
}
if (nextToken != JsonToken.START_OBJECT) {
throw new JsonParseException("Not a TLS Details object", jsonParser.getCurrentLocation());
}
TlsDetails tlsDetails = new TlsDetails();
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
String key = jsonParser.getCurrentName();
switch (key) {
case "tlsVersion":
tlsDetails.add(CloudTrailEventField.tlsVersion.name(), jsonParser.nextTextValue());
break;
case "cipherSuite":
tlsDetails.add(CloudTrailEventField.cipherSuite.name(), jsonParser.nextTextValue());
break;
case "clientProvidedHostHeader":
tlsDetails.add(CloudTrailEventField.clientProvidedHostHeader.name(), jsonParser.nextTextValue());
break;
default:
tlsDetails.add(key, this.parseDefaultValue(key));
break;
}
}
eventData.add(CloudTrailEventField.tlsDetails.name(), tlsDetails);
}
/**
* Parses the event with key as default value.
*
* If the value is JSON null, then we will return null.
* If the value is JSON object (of starting with START_ARRAY or START_OBject) , then we will convert the object to String.
* If the value is JSON scalar value (non-structured object), then we will return simply return it as String.
*
* @param key
* @throws IOException
*/
private String parseDefaultValue(String key) throws IOException {
jsonParser.nextToken();
String value = null;
JsonToken currentToken = jsonParser.getCurrentToken();
if (currentToken != JsonToken.VALUE_NULL) {
if (currentToken == JsonToken.START_ARRAY || currentToken == JsonToken.START_OBJECT) {
JsonNode node = jsonParser.readValueAsTree();
value = node.toString();
} else {
value = jsonParser.getValueAsString();
}
}
return value;
}
/**
* Parses attributes as a Map, used in both parseWebIdentitySessionContext and parseSessionContext
*
* @return attributes for either session context or web identity session context
* @throws IOException
*/
private Map parseAttributes() throws IOException {
if (jsonParser.nextToken() != JsonToken.START_OBJECT) {
throw new JsonParseException("Not a Attributes object", jsonParser.getCurrentLocation());
}
Map attributes = new HashMap<>();
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
String key = jsonParser.getCurrentName();
String value = jsonParser.nextTextValue();
attributes.put(key, value);
}
return attributes;
}
/**
* Parses attributes as a Map, used to parse InsightStatistics
*
* @return attributes for insight statistics
* @throws IOException
*/
private Map parseAttributesWithDoubleValues() throws IOException {
if (jsonParser.nextToken() != JsonToken.START_OBJECT) {
throw new JsonParseException("Not an Attributes object", jsonParser.getCurrentLocation());
}
Map attributes = new HashMap<>();
while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
String key = jsonParser.getCurrentName();
Double value = jsonParser.getValueAsDouble();
attributes.put(key, value);
}
return attributes;
}
/**
* This method convert a String to UUID type. Currently EventID is in UUID type.
*
* @param str that need to convert to UUID
* @return the UUID.
*/
private UUID convertToUUID(String str) {
return UUID.fromString(str);
}
/**
* This method convert a String to Date type. When parse error happened return current date.
*
* @param dateInString the String to convert to Date
* @return Date the date and time in coordinated universal time
* @throws IOException
*/
private Date convertToDate(String dateInString) throws IOException {
Date date = null;
if (dateInString != null) {
try {
date = LibraryUtils.getUtcSdf().parse(dateInString);
} catch (ParseException e) {
throw new IOException("Cannot parse " + dateInString + " as Date", e);
}
}
return date;
}
}