package FPauth-core

  1. Overview
  2. Docs

Source file authenticator.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
(**[Authenticator] is module which provides functions both for authentication and logout*)

open Base
open Dream
open Static

(**[Make] creates an instance of {!Auth_sign.AUTHENTICATOR} for a given model and variables*)
module Make (M : Auth_sign.MODEL) (V : Auth_sign.VARIABLES with type entity = M.t ) : (Auth_sign.AUTHENTICATOR with type entity = M.t) = struct
  
  type entity = M.t

  (** [strategy] is a function that tries to authenticate an entity*)
  type strategy = (module Auth_sign.STRATEGY with type entity = entity)

  module type Strategy = Auth_sign.STRATEGY with type entity = entity

  let set_authenticated request = 
    set_field request V.authenticated true;
    request

  (**[auth] is a recursive function for running strategies and verifying*)
  let rec auth (lst : strategy list) request ent : AuthResult.t promise =
    match lst with
    | [] -> set_field request V.auth_error (Error.of_string "End of strategy list");
            Lwt.return AuthResult.Rescue
    | (module S : Strategy)::strats -> 
      match%lwt S.call request ent with
      | Next -> auth strats request ent
      | Authenticated ent -> 
        let%lwt () =
        request |> set_authenticated |> V.update_current_user ent in
        Lwt.return AuthResult.Authenticated
      | Rescue err -> set_field request V.auth_error err;
                      Lwt.return AuthResult.Rescue
      | Redirect url -> Lwt.return (AuthResult.Redirect url)


  let name_in_list names (module S : Strategy) =
    List.exists names ~f:(String.equal S.name)

  let filter_strategies (strats: strategy list) names =
    List.filter strats ~f:(name_in_list names)

  (** [authenticate] runs all strategies from the list until one of them succeeds. 
  Sets session and field variables. Returns a promise. *)
  let authenticate (lst : strategy list) request =
    match%lwt M.identificate request with
    | Error err ->  set_field request V.auth_error err;
    Lwt.return AuthResult.Rescue
    | Ok ent -> 
      let filtered_strats = M.applicable_strats ent |> filter_strategies lst in
      auth filtered_strats request ent

  (** [logout] clears [auth] session field and sets {V.authenticated} to [false], making session unauthenticated.
  Note: the function does NOT modify {!V.current_user}. It will be set to [None] only for the next request.*)
  let logout request =
    set_field request V.authenticated false;
    request |> invalidate_session
end