Skip to content

Commit e648b64

Browse files
authored
Merge pull request #111 from hernoufM/session-api
Documentation for entire session part
2 parents 7ab642b + 189da8f commit e648b64

6 files changed

Lines changed: 216 additions & 8 deletions

File tree

src/session/ezCookieServer.mli

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
open EzAPIServerUtils
22

3+
(** Looks up request headers and returns map of cookies (cookie_name->cokie_value) *)
34
val get : Req.t -> string StringMap.t
5+
6+
(** Discards cookie in the 'Set-Cookie' header by setting its value to empty string and
7+
its max-age to 0*)
48
val clear : Req.t -> name:string -> (string * string)
9+
10+
(** Creates 'Set-Cokie' header with cookie whose name, value and some parameters are
11+
specified. *)
512
val set :
613
?secure:bool ->
714
?http_only:bool ->

src/session/ezSession.ml

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,15 @@ let debug = false
77

88
module TYPES = struct
99

10+
(** Foreign user without password, whose login is equal to [foreign_origin ^ foreign_token] and
11+
whose password is not req. *)
1012
type foreign_info = {
1113
foreign_origin : string;
1214
foreign_token : string;
1315
}
1416

17+
(** A session that helps to keep connection for the given user and stores useful information
18+
about his communication with the sever. *)
1519
type 'user_id session = {
1620
session_token : string;
1721
session_login : string;
@@ -20,14 +24,23 @@ module TYPES = struct
2024
session_foreign : foreign_info option;
2125
}
2226

27+
(** Main module that specifies the session parameters for given implementation of API server. *)
2328
module type SessionArg = sig
2429

30+
(** User identifier, which generally is the same as login *)
2531
type user_id
32+
33+
(** Associated to user information *)
2634
type user_info
2735

