aboutsummaryrefslogtreecommitdiffstats
path: root/tenant-auth
diff options
context:
space:
mode:
authorJon Marius Venstad <jvenstad@yahoo-inc.com>2019-06-07 17:27:22 +0200
committerJon Marius Venstad <jvenstad@yahoo-inc.com>2019-06-07 17:27:22 +0200
commitce08379e47b9e02836026d111e1a27681b21c715 (patch)
tree954830fead4acd24854a231b2d6d202676ac72ce /tenant-auth
parent65937b2191aad18db17403cdbf0b94db7aac7cc7 (diff)
Move tenant authentication to new module tenant-auth, to override internally
Diffstat (limited to 'tenant-auth')
-rw-r--r--tenant-auth/OWNERS1
-rw-r--r--tenant-auth/README.md1
-rw-r--r--tenant-auth/pom.xml40
-rw-r--r--tenant-auth/src/main/java/ai/vespa/hosted/auth/Authenticator.java73
-rw-r--r--tenant-auth/src/test/java/ai/vespa/hosted/auth/AuthenticatorTest.java5
5 files changed, 120 insertions, 0 deletions
diff --git a/tenant-auth/OWNERS b/tenant-auth/OWNERS
new file mode 100644
index 00000000000..d0a102ecbf4
--- /dev/null
+++ b/tenant-auth/OWNERS
@@ -0,0 +1 @@
+jonmv
diff --git a/tenant-auth/README.md b/tenant-auth/README.md
new file mode 100644
index 00000000000..0514b68400e
--- /dev/null
+++ b/tenant-auth/README.md
@@ -0,0 +1 @@
+# Utilities that authenticate users to the hosted Vespa API, or to hosted Vespa applications.
diff --git a/tenant-auth/pom.xml b/tenant-auth/pom.xml
new file mode 100644
index 00000000000..be8b42dd6c2
--- /dev/null
+++ b/tenant-auth/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>parent</artifactId>
+ <version>7-SNAPSHOT</version>
+ <relativePath>../parent/pom.xml</relativePath>
+ </parent>
+ <artifactId>tenant-auth</artifactId>
+ <description>Provides resources for authenticating with the hosted Vespa API or application containers</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>hosted-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>config-provisioning</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>security-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/tenant-auth/src/main/java/ai/vespa/hosted/auth/Authenticator.java b/tenant-auth/src/main/java/ai/vespa/hosted/auth/Authenticator.java
new file mode 100644
index 00000000000..6ecf1100630
--- /dev/null
+++ b/tenant-auth/src/main/java/ai/vespa/hosted/auth/Authenticator.java
@@ -0,0 +1,73 @@
+package ai.vespa.hosted.auth;
+
+import ai.vespa.hosted.api.ControllerHttpClient;
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.security.KeyUtils;
+import com.yahoo.security.SslContextBuilder;
+import com.yahoo.security.X509CertificateUtils;
+
+import javax.net.ssl.SSLContext;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.URI;
+import java.net.http.HttpRequest;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+import java.time.Instant;
+import java.util.Optional;
+
+/**
+ * Authenticates {@link HttpRequest}s against a hosted Vespa application based on mutual TLS.
+ *
+ * @author jonmv
+ */
+public class Authenticator {
+
+ /** Returns an SSLContext from "key" and "cert" files found under {@code System.getProperty("vespa.test.credentials.root")}. */
+ public SSLContext sslContext() {
+ try {
+ Path credentialsRoot = Path.of(System.getProperty("vespa.test.credentials.root"));
+ Path certificateFile = credentialsRoot.resolve("cert");
+ Path privateKeyFile = credentialsRoot.resolve("key");
+
+ X509Certificate certificate = X509CertificateUtils.fromPem(new String(Files.readAllBytes(certificateFile)));
+ if (Instant.now().isBefore(certificate.getNotBefore().toInstant())
+ || Instant.now().isAfter(certificate.getNotAfter().toInstant()))
+ throw new IllegalStateException("Certificate at '" + certificateFile + "' is valid between " +
+ certificate.getNotBefore() + " and " + certificate.getNotAfter() + " — not now.");
+
+ PrivateKey privateKey = KeyUtils.fromPemEncodedPrivateKey(new String(Files.readAllBytes(privateKeyFile)));
+ return new SslContextBuilder().withKeyStore(privateKey, certificate).build();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public HttpRequest.Builder authenticated(HttpRequest.Builder request) {
+ return request;
+ }
+
+ ApplicationId id = ApplicationId.from(requireNonBlankProperty("tenant"),
+ requireNonBlankProperty("application"),
+ getNonBlankProperty("instance").orElse("default"));
+
+ URI endpoint = URI.create(requireNonBlankProperty("endpoint"));
+ Path privateKeyFile = Paths.get(requireNonBlankProperty("privateKeyFile"));
+ Optional<Path> certificateFile = getNonBlankProperty("certificateFile").map(Paths::get);
+
+ ControllerHttpClient controller = certificateFile.isPresent()
+ ? ControllerHttpClient.withKeyAndCertificate(endpoint, privateKeyFile, certificateFile.get())
+ : ControllerHttpClient.withSignatureKey(endpoint, privateKeyFile, id);
+
+ static Optional<String> getNonBlankProperty(String name) {
+ return Optional.ofNullable(System.getProperty(name)).filter(value -> ! value.isBlank());
+ }
+
+ static String requireNonBlankProperty(String name) {
+ return getNonBlankProperty(name).orElseThrow(() -> new IllegalStateException("Missing required property '" + name + "'"));
+ }
+
+}
diff --git a/tenant-auth/src/test/java/ai/vespa/hosted/auth/AuthenticatorTest.java b/tenant-auth/src/test/java/ai/vespa/hosted/auth/AuthenticatorTest.java
new file mode 100644
index 00000000000..ff4bebce3ff
--- /dev/null
+++ b/tenant-auth/src/test/java/ai/vespa/hosted/auth/AuthenticatorTest.java
@@ -0,0 +1,5 @@
+package ai.vespa.hosted.auth;
+
+public class AuthenticatorTest {
+
+}