Merge "b/163140302 Add schema validation for x-security-fresh extension"
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtensionSchemaValidator.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtensionSchemaValidator.java
index f4eb1c5..c6ad87c 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtensionSchemaValidator.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtensionSchemaValidator.java
@@ -29,6 +29,8 @@
       Resources.getResource("SecurityDefinitionsSchema.json");
   private static final URL SECURITY_RULES_SCHEMA_URL =
       Resources.getResource("SecurityRulesSchema.json");
+  private static final URL SECURITY_FRESH_SCHEMA_URL =
+      Resources.getResource("SecurityFreshSchema.json");
 
   private final JsonSchemaFactory jsonSchemaFactory;
 
@@ -60,6 +62,10 @@
           break;
         case X_SECURITY_RULES:
           errors = validateExtensionContent(SECURITY_RULES_SCHEMA_URL, extension);
+          break;
+        case X_SECURITY_FRESH:
+          errors = validateExtensionContent(SECURITY_FRESH_SCHEMA_URL, extension);
+          break;
       }
     } else {
       errors = defaultErrors(extension);
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionName.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionName.java
index 488d068..31c4629 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionName.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionName.java
@@ -8,7 +8,8 @@
   X_SECURITY_TYPE("x-security-type"),
   X_SECURITY_ALLOW("x-security-allow"),
   X_SECURITY_TYPE_DEFINITIONS("x-security-type-definitions"),
-  X_SECURITY_RULES("x-security-rules");
+  X_SECURITY_RULES("x-security-rules"),
+  X_SECURITY_FRESH("x-security-fresh");
 
   private final String extensionName;
 
diff --git a/oas-core/src/main/resources/SecurityFreshSchema.json b/oas-core/src/main/resources/SecurityFreshSchema.json
new file mode 100644
index 0000000..00a1f63
--- /dev/null
+++ b/oas-core/src/main/resources/SecurityFreshSchema.json
@@ -0,0 +1,97 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "Security fresh schema",
+  "type": "object",
+  "properties": {
+    "last-reviewed": {
+      "type": "string",
+      "format":  "date-time"
+    },
+    "exempt": {
+      "type": "string",
+      "enum": ["true", "false", "default"]
+    },
+    "owners": {
+      "type": "array",
+      "items": {
+        "type": "string"
+      }
+    },
+    "review-frequency": {
+      "anyOf": [
+        {
+          "type": "string",
+          "enum": ["indefinite"]
+        },
+        {
+          "type": "integer",
+          "minimum": 1
+        }
+      ]
+    }
+  },
+  "required": [
+    "last-reviewed"
+  ],
+  "additionalProperties": false,
+  "tests":[
+    {
+      "id": "VALID_1",
+      "description": "List of strings",
+      "data": {
+        "last-reviewed": "2019-11-13T20:20:39+00:00",
+        "exempt": "true",
+        "owners": ["customemail@customdomain.com"],
+        "review-frequency": 60
+      },
+      "valid": true
+    },
+    {
+      "id": "VALID_2",
+      "description": "only last-reviewed",
+      "data": {
+        "last-reviewed": "2019-11-13T20:20:39+00:00"
+      },
+      "valid": true
+    },
+    {
+      "id": "VALID_3",
+      "description": "indefinite review frequency",
+      "data": {
+        "last-reviewed": "2019-11-13T20:20:39+00:00",
+        "exempt": "true",
+        "owners": ["customemail@customdomain.com"],
+        "review-frequency": "indefinite"
+      },
+      "valid": true
+    },
+    {
+      "id": "INVALID_1",
+      "description": "without last-review field",
+      "data": {},
+      "valid": false
+    },
+    {
+      "id": "INVALID_2",
+      "description": "last-reviewed in non-ISO8601 time format",
+      "data": {
+        "last-reviewed": "11-13-2019T20:20:39+00:00",
+        "exempt": "true",
+        "owners": ["customemail@customdomain.com"],
+        "review-frequency": "indefinite"
+      },
+      "valid": false
+    },
+    {
+      "id": "INVALID_3",
+      "description": "zero review frequency",
+      "data": {
+        "last-reviewed": "2019-11-13T20:20:39+00:00",
+        "exempt": "true",
+        "owners": ["customemail@customdomain.com"],
+        "review-frequency": 0
+      },
+      "valid": false
+    }
+  ]
+}
\ No newline at end of file
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtensionSchemaValidatorTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtensionSchemaValidatorTest.java
index 7112286..f3841ab 100644
--- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtensionSchemaValidatorTest.java
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtensionSchemaValidatorTest.java
@@ -1,5 +1,6 @@
 package com.apigee.security.oas.extendedvalidator;
 
+import static com.apigee.security.oas.extendedvalidator.ExtensionName.X_SECURITY_FRESH;
 import static com.apigee.security.oas.extendedvalidator.ExtensionName.X_SECURITY_RULES;
 import static com.apigee.security.oas.extendedvalidator.ExtensionName.X_SECURITY_TYPE;
 import static com.apigee.security.oas.extendedvalidator.ExtensionName.X_SECURITY_TYPE_DEFINITIONS;
@@ -53,6 +54,9 @@
       Resources.getResource("SecurityDefinitionsSchema.json");
   private static final URL SECURITY_RULES_SCHEMA_URL =
       Resources.getResource("SecurityRulesSchema.json");
+  private static final URL SECURITY_FRESH_SCHEMA_URL =
+      Resources.getResource("SecurityFreshSchema.json");
+
   private static final JsonNode emptyContent = new ObjectMapper().valueToTree("[]");
   private static final ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>>
       extensionPath =
@@ -114,7 +118,9 @@
                       SECURITY_DEFINITIONS_SCHEMA_URL,
                       X_SECURITY_TYPE_DEFINITIONS.getExtensionName()),
                   buildTestParameters(
-                      SECURITY_RULES_SCHEMA_URL, X_SECURITY_RULES.getExtensionName()))));
+                      SECURITY_RULES_SCHEMA_URL, X_SECURITY_RULES.getExtensionName()),
+                  buildTestParameters(
+                      SECURITY_FRESH_SCHEMA_URL, X_SECURITY_FRESH.getExtensionName()))));
     }
 
     @Test