|
19 | 19 | *) |
20 | 20 |
|
21 | 21 | (** OpenID Connect server with default scopes ({!Basic_scope}), ID Tokens |
22 | | - ({!Basic_ID_Token}) and client implementation ({!Basic}). |
| 22 | + ({!Basic_ID_Token}) and server implementation ({!Basic}). |
23 | 23 | *) |
24 | 24 |
|
| 25 | +(** {1 Exceptions. } *) |
| 26 | + |
25 | 27 | (** Exception raised when the given token doesn't exist. *) |
26 | 28 | exception No_such_saved_token |
27 | 29 |
|
28 | | -module type IDTOKEN = |
29 | | - sig |
30 | | - type scope |
31 | | - |
32 | | - type saved_token |
33 | | - |
34 | | - val saved_tokens : saved_token list ref |
35 | | - |
36 | | - val cycle_duration : int |
37 | | - |
38 | | - val number_of_cycle : int |
39 | | - |
40 | | - val id_client_of_saved_token : |
41 | | - saved_token -> |
42 | | - Os_types.OAuth2.Client.id |
43 | | - |
44 | | - val userid_of_saved_token : |
45 | | - saved_token -> |
46 | | - Os_types.User.id |
47 | | - |
48 | | - val token_type_of_saved_token : |
49 | | - saved_token -> |
50 | | - string |
51 | | - |
52 | | - val value_of_saved_token : |
53 | | - saved_token -> |
54 | | - string |
55 | | - |
56 | | - val id_token_of_saved_token : |
57 | | - saved_token -> |
58 | | - Jwt.t |
59 | | - |
60 | | - val scope_of_saved_token : |
61 | | - saved_token -> |
62 | | - scope list |
63 | | - |
64 | | - val secret_key_of_saved_token : |
65 | | - saved_token -> |
66 | | - string |
67 | | - |
68 | | - val counter_of_saved_token : |
69 | | - saved_token -> |
70 | | - int ref |
71 | | - |
72 | | - (* getters *) |
73 | | - (* ------- *) |
74 | | - |
75 | | - (* Returns true if the token already exists *) |
76 | | - val token_exists : |
77 | | - saved_token -> |
78 | | - bool |
79 | | - |
80 | | - (* Generate a token value *) |
81 | | - val generate_token_value : |
82 | | - unit -> |
83 | | - string |
84 | | - |
85 | | - (* Generate a new token *) |
86 | | - val generate_token : |
87 | | - id_client:Os_types.OAuth2.Client.id -> |
88 | | - userid:Os_types.User.id -> |
89 | | - scope:scope list -> |
90 | | - saved_token Lwt.t |
91 | | - |
92 | | - (* Save a token *) |
93 | | - val save_token : |
94 | | - saved_token -> |
95 | | - unit |
96 | | - |
97 | | - val remove_saved_token : |
98 | | - saved_token -> |
99 | | - unit |
100 | | - |
101 | | - val saved_token_of_id_client_and_value : |
102 | | - Os_types.OAuth2.Server.id -> |
103 | | - string -> |
104 | | - saved_token |
105 | | - |
106 | | - (* List all saved tokens *) |
107 | | - val list_tokens : |
108 | | - unit -> |
109 | | - saved_token list |
110 | | - |
111 | | - val saved_token_to_json : |
112 | | - saved_token -> |
113 | | - Yojson.Safe.json |
114 | | - end |
| 30 | +(** {2 Token representation. } *) |
| 31 | + |
| 32 | +(** Token interface used by the OpenID Connect server. *) |
| 33 | + |
| 34 | +module type IDTOKEN = sig |
| 35 | + (** List of permissions. Used to type the [scope] field in {!saved_token} *) |
| 36 | + type scope |
| 37 | + |
| 38 | + (** Token representation. The type is abstract to let the choice of the |
| 39 | + implementation. |
| 40 | + A token must contain at least: |
| 41 | + - the userid to know which user authorized. |
| 42 | + - the OAuth2.0 client ID to know the client to which the token is |
| 43 | + assigned. The ID is related to the database. |
| 44 | + - a value (the token value). |
| 45 | + - the token type (for example ["bearer"]). |
| 46 | + - the scopes list (of type {!scope}). Used to know which data the data |
| 47 | + service must send. |
| 48 | + - the ID token as a JSON Web Token (JWT). |
| 49 | + - the secret key used to sign the JWT. It is useful to check if the |
| 50 | + client sent the right ID token. This is the key used by HS256 to sign |
| 51 | + the token. |
| 52 | + - a counter which represents the number of times the token has been |
| 53 | + checked by the timer. |
| 54 | + *) |
| 55 | + type saved_token |
| 56 | + |
| 57 | + (** The list of all saved tokens. *) |
| 58 | + val saved_tokens : saved_token list ref |
| 59 | + |
| 60 | + (** Tokens must expire after a certain amount of time. For this reason, a |
| 61 | + timer {!Os_oauth2_shared.update_list_timer} checks all {!cycle_duration} |
| 62 | + seconds if the token has been generated after {!cycle_duration} * |
| 63 | + {!number_of_cycle} seconds. If it's the case, the token is removed. |
| 64 | + *) |
| 65 | + |
| 66 | + (** The duration of a cycle. *) |
| 67 | + val cycle_duration : int |
| 68 | + |
| 69 | + (** The number of cycle. *) |
| 70 | + val number_of_cycle : int |
| 71 | + |
| 72 | + (** Return the client ID. *) |
| 73 | + val id_client_of_saved_token : |
| 74 | + saved_token -> |
| 75 | + Os_types.OAuth2.Client.id |
| 76 | + |
| 77 | + (** Return the userid of the user who authorized. *) |
| 78 | + val userid_of_saved_token : |
| 79 | + saved_token -> |
| 80 | + Os_types.User.id |
| 81 | + |
| 82 | + (** Return the token type. *) |
| 83 | + val token_type_of_saved_token : |
| 84 | + saved_token -> |
| 85 | + string |
| 86 | + |
| 87 | + (** Return the token value. *) |
| 88 | + val value_of_saved_token : |
| 89 | + saved_token -> |
| 90 | + string |
| 91 | + |
| 92 | + (** Return the ID token as a JWT. *) |
| 93 | + val id_token_of_saved_token : |
| 94 | + saved_token -> |
| 95 | + Jwt.t |
| 96 | + |
| 97 | + (** Return the scope asked by the client. *) |
| 98 | + val scope_of_saved_token : |
| 99 | + saved_token -> |
| 100 | + scope list |
| 101 | + |
| 102 | + (** Return the secret key used to sign the JWT. *) |
| 103 | + val secret_key_of_saved_token : |
| 104 | + saved_token -> |
| 105 | + string |
| 106 | + |
| 107 | + (** Return the number of passed cycle. *) |
| 108 | + val counter_of_saved_token : |
| 109 | + saved_token -> |
| 110 | + int ref |
| 111 | + |
| 112 | + (** Return [true] if the token already exists *) |
| 113 | + val token_exists : |
| 114 | + saved_token -> |
| 115 | + bool |
| 116 | + |
| 117 | + (* Generate a token value *) |
| 118 | + val generate_token_value : |
| 119 | + unit -> |
| 120 | + string |
| 121 | + |
| 122 | + (* Generate a new token *) |
| 123 | + val generate_token : |
| 124 | + id_client:Os_types.OAuth2.Client.id -> |
| 125 | + userid:Os_types.User.id -> |
| 126 | + scope:scope list -> |
| 127 | + saved_token Lwt.t |
| 128 | + |
| 129 | + (** Save a token *) |
| 130 | + val save_token : |
| 131 | + saved_token -> |
| 132 | + unit |
| 133 | + |
| 134 | + (** Remove a token. *) |
| 135 | + val remove_saved_token : |
| 136 | + saved_token -> |
| 137 | + unit |
| 138 | + |
| 139 | + (** Return the saved token assigned to the client with given ID and |
| 140 | + value. |
| 141 | + *) |
| 142 | + val saved_token_of_id_client_and_value : |
| 143 | + Os_types.OAuth2.Server.id -> |
| 144 | + string -> |
| 145 | + saved_token |
| 146 | + |
| 147 | + (* List all saved tokens *) |
| 148 | + val list_tokens : |
| 149 | + unit -> |
| 150 | + saved_token list |
| 151 | + |
| 152 | + (** Return the saved token as a JSON. Used to send to the client. *) |
| 153 | + val saved_token_to_json : |
| 154 | + saved_token -> |
| 155 | + Yojson.Safe.json |
| 156 | +end |
115 | 157 |
|
116 | 158 | (** Basic module for scopes. |
| 159 | +
|
117 | 160 | [check_scope_list scope_list] returns [true] if every element in |
118 | 161 | [scope_list] is an available scope value. |
119 | 162 | If the list contains only [OpenID] or if the list doesn't contain [OpenID] |
120 | | - (mandatory scope in RFC), returns [false]. |
| 163 | + (mandatory scope in RFC), it returns [false]. |
121 | 164 | If an unknown scope value is in list (represented by [Unknown] value), |
122 | | - returns [false]. |
| 165 | + it returns [false]. |
123 | 166 | *) |
124 | 167 |
|
| 168 | +(** Basic scope *) |
125 | 169 | module Basic_scope : Os_oauth2_server.SCOPE |
126 | 170 |
|
| 171 | +(** MakeIDToken (Scope) returns a module of type {!IDTOKEN} with the type |
| 172 | + {!IDTOKEN.scope} equals to {!Scope.scope}. |
| 173 | +
|
| 174 | + Tokens are represented as a record with exactly the same fields available in |
| 175 | + the inferface {!IDTOKEN}. |
| 176 | +
|
| 177 | + The token type is always ["bearer"]. |
| 178 | +
|
| 179 | + The related JSON contains the fields: |
| 180 | + - ["token_type"] with value ["bearer"]. |
| 181 | + - ["token"] with the token value. |
| 182 | + - ["expires_in"] with the value [cycle_duration * number_of_cycle] i.e. 600 |
| 183 | + seconds. |
| 184 | + - ["id_token"] with the JWT. |
| 185 | +
|
| 186 | +
|
| 187 | + NOTE: If you want to implement another type of tokens, you need to implement |
| 188 | + another functor (with the [Scope.scope] type dependency) which returns a |
| 189 | + module of type {!IDTOKEN}. The resulting module can be given as parameter to |
| 190 | + the function {!Os_oauth2_server.MakeServer}. |
| 191 | + *) |
127 | 192 | module MakeIDToken : functor |
128 | 193 | (Scope : Os_oauth2_server.SCOPE) -> |
129 | 194 | (IDTOKEN with type scope = Scope.scope) |
130 | 195 |
|
| 196 | +(** Basic ID Token based on the scope from {!Basic_scope}. *) |
131 | 197 | module Basic_ID_token |
132 | 198 | : (IDTOKEN with |
133 | 199 | type scope = Basic_scope.scope) |
134 | 200 |
|
| 201 | +(** [Basic (Scope) (Token)] returns a module representing a OpenID Connect |
| 202 | + server. The available scopes come from {!Scope.scope} and the token related |
| 203 | + functions, types and representation come from {!Token}. |
| 204 | +
|
| 205 | + As an OpenID Connect server is based on an OAuth2.0, the server is generated |
| 206 | + with {!Os_oauth2_server.MakeServer}. |
| 207 | + *) |
135 | 208 | module Basic : (Os_oauth2_server.SERVER with |
136 | 209 | type scope = Basic_scope.scope and |
137 | 210 | type saved_token = Basic_ID_token.saved_token |
|
0 commit comments