aboutsummaryrefslogtreecommitdiffstats
path: root/hosted-api
diff options
context:
space:
mode:
authorJon Marius Venstad <venstad@gmail.com>2019-10-02 17:46:18 +0200
committerJon Marius Venstad <venstad@gmail.com>2019-10-02 17:46:18 +0200
commit70290819f83da07f76c2e5d70513a09ef6fd4f52 (patch)
tree590f5a2ad875889aa12d9cad3c1760a269e9fd78 /hosted-api
parent5927e7f3dca0781bf0dc2dde4737dac85d85788b (diff)
Construct PublicKeys from serialised keys in controller
Diffstat (limited to 'hosted-api')
-rw-r--r--hosted-api/src/main/java/ai/vespa/hosted/api/RequestSigner.java41
-rw-r--r--hosted-api/src/main/java/ai/vespa/hosted/api/RequestVerifier.java8
2 files changed, 44 insertions, 5 deletions
diff --git a/hosted-api/src/main/java/ai/vespa/hosted/api/RequestSigner.java b/hosted-api/src/main/java/ai/vespa/hosted/api/RequestSigner.java
index b2fd16b7975..5d314d90356 100644
--- a/hosted-api/src/main/java/ai/vespa/hosted/api/RequestSigner.java
+++ b/hosted-api/src/main/java/ai/vespa/hosted/api/RequestSigner.java
@@ -4,9 +4,10 @@ package ai.vespa.hosted.api;
import com.yahoo.security.KeyUtils;
import com.yahoo.security.SignatureUtils;
-import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.http.HttpRequest;
+import java.security.PrivateKey;
+import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.time.Clock;
@@ -15,6 +16,7 @@ import java.util.function.Supplier;
import static ai.vespa.hosted.api.Signatures.sha256Digest;
import static com.yahoo.security.SignatureAlgorithm.SHA256_WITH_ECDSA;
+import static java.nio.charset.StandardCharsets.UTF_8;
/**
* Signs HTTP request headers using a private key, for verification by the indicated public key.
@@ -25,6 +27,7 @@ public class RequestSigner {
private final Signature signer;
private final String keyId;
+ private final String base64PemPublicKey;
private final Clock clock;
/** Creates a new request signer from the given PEM encoded ECDSA key, with a public key with the given ID. */
@@ -34,8 +37,15 @@ public class RequestSigner {
/** Creates a new request signer with a custom clock. */
public RequestSigner(String pemPrivateKey, String keyId, Clock clock) {
- this.signer = SignatureUtils.createSigner(KeyUtils.fromPemEncodedPrivateKey(pemPrivateKey), SHA256_WITH_ECDSA);
+ this(KeyUtils.fromPemEncodedPrivateKey(pemPrivateKey), keyId, clock);
+ }
+
+ /** Creates a new request signer with a custom clock. */
+ public RequestSigner(PrivateKey privateKey, String keyId, Clock clock) {
+ this.signer = SignatureUtils.createSigner(privateKey, SHA256_WITH_ECDSA);
this.keyId = keyId;
+ this.base64PemPublicKey = Base64.getEncoder().encodeToString(KeyUtils.toPem(KeyUtils.extractPublicKey(privateKey)).getBytes(UTF_8));
+ PublicKey key = KeyUtils.extractPublicKey(privateKey);
this.clock = clock;
}
@@ -44,8 +54,8 @@ public class RequestSigner {
* <br>
* The request builder's method and data are set to the given arguments, and a hash of the
* content is computed and added to a header, together with other meta data, like the URI
- * of the request, the current UTC time, and the id of the public key which shall be used to
- * verify this signature.
+ * of the request, the current UTC time, and the id and value of the public key which shall
+ * be used to * verify this signature.
* Finally, a signature is computed from these fields, based on the private key of this, and
* added to the request as another header.
*/
@@ -60,6 +70,29 @@ public class RequestSigner {
request.setHeader("X-Timestamp", timestamp);
request.setHeader("X-Content-Hash", contentHash);
request.setHeader("X-Key-Id", keyId);
+ request.setHeader("X-Key", base64PemPublicKey);
+ request.setHeader("X-Authorization", signature);
+
+ request.method(method.name(), HttpRequest.BodyPublishers.ofInputStream(data));
+ return request.build();
+ }
+ catch (SignatureException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ // TODO jonmv: Simulates old clients — remove shortly (2 Oct 2019).
+ public HttpRequest legacySigned(HttpRequest.Builder request, Method method, Supplier<InputStream> data) {
+ try {
+ String timestamp = clock.instant().toString();
+ String contentHash = Base64.getEncoder().encodeToString(sha256Digest(data::get));
+ byte[] canonicalMessage = Signatures.canonicalMessageOf(method.name(), request.copy().build().uri(), timestamp, contentHash);
+ signer.update(canonicalMessage);
+ String signature = Base64.getEncoder().encodeToString(signer.sign());
+
+ request.setHeader("X-Timestamp", timestamp);
+ request.setHeader("X-Content-Hash", contentHash);
+ request.setHeader("X-Key-Id", keyId);
request.setHeader("X-Authorization", signature);
request.method(method.name(), HttpRequest.BodyPublishers.ofInputStream(data));
diff --git a/hosted-api/src/main/java/ai/vespa/hosted/api/RequestVerifier.java b/hosted-api/src/main/java/ai/vespa/hosted/api/RequestVerifier.java
index 9d85ec9bf6b..5a6bea54bce 100644
--- a/hosted-api/src/main/java/ai/vespa/hosted/api/RequestVerifier.java
+++ b/hosted-api/src/main/java/ai/vespa/hosted/api/RequestVerifier.java
@@ -5,6 +5,7 @@ import com.yahoo.security.KeyUtils;
import com.yahoo.security.SignatureUtils;
import java.net.URI;
+import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.time.Clock;
@@ -31,7 +32,12 @@ public class RequestVerifier {
/** Creates a new request verifier from the given PEM encoded ECDSA public key, with the given clock. */
public RequestVerifier(String pemPublicKey, Clock clock) {
- this.verifier = SignatureUtils.createVerifier(KeyUtils.fromPemEncodedPublicKey(pemPublicKey), SHA256_WITH_ECDSA);
+ this(KeyUtils.fromPemEncodedPublicKey(pemPublicKey), clock);
+ }
+
+ /** Creates a new request verifier from the given PEM encoded ECDSA public key, with the given clock. */
+ public RequestVerifier(PublicKey publicKey, Clock clock) {
+ this.verifier = SignatureUtils.createVerifier(publicKey, SHA256_WITH_ECDSA);
this.clock = clock;
}