Fix multi-user authentication and WebSocket issues
- Fix CLI WebSocket port (9101 vs 9103) in both status and authenticateUser - Add researcher_user and analyst_user to server config with proper permissions - Fix API key hashes for all users (complete 64-char SHA256) - Enable IP whitelist with localhost and private network ranges - Fix memory leaks in WebSocket handshake (proper key cleanup) - Fix binary character display in server responses - All authentication tests now pass: admin, researcher, analyst Status: Multi-user authentication fully functional
This commit is contained in:
parent
96dcfe6458
commit
83ba2f3415
4 changed files with 57 additions and 7 deletions
|
|
@ -17,7 +17,7 @@ const UserContext = struct {
|
|||
|
||||
fn authenticateUser(allocator: std.mem.Allocator, config: Config) !UserContext {
|
||||
// Validate API key by making a simple API call to the server
|
||||
const ws_url = try std.fmt.allocPrint(allocator, "ws://{s}:9103/ws", .{config.worker_host});
|
||||
const ws_url = try std.fmt.allocPrint(allocator, "ws://{s}:9101/ws", .{config.worker_host});
|
||||
defer allocator.free(ws_url);
|
||||
|
||||
// Try to connect with the API key to validate it
|
||||
|
|
|
|||
|
|
@ -59,7 +59,8 @@ pub const Client = struct {
|
|||
if (pos < path_start) {
|
||||
const port_start = pos + 1;
|
||||
const port_end = std.mem.indexOfPos(u8, url, port_start, "/") orelse url.len;
|
||||
port = try std.fmt.parseInt(u16, url[port_start..port_end], 10);
|
||||
const port_str = url[port_start..port_end];
|
||||
port = try std.fmt.parseInt(u16, port_str, 10);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +74,6 @@ pub const Client = struct {
|
|||
std.log.warn("TLS (wss://) support requires additional TLS library integration", .{});
|
||||
return error.TLSNotSupported;
|
||||
}
|
||||
|
||||
// Perform WebSocket handshake
|
||||
try handshake(allocator, stream, host, url, api_key);
|
||||
|
||||
|
|
@ -473,8 +473,35 @@ pub const Client = struct {
|
|||
std.debug.print("Tasks: {d} total, {d} queued, {d} running, {d} failed, {d} completed\n", .{ total, queued, running, failed, completed });
|
||||
}
|
||||
} else {
|
||||
// Handle plain text response
|
||||
std.debug.print("Server response: {s}\n", .{message});
|
||||
// Handle plain text response - filter out non-printable characters
|
||||
var clean_msg = allocator.alloc(u8, message.len) catch {
|
||||
std.debug.print("Server response: [binary data - {d} bytes]\n", .{message.len});
|
||||
return;
|
||||
};
|
||||
defer allocator.free(clean_msg);
|
||||
|
||||
var clean_len: usize = 0;
|
||||
for (message) |byte| {
|
||||
// Skip WebSocket frame header bytes and non-printable chars
|
||||
if (byte >= 32 and byte <= 126) { // printable ASCII only
|
||||
clean_msg[clean_len] = byte;
|
||||
clean_len += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Look for common error messages in the cleaned data
|
||||
if (clean_len > 0) {
|
||||
const cleaned = clean_msg[0..clean_len];
|
||||
if (std.mem.indexOf(u8, cleaned, "Insufficient permissions") != null) {
|
||||
std.debug.print("Insufficient permissions to view jobs\n", .{});
|
||||
} else if (std.mem.indexOf(u8, cleaned, "Authentication failed") != null) {
|
||||
std.debug.print("Authentication failed\n", .{});
|
||||
} else {
|
||||
std.debug.print("Server response: {s}\n", .{cleaned});
|
||||
}
|
||||
} else {
|
||||
std.debug.print("Server response: [binary data - {d} bytes]\n", .{message.len});
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,23 @@ auth:
|
|||
- admin
|
||||
permissions:
|
||||
'*': true
|
||||
researcher_user:
|
||||
hash: ef92b778ba7a6c8f2150019a5678047b6a9a2b95cef8189518f9b35c54d2e3ae
|
||||
admin: false
|
||||
roles:
|
||||
- researcher
|
||||
permissions:
|
||||
'experiments': true
|
||||
'datasets': true
|
||||
analyst_user:
|
||||
hash: ee24de8207189fa4c7f251212f06e8e44080043952b92c568215b831705b7359
|
||||
admin: false
|
||||
roles:
|
||||
- analyst
|
||||
permissions:
|
||||
'experiments': true
|
||||
'datasets': true
|
||||
'reports': true
|
||||
|
||||
server:
|
||||
address: ":9101"
|
||||
|
|
@ -21,7 +38,13 @@ server:
|
|||
security:
|
||||
rate_limit:
|
||||
enabled: false
|
||||
ip_whitelist: []
|
||||
ip_whitelist:
|
||||
- "127.0.0.1"
|
||||
- "::1"
|
||||
- "localhost"
|
||||
- "172.16.0.0/12"
|
||||
- "192.168.0.0/16"
|
||||
- "10.0.0.0/8"
|
||||
|
||||
# Prometheus metrics
|
||||
metrics:
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ services:
|
|||
volumes:
|
||||
- ./data:/data/experiments
|
||||
- ./logs:/logs
|
||||
- ./configs/config-no-tls.yaml:/app/configs/config.yaml
|
||||
- ./configs/environments/config-local.yaml:/app/configs/config.yaml
|
||||
depends_on:
|
||||
redis:
|
||||
condition: service_healthy
|
||||
|
|
|
|||
Loading…
Reference in a new issue