diff --git a/src/main/java/io/digitalstate/stix/datamarkings/objects/Tlps.java b/src/main/java/io/digitalstate/stix/datamarkings/objects/Tlps.java new file mode 100644 index 0000000..0c93f2e --- /dev/null +++ b/src/main/java/io/digitalstate/stix/datamarkings/objects/Tlps.java @@ -0,0 +1,71 @@ +package io.digitalstate.stix.datamarkings.objects; + +import io.digitalstate.stix.common.StixInstant; +import io.digitalstate.stix.datamarkings.MarkingDefinition; + +public class Tlps { + + public static final MarkingDefinition TLP_WHITE = Tlps.getTlpWhiteMD(); + public static final MarkingDefinition TLP_GREEN = Tlps.getTlpGreenMD(); + public static final MarkingDefinition TLP_AMBER = Tlps.getTlpAmberMD(); + public static final MarkingDefinition TLP_RED = Tlps.getTlpRedMD(); + + public static final String TLP_WHITE_VALUE = "white"; + public static final String TLP_GREEN_VALUE = "green"; + public static final String TLP_AMBER_VALUE = "amber"; + public static final String TLP_RED_VALUE = "red"; + + public static final String TLP_TYPE_VALUE = "tlp"; + + + /** + * Factory methods to create the known types + */ + private static MarkingDefinition getTlpWhiteMD() { + MarkingDefinition.Builder builder = MarkingDefinition.builder() + .id("marking-definition--613f2e26-407d-48c7-9eca-b8e91df99dc9") + .definitionType(TLP_TYPE_VALUE) + .created(StixInstant.parse("2017-01-20T00:00:00.000Z")) + .definition(Tlp.builder() + .tlp(TLP_WHITE_VALUE) + .build()); + + return builder.build(); + } + + private static MarkingDefinition getTlpGreenMD() { + MarkingDefinition.Builder builder = MarkingDefinition.builder() + .id("marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da") + .definitionType(TLP_TYPE_VALUE) + .created(StixInstant.parse("2017-01-20T00:00:00.000Z")) + .definition(Tlp.builder() + .tlp(TLP_GREEN_VALUE) + .build()); + + return builder.build(); + } + + private static MarkingDefinition getTlpAmberMD() { + MarkingDefinition.Builder builder = MarkingDefinition.builder() + .id("marking-definition--f88d31f6-486f-44da-b317-01333bde0b82") + .definitionType(TLP_TYPE_VALUE) + .created(StixInstant.parse("2017-01-20T00:00:00.000Z")) + .definition(Tlp.builder() + .tlp(TLP_AMBER_VALUE) + .build()); + + return builder.build(); + } + + private static MarkingDefinition getTlpRedMD() { + MarkingDefinition.Builder builder = MarkingDefinition.builder() + .id("marking-definition--5e57c739-391a-4eb3-b6be-7d15ca92d5ed") + .definitionType(TLP_TYPE_VALUE) + .created(StixInstant.parse("2017-01-20T00:00:00.000Z")) + .definition(Tlp.builder() + .tlp(TLP_RED_VALUE) + .build()); + + return builder.build(); + } +} diff --git a/src/main/java/io/digitalstate/stix/json/StixParsers.java b/src/main/java/io/digitalstate/stix/json/StixParsers.java index bc253ee..c8d1e8b 100644 --- a/src/main/java/io/digitalstate/stix/json/StixParsers.java +++ b/src/main/java/io/digitalstate/stix/json/StixParsers.java @@ -118,7 +118,7 @@ public static BundleObject parseBundle(String bundleJsonString) throws IOExcepti try { return getJsonMapper().readValue(bundleJsonString, BundleObject.class); } catch (IOException ex) { - if (ValidationException.class.isAssignableFrom(ex.getCause().getClass())) { + if (ex.getCause() != null && ValidationException.class.isAssignableFrom(ex.getCause().getClass())) { throw new StixParserValidationException((ValidationException) ex.getCause()); } else { throw ex; @@ -130,7 +130,7 @@ public static BundleableObject parseObject(String objectJsonString) throws IOExc try { return getJsonMapper().readValue(objectJsonString, BundleableObject.class); } catch (IOException ex) { - if (ValidationException.class.isAssignableFrom(ex.getCause().getClass())) { + if (ex.getCause() != null && ValidationException.class.isAssignableFrom(ex.getCause().getClass())) { throw new StixParserValidationException((ValidationException) ex.getCause()); } else { throw ex; diff --git a/src/test/groovy/faker/StixMockDataGenerator.groovy b/src/test/groovy/faker/StixMockDataGenerator.groovy index f22ad3a..bab02c6 100644 --- a/src/test/groovy/faker/StixMockDataGenerator.groovy +++ b/src/test/groovy/faker/StixMockDataGenerator.groovy @@ -11,6 +11,7 @@ import io.digitalstate.stix.datamarkings.GranularMarking import io.digitalstate.stix.datamarkings.MarkingDefinition import io.digitalstate.stix.datamarkings.objects.Statement import io.digitalstate.stix.datamarkings.objects.Tlp +import io.digitalstate.stix.datamarkings.objects.Tlps import io.digitalstate.stix.sdo.DomainObject import io.digitalstate.stix.sdo.objects.* import io.digitalstate.stix.sdo.types.* @@ -1980,7 +1981,10 @@ public class StixMockDataGenerator { switch (type) { case "tlp": - builder.definition(mockTlpMakingObject()) + // builder.definition(mockTlpMakingObject()) + // If we generate a TLP, we will just use the STIX Spec TLPs to match the spec. + // You can uncomment the previous builder line if you want to go back to random TLP creation + return mockTlpMakingDef() break case "statement": builder.definition(mockStatementMarkingObject()) @@ -2018,6 +2022,27 @@ public class StixMockDataGenerator { return builder.build() } + /** + * Generates a TLP Marking Definition based on the STIX Spec default TLP values + * @return MarkingDefinition for random TLP from the STIX Spec. + */ + MarkingDefinition mockTlpMakingDef() { + String tlpValue = mock.fromStrings(new TlpLevels().getAllTerms().toList()).get() + + switch (tlpValue){ + case "white": + return Tlps.TLP_WHITE + case "green": + return Tlps.TLP_GREEN + case "amber": + return Tlps.TLP_AMBER + case "red": + return Tlps.TLP_RED + default: + throw new IllegalArgumentException("TLP Value is not valid") + } + } + GranularMarking mockGranularMarking() { GranularMarking.Builder builder = GranularMarking.builder() diff --git a/src/test/groovy/stix/datamarkings/TLPmarkingsSpec.groovy b/src/test/groovy/stix/datamarkings/TLPmarkingsSpec.groovy new file mode 100644 index 0000000..cf322cd --- /dev/null +++ b/src/test/groovy/stix/datamarkings/TLPmarkingsSpec.groovy @@ -0,0 +1,122 @@ +package stix.datamarkings + +import org.skyscreamer.jsonassert.JSONAssert +import org.skyscreamer.jsonassert.JSONCompareMode + +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.ObjectMapper + +import io.digitalstate.stix.bundle.Bundle +import io.digitalstate.stix.common.StixInstant +import io.digitalstate.stix.datamarkings.MarkingDefinition +import io.digitalstate.stix.datamarkings.objects.Tlps +import io.digitalstate.stix.json.StixParsers +import io.digitalstate.stix.sdo.objects.Indicator +import spock.lang.Shared +import spock.lang.Specification + +class TlpMarkingsSpec extends Specification { + + @Shared + ObjectMapper mapper = new ObjectMapper() + + def "TLP Defaults Creation Test: WHITE"() { + when: "Create TLP:white from pre-built TLPs" + + MarkingDefinition originalMarkingDefinition = Tlps.TLP_WHITE + + then: "Convert Marking Definition to Json" + JsonNode originalJson = mapper.readTree(originalMarkingDefinition.toJsonString()) + String originalJsonString = mapper.writeValueAsString(originalJson) +// println "Original Json: ${originalJsonString}" + + then: "Parse Json back into Marking Definition Object" + MarkingDefinition parsedMarkingDefinition = (MarkingDefinition)StixParsers.parseObject(originalJsonString) + MarkingDefinition parsedMarkingDefinitionGeneric = StixParsers.parse(originalJsonString, MarkingDefinition.class) +// println "Parsed Object: ${parsedMarkingDefinition}" + + //@TODO needs to be setup to handle dehydrated object comparison +// then: "Parsed object should match Original object" +// assert originalMarkingDefinition == parsedMarkingDefinition + + then: "Convert Parsed Marking Definition Object back to into Json" + JsonNode newJson = mapper.readTree(parsedMarkingDefinition.toJsonString()) + String newJsonString = mapper.writeValueAsString(newJson) +// println "New Json: ${newJsonString}" + + then: "New Json should match Original Json" + JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) + + } + + def "Test indicator with Default TLP markings"() { + when: "Create TLP:green" + + MarkingDefinition TlpGreen = Tlps.TLP_GREEN + StixInstant now = new StixInstant() + + Indicator ind = Indicator.builder() + .id("indicator--59ccb738-921a-4941-8ab2-33da522bd4e1") + .created(now) + .modified(now) + .addLabel("malicious-activity") + .name("128.0.0.1") + .pattern("[ipv4-addr:value = '128.0.0.1']") + .validFrom(now) + .addObjectMarkingRef(TlpGreen) + .build() + + then: "Convert Marking Definition to Json" + JsonNode originalJson = mapper.readTree(ind.toJsonString()) + String originalJsonString = mapper.writeValueAsString(originalJson) +// println "Original Json: ${originalJsonString}" + + then: "Parse Json back into Marking Definition Object" + Indicator parsed = (Indicator)StixParsers.parseObject(originalJsonString) + Indicator parsedGeneric = StixParsers.parse(originalJsonString, Indicator.class) +// println "Parsed Object: ${parsed}" + + //@TODO needs to be setup to handle dehydrated object comparison +// then: "Parsed object should match Original object" +// assert originalMarkingDefinition == parsedMarkingDefinition + + then: "Convert Parsed Marking Definition Object back to into Json" + JsonNode newJson = mapper.readTree(parsed.toJsonString()) + String newJsonString = mapper.writeValueAsString(newJson) +// println "New Json: ${newJsonString}" + + then: "New Json should match Original Json" + JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) + + } + + def "bundle with statement and tlp"() { + when:"setup file access to bundle" + + String bundleJson = getClass() + .getResource("/stix/baseline/json/sdo/markings/datamarkings.json").getText("UTF-8") + + then: "Parse json into bundle" + Bundle bundle = (Bundle)StixParsers.parseBundle(bundleJson) + println bundle.inspect() + println bundle.toJsonString() + + then: "Convert Bundle to Json" + JsonNode originalJson = mapper.readTree(bundle.toJsonString()) + String originalJsonString = mapper.writeValueAsString(originalJson) + println "Original Json: ${originalJsonString}" + + then: "Parse Json back into Bundle Object" + Bundle parsed = StixParsers.parseBundle(originalJsonString) + println "Parsed Object: ${parsed}" + + then: "Convert Parsed Bundlen Object back to into Json" + JsonNode newJson = mapper.readTree(parsed.toJsonString()) + String newJsonString = mapper.writeValueAsString(newJson) + println "New Json: ${newJsonString}" + + then: "New Json should match Original Json" + JSONAssert.assertEquals(originalJsonString, newJsonString, JSONCompareMode.NON_EXTENSIBLE) + + } +} diff --git a/src/test/resources/stix/baseline/json/sdo/markings/datamarkings.json b/src/test/resources/stix/baseline/json/sdo/markings/datamarkings.json new file mode 100644 index 0000000..5eece9b --- /dev/null +++ b/src/test/resources/stix/baseline/json/sdo/markings/datamarkings.json @@ -0,0 +1,42 @@ +{ + "type": "bundle", + "id": "bundle--6fab341c-36c5-4a7f-be29-0a6e3b85e7b0", + "spec_version": "2.0", + "objects": [ + { + "type": "marking-definition", + "id": "marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da", + "created": "2016-08-01T00:00:00.000Z", + "definition_type": "statement", + "definition": { + "statement": "Copyright 2016, Example Corp" + } + }, + { + "type": "marking-definition", + "id": "marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da", + "created": "2017-01-20T00:00:00.000Z", + "definition_type": "tlp", + "definition": { + "tlp": "green" + } + }, + { + "type": "indicator", + "id": "indicator--59ccb738-921a-4941-8ab2-33da522bd4e1", + "valid_from": "2019-05-16T14:41:39.655Z", + "name": "128.0.0.1", + "created": "2019-05-16T14:41:39.655Z", + "modified": "2019-05-16T14:41:39.655Z", + "revoked": false, + "labels": [ + "malicious-activity" + ], + "pattern": "[ipv4-addr:value = '128.0.0.1']", + "object_marking_refs": [ + "marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da", + "marking-definition--34098fce-860f-48ae-8e50-ebd3cc5e41da" + ] + } + ] +}