summaryrefslogtreecommitdiffstats
path: root/config-model
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@verizonmedia.com>2020-01-10 17:56:12 +0100
committerBjørn Christian Seime <bjorncs@verizonmedia.com>2020-01-13 16:26:40 +0100
commite4f98750a282bbd66482d0e7a1cd16e454728e85 (patch)
tree4438f29f4b3cac5ae3f56c4a5bc7a2233eae1ec9 /config-model
parentff6f9d5a0064b6084c66e0b8dde45ca0f35dfd58 (diff)
Validate presence of http filter when 'access-control' is enabled
Add AccessControlFilterValidator that verifies precense of http filter. Remove use of 'access-control' in ImplicitIndexingClusterTest. Introduce HostedConfigModelRegistry for hosted specific tests using 'access-control'.
Diffstat (limited to 'config-model')
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/test/HostedConfigModelRegistry.java19
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/test/ModelBuilderAddingAccessControlFilter.java86
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/AccessControlFilterValidator.java39
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java1
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/AccessControlFilterValidatorTest.java61
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/search/ImplicitIndexingClusterTest.java11
6 files changed, 209 insertions, 8 deletions
diff --git a/config-model/src/main/java/com/yahoo/config/model/test/HostedConfigModelRegistry.java b/config-model/src/main/java/com/yahoo/config/model/test/HostedConfigModelRegistry.java
new file mode 100644
index 00000000000..9099a527dea
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/config/model/test/HostedConfigModelRegistry.java
@@ -0,0 +1,19 @@
+// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.test;
+
+import com.yahoo.config.model.ConfigModelRegistry;
+import com.yahoo.config.model.MapConfigModelRegistry;
+
+/**
+ * Creates a {@link ConfigModelRegistry} instance that simulates the hosted environment.
+ *
+ * @author bjorncs
+ */
+public class HostedConfigModelRegistry {
+
+ private HostedConfigModelRegistry() {}
+
+ public static ConfigModelRegistry create() {
+ return MapConfigModelRegistry.createFromList(new ModelBuilderAddingAccessControlFilter());
+ }
+}
diff --git a/config-model/src/main/java/com/yahoo/config/model/test/ModelBuilderAddingAccessControlFilter.java b/config-model/src/main/java/com/yahoo/config/model/test/ModelBuilderAddingAccessControlFilter.java
new file mode 100644
index 00000000000..c69efd5d447
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/config/model/test/ModelBuilderAddingAccessControlFilter.java
@@ -0,0 +1,86 @@
+// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.test;
+
+import com.yahoo.component.ComponentId;
+import com.yahoo.component.ComponentSpecification;
+import com.yahoo.component.chain.dependencies.Dependencies;
+import com.yahoo.component.chain.model.ChainedComponentModel;
+import com.yahoo.config.model.ConfigModel;
+import com.yahoo.config.model.ConfigModelContext;
+import com.yahoo.config.model.builder.xml.ConfigModelBuilder;
+import com.yahoo.config.model.builder.xml.ConfigModelId;
+import com.yahoo.container.bundle.BundleInstantiationSpecification;
+import com.yahoo.vespa.model.container.ApplicationContainerCluster;
+import com.yahoo.vespa.model.container.ContainerModel;
+import com.yahoo.vespa.model.container.component.chain.Chain;
+import com.yahoo.vespa.model.container.http.AccessControl;
+import com.yahoo.vespa.model.container.http.Filter;
+import com.yahoo.vespa.model.container.http.Http;
+import com.yahoo.vespa.model.container.xml.ContainerModelBuilder;
+import org.w3c.dom.Element;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * A {@link ConfigModelBuilder} that configures a dummy filter component to the {@link AccessControl#ACCESS_CONTROL_CHAIN_ID} filter chain.
+ *
+ * @author bjorncs
+ */
+public class ModelBuilderAddingAccessControlFilter
+ extends ConfigModelBuilder<ModelBuilderAddingAccessControlFilter.ModelPlaceholder> {
+
+ public ModelBuilderAddingAccessControlFilter() {
+ super(ModelPlaceholder.class);
+ }
+
+ @Override
+ public List<ConfigModelId> handlesElements() { return ContainerModelBuilder.configModelIds; }
+
+ @Override
+ public void doBuild(ModelPlaceholder model, Element spec, ConfigModelContext modelContext) {
+ for (ContainerModel containerModel : model.containers) {
+ addFilterToContainerCluster(containerModel);
+ }
+ }
+
+ private static void addFilterToContainerCluster(ContainerModel containerModel) {
+ if (!(containerModel.getCluster() instanceof ApplicationContainerCluster)) return;
+ ApplicationContainerCluster cluster = (ApplicationContainerCluster) containerModel.getCluster();
+ Http http = cluster.getHttp();
+ if (http.getAccessControl().isPresent()) {
+ Chain<Filter> chain = http.getFilterChains()
+ .allChains()
+ .getComponent(AccessControl.ACCESS_CONTROL_CHAIN_ID);
+ if (chain == null) return;
+ if (!chain.getInnerComponents().isEmpty()) return;
+ chain.addInnerComponent(new DummyAccessControlFilterModel());
+ }
+ }
+
+ public static class ModelPlaceholder extends ConfigModel {
+ final Collection<ContainerModel> containers;
+
+ public ModelPlaceholder(ConfigModelContext modelContext, Collection<ContainerModel> containers) {
+ super(modelContext);
+ this.containers = containers;
+ }
+
+ @Override
+ public boolean isServing() { return false; }
+ }
+
+ private static class DummyAccessControlFilterModel extends Filter {
+
+ DummyAccessControlFilterModel() { super(createDummyComponentModel()); }
+
+ static ChainedComponentModel createDummyComponentModel() {
+ return new ChainedComponentModel(
+ new BundleInstantiationSpecification(
+ new ComponentId("dummy-filter"),
+ new ComponentSpecification("com.test.DummyAccessControlFilter"),
+ new ComponentSpecification("dummy-bundle")),
+ Dependencies.emptyDependencies());
+ }
+ }
+}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/AccessControlFilterValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/AccessControlFilterValidator.java
new file mode 100644
index 00000000000..774f0ba52bc
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/AccessControlFilterValidator.java
@@ -0,0 +1,39 @@
+// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.model.application.validation;
+
+import com.yahoo.config.model.deploy.DeployState;
+import com.yahoo.vespa.model.VespaModel;
+import com.yahoo.vespa.model.container.component.chain.Chain;
+import com.yahoo.vespa.model.container.http.AccessControl;
+import com.yahoo.vespa.model.container.http.Filter;
+import com.yahoo.vespa.model.container.http.FilterChains;
+import com.yahoo.vespa.model.container.http.Http;
+
+/**
+ * Validates that 'access-control' is not enabled when no access control filter implementation is available.
+ *
+ * @author bjorncs
+ */
+public class AccessControlFilterValidator extends Validator {
+
+ @Override
+ public void validate(VespaModel model, DeployState deployState) {
+ model.getContainerClusters().forEach((id, cluster) -> {
+ Http http = cluster.getHttp();
+ if (http != null) {
+ if (http.getAccessControl().isPresent()) {
+ verifyAccessControlFilterPresent(http);
+ }
+ }
+ });
+ }
+
+ private static void verifyAccessControlFilterPresent(Http http) {
+ FilterChains filterChains = http.getFilterChains();
+ Chain<Filter> chain = filterChains.allChains().getComponent(AccessControl.ACCESS_CONTROL_CHAIN_ID);
+ if (chain.getInnerComponents().isEmpty()) {
+ // No access control filter configured - it's up to a config model plugin to provide an implementation of an access control filter.
+ throw new IllegalArgumentException("The 'access-control' feature is not available in open-source Vespa.");
+ }
+ }
+}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java
index dde2f62ee8f..4959970d98e 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java
@@ -57,6 +57,7 @@ public class Validation {
new RankingConstantsValidator().validate(model, deployState);
new SecretStoreValidator().validate(model, deployState);
new TlsSecretsValidator().validate(model, deployState);
+ new AccessControlFilterValidator().validate(model, deployState);
List<ConfigChangeAction> result = Collections.emptyList();
if (deployState.getProperties().isFirstTimeDeployment()) {
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/AccessControlFilterValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/AccessControlFilterValidatorTest.java
new file mode 100644
index 00000000000..8fad2aa9af4
--- /dev/null
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/AccessControlFilterValidatorTest.java
@@ -0,0 +1,61 @@
+package com.yahoo.vespa.model.application.validation;// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+import com.yahoo.config.model.MapConfigModelRegistry;
+import com.yahoo.config.model.NullConfigModelRegistry;
+import com.yahoo.config.model.deploy.DeployState;
+import com.yahoo.config.model.test.MockApplicationPackage;
+import com.yahoo.config.model.test.ModelBuilderAddingAccessControlFilter;
+import com.yahoo.vespa.model.VespaModel;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+
+/**
+ * @author bjorncs
+ */
+public class AccessControlFilterValidatorTest {
+
+ private static final String SERVICES_XML = String.join(
+ "\n",
+ "<services version='1.0'>",
+ " <container id='container-cluster-with-access-control' version='1.0'>",
+ " <http>",
+ " <filtering>",
+ " <access-control domain='foo' read='true' write='true'/>",
+ " </filtering>",
+ " </http>",
+ " </container>",
+ "</services>");
+
+ @Rule
+ public ExpectedException exceptionRule = ExpectedException.none();
+
+ @Test
+ public void validator_fails_with_empty_access_control_filter_chain() throws IOException, SAXException {
+ DeployState deployState = createDeployState();
+ VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState);
+
+ exceptionRule.expect(IllegalArgumentException.class);
+ exceptionRule.expectMessage("The 'access-control' feature is not available in open-source Vespa.");
+ new AccessControlFilterValidator().validate(model, deployState);
+ }
+
+ @Test
+ public void validator_accepts_non_empty_access_control_filter_chain() throws IOException, SAXException {
+ DeployState deployState = createDeployState();
+ VespaModel model = new VespaModel(
+ MapConfigModelRegistry.createFromList(new ModelBuilderAddingAccessControlFilter()),
+ deployState);
+
+ new AccessControlFilterValidator().validate(model, deployState);
+ }
+
+ private static DeployState createDeployState() {
+ return new DeployState.Builder()
+ .applicationPackage(new MockApplicationPackage.Builder().withServices(SERVICES_XML).build())
+ .build();
+ }
+} \ No newline at end of file
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/search/ImplicitIndexingClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/search/ImplicitIndexingClusterTest.java
index 66ed86e3eaa..30a36715a17 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/search/ImplicitIndexingClusterTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/search/ImplicitIndexingClusterTest.java
@@ -24,7 +24,9 @@ public class ImplicitIndexingClusterTest {
" <container version=\"1.0\" id=\"jdisc\">\n" + //
" <search />\n" + //
" <nodes count=\"1\" />\n" + //
- ACCESS_CONTROL_XML + //
+ " <http>\n" + //
+ " <server id=\"bar\" port=\"4080\" />\n" + //
+ " </http>\n" + //
" </container>\n" + //
" <content id=\"music\" version=\"1.0\">\n" + //
" <redundancy>1</redundancy>\n" + //
@@ -42,13 +44,6 @@ public class ImplicitIndexingClusterTest {
assertNotNull("Indexing chain not added to jdisc", jdisc.getDocprocChains().allChains().getComponent("indexing"));
}
- private final String ACCESS_CONTROL_XML = "<http>\n" +//
- " <filtering>\n" +//
- " <access-control domain=\"foo\" />\n" +//
- " </filtering>\n" +//
- " <server id=\"bar\" port=\"4080\" />\n" +//
- "</http>\n";
-
private static VespaModel buildMultiTenantVespaModel(String servicesXml) {
ModelContext.Properties properties = new TestProperties().setMultitenant(true).setHostedVespa(true);
DeployState.Builder deployStateBuilder = new DeployState.Builder()