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

@ -55,6 +55,7 @@ module Configure =
|> ignore |> ignore
let config = svc.BuildServiceProvider().GetRequiredService<IConfiguration>() let config = svc.BuildServiceProvider().GetRequiredService<IConfiguration>()
let authConfig = config.GetSection "Tokens" let authConfig = config.GetSection "Tokens"
let iss = authConfig.["Issuer"]
svc.AddAuthentication() svc.AddAuthentication()
.AddCookie( .AddCookie(
fun opts -> fun opts ->
@ -62,17 +63,16 @@ module Configure =
opts.Cookie.HttpOnly <- false opts.Cookie.HttpOnly <- false
opts.Cookie.SameSite <- SameSiteMode.Strict opts.Cookie.SameSite <- SameSiteMode.Strict
opts.SlidingExpiration <- true opts.SlidingExpiration <- true
opts.ClaimsIssuer <- authConfig.["Issuer"]) opts.ClaimsIssuer <- iss)
.AddJwtBearer( .AddJwtBearer(
fun opts -> fun opts ->
opts.SaveToken <- true opts.SaveToken <- true
opts.ClaimsIssuer <- "PrayerTracker" opts.ClaimsIssuer <- iss
opts.TokenValidationParameters <- TokenValidationParameters () opts.TokenValidationParameters <- TokenValidationParameters (
opts.TokenValidationParameters.ValidIssuer <- authConfig.["Issuer"] ValidIssuer = iss,
opts.TokenValidationParameters.ValidAudience <- authConfig.["Issuer"] ValidAudience = iss,
opts.TokenValidationParameters.IssuerSigningKey <- SymmetricSecurityKey (Convert.FromBase64String authConfig.["Key"])) IssuerSigningKey = SymmetricSecurityKey (Convert.FromBase64String authConfig.["Key"])))
|> ignore |> ignore
let config = svc.BuildServiceProvider().GetRequiredService<IConfiguration>()
let crypto = config.GetSection "CookieCrypto" let crypto = config.GetSection "CookieCrypto"
CookieCrypto (crypto.["Key"], crypto.["IV"]) |> setCrypto CookieCrypto (crypto.["Key"], crypto.["IV"]) |> setCrypto
svc.AddDbContext<AppDbContext>( svc.AddDbContext<AppDbContext>(
@ -195,7 +195,7 @@ module Configure =
.UseStaticFiles() .UseStaticFiles()
.UseSession() .UseSession()
.UseRequestLocalization(app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>().Value) .UseRequestLocalization(app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>().Value)
.UseAuthentication() .UseSecurityMiddleware()
.UseGiraffe(webApp) .UseGiraffe(webApp)
|> ignore |> ignore
Views.I18N.setUpFactories <| app.ApplicationServices.GetRequiredService<IStringLocalizerFactory> () 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 /// Properties stored in the Small Group cookie
type GroupCookie = 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">] [<JsonProperty "g">]
GroupId : Guid GroupId : Guid
/// The password hash of the small group /// The password hash of the small group
@ -100,8 +102,10 @@ type TimeoutCookie =
/// The payload for the user's "Remember Me" cookie /// The payload for the user's "Remember Me" cookie
type UserCookie = type UserCookie =
{ /// The Id of the group into to which the user is logged { /// The token representing the current user's logged in claims
[< JsonProperty "g">] token : string
/// The Id of the group into to which the user is logged
[<JsonProperty "g">]
GroupId : Guid GroupId : Guid
/// The Id of the user /// The Id of the user
[<JsonProperty "i">] [<JsonProperty "i">]

View File

@ -1,6 +1,7 @@
[<AutoOpen>] [<AutoOpen>]
module PrayerTracker.Extensions module PrayerTracker.Extensions
open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.Http open Microsoft.AspNetCore.Http
open Microsoft.FSharpLu open Microsoft.FSharpLu
open Newtonsoft.Json open Newtonsoft.Json
@ -44,3 +45,9 @@ type ISession with
type HttpContext with type HttpContext with
/// Get the EF database context from DI /// Get the EF database context from DI
member this.dbContext () : AppDbContext = downcast this.RequestServices.GetService typeof<AppDbContext> 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> <ItemGroup>
<None Include="appsettings.json" /> <None Include="appsettings.json" />
<Compile Include="Extensions.fs" />
<Compile Include="Cookies.fs" /> <Compile Include="Cookies.fs" />
<Compile Include="Email.fs" /> <Compile Include="Email.fs" />
<Compile Include="SecurityMiddleware.fs" />
<Compile Include="Extensions.fs" />
<Compile Include="CommonFunctions.fs" /> <Compile Include="CommonFunctions.fs" />
<Compile Include="Church.fs" /> <Compile Include="Church.fs" />
<Compile Include="Home.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
}