all repos — litestore @ 5cfd43c13e38cf73a1a9965764e20a41c33a6e29

A minimalist nosql document store.

Implemented basic support for OAuth2 authentication/authorization.
h3rald h3rald@h3rald.com
Sun, 14 Oct 2018 14:12:57 +0200
commit

5cfd43c13e38cf73a1a9965764e20a41c33a6e29

parent

5fc6edc72c51ffc7472dce665824607e88480375

M .gitignore.gitignore

@@ -4,6 +4,7 @@ *.db

*.db-journal http_api test.nim +auth.json html5 css3 sqlite3_analyzer
M litestore.nimblelitestore.nimble

@@ -23,7 +23,7 @@ skipDirs = @["test"]

# Dependencies -requires "nim >= 0.18.0" +requires "nim >= 0.18.0", "https://github.com/h3rald/nim-jwt" # Build
M src/litestorepkg/lib/cli.nimsrc/litestorepkg/lib/cli.nim

@@ -1,7 +1,8 @@

import parseopt, strutils, - strtabs + strtabs, + json import logger, config,

@@ -16,6 +17,7 @@ directory:string = ""

readonly = false logLevel = "warn" mount = false + auth = newJNull() exOperation:string = "" exFile:string = "" exBody:string = ""

@@ -129,6 +131,10 @@ of "type", "t":

if val == "": fail(113, "Content type not specified.") exType = val + of "auth": + if val == "": + fail(114, "Authentication/Authorization configuration file not specified.") + auth = val.parseFile of "mount", "m": mount = true of "version", "v":

@@ -166,6 +172,7 @@ LS.directory = directory

LS.readonly = readonly LS.favicon = favicon LS.loglevel = loglevel +LS.auth = auth LS.mount = mount LS.execution.file = exFile LS.execution.body = exBody
M src/litestorepkg/lib/server.nimsrc/litestorepkg/lib/server.nim

@@ -7,7 +7,10 @@ pegs,

strtabs, logger, cgi, - os + os, + json, + tables, + jwt import types, utils,

@@ -33,6 +36,30 @@ LOG.info("Exiting...")

quit() proc processApiUrl(req: LSRequest, LS: LiteStore, info: ResourceInfo): LSResponse = + let reqUri = info.resource & "/" & info.id + let uriParts = reqUri.split("/") + let uri = "/" & uriParts[0..uriParts.len-2].join("/") & "/" + let reqMethod = $req.reqMethod + # Authentication/Authorization + if LS.auth != newJNull(): + if LS.auth["access"].hasKey(uri): + let access = LS.auth["access"][uri] + if access.hasKey(reqMethod): + if not req.headers.hasKey("Authorization"): + return resError(Http401, "Unauthorized - No token") + let token = req.headers["Authorization"].replace(peg"^ 'Bearer '", "") + # Validate token + try: + let jwt = token.toJwt() + var sig = LS.auth["signature"].getStr + discard verify(jwt, sig) + verifyTimeClaims(jwt) + # Validate scope + let scopes = $jwt.claims["scope"].node.str.split(peg"\s+") + if not scopes.contains access[reqMethod].getStr: + return resError(Http403, "Forbidden - You are not permitted to access this resource") + except: + return resError(Http401, "Unauthorized - Invalid token") if info.version == "v4": if info.resource.match(peg"^docs / info / tags$"): return api_v4.route(req, LS, info.resource, info.id)
M src/litestorepkg/lib/types.nimsrc/litestorepkg/lib/types.nim

@@ -2,6 +2,7 @@ import

x_db_sqlite, asynchttpserver, pegs, + json, strtabs import config

@@ -76,6 +77,7 @@ mount*: bool

readonly*: bool appname*: string appversion*: string + auth*: JsonNode favicon*:string loglevel*:string LSRequest* = asynchttpserver.Request