feat: flesh out server
This commit is contained in:
1 parent
4e3fa110d0
commit
54919cf85c
1 file changed
+157
+157
@@ -5488,3 +5488,160 @@ test "server with auth enabled rejects unauthenticated requests, ping excepted"
|
||||
var client = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||
defer client.close();
|
||||
|
||||
try client.ping();
|
||||
try std.testing.expectError(client_mod.ClientError.ServerUnauthorized, client.get(allocator, "k"));
|
||||
try std.testing.expectError(client_mod.ClientError.ServerUnauthorized, client.set("k", "v"));
|
||||
try std.testing.expectEqual(@as(u64, 2), server.unauthorizedTotal.get());
|
||||
}
|
||||
|
||||
test "server rejects a bad password and accepts the correct one, then serves requests" {
|
||||
const allocator = std.testing.allocator;
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
const path = try tmp.dir.realpathAlloc(allocator, ".");
|
||||
defer allocator.free(path);
|
||||
|
||||
var db = try testDb(allocator, path);
|
||||
defer db.close();
|
||||
const store = authmod.Store.init(&db);
|
||||
try store.createUser(allocator, "alice", "hunter2", .readwrite, 16);
|
||||
|
||||
const address = try std.net.Address.parseIp("127.0.0.1", 0);
|
||||
var server = try Server.init(allocator, &db, address);
|
||||
server.enableAuth(store);
|
||||
try server.start();
|
||||
defer server.stop();
|
||||
|
||||
const client_mod = @import("client.zig");
|
||||
var client = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||
defer client.close();
|
||||
|
||||
try std.testing.expectError(client_mod.ClientError.ServerUnauthorized, client.authenticate("alice", "wrong"));
|
||||
try client.authenticate("alice", "hunter2");
|
||||
|
||||
try client.set("k", "v");
|
||||
const got = try client.get(allocator, "k");
|
||||
defer if (got) |g| allocator.free(g);
|
||||
try std.testing.expectEqualStrings("v", got.?);
|
||||
}
|
||||
|
||||
test "server enforces readonly role: reads succeed, writes are forbidden" {
|
||||
const allocator = std.testing.allocator;
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
const path = try tmp.dir.realpathAlloc(allocator, ".");
|
||||
defer allocator.free(path);
|
||||
|
||||
var db = try testDb(allocator, path);
|
||||
defer db.close();
|
||||
const store = authmod.Store.init(&db);
|
||||
try store.createUser(allocator, "viewer", "pass", .readonly, 16);
|
||||
|
||||
const address = try std.net.Address.parseIp("127.0.0.1", 0);
|
||||
var server = try Server.init(allocator, &db, address);
|
||||
server.enableAuth(store);
|
||||
try server.start();
|
||||
defer server.stop();
|
||||
|
||||
const client_mod = @import("client.zig");
|
||||
var client = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||
defer client.close();
|
||||
|
||||
try client.authenticate("viewer", "pass");
|
||||
const got = try client.get(allocator, "missing");
|
||||
try std.testing.expect(got == null);
|
||||
try std.testing.expectError(client_mod.ClientError.ServerForbidden, client.set("k", "v"));
|
||||
try std.testing.expectError(client_mod.ClientError.ServerForbidden, client.delete("k"));
|
||||
try std.testing.expectError(client_mod.ClientError.ServerForbidden, client.compact());
|
||||
const txnEntries = [_]protocol.TxnOpEntry{
|
||||
.{ .verb = .put, .table = "accounts", .pk = .{ .int = 1 } },
|
||||
};
|
||||
try std.testing.expectError(client_mod.ClientError.ServerForbidden, client.txnOp(&txnEntries));
|
||||
try std.testing.expectEqual(@as(u64, 4), server.forbiddenTotal.get());
|
||||
}
|
||||
|
||||
test "server without enableSessions returns no token from authenticate" {
|
||||
const allocator = std.testing.allocator;
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
const path = try tmp.dir.realpathAlloc(allocator, ".");
|
||||
defer allocator.free(path);
|
||||
|
||||
var db = try testDb(allocator, path);
|
||||
defer db.close();
|
||||
const store = authmod.Store.init(&db);
|
||||
try store.createUser(allocator, "alice", "hunter2", .readwrite, 16);
|
||||
|
||||
const address = try std.net.Address.parseIp("127.0.0.1", 0);
|
||||
var server = try Server.init(allocator, &db, address);
|
||||
server.enableAuth(store);
|
||||
try server.start();
|
||||
defer server.stop();
|
||||
|
||||
const client_mod = @import("client.zig");
|
||||
var client = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||
defer client.close();
|
||||
|
||||
try client.authenticate("alice", "hunter2");
|
||||
try std.testing.expect(client.sessionToken() == null);
|
||||
}
|
||||
|
||||
test "a session token from one connection authenticates a brand new connection without a password" {
|
||||
const allocator = std.testing.allocator;
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
const path = try tmp.dir.realpathAlloc(allocator, ".");
|
||||
defer allocator.free(path);
|
||||
|
||||
var db = try testDb(allocator, path);
|
||||
defer db.close();
|
||||
const store = authmod.Store.init(&db);
|
||||
try store.createUser(allocator, "alice", "hunter2", .readwrite, 16);
|
||||
|
||||
var sessions = sessionmod.SessionStore.init(allocator);
|
||||
defer sessions.deinit();
|
||||
|
||||
const address = try std.net.Address.parseIp("127.0.0.1", 0);
|
||||
var server = try Server.init(allocator, &db, address);
|
||||
server.enableAuth(store);
|
||||
server.enableSessions(&sessions, 60 * std.time.ns_per_s);
|
||||
try server.start();
|
||||
defer server.stop();
|
||||
|
||||
const client_mod = @import("client.zig");
|
||||
|
||||
var first = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||
try first.authenticate("alice", "hunter2");
|
||||
const token = try allocator.dupe(u8, first.sessionToken().?);
|
||||
defer allocator.free(token);
|
||||
first.close();
|
||||
|
||||
// A fully independent second connection, never given the password.
|
||||
var second = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||
defer second.close();
|
||||
try std.testing.expectError(client_mod.ClientError.ServerUnauthorized, second.get(allocator, "k"));
|
||||
try second.authenticateWithToken(token);
|
||||
try second.set("k", "v");
|
||||
const got = try second.get(allocator, "k");
|
||||
defer if (got) |g| allocator.free(g);
|
||||
try std.testing.expectEqualStrings("v", got.?);
|
||||
}
|
||||
|
||||
test "auth_token is rejected as unauthorized when sessions are not enabled" {
|
||||
const allocator = std.testing.allocator;
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
const path = try tmp.dir.realpathAlloc(allocator, ".");
|
||||
defer allocator.free(path);
|
||||
|
||||
var db = try testDb(allocator, path);
|
||||
defer db.close();
|
||||
const store = authmod.Store.init(&db);
|
||||
try store.createUser(allocator, "alice", "hunter2", .readwrite, 16);
|
||||
|
||||
const address = try std.net.Address.parseIp("127.0.0.1", 0);
|
||||
var server = try Server.init(allocator, &db, address);
|
||||
server.enableAuth(store);
|
||||
try server.start();
|
||||
defer server.stop();
|
||||
|
||||
Reference in new issue
Block a user