WIP: tests, REST API support (auth).

This commit is contained in:
Jonathan Bernard
2017-03-19 06:34:42 -05:00
parent 2551affd4b
commit b5a70f6de0
13 changed files with 211 additions and 20 deletions

View File

@ -0,0 +1,120 @@
import asyncdispatch, bcrypt, jester, json, jwt, osproc, sequtils, tempfile, times
import ./configuration, ./core, private/util
settings:
port = Port(8180)
type Worker = object
process*: Process
workingDir*: string
type
Session = object
user*: UserRef
issuedAt*, expires*: TimeInfo
const ISO_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"
const BCRYPT_ROUNDS = 16
proc makeJsonResp(status: HttpCode, details: string = ""): string =
result = $(%* {
"statusCode": status.int,
"status": $status,
"details": details
})
proc newSession(user: UserRef): Session =
result = Session(
user: user,
issuedAt: getGMTime(getTime()),
expires: daysForward(7))
proc toJWT(session: Session): JWT =
result = JWT(
header: JOSEHeader(alg: HS256, typ: "jwt"),
claims: toClaims(%*{
"sub": session.user.name,
"iss": session.issuedAt.format(ISO_TIME_FORMAT),
"exp": session.expires.format(ISO_TIME_FORMAT) }))
proc extractSession(cfg: StrawBossConfig, request: Request): Session =
# Find the auth header
if not request.headers.hasKey("Authentication"):
raiseEx "No auth token."
# Read and verify the JWT token
let jwt = toJWT(request.headers["Authentication"])
var secret = cfg.authSecret
if not jwt.verify(secret): raiseEx "Unable to verify auth token."
jwt.verifyTimeClaims()
# Find the user record (if authenticated)
let username = jwt.claims["sub"].node.str
let users = cfg.users.filterIt(it.name == username)
if users.len != 1: raiseEx "Could not find session user."
result = Session(
user: users[0],
issuedAt: parse(jwt.claims["iat"].node.str, ISO_TIME_FORMAT),
expires: parse(jwt.claims["exp"].node.str, ISO_TIME_FORMAT))
template requireAuth() =
var session {.inject.}: Session
try: session = extractSession(givenCfg, request)
except: resp(Http401, makeJsonResp(Http401), "application/json")
proc spawnWorker(req: RunRequest): Worker =
let dir = mkdtemp()
var args = @["run", req.projectName, req.stepName, "-r", req.buildRef, "-w", dir]
if req.forceRebuild: args.add("-f")
result = Worker(
process: startProcess("strawboss", ".", args, loadEnv(), {poUsePath}),
workingDir: dir)
proc start*(givenCfg: StrawBossConfig): void =
var workers: seq[Worker] = @[]
routes:
get "/api/ping":
resp($(%*"pong"), "application/json")
get "/api/auth-token":
resp(Http501, makeJsonResp(Http501), "application/json")
get "/api/projects":
requireAuth()
resp($(%(givenCfg.projects)), "application/json")
get "/api/auth-token":
var username, pwd: string
try:
username = @"username"
pwd = @"password"
except: resp(Http401, makeJsonResp(Http401, "fields 'username' and 'password' required"))
let users = givenCfg.users.filterIt(it.name == username)
if users.len != 1:
resp(Http401, makeJsonResp(Http401, "invalid username or password"))
let user = users[0]
# generate salt
let salt = genSalt(BCRYPT_ROUNDS)
# bcrypt
let hashedPwd = hash(pwd, salt)
stdout.writeLine "Hashed pwd is " & $hashedPwd
resp(Http501, makeJsonResp(Http501))
post "/api/project/@projectName/@stepName/run/@buildRef?":
workers.add(spawnWorker(RunRequest(
projectName: @"projectName",
stepName: @"stepName",
buildRef: if @"buildRef" != "": @"buildRef" else: nil,
forceRebuild: false))) # TODO support this with optional query params
runForever()