From 167b8b7bb45067c3f40eab98b1cf5ee876fbb582 Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Tue, 17 Nov 2020 20:07:28 -0500 Subject: [PATCH] WIP --- src/JobsJobsJobs.Api/Auth.fs | 26 ++++++++++++++++---- src/JobsJobsJobs.Api/Handlers.fs | 18 ++++++++++++++ src/JobsJobsJobs.Api/JobsJobsJobs.Api.fsproj | 3 ++- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/JobsJobsJobs.Api/Auth.fs b/src/JobsJobsJobs.Api/Auth.fs index 2eb3737..1393794 100644 --- a/src/JobsJobsJobs.Api/Auth.fs +++ b/src/JobsJobsJobs.Api/Auth.fs @@ -12,13 +12,14 @@ type FSharpJsonSerializer () = Json.deserialize<'T> json +open Data +open Domain +open JWT.Algorithms +open JWT.Builder +open System open System.Net.Http open System.Net.Http.Headers -open Data -open JWT.Builder -open JobsJobsJobs.Api.Domain -open JWT.Algorithms -open System +open JWT.Exceptions /// Verify a user's credentials with No Agenda Social let verifyWithMastodon accessToken = async { @@ -53,3 +54,18 @@ let createJwt citizenId = async { | Ok None -> return Error (exn "Citizen record not found") | Error exn -> return Error exn } + +/// Validate the given token +let validateJwt token = + try + let paylod = + JwtBuilder() + .WithAlgorithm(HMACSHA256Algorithm ()) + // TODO: generate separate secret for server + .WithSecret(config.auth.secret) + .MustVerifySignature() + .Decode> token + CitizenId.tryParse (paylod.["sub"] :?> string) + with + | :? TokenExpiredException -> Error "Token is expired" + | :? SignatureVerificationException -> Error "Invalid token signature" diff --git a/src/JobsJobsJobs.Api/Handlers.fs b/src/JobsJobsJobs.Api/Handlers.fs index 695cc80..4f2967d 100644 --- a/src/JobsJobsJobs.Api/Handlers.fs +++ b/src/JobsJobsJobs.Api/Handlers.fs @@ -12,10 +12,28 @@ module private Internal = open Suave.Writers + /// Read the JWT and get the authorized user ID + let authorizedUser : WebPart = + fun ctx -> + match ctx.request.header "Authorization" with + | Choice1Of2 bearer -> + let token = (bearer.Split " ").[1] + match Auth.validateJwt token with + | Ok citizenId -> + setUserData "citizenId" citizenId ctx + | Error err -> + RequestErrors.BAD_REQUEST err ctx + | Choice2Of2 _ -> + RequestErrors.BAD_REQUEST "Authorization header must be specified" ctx + /// Send a JSON response let json x = Successful.OK (Json.serialize x) >=> setMimeType "application/json; charset=utf-8" + + /// Get the current citizen ID from the context + let currentCitizenId ctx = + ctx.userState.["citizenId"] :?> CitizenId /// Handler to return the Vue application diff --git a/src/JobsJobsJobs.Api/JobsJobsJobs.Api.fsproj b/src/JobsJobsJobs.Api/JobsJobsJobs.Api.fsproj index dc83e6c..2dc0480 100644 --- a/src/JobsJobsJobs.Api/JobsJobsJobs.Api.fsproj +++ b/src/JobsJobsJobs.Api/JobsJobsJobs.Api.fsproj @@ -2,7 +2,8 @@ Exe - netcoreapp3.1 + net5.0 + preview