nimbus-eth1/hive_integration/nodocker/engine/auths_tests.nim

148 lines
4.4 KiB
Nim

# Nimbus
# Copyright (c) 2023-2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed except
# according to those terms.
import
std/[base64, times, strutils],
test_env,
chronicles,
nimcrypto/[hmac, sha2],
web3/engine_api_types,
web3/conversions,
json_rpc/[rpcclient],
./types
# JWT Authentication Related
const
defaultJwtTokenSecretBytes = "secretsecretsecretsecretsecretse"
maxTimeDriftSeconds = 60'i64
defaultProtectedHeader = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9"
createRpcSigsFromNim(RpcClient):
proc engine_getClientVersionV1(version: ClientVersionV1): seq[ClientVersionV1]
func base64urlEncode(x: auto): string =
base64.encode(x, safe = true).replace("=", "")
func prepareAuthCallToken(secret: string, time: int64): string =
let key = cast[seq[byte]](secret)
let payload = """{"iat": $1}""" % [$time]
let token = defaultProtectedHeader & "." & payload.base64urlEncode
let sig = base64urlEncode(sha256.hmac(key, token).data)
token & "." & sig
proc getClient(env: TestEnv, token: string): RpcHttpClient =
proc authHeaders(): seq[(string, string)] =
@[("Authorization", "Bearer " & token)]
let client = newRpcHttpClient(getHeaders = authHeaders)
waitFor client.connect("127.0.0.1", env.engine.httpPort, false)
return client
template genAuthTest(procName: untyped, timeDriftSeconds: int64, customAuthSecretBytes: string, authOK: bool) =
proc procName(env: TestEnv): bool =
# Default values
var
# All test cases send a simple ClientVersionV1 to check the Authentication mechanism (JWT)
tVersion = default(ClientVersionV1) # handler doesn't check contents
testSecret = customAuthSecretBytes
testTime = getTime().toUnix
if testSecret.len == 0:
testSecret = defaultJwtTokenSecretBytes
if timeDriftSeconds != 0:
testTime = testTime + timeDriftSeconds
let token = prepareAuthCallToken(testSecret, testTime)
let client = getClient(env, token)
try:
discard waitFor client.engine_getClientVersionV1(tVersion)
testCond authOk:
error "Authentication was supposed to fail authentication but passed"
except CatchableError:
testCond not authOk:
error "Authentication was supposed to pass authentication but failed"
return true
genAuthTest(authTest1, 0'i64, "", true)
genAuthTest(authTest2, 0'i64, "secretsecretsecretsecretsecrets", false)
genAuthTest(authTest3, 0'i64, "\0secretsecretsecretsecretsecretse", false)
genAuthTest(authTest4, -1 - maxTimeDriftSeconds, "", false)
genAuthTest(authTest5, 1 - maxTimeDriftSeconds, "", true)
genAuthTest(authTest6, maxTimeDriftSeconds + 1, "", false)
genAuthTest(authTest7, maxTimeDriftSeconds - 1, "", true)
type
AuthSpec* = ref object of BaseSpec
exec*: proc(env: TestEnv): bool
proc specExecute(ws: BaseSpec): bool =
let
ws = AuthSpec(ws)
env = TestEnv.new("", true)
env.engine.setRealTTD()
result = ws.exec(env)
env.close()
# JWT Authentication Tests
let authTestList* = [
TestDesc(
name: "JWT Authentication: No time drift, correct secret",
run: specExecute,
spec: AuthSpec(
exec: authTest1,
)
),
TestDesc(
name: "JWT Authentication: No time drift, incorrect secret (shorter)",
run: specExecute,
spec: AuthSpec(
exec: authTest2,
)
),
TestDesc(
name: "JWT Authentication: No time drift, incorrect secret (longer)",
run: specExecute,
spec: AuthSpec(
exec: authTest3,
)
),
TestDesc(
name: "JWT Authentication: Negative time drift, exceeding limit, correct secret",
run: specExecute,
spec: AuthSpec(
exec: authTest4,
)
),
TestDesc(
name: "JWT Authentication: Negative time drift, within limit, correct secret",
run: specExecute,
spec: AuthSpec(
exec: authTest5,
)
),
TestDesc(
name: "JWT Authentication: Positive time drift, exceeding limit, correct secret",
run: specExecute,
spec: AuthSpec(
exec: authTest6,
)
),
TestDesc(
name: "JWT Authentication: Positive time drift, within limit, correct secret",
run: specExecute,
spec: AuthSpec(
exec: authTest7,
)
)
]