Merge "b/163175421 Add scope validation for x-security-fresh and x-security-rules"
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtensionScopeValidator.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtensionScopeValidator.java
index 8ff013a..ac576b2 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtensionScopeValidator.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtensionScopeValidator.java
@@ -1,9 +1,13 @@
 package com.apigee.security.oas.extendedvalidator;
 
 import static com.apigee.security.oas.extendedvalidator.ErrorMessage.X_SECURITY_ALLOW_SCOPE_ERROR;
+import static com.apigee.security.oas.extendedvalidator.ErrorMessage.X_SECURITY_FRESH_SCOPE_ERROR;
+import static com.apigee.security.oas.extendedvalidator.ErrorMessage.X_SECURITY_RULES_SCOPE_ERROR;
 import static com.apigee.security.oas.extendedvalidator.ErrorMessage.X_SECURITY_TYPE_DEFINITIONS_SCOPE_ERROR;
 import static com.apigee.security.oas.extendedvalidator.ErrorMessage.X_SECURITY_TYPE_SCOPE_ERROR;
 import static com.apigee.security.oas.extendedvalidator.ExtensionName.X_SECURITY_ALLOW;
+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;
 import static com.apigee.security.oas.extendedvalidator.ExtensionName.valueOfExtensionName;
@@ -17,6 +21,7 @@
 import com.google.common.flogger.FluentLogger;
 import java.util.Optional;
 import org.openapi4j.parser.model.OpenApiSchema;
+import org.openapi4j.parser.model.v3.Info;
 import org.openapi4j.parser.model.v3.OpenApi3;
 import org.openapi4j.parser.model.v3.Operation;
 import org.openapi4j.parser.model.v3.Parameter;
@@ -30,7 +35,9 @@
           ImmutableMap.of(
               X_SECURITY_TYPE, X_SECURITY_TYPE_SCOPE_ERROR,
               X_SECURITY_ALLOW, X_SECURITY_ALLOW_SCOPE_ERROR,
-              X_SECURITY_TYPE_DEFINITIONS, X_SECURITY_TYPE_DEFINITIONS_SCOPE_ERROR));
+              X_SECURITY_TYPE_DEFINITIONS, X_SECURITY_TYPE_DEFINITIONS_SCOPE_ERROR,
+              X_SECURITY_FRESH, X_SECURITY_FRESH_SCOPE_ERROR,
+              X_SECURITY_RULES, X_SECURITY_RULES_SCOPE_ERROR));
 
   private static final ImmutableMap<ExtensionName, ImmutableSet<Class<? extends OpenApiSchema>>>
       allowedParentsMap =
@@ -38,7 +45,9 @@
               ImmutableMap.of(
                   X_SECURITY_TYPE, ImmutableSet.of(Schema.class, Parameter.class),
                   X_SECURITY_ALLOW, ImmutableSet.of(Operation.class),
-                  X_SECURITY_TYPE_DEFINITIONS, ImmutableSet.of(OpenApi3.class)));
+                  X_SECURITY_TYPE_DEFINITIONS, ImmutableSet.of(OpenApi3.class),
+                  X_SECURITY_FRESH, ImmutableSet.of(OpenApi3.class, Info.class),
+                  X_SECURITY_RULES, ImmutableSet.of(OpenApi3.class)));
 
   /**
    * Validates the scope of an supported {@link Extension} by contrasting it against its appropriate
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ErrorMessage.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ErrorMessage.java
index 40b6c53..fe13127 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ErrorMessage.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ErrorMessage.java
@@ -10,6 +10,9 @@
       "extension should be under a paths operation object like get, post, patch, etc."),
   X_SECURITY_TYPE_DEFINITIONS_SCOPE_ERROR(
       "INVALID_SCOPE", "extension should be on the top-level scope."),
+  X_SECURITY_FRESH_SCOPE_ERROR(
+      "INVALID_SCOPE", "extension should be on top-level or sub-level scope."),
+  X_SECURITY_RULES_SCOPE_ERROR("INVALID_SCOPE", "extension should be on top-level scope."),
   INVALID_SCHEMA("INVALID_SCHEMA", "extension has an invalid schema.");
 
   private final String errorType;
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtensionScopeValidatorTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtensionScopeValidatorTest.java
index aab22ec..dfbf7fd 100644
--- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtensionScopeValidatorTest.java
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtensionScopeValidatorTest.java
@@ -1,6 +1,8 @@
 package com.apigee.security.oas.extendedvalidator;
 
 import static com.apigee.security.oas.extendedvalidator.ExtensionName.X_SECURITY_ALLOW;
+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;
 import static org.assertj.core.api.Assertions.assertThat;
@@ -151,4 +153,52 @@
         .extracting(ExtensionValidationMessage::type)
         .isEqualTo("INVALID_SCOPE");
   }
+
+  @Test
+  public void validate_validScopeSecurityFreshExtension_returnsEmptyErrorSet() {
+    ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> path =
+        createPathList(new Class[] {OpenApi3.class});
+    when(extension.getExtensionName()).thenReturn(X_SECURITY_FRESH.getExtensionName());
+    when(extension.getExtensionPath()).thenReturn(path);
+
+    assertThat(validator.validate(extension)).isEmpty();
+  }
+
+  @Test
+  public void validate_invalidScopeSecurityFreshExtension_returnsInvalidScopeErrorType() {
+    ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> path =
+        createPathList(new Class[] {OpenApi3.class, Path.class});
+    when(extension.getExtensionName()).thenReturn(X_SECURITY_FRESH.getExtensionName());
+    when(extension.getExtensionPath()).thenReturn(path);
+
+    assertThat(validator.validate(extension))
+        .hasSize(1)
+        .first()
+        .extracting(ExtensionValidationMessage::type)
+        .isEqualTo("INVALID_SCOPE");
+  }
+
+  @Test
+  public void validate_validScopeSecurityRulesExtension_returnsEmptyErrorSet() {
+    ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> path =
+        createPathList(new Class[] {OpenApi3.class});
+    when(extension.getExtensionName()).thenReturn(X_SECURITY_RULES.getExtensionName());
+    when(extension.getExtensionPath()).thenReturn(path);
+
+    assertThat(validator.validate(extension)).isEmpty();
+  }
+
+  @Test
+  public void validate_invalidScopeSecurityRulesExtension_returnsInvalidScopeErrorType() {
+    ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> path =
+        createPathList(new Class[] {OpenApi3.class, Path.class});
+    when(extension.getExtensionName()).thenReturn(X_SECURITY_RULES.getExtensionName());
+    when(extension.getExtensionPath()).thenReturn(path);
+
+    assertThat(validator.validate(extension))
+        .hasSize(1)
+        .first()
+        .extracting(ExtensionValidationMessage::type)
+        .isEqualTo("INVALID_SCOPE");
+  }
 }