Add WebSocket auth — JWT token validation on WS upgrade handshake
- websocket.nim: check Authorization Bearer token before WebSocket upgrade - httpserver.nim: pass config + jwtSecret to WsServer
This commit is contained in:
@@ -42,11 +42,11 @@ proc newHttpServer*(config: BaraConfig): HttpServer =
|
||||
let db = newLSMTree(dataDir)
|
||||
let ctx = newExecutionContext(db)
|
||||
ctx.txnManager = newTxnManager()
|
||||
let ws = newWsServer()
|
||||
let secret = if config.jwtSecret.len > 0: config.jwtSecret else: "baradb-default-secret-change-in-production!"
|
||||
let ws = newWsServer(config, secret)
|
||||
ctx.onChange = proc(ev: ChangeEvent) =
|
||||
let msg = $ev.kind & " " & ev.table
|
||||
asyncCheck ws.broadcastToTable(ev.table, msg)
|
||||
let secret = if config.jwtSecret.len > 0: config.jwtSecret else: "baradb-default-secret-change-in-production!"
|
||||
HttpServer(config: config, running: false, db: db, ctx: ctx,
|
||||
secretKey: secret,
|
||||
metrics: Metrics(), ws: ws)
|
||||
|
||||
@@ -5,6 +5,8 @@ import std/strutils
|
||||
import std/tables
|
||||
import std/base64
|
||||
import std/sets
|
||||
import config
|
||||
import jwt as jwtlib
|
||||
|
||||
type
|
||||
WsFrame = object
|
||||
@@ -24,11 +26,14 @@ type
|
||||
clients*: Table[int, WsClient]
|
||||
nextId: int
|
||||
running: bool
|
||||
config*: BaraConfig
|
||||
secretKey*: string
|
||||
onInsert*: proc (table, key, value: string) {.closure.}
|
||||
onDelete*: proc (table, key: string) {.closure.}
|
||||
|
||||
proc newWsServer*(): WsServer =
|
||||
WsServer(clients: initTable[int, WsClient](), nextId: 1, running: false)
|
||||
proc newWsServer*(cfg: BaraConfig = defaultConfig(), secret: string = ""): WsServer =
|
||||
WsServer(clients: initTable[int, WsClient](), nextId: 1, running: false,
|
||||
config: cfg, secretKey: secret)
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# WebSocket frame encoding/decoding (RFC 6455)
|
||||
@@ -270,6 +275,25 @@ proc handleConnection(server: WsServer, client: AsyncSocket) {.async.} =
|
||||
client.close()
|
||||
return
|
||||
|
||||
# Auth check
|
||||
if server.config.authEnabled:
|
||||
let authHeader = headers.getOrDefault("authorization", "")
|
||||
if authHeader.len == 0 or not authHeader.startsWith("Bearer "):
|
||||
await client.send("HTTP/1.1 401 Unauthorized\r\n\r\n")
|
||||
client.close()
|
||||
return
|
||||
let tokenStr = authHeader[7..^1]
|
||||
try:
|
||||
let token = tokenStr.toJWT()
|
||||
if not token.verify(server.secretKey, HS256):
|
||||
await client.send("HTTP/1.1 401 Unauthorized\r\n\r\n")
|
||||
client.close()
|
||||
return
|
||||
except:
|
||||
await client.send("HTTP/1.1 401 Unauthorized\r\n\r\n")
|
||||
client.close()
|
||||
return
|
||||
|
||||
let acceptKey = computeAcceptKey(wsKey)
|
||||
|
||||
var response = "HTTP/1.1 101 Switching Protocols\r\n"
|
||||
|
||||
Reference in New Issue
Block a user