36+
(** Json encoding for user's id *)
2837
val user_id_encoding : user_id Json_encoding.encoding
38+
39+
(** Json encoding for user's information *)
2940
val user_info_encoding : user_info Json_encoding.encoding
3041

42+
(** RPC path where authentication services like {b connect}, {b login} and {b logout}
43+
would be placed. *)
3144
val rpc_path : string list (* ["v1"] *)
3245

3346
(*
@@ -36,67 +49,86 @@ module TYPES = struct
3649
(`CSRF "X-Csrf-Token" `).
3750
*)
3851

52+
(** Describes two ways to store a token within a client request:
53+
- Store as a cookie associated with the given cookie name.
54+
- Store as a CSRF header with the given name. *)
3955
val token_kind : [`Cookie of string | `CSRF of string ]
4056
end
4157

58+
(** Authentification information returned by server after successful connection *)
4259
type ('user_id, 'user_info) auth = {
4360
auth_login : string;
4461
auth_user_id : 'user_id;
4562
auth_token : string;
4663
auth_user_info : 'user_info;
4764
}
4865

66+
(** Challenge that should be resolved to be able to connect *)
4967
type auth_needed = {
5068
challenge_id : string;
5169
challenge : string;
5270
}
5371

72+
(** Connection response, that either describes user information if connection successes either
73+
describes challenge to resolve to be able to connect *)
5474
type 'auth connect_response =
5575
| AuthOk of 'auth
5676
| AuthNeeded of auth_needed
5777

78+
(** Logining request, that contains the login and the challenge resolution obtained by hashing
79+
challenge and password provided by the user. *)
5880
type local_login_message = {
5981
login_user : string;
6082
login_challenge_id : string;
6183
login_challenge_reply : string;
6284
}
6385

86+
(** Logining request, that could be asked either by user with the password provided either by a
87+
foreign user without a password. *)
6488
type login_message =
6589
| Local of local_login_message
6690
| Foreign of foreign_info
6791

92+
(** Possible logining outcomes. *)
6893
type ('user_id, 'user_info) login_response =
6994
| LoginOk of ('user_id, 'user_info) auth
7095
| LoginWait of 'user_id
7196

97+
(** Errors that could be raised while logining. *)
7298
type login_error =
7399
[ `Bad_user_or_password
74100
| `User_not_registered
75101
| `Unverified_user
76102
| `Challenge_not_found_or_expired of string
77103
| `Invalid_session_login of string ]
78104

105+
(** Errors that could be raised while disconnecting. *)
79106
type logout_error =
80107
[ `Invalid_session_logout of string]
81108

109+
(** Errors that could be raised while connecting. *)
82110
type connect_error =
83111
[ `Session_expired | `Invalid_session_connect of string ]
84112

85113
end
86114

87115
open TYPES
88116

117+
(** Hash module, that hashing algorithms. *)
89118
module Hash = struct
90119

91120
include EzHash
92121

122+
(** Hashed version of the password that is computed by the hash function applied on
123+
[login ^ password] *)
93124
let password ~login ~password =
94125
let s = hash (login ^ password) in
95126
if debug then
96127
EzDebug.printf "EzSession.Hash.password:\n %S %S => %S"
97128
login password s;
98129
s
99-
130+
(** Hashed version of the challenge that is computed by the hash function applied on
131+
[challenge ^ pwhash] *)
100132
let challenge ~challenge ~pwhash =
101133
let s = hash (challenge ^ pwhash) in
102134
if debug then
@@ -106,6 +138,7 @@ module Hash = struct
106138

107139
end
108140

141+
(** Output signature for Make functor *)
109142
module type M = sig
110143
type user_id
111144
type user_info
@@ -120,10 +153,14 @@ module type M = sig
120153
val logout : (auth_needed, logout_error, token_security) EzAPI.service0
121154
end
122155

156+
(** Main functor that produces definition for authentication services and encodings for types used
157+
by service's input, output and errors. *)
123158
module Make(S : SessionArg) = struct
124159

125160
type nonrec auth = (S.user_id, S.user_info) auth
126161

162+
(** Encodings for data types used in server's requests/responses and for error cases that
163+
could be raised by one of them. *)
127164
module Encoding = struct
128165
open Json_encoding
129166

@@ -281,42 +318,60 @@ module Make(S : SessionArg) = struct
281318

282319
end
283320

321+
(** Definition for services and their security's configuration. *)
284322
module Service = struct
285323
type user_id = S.user_id
286324
type user_info = S.user_info
287325
type nonrec auth = auth
288326

327+
(** Documentation section for openapi. *)
289328
let section_session = EzAPI.Doc.section "Session Requests"
290329

330+
(** Parameter with name {i token} that stores an authentication token string *)
291331
let param_token =
292332
EzAPI.Param.string ~name:"token" ~descr:"An authentication token" "token"
293333

334+
(** Type that represents security by authentication token and the way that request uses
335+
to store it. *)
294336
type token_security =
295337
[ EzAPI.Security.cookie | EzAPI.Security.header | EzAPI.Security.query ]
296338

339+
(** Security that requires [param_token] parameter in query. *)
297340
let param_security =
298341
EzAPI.(`Query {
299342
Security.ref_name = "Token parameter";
300343
name = param_token
301344
})
302345

346+
(** Security that checks [S.token_kind]:
347+
If it is a CSRF token, then requires a CSRF header.
348+
Otherwise requires token to be found in the cookies.
349+
*)
303350
let header_cookie_security =
304351
match S.token_kind with
305352
| `CSRF name ->
306353
EzAPI.(`Header { Security.ref_name = name ^ " Header"; name })
307354
| `Cookie name ->
308355
EzAPI.(`Cookie { Security.ref_name = name ^ " Cookie"; name })
309356

357+
(** Security that combines [param_security] and [header_cookie_security]
358+
in the corresponding order. Represents the security configuration for
359+
[connect] and [logout] requests.
360+
*)
310361
let security : token_security list = [
311362
param_security; (* Parameter fisrt *)
312363
header_cookie_security; (* Header CSRF or Cookie *)
313364
]
314-
365+
366+
(** Defines path to authentication services *)
315367
let rpc_root =
316368
List.fold_left (fun path s ->
317369
EzAPI.Path.( path // s )
318370
) EzAPI.Path.root S.rpc_path
319371

372+
(** Connection service that requires authentication token. For more details, see corresponding
373+
[EzSessionServer.Make.connect] handler and default client request implementation
374+
[EzSessionClient.Make.connect]. *)
320375
let connect : (auth connect_response, connect_error, token_security) EzAPI.service0 =
321376
EzAPI.service
322377
~section:section_session
@@ -326,6 +381,8 @@ module Make(S : SessionArg) = struct
326381
~security
327382
EzAPI.Path.(rpc_root // "connect")
328383

384+
(** Logining service. For more details, see corresponding [EzSessionServer.Make.login] handler
385+
and default client request implementation [EzSessionClient.Make.login]. *)
329386
let login : (login_message, (S.user_id, S.user_info) login_response, login_error, EzAPI.Security.none) EzAPI.post_service0 =
330387
EzAPI.post_service
331388
~section:section_session
@@ -339,6 +396,9 @@ module Make(S : SessionArg) = struct
339396
Encoding.invalid_session_login_case]
340397
EzAPI.Path.(rpc_root // "login")
341398

399+
(** Disconnection service that requires authentication token. For more details, see corresponding
400+
[EzSessionServer.Make.logout] handler and default client request implementation
401+
[EzSessionClient.Make.logout]. *)
342402
let logout : (auth_needed, logout_error, token_security) EzAPI.service0 =
343403
EzAPI.service
344404
~section:section_session

src/session/ezSessionClient.mli

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,44 @@ module Make(S: EzSession.TYPES.SessionArg) : sig
55
an already authenticated user. Otherwise (CSRF protection),
66
a token can be provided (saved in local storage).
77
*)
8+
9+
(** See {EzSession.TYPES.SessionArg.user_id}. *)
810
type user_id = S.user_id
11+
12+
(** See {EzSession.TYPES.SessionArg.user_info}. *)
913
type user_info = S.user_info
14+
15+
(** See {EzSession.TYPES.auth}. *)
1016
type nonrec auth = (S.user_id, S.user_info) EzSession.TYPES.auth
1117

18+
(** See {!EzSession.Make} *)
1219
module Service : EzSession.M with type user_id = user_id
1320
and type user_info = user_info
1421

22+
(** Error that could be raised by [login] request. *)
1523
type login_error = [
1624
| EzSession.TYPES.login_error
1725
| EzSession.TYPES.connect_error
1826
| EzSession.TYPES.logout_error
1927
| `Too_many_login_attempts
2028
| `Session_expired ]
2129

30+
(** Performs request to the server's authentication service if actual state is set to
31+
disconnected and calls callback on the response result. If state is set to connected or
32+
authenticated, then callback is called on actual connection/authentication status without
33+
performing request, unless [token] is specified. *)
2234
val connect :
2335
EzAPI.base_url ->
2436
?token:string ->
2537
(((S.user_id, S.user_info) EzSession.TYPES.auth option, EzSession.TYPES.connect_error) result -> unit) -> unit
2638

39+
(** Performs request to the server's login service. If actual state is set to disconnected,
40+
then firstly, it performs [connect] request. If connect request returns authentication
41+
information for different user (if token or cookies wasn't updated) or if other user is
42+
already autenticated, it performs logout for this user, and retry logining. If user is
43+
connected but not authenticated, it constructs challenge reply by using user's [login] and
44+
[password] or uses foreign user information to authenticate. Calls callback on
45+
authentification status. *)
2746
val login :
2847
?format:(string -> string) ->
2948
EzAPI.base_url ->
@@ -32,21 +51,28 @@ module Make(S: EzSession.TYPES.SessionArg) : sig
3251
?foreign:(string * string) -> (* foreing auth : origin, token *)
3352
(((S.user_id, S.user_info) EzSession.TYPES.auth, login_error) result -> unit) -> unit
3453

54+
(** Performs request to the server's logout service if actual state is set to authenticated.
55+
After this step, state is set to connected. Callback is called with [Ok true] if logout was
56+
successfully performed. If previous state wasn't set to authenticated, then callback is
57+
called with [Ok false]. *)
3558
val logout :
3659
EzAPI.base_url ->
3760
token:string -> ((bool, EzSession.TYPES.logout_error) result -> unit) -> unit
3861

39-
(* Tell the network layer that we think that the session has ended
62+
(** Tell the network layer that we think that the session has ended
4063
(a request probably returned an error status for missing auth).
4164
Since the state is kept internally, we have to do this first to
42-
trigger a full reconnection by `login`.
43-
*)
65+
trigger a full reconnection by `login`. *)
4466
val disconnected : unit -> unit
4567

4668
(* In `CSRF mode, these headers should be added to all queries that
4769
need authentication *)
70+
71+
(** Returns authentication headers depending on [S.token_kind] for client requests.
72+
It doesn't include cookies because cookies are automatically added by browser. *)
4873
val auth_headers : token:string -> (string * string) list
4974

75+
(** Gets current authentication status, if exists. *)
5076
val get : unit -> (S.user_id, S.user_info) EzSession.TYPES.auth option
5177

5278
end

0 commit comments

Comments
 (0)