Merge "b/163430475 Add missing traversal test classes"
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtendedValidator.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtendedValidator.java
index 18400b8..f7b7551 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtendedValidator.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtendedValidator.java
@@ -1,5 +1,7 @@
package com.apigee.security.oas.extendedvalidator;
+import static com.apigee.security.oas.extendedvalidator.ExtensionName.valueOfExtensionName;
+
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
@@ -10,19 +12,44 @@
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private final TraversalHelperFactory traversalHelperFactory;
+ private final ExtensionSchemaValidator schemaValidator;
+ private final ExtensionScopeValidator scopeValidator;
@Inject
- BaseExtendedValidator(TraversalHelperFactory traversalHelperFactory) {
+ BaseExtendedValidator(
+ TraversalHelperFactory traversalHelperFactory,
+ ExtensionSchemaValidator schemaValidator,
+ ExtensionScopeValidator scopeValidator) {
this.traversalHelperFactory = traversalHelperFactory;
+ this.schemaValidator = schemaValidator;
+ this.scopeValidator = scopeValidator;
}
@Override
- public void validate(OpenApi3 openApiSpec) {
+ public ImmutableSet<ExtensionValidationMessage> validate(OpenApi3 openApiSpec) {
+ ImmutableSet<Extension> extensions = collectExtensions(openApiSpec);
+
+ logger.atInfo().log("Found %s extensions", extensions.size());
+
+ return validateSchemaAndScope(extensions);
+ }
+
+ private ImmutableSet<Extension> collectExtensions(OpenApi3 openApiSpec) {
TraversalHelper traversalHelper = traversalHelperFactory.create(ImmutableList.of());
traversalHelper.sendOpenApiTraversal(openApiSpec);
- ImmutableSet<Extension> extensions = traversalHelper.traverse();
+ return traversalHelper.traverse();
+ }
- // TODO(b/161441872) : Add extension validation logic
- logger.atInfo().log("%s", extensions);
+ private ImmutableSet<ExtensionValidationMessage> validateSchemaAndScope(
+ ImmutableSet<Extension> extensions) {
+
+ return extensions.stream()
+ .filter(extension -> valueOfExtensionName(extension.getExtensionName()).isPresent())
+ .flatMap(
+ extension ->
+ ImmutableSet.<ExtensionValidationMessage>builder()
+ .addAll(extension.validate(schemaValidator))
+ .addAll(extension.validate(scopeValidator)).build().stream())
+ .collect(ImmutableSet.toImmutableSet());
}
}
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/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidator.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidator.java
index dae3f6b..44cc68c 100644
--- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidator.java
+++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidator.java
@@ -1,5 +1,6 @@
package com.apigee.security.oas.extendedvalidator;
+import com.google.common.collect.ImmutableSet;
import org.openapi4j.parser.model.v3.OpenApi3;
/**
@@ -9,5 +10,5 @@
public interface ExtendedValidator {
/** Validates ApiSecurityTool's extensions in passed {@link OpenApi3} object. */
- void validate(OpenApi3 openApi3);
+ ImmutableSet<ExtensionValidationMessage> validate(OpenApi3 openApi3);
}
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtendedValidatorTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtendedValidatorTest.java
index 46871da..86be8d9 100644
--- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtendedValidatorTest.java
+++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtendedValidatorTest.java
@@ -1,10 +1,15 @@
package com.apigee.security.oas.extendedvalidator;
+import static com.apigee.security.oas.extendedvalidator.ExtensionName.X_SECURITY_TYPE;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -23,7 +28,13 @@
@Rule public final MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
@Mock private OpenApi3 openApiSpec;
+ @Mock private Extension supportedExtension;
+ @Mock private Extension unsupportedExtension;
+ @Mock private ExtensionValidationMessage schemaMessage;
+ @Mock private ExtensionValidationMessage scopeMessage;
+ @Mock private ExtensionSchemaValidator schemaValidator;
+ @Mock private ExtensionScopeValidator scopeValidator;
@Mock private TraversalHelperFactory traversalHelperFactory;
@Mock private TraversalHelper traversalHelper;
@InjectMocks private BaseExtendedValidator baseExtendedValidator;
@@ -32,12 +43,45 @@
@Before
public void setup() {
when(traversalHelperFactory.create(any(ImmutableList.class))).thenReturn(traversalHelper);
+ when(traversalHelper.traverse()).thenReturn(ImmutableSet.of(unsupportedExtension));
}
@Test
public void validate_openApiSpec_callsTraversalCoordinatorTraverse() {
+ when(unsupportedExtension.getExtensionName()).thenReturn("x-custom");
+
baseExtendedValidator.validate(openApiSpec);
verify(traversalHelper).sendOpenApiTraversal(openApiSpec);
}
+
+ @Test
+ public void validate_supportedExtension_callsExtensionValidate() {
+ when(supportedExtension.getExtensionName()).thenReturn(X_SECURITY_TYPE.getExtensionName());
+ when(supportedExtension.validate(any(ExtensionValidator.class))).thenReturn(ImmutableSet.of());
+ when(traversalHelper.traverse()).thenReturn(ImmutableSet.of(supportedExtension));
+
+ baseExtendedValidator.validate(openApiSpec);
+
+ verify(supportedExtension, atLeastOnce()).validate(any(ExtensionValidator.class));
+ }
+
+ @Test
+ public void validate_unsupportedExtension_shouldNotCallExtensionValidate() {
+ when(unsupportedExtension.getExtensionName()).thenReturn("x-custom");
+
+ baseExtendedValidator.validate(openApiSpec);
+
+ verify(unsupportedExtension, never()).validate(any(ExtensionValidator.class));
+ }
+
+ @Test
+ public void validate_withExtensions_returnsExactExtensionValidationMessages() {
+ when(supportedExtension.getExtensionName()).thenReturn(X_SECURITY_TYPE.getExtensionName());
+ when(traversalHelper.traverse()).thenReturn(ImmutableSet.of(supportedExtension));
+ when(supportedExtension.validate(schemaValidator)).thenReturn(ImmutableSet.of(schemaMessage));
+ when(supportedExtension.validate(scopeValidator)).thenReturn(ImmutableSet.of(scopeMessage));
+
+ assertThat(baseExtendedValidator.validate(openApiSpec)).hasSize(2);
+ }
}
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");
+ }
}