feat: fill in server
This commit is contained in:
1 parent
b65cde74c6
commit
5a74f25cfa
1 file changed
+161
+161
@@ -5803,3 +5803,164 @@ test "user_admin requires admin role once auth is enabled" {
|
|||||||
try server.start();
|
try server.start();
|
||||||
defer server.stop();
|
defer server.stop();
|
||||||
|
|
||||||
|
const client_mod = @import("client.zig");
|
||||||
|
|
||||||
|
var viewer = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||||
|
defer viewer.close();
|
||||||
|
try viewer.authenticate("viewer", "pass");
|
||||||
|
try std.testing.expectError(client_mod.ClientError.ServerForbidden, viewer.adminCreateUser("nobody", "x", .readonly, 16));
|
||||||
|
|
||||||
|
var admin = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||||
|
defer admin.close();
|
||||||
|
try admin.authenticate("root", "toor");
|
||||||
|
try admin.adminCreateUser("bob", "b-pass", .readwrite, 16);
|
||||||
|
|
||||||
|
const users = try admin.adminListUsers(allocator);
|
||||||
|
defer authmod.freeUserList(allocator, users);
|
||||||
|
try std.testing.expectEqual(@as(usize, 3), users.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "user_admin set_password, set_role, and delete round trip over the wire, enforced by real auth" {
|
||||||
|
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);
|
||||||
|
|
||||||
|
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 admin = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||||
|
defer admin.close();
|
||||||
|
try admin.authenticate("root", "toor");
|
||||||
|
|
||||||
|
try admin.adminCreateUser("alice", "old-pass", .readonly, 16);
|
||||||
|
|
||||||
|
// The freshly created account really authenticates against the live,
|
||||||
|
// enforced auth store - not just written to a table nobody checks.
|
||||||
|
var probe = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||||
|
defer probe.close();
|
||||||
|
try probe.authenticate("alice", "old-pass");
|
||||||
|
|
||||||
|
try admin.adminSetPassword("alice", "new-pass", 16);
|
||||||
|
var probe2 = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||||
|
defer probe2.close();
|
||||||
|
try std.testing.expectError(client_mod.ClientError.ServerUnauthorized, probe2.authenticate("alice", "old-pass"));
|
||||||
|
try probe2.authenticate("alice", "new-pass");
|
||||||
|
|
||||||
|
try admin.adminSetRole("alice", .admin);
|
||||||
|
const users = try admin.adminListUsers(allocator);
|
||||||
|
defer authmod.freeUserList(allocator, users);
|
||||||
|
var sawAlice = false;
|
||||||
|
for (users) |u| {
|
||||||
|
if (std.mem.eql(u8, u.username, "alice")) {
|
||||||
|
try std.testing.expectEqual(authmod.Role.admin, u.role);
|
||||||
|
sawAlice = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try std.testing.expect(sawAlice);
|
||||||
|
|
||||||
|
try admin.adminDeleteUser("alice");
|
||||||
|
var probe3 = try client_mod.Client.connect(allocator, server.boundAddress());
|
||||||
|
defer probe3.close();
|
||||||
|
try std.testing.expectError(client_mod.ClientError.ServerUnauthorized, probe3.authenticate("alice", "new-pass"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "user_admin reports conflict on duplicate create and not-found on missing user" {
|
||||||
|
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", .readonly, 16);
|
||||||
|
try std.testing.expectError(client_mod.ClientError.ServerConflict, client.adminCreateUser("alice", "other", .admin, 16));
|
||||||
|
try std.testing.expectError(client_mod.ClientError.ServerUserNotFound, client.adminSetPassword("ghost", "x", 16));
|
||||||
|
try std.testing.expectError(client_mod.ClientError.ServerUserNotFound, client.adminSetRole("ghost", .admin));
|
||||||
|
try std.testing.expectError(client_mod.ClientError.ServerUserNotFound, client.adminDeleteUser("ghost"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "server rejects a malformed user_admin frame with bad_request without crashing" {
|
||||||
|
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 stream = try std.net.tcpConnectToAddress(server.boundAddress());
|
||||||
|
defer stream.close();
|
||||||
|
|
||||||
|
try protocol.writeFrame(stream.writer(), @intFromEnum(protocol.Op.user_admin), "\x00");
|
||||||
|
var frame = try protocol.readFrame(allocator, stream.reader());
|
||||||
|
defer frame.deinit();
|
||||||
|
try std.testing.expectEqual(@intFromEnum(protocol.Status.bad_request), frame.tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "server metrics register into an external Prometheus registry" {
|
||||||
|
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);
|
||||||
|
server.enableRateLimit(1, 1000);
|
||||||
|
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.ping();
|
||||||
|
client.ping() catch {};
|
||||||
|
|
||||||
|
var reg = metrics.Registry.init(allocator);
|
||||||
|
defer reg.deinit();
|
||||||
|
try server.registerMetrics(®);
|
||||||
|
|
||||||
|
var buf = std.ArrayList(u8).init(allocator);
|
||||||
|
defer buf.deinit();
|
||||||
|
try reg.exportText(allocator, buf.writer());
|
||||||
|
try std.testing.expect(std.mem.indexOf(u8, buf.items, "cobalt_server_requests_total 2\n") != null);
|
||||||
|
try std.testing.expect(std.mem.indexOf(u8, buf.items, "cobalt_server_rate_limited_total 1\n") != null);
|
||||||
|
try std.testing.expect(std.mem.indexOf(u8, buf.items, "cobalt_server_conn_rate_limited_total 0\n") != null);
|
||||||
|
try std.testing.expect(std.mem.indexOf(u8, buf.items, "cobalt_server_unauthorized_total 0\n") != null);
|
||||||
|
try std.testing.expect(std.mem.indexOf(u8, buf.items, "cobalt_server_forbidden_total 0\n") != null);
|
||||||
|
try std.testing.expect(std.mem.indexOf(u8, buf.items, "cobalt_server_session_expired_total 0\n") != null);
|
||||||
|
try std.testing.expect(std.mem.indexOf(u8, buf.items, "cobalt_server_sessions_swept_total 0\n") != null);
|
||||||
|
try std.testing.expect(std.mem.indexOf(u8, buf.items, "cobalt_server_ttl_swept_total 0\n") != null);
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user