More work; doesn't even build at this point

Why isn't JWT documented on .NET Core..... :/
This commit is contained in:
Daniel J. Summers 2019-09-28 21:30:35 -05:00
parent a690729cf9
commit 1154ae33b4
5 changed files with 80 additions and 14 deletions

View File

@ -53,8 +53,9 @@ module Configure =
.AddAntiforgery()
.AddSingleton<IClock>(SystemClock.Instance)
|> ignore
let config = svc.BuildServiceProvider().GetRequiredService<IConfiguration>()
let config = svc.BuildServiceProvider().GetRequiredService<IConfiguration>()
let authConfig = config.GetSection "Tokens"
let iss = authConfig.["Issuer"]
svc.AddAuthentication()
.AddCookie(
fun opts ->
@ -62,17 +63,16 @@ module Configure =
opts.Cookie.HttpOnly <- false
opts.Cookie.SameSite <- SameSiteMode.Strict
opts.SlidingExpiration <- true
opts.ClaimsIssuer <- authConfig.["Issuer"])
opts.ClaimsIssuer <- iss)
.AddJwtBearer(
fun opts ->
opts.SaveToken <- true
opts.ClaimsIssuer <- "PrayerTracker"
opts.TokenValidationParameters <- TokenValidationParameters ()
opts.TokenValidationParameters.ValidIssuer <- authConfig.["Issuer"]
opts.TokenValidationParameters.ValidAudience <- authConfig.["Issuer"]
opts.TokenValidationParameters.IssuerSigningKey <- SymmetricSecurityKey (Convert.FromBase64String authConfig.["Key"]))
opts.SaveToken <- true
opts.ClaimsIssuer <- iss
opts.TokenValidationParameters <- TokenValidationParameters (
ValidIssuer = iss,
ValidAudience = iss,
IssuerSigningKey = SymmetricSecurityKey (Convert.FromBase64String authConfig.["Key"])))
|> ignore
let config = svc.BuildServiceProvider().GetRequiredService<IConfiguration>()
let crypto = config.GetSection "CookieCrypto"
CookieCrypto (crypto.["Key"], crypto.["IV"]) |> setCrypto
svc.AddDbContext<AppDbContext>(
@ -195,7 +195,7 @@ module Configure =
.UseStaticFiles()
.UseSession()
.UseRequestLocalization(app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>().Value)
.UseAuthentication()
.UseSecurityMiddleware()
.UseGiraffe(webApp)
|> ignore
Views.I18N.setUpFactories <| app.ApplicationServices.GetRequiredService<IStringLocalizerFactory> ()

View File

@ -58,7 +58,9 @@ let setCrypto c = Crypto.crypto <- c
/// Properties stored in the Small Group cookie
type GroupCookie =
{ /// The Id of the small group
{ /// The token representing the group's claims
token : string
/// The Id of the small group
[<JsonProperty "g">]
GroupId : Guid
/// The password hash of the small group
@ -100,8 +102,10 @@ type TimeoutCookie =
/// The payload for the user's "Remember Me" cookie
type UserCookie =
{ /// The Id of the group into to which the user is logged
[< JsonProperty "g">]
{ /// The token representing the current user's logged in claims
token : string
/// The Id of the group into to which the user is logged
[<JsonProperty "g">]
GroupId : Guid
/// The Id of the user
[<JsonProperty "i">]

View File

@ -1,6 +1,7 @@
[<AutoOpen>]
module PrayerTracker.Extensions
open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.Http
open Microsoft.FSharpLu
open Newtonsoft.Json
@ -44,3 +45,9 @@ type ISession with
type HttpContext with
/// Get the EF database context from DI
member this.dbContext () : AppDbContext = downcast this.RequestServices.GetService typeof<AppDbContext>
type IApplicationBuilder with
/// Insert the PrayerTracker custom security middleware into the request pipeline
member this.UseSecurityMiddleware () =
this.UseMiddleware<SecurityMiddleware>();

View File

@ -15,9 +15,10 @@
<ItemGroup>
<None Include="appsettings.json" />
<Compile Include="Extensions.fs" />
<Compile Include="Cookies.fs" />
<Compile Include="Email.fs" />
<Compile Include="SecurityMiddleware.fs" />
<Compile Include="Extensions.fs" />
<Compile Include="CommonFunctions.fs" />
<Compile Include="Church.fs" />
<Compile Include="Home.fs" />

View File

@ -0,0 +1,54 @@
namespace PrayerTracker
open FSharp.Control.Tasks.V2.ContextInsensitive
open Microsoft.AspNetCore.Http
open Cookies
open System.IdentityModel.Tokens.Jwt
open System
open System.Security.Claims
open Microsoft.IdentityModel.Tokens
/// Middleware to obtain the current user or group from a cookie or the authorization header
type SecurityMiddleware (next : RequestDelegate) =
/// Try to get a JWT from the user's logged in cookie
let tryGetJwtFromUserCookie (ctx : HttpContext) =
match UserCookie.fromPayload ctx.Request.Cookies.[Key.Cookie.user] with
| Some cookie -> Some cookie.token
| None -> None
/// Try to get a JWT from a group's logged in cookie
let tryGetJwtFromGroupCookie (ctx : HttpContext) =
match GroupCookie.fromPayload ctx.Request.Cookies.[Key.Cookie.group] with
| Some cookie -> Some cookie.token
| None -> None
/// Try to get a JWT from the Authorization header
let tryGetJwtFromAuthHeader (ctx : HttpContext) =
match ctx.Request.Headers.["Authorization"] |> Seq.tryFind (fun x -> x.StartsWith "Bearer ") with
| Some hdr -> Some (hdr.Replace ("Bearer ", ""))
| None -> None
/// Attempt to get the user either from a cookie or an Authorization header
member __.Invoke ctx =
task {
let jwt =
seq {
tryGetJwtFromUserCookie ctx
tryGetJwtFromGroupCookie ctx
tryGetJwtFromAuthHeader ctx
}
|> Seq.tryFind Option.isSome
|> Option.flatten
match jwt with
| Some token ->
let handler = JwtSecurityTokenHandler ()
let mutable x : JwtSecurityToken ref = JwtSecurityToken () // does not build
let usr = handler.ValidateToken(token, TokenValidationParameters (), x) // JwtSecurityTokenHandler. ClaimsPrincipal ()
ctx.User <- usr
()
| None -> ()
do! next.Invoke ctx
}