aboutsummaryrefslogtreecommitdiffstats
path: root/controller-server
diff options
context:
space:
mode:
authorØyvind Grønnesby <oyving@verizonmedia.com>2020-03-03 09:53:37 +0100
committerØyvind Grønnesby <oyving@verizonmedia.com>2020-03-03 09:53:37 +0100
commitc504788f5f61acdca835e97a56263d5f2af686b2 (patch)
tree82847d29f324184f386a2a7c9053a3f8f5fc0160 /controller-server
parent25707b0248f895e17058c09a782e1c88914a542f (diff)
Fail early on missing security/clients.pem in application package
Diffstat (limited to 'controller-server')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java6
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java7
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerCloudTest.java9
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java77
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java2
5 files changed, 92 insertions, 9 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
index 1c8279f6d8d..98808ea5686 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java
@@ -1956,6 +1956,12 @@ public class ApplicationApiHandler extends LoggingRequestHandler {
ApplicationPackage applicationPackage = new ApplicationPackage(dataParts.get(EnvironmentResource.APPLICATION_ZIP), true);
+ // if we are in public and 'security/clients.pem' is not present (i.e. we don't have any trusted
+ // certificates), we should fail early instead of waiting for the configserver to fail.
+ if (controller.system().isPublic() && applicationPackage.trustedCertificates().isEmpty()) {
+ throw new IllegalArgumentException("Missing required file 'security/clients.pem'");
+ }
+
controller.applications().verifyApplicationIdentityConfiguration(TenantName.from(tenant),
Optional.empty(),
Optional.empty(),
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java
index df8787a2a4b..5c80e7e2524 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ContainerTester.java
@@ -5,24 +5,17 @@ import com.yahoo.application.container.JDisc;
import com.yahoo.application.container.handler.Request;
import com.yahoo.application.container.handler.Response;
import com.yahoo.component.ComponentSpecification;
-import com.yahoo.component.Version;
import com.yahoo.config.provision.ApplicationName;
-import com.yahoo.config.provision.zone.ZoneApi;
import com.yahoo.container.http.filter.FilterChainRepository;
import com.yahoo.jdisc.http.filter.SecurityRequestFilter;
import com.yahoo.jdisc.http.filter.SecurityRequestFilterChain;
import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.athenz.api.AthenzIdentity;
import com.yahoo.vespa.hosted.controller.Controller;
-import com.yahoo.vespa.hosted.controller.api.identifiers.ScrewdriverId;
import com.yahoo.vespa.hosted.controller.api.integration.athenz.ApplicationAction;
import com.yahoo.vespa.hosted.controller.api.integration.athenz.AthenzClientFactoryMock;
-import com.yahoo.vespa.hosted.controller.application.SystemApplication;
-import com.yahoo.vespa.hosted.controller.athenz.HostedAthenzIdentities;
import com.yahoo.vespa.hosted.controller.integration.ConfigServerMock;
import com.yahoo.vespa.hosted.controller.integration.ServiceRegistryMock;
-import com.yahoo.vespa.hosted.controller.versions.ControllerVersion;
-import com.yahoo.vespa.hosted.controller.versions.VersionStatus;
import org.junit.ComparisonFailure;
import java.io.File;
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerCloudTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerCloudTest.java
index 16447f47ee8..72b2014894d 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerCloudTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/ControllerContainerCloudTest.java
@@ -1,12 +1,14 @@
// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.restapi;
+import ai.vespa.hosted.api.MultiPartStreamer;
import com.yahoo.application.container.handler.Request;
import com.yahoo.config.provision.SystemName;
import com.yahoo.vespa.hosted.controller.api.integration.user.User;
import com.yahoo.vespa.hosted.controller.api.role.Role;
import com.yahoo.vespa.hosted.controller.api.role.SecurityContext;
import com.yahoo.vespa.hosted.controller.api.role.SimplePrincipal;
+import com.yahoo.yolean.Exceptions;
import java.nio.charset.StandardCharsets;
import java.security.Principal;
@@ -68,12 +70,17 @@ public class ControllerContainerCloudTest extends ControllerContainerTest {
private Principal principal = () -> "user@test";
private User user;
private Set<Role> roles = Set.of(Role.everyone());
+ private String contentType;
private RequestBuilder(String path, Request.Method method) {
this.path = path;
this.method = method;
}
+ public RequestBuilder contentType(String contentType) { this.contentType = contentType; return this; }
+ public RequestBuilder data(MultiPartStreamer streamer) {
+ return Exceptions.uncheck(() -> data(streamer.data().readAllBytes()).contentType(streamer.contentType()));
+ }
public RequestBuilder data(byte[] data) { this.data = data; return this; }
public RequestBuilder data(String data) { this.data = data.getBytes(StandardCharsets.UTF_8); return this; }
public RequestBuilder principal(String principal) { this.principal = new SimplePrincipal(principal); return this; }
@@ -85,7 +92,7 @@ public class ControllerContainerCloudTest extends ControllerContainerTest {
Request request = new Request("http://localhost:8080" + path, data, method, principal);
request.getAttributes().put(SecurityContext.ATTRIBUTE_NAME, new SecurityContext(principal, roles));
if (user != null) request.getAttributes().put(User.ATTRIBUTE_NAME, user);
- request.getHeaders().put("Content-Type", "application/json");
+ request.getHeaders().put("Content-Type", contentType);
return request;
}
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
new file mode 100644
index 00000000000..ef7c66e22b3
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
@@ -0,0 +1,77 @@
+package com.yahoo.vespa.hosted.controller.restapi.application;
+
+import com.yahoo.config.provision.ApplicationName;
+import com.yahoo.config.provision.Environment;
+import com.yahoo.config.provision.TenantName;
+import com.yahoo.vespa.hosted.controller.api.integration.user.User;
+import com.yahoo.vespa.hosted.controller.ControllerTester;
+import com.yahoo.vespa.hosted.controller.api.role.Role;
+import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId;
+import com.yahoo.vespa.hosted.controller.deployment.ApplicationPackageBuilder;
+import com.yahoo.vespa.hosted.controller.deployment.DeploymentTester;
+import com.yahoo.vespa.hosted.controller.restapi.ContainerTester;
+import com.yahoo.vespa.hosted.controller.restapi.ControllerContainerCloudTest;
+import com.yahoo.vespa.hosted.controller.security.CloudTenantSpec;
+import com.yahoo.vespa.hosted.controller.security.Credentials;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Set;
+
+import static com.yahoo.application.container.handler.Request.Method.POST;
+import static com.yahoo.vespa.hosted.controller.restapi.application.ApplicationApiTest.createApplicationSubmissionData;
+
+public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
+
+ private static final String responseFiles = "src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/";
+
+ private ContainerTester tester;
+ private DeploymentTester deploymentTester;
+
+ private static final TenantName tenantName = TenantName.from("scoober");
+ private static final ApplicationName applicationName = ApplicationName.from("albums");
+ private static final User developerUser = new User("developer", "Joe Developer", "", "");
+
+ @Before
+ public void before() {
+ tester = new ContainerTester(container, responseFiles);
+ deploymentTester = new DeploymentTester(new ControllerTester(tester));
+ deploymentTester.controllerTester().computeVersionStatus();
+ }
+
+ @Test
+ public void test_missing_security_clients_pem() {
+ setupTenantAndApplication();
+
+ var application = prodBuilder().build();
+
+ var deployRequest = request("/application/v4/tenant/scoober/application/albums/submit", POST)
+ .data(createApplicationSubmissionData(application, 0))
+ .roles(Set.of(Role.developer(tenantName)));
+
+ tester.assertResponse(
+ deployRequest,
+ "{\"error-code\":\"BAD_REQUEST\",\"message\":\"Missing required file 'security/clients.pem'\"}",
+ 400);
+ }
+
+
+ private ApplicationPackageBuilder prodBuilder() {
+ return new ApplicationPackageBuilder()
+ .instances("default")
+ .environment(Environment.prod)
+ .region("aws-us-east-1c");
+ }
+
+ private void setupTenantAndApplication() {
+ var tenantSpec = new CloudTenantSpec(tenantName, "");
+ tester.controller().tenants().create(tenantSpec, credentials("developer@scoober"));
+
+ var appId = TenantAndApplicationId.from(tenantName, applicationName);
+ tester.controller().applications().createApplication(appId, credentials("developer@scoober"));
+ }
+
+ private static Credentials credentials(String name) {
+ return new Credentials(() -> name);
+ }
+}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
index 45d87c6756a..407cae2bd3a 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
@@ -1502,7 +1502,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
return streamer;
}
- private MultiPartStreamer createApplicationSubmissionData(ApplicationPackage applicationPackage, long projectId) {
+ static MultiPartStreamer createApplicationSubmissionData(ApplicationPackage applicationPackage, long projectId) {
return new MultiPartStreamer().addJson(EnvironmentResource.SUBMIT_OPTIONS, "{\"repository\":\"repository1\",\"branch\":\"master\",\"commit\":\"commit1\","
+ "\"projectId\":" + projectId + ",\"authorEmail\":\"a@b\"}")
.addBytes(EnvironmentResource.APPLICATION_ZIP, applicationPackage.zippedContent())