feat: continue work on server
This commit is contained in:
1 parent
54919cf85c
commit
b65cde74c6
1 file changed
+158
+158
@@ -5645,3 +5645,161 @@ test "auth_token is rejected as unauthorized when sessions are not enabled" {
|
||||
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.authenticateWithToken("whatever"));
|
||||
}
|
||||
|
||||
test "an unknown or garbage session token is rejected" {
|
||||
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 client = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||
defer client.close();
|
||||
try std.testing.expectError(client_mod.ClientError.ServerUnauthorized, client.authenticateWithToken("not-a-real-token"));
|
||||
}
|
||||
|
||||
test "an expired session forces re-authentication even on the same open connection" {
|
||||
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, 500 * std.time.ns_per_ms);
|
||||
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 client.set("k", "v");
|
||||
|
||||
std.time.sleep(700 * std.time.ns_per_ms);
|
||||
try std.testing.expectError(client_mod.ClientError.ServerUnauthorized, client.get(allocator, "k"));
|
||||
try std.testing.expectEqual(@as(u64, 1), server.sessionExpiredTotal.get());
|
||||
|
||||
// The very same connection re-authenticates and keeps working - the
|
||||
// socket itself was never the thing that expired, only the session.
|
||||
try client.authenticate("alice", "hunter2");
|
||||
const got = try client.get(allocator, "k");
|
||||
defer if (got) |g| allocator.free(g);
|
||||
try std.testing.expectEqualStrings("v", got.?);
|
||||
}
|
||||
|
||||
test "each connection authenticates independently under auth enforcement" {
|
||||
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 clientA = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||
defer clientA.close();
|
||||
var clientB = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||
defer clientB.close();
|
||||
|
||||
try clientA.authenticate("alice", "hunter2");
|
||||
try clientA.set("shared", "1");
|
||||
|
||||
// clientB never authenticated - a separate socket does not inherit
|
||||
// clientA's role even though it hits the exact same server/store.
|
||||
try std.testing.expectError(client_mod.ClientError.ServerUnauthorized, clientB.get(allocator, "shared"));
|
||||
}
|
||||
|
||||
test "server without auth enabled allows user_admin to create and list users" {
|
||||
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 address = try std.net.Address.parseIp("127.0.0.1", 0);
|
||||
var server = try Server.init(allocator, &db, address);
|
||||
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.adminCreateUser("alice", "hunter2", .readwrite, 16);
|
||||
const users = try client.adminListUsers(allocator);
|
||||
defer authmod.freeUserList(allocator, users);
|
||||
try std.testing.expectEqual(@as(usize, 1), users.len);
|
||||
try std.testing.expectEqualStrings("alice", users[0].username);
|
||||
try std.testing.expectEqual(authmod.Role.readwrite, users[0].role);
|
||||
|
||||
// The account just created over the wire really works for real auth.
|
||||
var second = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||
defer second.close();
|
||||
try second.authenticate("alice", "hunter2");
|
||||
}
|
||||
|
||||
test "user_admin requires admin role once auth is 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, "root", "toor", .admin, 16);
|
||||
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();
|
||||
|
||||
Reference in new issue
Block a user