Remove dependence on logging framework. Just raise exceptions instead.

This commit is contained in:
Jonathan Bernard 2025-01-05 01:55:50 -06:00
parent feeef6429c
commit 9f302556f6
3 changed files with 9 additions and 33 deletions

View File

@ -1,6 +1,6 @@
# Package # Package
version = "0.4.1" version = "0.4.2"
author = "Jonathan Bernard" author = "Jonathan Bernard"
description = "Jonathan's opinionated extensions and auth layer for Jester." description = "Jonathan's opinionated extensions and auth layer for Jester."
license = "MIT" license = "MIT"
@ -15,7 +15,7 @@ requires "nim >= 1.6.2"
requires @["bcrypt", "mummy", "uuids", "webby"] requires @["bcrypt", "mummy", "uuids", "webby"]
# from https://git.jdb-software.com/jdb/nim-packages # from https://git.jdb-software.com/jdb/nim-packages
requires @["jwt_full >= 0.2.0", "namespaced_logging >= 0.3.0"] requires @["jwt_full >= 0.2.0"]
task unittest, "Runs the unit test suite.": task unittest, "Runs the unit test suite.":
exec "nim c -r test/runner" exec "nim c -r test/runner"

View File

@ -1,5 +1,5 @@
import std/[json, jsonutils, logging, options, sequtils, strtabs, strutils] import std/[json, jsonutils, options, sequtils, strtabs, strutils]
import mummy, namespaced_logging, webby import mummy, webby
import std/httpcore except HttpHeaders import std/httpcore except HttpHeaders
@ -7,12 +7,6 @@ import ./apierror
const CONTENT_TYPE_JSON* = "application/json" const CONTENT_TYPE_JSON* = "application/json"
var logNs {.threadvar.}: LoggingNamespace
template log(): untyped =
if logNs.isNil: logNs = getLoggerForNamespace("buffoonery/apiutils", lvlDebug)
logNs
## Response Utilities ## Response Utilities
## ------------------ ## ------------------
@ -65,11 +59,9 @@ proc makeCorsHeaders*(
} }
else: else:
if reqOrigin.isSome: if reqOrigin.isSome:
log().debug "Unrecognized Origin '" & reqOrigin.get & "', excluding CORS headers." @{"X-Invalid-Origin-Details": "Unrecognized origin '" & reqOrigin.get & "'."}
else: else:
log().debug "No Origin supplied, excluding CORS headers." @{"X-Invalid-Origin-Details": "Missing Origin."}
log().debug "Valid origins: " & allowedOrigins.join(", ")
@{:}
proc makeCorsHeaders*( proc makeCorsHeaders*(

View File

@ -1,6 +1,5 @@
import std/[cookies, json, logging, options, sequtils, strtabs, import std/[cookies, json, options, sequtils, strtabs, strutils, tables, times]
strutils, tables, times] import mummy, uuids, webby
import mummy, namespaced_logging, uuids, webby
import std/httpclient except HttpHeaders import std/httpclient except HttpHeaders
import jwt_full, jwt_full/encoding import jwt_full, jwt_full/encoding
@ -28,12 +27,6 @@ type
issuerKeys: TableRef[string, JwkSet] issuerKeys: TableRef[string, JwkSet]
var logNs {.threadvar.}: LoggingNamespace
template log(): untyped =
if logNs.isNil: logNs = getLoggerForNamespace("buffoonery/auth", lvlDebug)
logNs
proc failAuth*(reason: string, parentException: ref Exception = nil) = proc failAuth*(reason: string, parentException: ref Exception = nil) =
## Syntactic sugar to raise an AuthError. Reason will be the exception ## Syntactic sugar to raise an AuthError. Reason will be the exception
@ -74,20 +67,17 @@ proc fetchJWKs(openIdConfigUrl: string): JwkSet {.gcsafe.} =
let http = newHttpClient() let http = newHttpClient()
# Inspect the OAuth metadata via the well-known address. # Inspect the OAuth metadata via the well-known address.
log().debug "fetchJwks: Fetching metadata from " & openIdConfigUrl
let metadata = parseJson(http.getContent(openIdConfigUrl)) let metadata = parseJson(http.getContent(openIdConfigUrl))
# Fetch the keys from the jwk_keys URI. # Fetch the keys from the jwk_keys URI.
let jwksKeysURI = metadata.getOrFail("jwks_uri").getStr let jwksKeysURI = metadata.getOrFail("jwks_uri").getStr
debug "fetchJwks: Fetching JWKs from " & jwksKeysURI
let jwksKeys = parseJson(http.getContent(jwksKeysURI)) let jwksKeys = parseJson(http.getContent(jwksKeysURI))
# Parse and load the keys provided. # Parse and load the keys provided.
return initJwkSet(jwksKeys) return initJwkSet(jwksKeys)
except: except:
log().error "unable to fetch issuer signing keys: " & getCurrentExceptionMsg() failAuth("unable to fetch isser signing keys", getCurrentException())
failAuth "unable to fetch isser signing keys"
proc addSigningKeys*(ctx: ApiAuthContext, issuer: string, keySet: JwkSet): void = proc addSigningKeys*(ctx: ApiAuthContext, issuer: string, keySet: JwkSet): void =
@ -97,7 +87,6 @@ proc addSigningKeys*(ctx: ApiAuthContext, issuer: string, keySet: JwkSet): void
if ctx.issuerKeys.isNil: ctx.issuerKeys = newTable[string, JwkSet]() if ctx.issuerKeys.isNil: ctx.issuerKeys = newTable[string, JwkSet]()
ctx.issuerKeys[issuer] = keySet ctx.issuerKeys[issuer] = keySet
except: except:
log().error "unable to add a set of signing keys: " & getCurrentExceptionMsg()
raise getCurrentException() raise getCurrentException()
@ -134,7 +123,6 @@ proc findSigningKey*(ctx: ApiAuthContext, jwt: JWT, allowFetch = true): JWK {.gc
failAuth "unable to find JWT signing key" failAuth "unable to find JWT signing key"
except: except:
log().error "unable to find JWT signing key: " & getCurrentExceptionMsg()
failAuth("unable to find JWT signing key", getCurrentException()) failAuth("unable to find JWT signing key", getCurrentException())
@ -142,7 +130,6 @@ proc validateJWT*(ctx: ApiAuthContext, jwt: JWT) =
## Given a JWT, validate that it is a well-formed JWT, validate the issuer's ## Given a JWT, validate that it is a well-formed JWT, validate the issuer's
## signature on the token, and validate all the claims that it preesnts. ## signature on the token, and validate all the claims that it preesnts.
try: try:
log().debug "Validating JWT: " & $jwt
if jwt.claims.iss.isNone: failAuth "Missing 'iss' claim." if jwt.claims.iss.isNone: failAuth "Missing 'iss' claim."
let jwtIssuer = jwt.claims.iss.get let jwtIssuer = jwt.claims.iss.get
@ -157,9 +144,6 @@ proc validateJWT*(ctx: ApiAuthContext, jwt: JWT) =
if jwt.claims.exp.isNone: failAuth "Missing or invalid 'exp' claim." if jwt.claims.exp.isNone: failAuth "Missing or invalid 'exp' claim."
if not ctx.validAudiences.contains(jwt.claims.aud.get): if not ctx.validAudiences.contains(jwt.claims.aud.get):
log().debug(
"Valid audiences: $#\ttoken audience: $#" %
[$ctx.validAudiences, jwt.claims.aud.get])
failAuth "JWT is not for us (invalid audience)." failAuth "JWT is not for us (invalid audience)."
let signingAlgorithm = jwt.header.alg.get let signingAlgorithm = jwt.header.alg.get