Configure gateway limits and encrypted storage

This commit is contained in:
admin committed 2026-10-11 01:24:09 +02:00
1 parent 43987bbadb
commit 510e519bd1
23 files changed
+480 -17

No files matched your search

@@ -0,0 +1,42 @@
package cloud.lunarsky.store;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
public final class EncryptedVolumeTest {
private static void rejected(Map<String, String> configuration) throws Exception {
try {
EncryptedVolume.requireConfigured(configuration);
throw new AssertionError("Unavailable encrypted storage was accepted");
} catch (IOException expected) { }
}
public static void main(String[] args) throws Exception {
Path directory = Files.createTempDirectory("objectstore-encrypted-volume-");
Path marker = directory.resolve(".objectstore-encrypted");
String id = "0123456789abcdef0123456789abcdef";
Map<String, String> configuration = Map.of(
"ENCRYPTED_VOLUME_MARKER_FILE", marker.toString(), "ENCRYPTED_VOLUME_ID", id);
try {
EncryptedVolume.requireConfigured(Map.of());
rejected(configuration);
Files.writeString(marker, id + "\n");
EncryptedVolume.requireConfigured(configuration);
rejected(Map.of("ENCRYPTED_VOLUME_MARKER_FILE", marker.toString()));
rejected(Map.of("ENCRYPTED_VOLUME_MARKER_FILE", marker.toString(),
"ENCRYPTED_VOLUME_ID", "fedcba9876543210fedcba9876543210"));
Files.delete(marker);
Path elsewhere = directory.resolve("elsewhere");
Files.writeString(elsewhere, id + "\n");
Files.createSymbolicLink(marker, elsewhere);
rejected(configuration);
} finally {
Files.deleteIfExists(marker);
Files.deleteIfExists(directory.resolve("elsewhere"));
Files.delete(directory);
}
System.out.println("Encrypted volume marker tests passed");
}
}
+68 -2
View File
@@ -806,15 +806,70 @@ public final class HttpTest {
throw new AssertionError("Completed multipart version was not retained");
}
private static int virtualHostPut(int port, String host, String signedHost, byte[] body) throws Exception {
URI signed = URI.create("http://" + signedHost + ":" + port + "/photos/cat.jpg");
HttpRequest request = signedUri(signed, "PUT", body, Map.of());
String headers = "PUT /photos/cat.jpg HTTP/1.1\r\nHost: " + host + ":" + port +
"\r\nAuthorization: " + request.headers().firstValue("authorization").orElseThrow() +
"\r\nx-amz-date: " + request.headers().firstValue("x-amz-date").orElseThrow() +
"\r\nx-amz-content-sha256: " + request.headers().firstValue("x-amz-content-sha256").orElseThrow() +
"\r\nContent-Length: " + body.length + "\r\nConnection: close\r\n\r\n";
try (var socket = new java.net.Socket("127.0.0.1", port)) {
socket.setSoTimeout(5000);
socket.getOutputStream().write(headers.getBytes(StandardCharsets.US_ASCII));
socket.getOutputStream().write(body);
String response = new String(socket.getInputStream().readAllBytes(), StandardCharsets.ISO_8859_1);
return Integer.parseInt(response.split(" ", 3)[1]);
}
}
private static void testGatewayConcurrency(DiskStore store, HttpClient client,
java.util.concurrent.Executor executor) throws Exception {
HttpServer limited = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 16);
var app = new Main(store, new MultipartStore(store),
new SigV4(ACCESS, SECRET, REGION, Clock.systemUTC()), "objects",
ClientLimits.disabled(), 1, "");
limited.setExecutor(executor);
limited.createContext("/", app::handle);
limited.start();
int port = limited.getAddress().getPort();
String base = "http://127.0.0.1:" + port;
byte[] body = {42};
HttpRequest request = signedUri(URI.create(base + "/objects/held"), "PUT", body, Map.of());
try (var socket = new java.net.Socket("127.0.0.1", port)) {
socket.setSoTimeout(5000);
String headers = "PUT /objects/held HTTP/1.1\r\nHost: 127.0.0.1:" + port +
"\r\nAuthorization: " + request.headers().firstValue("authorization").orElseThrow() +
"\r\nx-amz-date: " + request.headers().firstValue("x-amz-date").orElseThrow() +
"\r\nx-amz-content-sha256: " + request.headers().firstValue("x-amz-content-sha256").orElseThrow() +
"\r\nContent-Length: 1\r\nConnection: close\r\n\r\n";
socket.getOutputStream().write(headers.getBytes(StandardCharsets.US_ASCII));
boolean refused = false;
for (int attempt = 0; attempt < 50 && !refused; attempt++) {
int status = client.send(HttpRequest.newBuilder(URI.create(base + "/health")).GET().build(),
HttpResponse.BodyHandlers.discarding()).statusCode();
refused = status == 503;
if (!refused) Thread.sleep(10);
}
if (!refused) throw new AssertionError("Configured gateway concurrency cap was not enforced");
socket.getOutputStream().write(body);
String finished = new String(socket.getInputStream().readAllBytes(), StandardCharsets.ISO_8859_1);
if (!finished.startsWith("HTTP/1.1 200 "))
throw new AssertionError("Held request did not complete after releasing its body");
} finally {
limited.stop(0);
}
}
public static void main(String[] args) throws Exception {
Path root = Files.createTempDirectory("store-http-test-");
var executor = Executors.newVirtualThreadPerTaskExecutor();
HttpServer server = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 16);
DiskStore store = new DiskStore(root, 1024, 4096);
try {
var app = new Main(store,
var app = new Main(store, new MultipartStore(store),
new SigV4(Map.of(ACCESS, SECRET, SECONDARY, SECONDARY_SECRET),
ACCESS, REGION, Clock.systemUTC()), "objects");
ACCESS, REGION, Clock.systemUTC()), "objects", ClientLimits.disabled(), 16, "s3.test");
server.setExecutor(executor);
server.createContext("/", app::handle);
server.start();
@@ -834,6 +889,17 @@ public final class HttpTest {
testBuckets(client, base);
testVersioning(client, base);
testAcl(client, base);
byte[] hostedBody = "virtual host".getBytes(StandardCharsets.UTF_8);
int port = server.getAddress().getPort();
if (virtualHostPut(port, "objects.s3.test", "objects.s3.test", hostedBody) != 200)
throw new AssertionError("Signed virtual-hosted upload failed");
try (var opened = store.open("objects", "photos/cat.jpg")) {
if (!java.util.Arrays.equals(hostedBody, opened.stream().readAllBytes()))
throw new AssertionError("Virtual-hosted bucket or key was parsed incorrectly");
}
if (virtualHostPut(port, "objects.s3.test", "other.s3.test", hostedBody) != 403)
throw new AssertionError("Changing a signed virtual hostname was accepted");
testGatewayConcurrency(store, client, executor);
System.out.println("HTTP tests passed: capabilities, objects, copy, checksums, listing, multipart, attributes, buckets, versioning, ACLs");
} finally {
server.stop(0);