b/162508047 Add Path Traversal Change-Id: I8a0456c6a2d78649984fe0fa03819318f2bd9e25
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseTraversalHelper.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseTraversalHelper.java index 701ba8a..58e4e14 100644 --- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseTraversalHelper.java +++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseTraversalHelper.java
@@ -15,6 +15,7 @@ import org.openapi4j.parser.model.v3.OpenApi3; import org.openapi4j.parser.model.v3.Operation; import org.openapi4j.parser.model.v3.Parameter; +import org.openapi4j.parser.model.v3.Path; import org.openapi4j.parser.model.v3.Response; import org.openapi4j.parser.model.v3.SecurityRequirement; import org.openapi4j.parser.model.v3.Server; @@ -116,6 +117,17 @@ } @Override + public void sendPathTraversals(ImmutableMap<String, Path> pathMap) { + Optional.ofNullable(pathMap) + .ifPresent( + paths -> + paths.forEach( + (name, path) -> + coordinator.handleTraversalCommand( + factory.create(path, traversalPath, name)))); + } + + @Override public void sendResponseTraversals(ImmutableMap<String, Response> responses) { Optional.ofNullable(responses) .ifPresent( @@ -139,8 +151,8 @@ } @Override - public void sendServerTraversals(ImmutableList<Server> serversList) { - Optional.ofNullable(serversList) + public void sendServerTraversals(ImmutableList<Server> serverList) { + Optional.ofNullable(serverList) .ifPresent( servers -> servers.forEach(
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/CallbackTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/CallbackTraversal.java index ca89f3c..7ed41fc 100644 --- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/CallbackTraversal.java +++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/CallbackTraversal.java
@@ -29,6 +29,10 @@ @Override public void traverse() { // TODO(b/161441872): Process extensions. - // TODO(b/162508047): Add path object traversal and callback object traversal logic. + + TraversalHelper traversalHelper = traversalHelperFactory.create(getUpdatedTraversalPath()); + + traversalHelper.sendPathTraversals( + Immutables.toImmutableMap(openApiSchemaObj.getCallbackPaths())); } }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversal.java index 1709d93..07b547f 100644 --- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversal.java +++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversal.java
@@ -1,6 +1,7 @@ package com.apigee.security.oas.extendedvalidator; import static com.apigee.security.oas.extendedvalidator.Immutables.toImmutableList; +import static com.apigee.security.oas.extendedvalidator.Immutables.toImmutableMap; import com.google.common.collect.ImmutableList; import com.google.inject.assistedinject.Assisted; @@ -29,6 +30,8 @@ traversalHelper.sendInfoTraversal(openApiSchemaObj.getInfo()); traversalHelper.sendServerTraversals(toImmutableList(openApiSchemaObj.getServers())); traversalHelper.sendTagTraversals(toImmutableList(openApiSchemaObj.getTags())); - // TODO(b/162508047): Add path object traversal and callback object traversal logic. + traversalHelper.sendPathTraversals(toImmutableMap(openApiSchemaObj.getPaths())); + // TODO(b/162682119): Send OpenApiSpecification SecurityRequirements to TraversalHelper. + // TODO(b/162677159): Send Components traversal. } }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/PathTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/PathTraversal.java new file mode 100644 index 0000000..5ba0797 --- /dev/null +++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/PathTraversal.java
@@ -0,0 +1,42 @@ +package com.apigee.security.oas.extendedvalidator; + +import com.google.common.collect.ImmutableList; +import com.google.inject.assistedinject.Assisted; +import java.util.Map; +import java.util.Optional; +import javax.inject.Inject; +import org.openapi4j.parser.model.OpenApiSchema; +import org.openapi4j.parser.model.v3.Path; + +/** A {@link Traversal} that traverses a {@link Path} object. */ +final class PathTraversal extends Traversal<Path> implements PathTraversalCommand { + + @Inject + PathTraversal( + TraversalHelperFactory traversalHelperFactory, + ExtensionValidationIntegrator extensionValidationIntegrator, + @Assisted + ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath, + @Assisted Path openApiSchemaObj, + @Assisted String name) { + super( + traversalHelperFactory, + extensionValidationIntegrator, + traversalPath, + openApiSchemaObj, + name); + } + + @Override + public void traverse() { + // TODO(b/161441872): Process extensions. + + TraversalHelper traversalHelper = traversalHelperFactory.create(getUpdatedTraversalPath()); + + traversalHelper.sendParameterTraversals( + Immutables.toImmutableList(openApiSchemaObj.getParameters())); + traversalHelper.sendServerTraversals(Immutables.toImmutableList(openApiSchemaObj.getServers())); + traversalHelper.sendOperationTraversals( + Immutables.toImmutableMap(openApiSchemaObj.getOperations())); + } +}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/PathTraversalCommand.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/PathTraversalCommand.java new file mode 100644 index 0000000..0a3db17 --- /dev/null +++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/PathTraversalCommand.java
@@ -0,0 +1,4 @@ +package com.apigee.security.oas.extendedvalidator; + +/** A {@link TraversalCommand} interface for {@link PathTraversal}. */ +public interface PathTraversalCommand extends TraversalCommand {}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TagTraversal.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TagTraversal.java index 1300951..c6e9a40 100644 --- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TagTraversal.java +++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TagTraversal.java
@@ -26,6 +26,7 @@ // TODO(b/161441872): Process extensions. TraversalHelper traversalHelper = traversalHelperFactory.create(getUpdatedTraversalPath()); + traversalHelper.sendExternalDocsTraversal(openApiSchemaObj.getExternalDocs()); } }
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactory.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactory.java index 2167c17..654187b 100644 --- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactory.java +++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactory.java
@@ -12,6 +12,7 @@ import org.openapi4j.parser.model.v3.OpenApi3; import org.openapi4j.parser.model.v3.Operation; import org.openapi4j.parser.model.v3.Parameter; +import org.openapi4j.parser.model.v3.Path; import org.openapi4j.parser.model.v3.Response; import org.openapi4j.parser.model.v3.SecurityRequirement; import org.openapi4j.parser.model.v3.Server; @@ -56,6 +57,11 @@ Parameter parameter, ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath); + PathTraversalCommand create( + Path path, + ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath, + String name); + ResponseTraversalCommand create( Response response, ImmutableList<Map.Entry<Class<? extends OpenApiSchema>, Optional<String>>> traversalPath,
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactoryModule.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactoryModule.java index fb3d8a7..a226e1a 100644 --- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactoryModule.java +++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactoryModule.java
@@ -18,6 +18,7 @@ OpenApiSpecificationTraversalCommand.class, OpenApiSpecificationTraversal.class) .implement(OperationTraversalCommand.class, OperationTraversal.class) .implement(ParameterTraversalCommand.class, ParameterTraversal.class) + .implement(PathTraversalCommand.class, PathTraversal.class) .implement(ResponseTraversalCommand.class, ResponseTraversal.class) .implement( SecurityRequirementTraversalCommand.class, SecurityRequirementTraversal.class)
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalHelper.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalHelper.java index c2c6c94..1f6ea32 100644 --- a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalHelper.java +++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/TraversalHelper.java
@@ -10,6 +10,7 @@ import org.openapi4j.parser.model.v3.OpenApi3; import org.openapi4j.parser.model.v3.Operation; import org.openapi4j.parser.model.v3.Parameter; +import org.openapi4j.parser.model.v3.Path; import org.openapi4j.parser.model.v3.Response; import org.openapi4j.parser.model.v3.SecurityRequirement; import org.openapi4j.parser.model.v3.Server; @@ -35,6 +36,8 @@ void sendParameterTraversals(ImmutableList<Parameter> parameters); + void sendPathTraversals(ImmutableMap<String, Path> paths); + void sendResponseTraversals(ImmutableMap<String, Response> responses); void sendSecurityRequirementTraversals(ImmutableList<SecurityRequirement> securityRequirements);
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/CallbackTraversalTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/CallbackTraversalTest.java new file mode 100644 index 0000000..dc4944d --- /dev/null +++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/CallbackTraversalTest.java
@@ -0,0 +1,67 @@ +package com.apigee.security.oas.extendedvalidator; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.mockito.quality.Strictness; +import org.openapi4j.parser.model.v3.Callback; +import org.openapi4j.parser.model.v3.Path; + +@RunWith(JUnit4.class) +public class CallbackTraversalTest { + + private final ImmutableMap<String, Path> callbackPaths = + ImmutableMap.of("one", new Path(), "two", new Path(), "three", new Path()); + + private CallbackTraversal callbackTraversal; + + @Rule public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS); + @Mock private TraversalHelperFactory traversalHelperFactory; + @Mock private TraversalHelper traversalHelper; + @Mock private ExtensionValidationIntegrator extensionValidationIntegrator; + @Mock private Callback callback; + + /** Sets up live and mocked instances for testing. */ + @Before + public void setup() { + callbackTraversal = + new CallbackTraversal( + traversalHelperFactory, + extensionValidationIntegrator, + ImmutableList.of(), + callback, + "name"); + + when(callback.getCallbackPaths()).thenReturn(callbackPaths); + + when(traversalHelperFactory.create(any(ImmutableList.class))).thenReturn(traversalHelper); + } + + @Test + public void traverse_sendsCallbackPathsToTraversalHelper() { + callbackTraversal.traverse(); + + verify(traversalHelper).sendPathTraversals(callbackPaths); + } + + @Test + public void traverse_nullCallbackPathsMember_doesNotFail() { + when(callback.getCallbackPaths()).thenReturn(null); + + callbackTraversal.traverse(); + + verify(traversalHelper, atLeastOnce()).sendPathTraversals(any()); + } +}
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversalTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversalTest.java index 4df4f5d..efe1ae1 100644 --- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversalTest.java +++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/OpenApiSpecificationTraversalTest.java
@@ -6,6 +6,7 @@ import static org.mockito.Mockito.when; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -18,6 +19,7 @@ import org.openapi4j.parser.model.v3.ExternalDocs; import org.openapi4j.parser.model.v3.Info; import org.openapi4j.parser.model.v3.OpenApi3; +import org.openapi4j.parser.model.v3.Path; import org.openapi4j.parser.model.v3.Server; import org.openapi4j.parser.model.v3.Tag; @@ -38,6 +40,9 @@ ImmutableList.of(new Server(), new Server(), new Server()); private final ImmutableList<Tag> tags = ImmutableList.of(new Tag(), new Tag(), new Tag()); + private final ImmutableMap<String, Path> paths = + ImmutableMap.of("one", new Path(), "two", new Path(), "three", new Path()); + private OpenApiSpecificationTraversal openApiSpecificationTraversal; /** Sets up live and mocked instances for testing. */ @@ -48,33 +53,45 @@ traversalHelperFactory, extensionValidationIntegrator, openApiSpec); when(openApiSpec.getServers()).thenReturn(servers); - when(openApiSpec.getTags()).thenReturn(tags); - when(openApiSpec.getInfo()).thenReturn(info); - when(openApiSpec.getExternalDocs()).thenReturn(externalDocs); + when(openApiSpec.getPaths()).thenReturn(paths); when(traversalHelperFactory.create(any(ImmutableList.class))).thenReturn(traversalHelper); } @Test - public void traverse_sendsInfoToTraversalHelper() { - openApiSpecificationTraversal.traverse(); - - verify(traversalHelperFactory, atLeastOnce()).create(any(ImmutableList.class)); - verify(traversalHelper).sendInfoTraversal(info); - } - - @Test public void traverse_sendsExternalDocsToTraversalHelper() { openApiSpecificationTraversal.traverse(); - verify(traversalHelperFactory, atLeastOnce()).create(any(ImmutableList.class)); verify(traversalHelper).sendExternalDocsTraversal(externalDocs); } @Test + public void traverse_sendsInfoToTraversalHelper() { + openApiSpecificationTraversal.traverse(); + + verify(traversalHelper).sendInfoTraversal(info); + } + + @Test + public void traverse_sendsPathsToTraversalHelper() { + openApiSpecificationTraversal.traverse(); + + verify(traversalHelper).sendPathTraversals(paths); + } + + @Test + public void traverse_nullPathsMember_doesNotFail() { + when(openApiSpec.getPaths()).thenReturn(null); + + openApiSpecificationTraversal.traverse(); + + verify(traversalHelper, atLeastOnce()).sendPathTraversals(any()); + } + + @Test public void traverse_sendsServersToTraversalHelper() { openApiSpecificationTraversal.traverse();
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/PathTraversalTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/PathTraversalTest.java new file mode 100644 index 0000000..042f0a4 --- /dev/null +++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/PathTraversalTest.java
@@ -0,0 +1,108 @@ +package com.apigee.security.oas.extendedvalidator; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.mockito.quality.Strictness; +import org.openapi4j.parser.model.v3.Operation; +import org.openapi4j.parser.model.v3.Parameter; +import org.openapi4j.parser.model.v3.Path; +import org.openapi4j.parser.model.v3.Server; + +@RunWith(JUnit4.class) +public class PathTraversalTest { + + private final ImmutableList<Parameter> parameters = + ImmutableList.of(new Parameter(), new Parameter(), new Parameter(), new Parameter()); + private final ImmutableList<Server> servers = + ImmutableList.of(new Server(), new Server(), new Server()); + + private final ImmutableMap<String, Operation> operations = + ImmutableMap.of("one", new Operation(), "two", new Operation(), "three", new Operation()); + + private PathTraversal pathTraversal; + + @Rule public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS); + @Mock private TraversalHelperFactory traversalHelperFactory; + @Mock private TraversalHelper traversalHelper; + @Mock private ExtensionValidationIntegrator extensionValidationIntegrator; + @Mock private Path path; + + /** Sets up live and mocked instances for testing. */ + @Before + public void setup() { + pathTraversal = + new PathTraversal( + traversalHelperFactory, + extensionValidationIntegrator, + ImmutableList.of(), + path, + "name"); + + when(path.getOperations()).thenReturn(operations); + when(path.getParameters()).thenReturn(parameters); + when(path.getServers()).thenReturn(servers); + + when(traversalHelperFactory.create(any(ImmutableList.class))).thenReturn(traversalHelper); + } + + @Test + public void traverse_sendsOperationsToTraversalHelper() { + pathTraversal.traverse(); + + verify(traversalHelper).sendOperationTraversals(operations); + } + + @Test + public void traverse_nullOperationsMember_doesNotFail() { + when(path.getOperations()).thenReturn(null); + + pathTraversal.traverse(); + + verify(traversalHelper, atLeastOnce()).sendOperationTraversals(any()); + } + + @Test + public void traverse_sendsParametersToTraversalHelper() { + pathTraversal.traverse(); + + verify(traversalHelper).sendParameterTraversals(parameters); + } + + @Test + public void traverse_nullParametersMember_doesNotFail() { + when(path.getParameters()).thenReturn(null); + + pathTraversal.traverse(); + + verify(traversalHelper, atLeastOnce()).sendParameterTraversals(any()); + } + + @Test + public void traverse_sendsServersToTraversalHelper() { + pathTraversal.traverse(); + + verify(traversalHelper).sendServerTraversals(servers); + } + + @Test + public void traverse_nullServersMember_doesNotFail() { + when(path.getServers()).thenReturn(null); + + pathTraversal.traverse(); + + verify(traversalHelper, atLeastOnce()).sendServerTraversals(any()); + } +}
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactoryTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactoryTest.java index 9f8e177..455543d 100644 --- a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactoryTest.java +++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/TraversalCommandFactoryTest.java
@@ -19,6 +19,7 @@ import org.openapi4j.parser.model.v3.OpenApi3; import org.openapi4j.parser.model.v3.Operation; import org.openapi4j.parser.model.v3.Parameter; +import org.openapi4j.parser.model.v3.Path; import org.openapi4j.parser.model.v3.Response; import org.openapi4j.parser.model.v3.SecurityRequirement; import org.openapi4j.parser.model.v3.Server; @@ -75,6 +76,11 @@ } @Test + public void create_pathAndNamePassed_returnsNonNullObject() { + assertThat(traversalCommandFactory.create(new Path(), traversalPath, "name")).isNotNull(); + } + + @Test public void create_responseAndNamePassed_returnsNonNullObject() { assertThat(traversalCommandFactory.create(new Response(), traversalPath, "name")).isNotNull(); }