Browse Source

Improve token.md

tags/v0.0.2
Tobias Schneider 2 years ago
parent
commit
bed61948e6
1 changed files with 232 additions and 115 deletions
  1. 232
    115
      doc/tokens.md

+ 232
- 115
doc/tokens.md View File

@@ -1,126 +1,232 @@
1
-JWT token authentication Prosody plugin
2
-==================
1
+# JSON Web Token (JWT) authentication Prosody plugin
3 2
 
4
-This plugin implements a Prosody authentication provider that verifies a client connection based on a JWT token described in [RFC7519].
5
-It allows use of an external form of authentication with lib-jitsi-meet. Once your user authenticates you need to
6
-generate the JWT token as described in the RFC and pass it to your client app. Once it connects with a valid token it is considered authenticated by the jitsi-meet system.
3
+This plugin implements a **Prosody authentication provider** that verifies a client connection based on a JWT
4
+described in [RFC7519]. It allows use of an external form of authentication with _lib-jitsi-meet_.
5
+Once your user authenticates you need to generate the JWT as described in the RFC and pass it to your client app.
6
+Once it connects with a valid token, it is considered authenticated by the jitsi-meet system.
7 7
 
8
-During configuration you will need to provide the *application ID* that identifies the client and a *secret* shared by both server and JWT token generator. Like described in the RFC, the secret is used to compute a HMAC hash value which allows authentication of the generated token. There are many existing libraries which can be used to implement token generation. More info can be found here: [http://jwt.io/#libraries-io]
8
+During configuration, you can choose between two JWT validation methods:
9 9
 
10
-JWT token authentication works with BOSH and websocket connections.
10
+* Shared Secret Validation or
11
+* Public Key Validation 
11 12
 
12
-[RFC7519]: https://tools.ietf.org/html/rfc7519
13
-[http://jwt.io/#libraries-io]: http://jwt.io/#libraries-io
13
+In both cases you will need to provide the _application ID_ that identifies the client.
14
+
15
+For the **Shared Secret Validation** an _application secret_ is shared by both the server (Prosody) and the JWT
16
+generation. Take a look at an example structure in [Example Structure > Shared Secret Validation](#shared-secret-validation).
17
+Like described in the RFC, the _shared secret_ is used to compute a HMAC hash value which allows authentication of the 
18
+generated token. There are many existing libraries which can be used to implement token generation. More info can be 
19
+found here: [http://jwt.io/#libraries-io]
20
+
21
+For the **Public Key Validation** a _key server_ must be provided via `asap_key_server` to verify the token against a 
22
+provided public key on the given key server. An example structure can be view in [Example Structure > Publiy Key Validation](#public-key-validation)
23
+
24
+JWT authentication works with BOSH and WebSocket connections.
14 25
 
15
-### Token structure
26
+### Token Structure
16 27
 
17 28
 The following JWT claims are used in the authentication token:
18
-- 'iss' specifies the *application ID* which identifies the client app connecting to the server. It should be negotiated with the service provider before generating the token.
19
-- 'room' contains the name of the room for which the token has been allocated. This is *NOT* the full MUC room address. An example assuming that we have full MUC 'conference1@muc.server.net' would be that 'conference1' should be used here.  Alternately, a '*' may be provided, allowing access to all rooms within the domain.
20
-- 'exp' token expiration timestamp as defined in the RFC
21
-- 'sub' contains EITHER the lowercase name of the tenant (for a conference like TENANT1/ROOM with would be 'tenant1') OR the lowercase name of the domain used when authenticating with this token (for a conference like /ROOM). By default assuming that we have full MUC 'conference1@muc.server.net' then 'server.net' should be used here.  Alternately, a '*' may be provided, allowing access to rooms in all tenants within the domain or all domains within the server.
22
-- 'aud' application identifier. This value indicates what service is consuming the token.  It should be negotiated with the service provider before generating the token.
23 29
 
24
-The secret is used to compute the HMAC hash value and verify the token for HS256 tokens.  
25
-- It is now possible to define the algorithm type used, simply update the prosody.cfg.lua file with your chosen type. e.g `signature_algorithm = "HS512"`
30
+- 'iss'
31
+  - specifies the _application ID_ which identifies the client.
32
+    It should be negotiated with the service provider before generating the token.
33
+- 'room'
34
+  - contains either
35
+    - the name of the room - This is *NOT* the full MUC room address.  
36
+      For a full MUC like 'conference1@muc.server.net' it would be 'conference1'.
37
+    - alternatively '*' - allowing access to all rooms within the domain.
38
+- 'exp'
39
+  - token expiration timestamp as defined in the [RFC7519]
40
+- 'sub'
41
+  - contains either
42
+    - the lowercase _tenant_ - for a conference like 'TENANT1/ROOM' it would be 'tenant1', see example below.
43
+    - the lowercase _domain_ - for a full MUC like 'conference1@muc.server.net' it would be 'server.net'.
44
+    - alternatively '*' - allowing access to all rooms in all tenants within the domain or all domains within the server.
45
+- 'aud'
46
+  - application identifier - indicates what service is consuming the token.
47
+    It should be negotiated with the service provider before generating the token.
48
+
49
+**Sub with tenant** If the 'sub' contains the tenant. You need to define the tenant in the `muc` when creating a new `JitsiConnection` in the options 
50
+within the `hosts` section, see
51
+
52
+```javascript
53
+    const connection = new JitsiMeetJS.JitsiConnection(
54
+    '${applicationId}',
55
+    '${token}',
56
+    {
57
+        serviceUrl: 'wss://server.net/tenant/xmpp-websocket',
58
+        hosts: {
59
+            domain: 'muc.server.net',
60
+            muc: 'conference1.tenant.muc.server.net',
61
+        },
62
+    },
63
+);
64
+```
65
+
66
+**Different signature algorithm** It is possible to define the algorithm type used, simply update the `prosody.cfg.lua` file with your chosen type.
67
+e.g `signature_algorithm = "HS512"`
68
+
69
+For **Shared Secret Validation** the _shared secret_ is used to compute the HMAC hash value and verify the token for HSXXX (e.g. HS256) tokens. 
70
+Alternatively for the **Public Key Validation** the token may be signed by a private key and authorized via a public
71
+keyserver using RSXXX (e.g. RS256) tokens. In this mode, the 'kid' header of the JWT must be set to the name of the public key.
72
+Prosody must be configured to fetch and confirm keys from a pre-configured public keyserver via `asap_key_server`
73
+see [Manual plugin configuration > 2.](#manual-plugin-configuration)
26 74
 
27
-Alternately the token may be signed by a private key and authorized via a public keyserver using RS256 tokens.  In this mode, the 'kid' header of the JWT must be set to the name of the public key.  The backend server must be configured to fetch and confirm keys from a pre-configured public keyserver.
75
+### Token Identifiers Structure (Optional)
28 76
 
29
-### Token Identifiers
77
+In addition to the basic claims used in authentication, the token can also provide optional user display information in the 
78
+'context' field within the JWT payload. None of the information in the context field is used for token validation:
30 79
 
31
-In addition to the basic claims used in authentication, the token can also provide user display information in the 'context' field within the JWT payload. None of the information in the context field is used for token validation:
32
-- 'group' is a string which specifies the group the user belongs to.  Intended for use in reporting/analytics, not used for token validation.
80
+- 'group' is a string which specifies the group the user belongs to. Intended for use in reporting/analytics, not used
81
+  for token validation.
33 82
 - 'user' is an object which contains display information for the current user
34
-  - 'id' is a user identifier string.  Intended for use in reporting/analytics
35
-  - 'name' is the display name of the user
36
-  - 'email' is the email of the user
37
-  - 'avatar' is the URL of the avatar for the user
38
-> Note: As the moment all fields in 'user' need to be a valid string, numeric types or `null` will generate an exception.
39
-- 'callee' is an optional object containing display information when launching a 1-1 video call with a single other participant. It is used to display an overlay to the first user, before the second user joins.
40
-  - 'id' is a user identifier string.  Intended for use in reporting/analytics
41
-  - 'name' is the display name of the 'callee' user
42
-  - 'avatar' is the URL of the avatar of the 'callee'
43
-
44
-#### Access token identifiers / context
45
-To access the data in lib-jitsi-meet you have to enable the prosody module `mod_presence_identity` in your config.
83
+    - 'id' is a user identifier string. Intended for use in reporting/analytics
84
+    - 'name' is the display name of the user
85
+    - 'email' is the email of the user
86
+    - 'avatar' is the URL of the avatar for the user
87
+- 'callee' is an optional object containing display information when launching a 1-1 video call with a single other
88
+  participant. It is used to display an overlay to the first user, before the second user joins.
89
+    - 'id' is a user identifier string. Intended for use in reporting/analytics
90
+    - 'name' is the display name of the 'callee' user
91
+    - 'avatar' is the URL of the avatar of the 'callee'
92
+
93
+**Note:** At the moment all fields in 'user' need to be a valid string, numeric types or `null` will generate an exception.
94
+
95
+#### Retrieve 'Token Identifiers' Data
96
+
97
+To retrieve the data from `context` in _lib-jitsi-meet_ you have to enable the Prosody module `mod_presence_identity` in your config.
46 98
 
47 99
 ```lua
48 100
 VirtualHost "jitmeet.example.com"
49 101
     modules_enabled = { "presence_identity" }
50 102
 ```
51 103
 
52
-The data is now available in the identity in the JitsiParticipant class. You can access them by e.g. listening to the `USER_JOINED` event.
104
+The data is now available in the identity in the JitsiParticipant class. You can retrieve it by e.g. listening to
105
+the `USER_JOINED` event.
106
+
107
+**Note:** The values in the token shall always be valid values. If you define e.g. the avatar as `null` it will throw an
108
+error.
109
+
110
+### Token Examples
111
+
112
+There are two ways to validate the JWT. First one by **Public Key Validation** and the second one by a **Shared Secret Validation**.
113
+The following examples shows the differences of both structures. For example the `kid` key is only needed for public key
114
+validation to define the public key to validate against.
115
+
116
+**Note:** the context structure is optional for both, the secret shared and public key validation and is only needed to
117
+display personal information and for statistic purposes.
118
+
119
+#### Public Key Validation
53 120
 
54
-NOTE: The values in the token shall always be valid values. If you define e.g. the avatar as `null` it will throw an error.
121
+##### Headers
55 122
 
56
-### Example Token
57
-#### Headers (using RS256 public key validation)
123
+`kid` must be the name of the public key to validate the token against.
124
+
125
+```json
126
+{
127
+    "kid": "your_public_key_name",
128
+    "typ": "JWT",
129
+    "alg": "RS256"
130
+}
58 131
 ```
132
+
133
+##### Payload
134
+
135
+```json
59 136
 {
60
-  "kid": "jitsi/custom_key_name",
61
-  "typ": "JWT",
62
-  "alg": "RS256"
137
+    "context": {
138
+        "user": {
139
+            "avatar": "https:/gravatar.com/avatar/abc123",
140
+            "name": "John Doe",
141
+            "email": "jdoe@example.com",
142
+            "id": "abcd:a1b2c3-d4e5f6-0abc1-23de-abcdef01fedcba"
143
+        },
144
+        "group": "a123-123-456-789"
145
+    },
146
+    "aud": "jitsi",
147
+    "iss": "my_client",
148
+    "sub": "meet.jit.si",
149
+    "room": "*",
150
+    "exp": 1500006923
63 151
 }
64 152
 ```
65
-#### Payload
153
+
154
+#### Shared Secret Validation
155
+
156
+##### Headers
157
+
158
+```json
159
+{
160
+    "typ": "JWT",
161
+    "alg": "RS256"
162
+}
66 163
 ```
164
+
165
+##### Payload
166
+
167
+```json
67 168
 {
68
-  "context": {
69
-    "user": {
70
-      "avatar": "https:/gravatar.com/avatar/abc123",
71
-      "name": "John Doe",
72
-      "email": "jdoe@example.com",
73
-      "id": "abcd:a1b2c3-d4e5f6-0abc1-23de-abcdef01fedcba"
169
+    "context": {
170
+        "user": {
171
+            "avatar": "https:/gravatar.com/avatar/abc123",
172
+            "name": "John Doe",
173
+            "email": "jdoe@example.com",
174
+            "id": "abcd:a1b2c3-d4e5f6-0abc1-23de-abcdef01fedcba"
175
+        },
176
+        "group": "a123-123-456-789"
74 177
     },
75
-    "group": "a123-123-456-789"
76
-  },
77
-  "aud": "jitsi",
78
-  "iss": "my_client",
79
-  "sub": "meet.jit.si",
80
-  "room": "*",
81
-  "exp": 1500006923
178
+    "aud": "jitsi",
179
+    "iss": "my_client",
180
+    "sub": "meet.jit.si",
181
+    "room": "*",
182
+    "exp": 1500006923
82 183
 }
83 184
 ```
185
+
84 186
 ### Token verification
85 187
 
86
-JWT token is currently checked in 2 places:
87
-- when a user connects to Prosody through BOSH. The token value is passed as the 'token' query paramater of the BOSH URL. User uses XMPP anonymous authentication method.
88
-- when a MUC room is being created/joined Prosody compares the 'room' claim with the actual name of the room. In addition, the 'sub' claim is compare to either the tenant (for TENANT/ROOM URLs) or the base domain (for /ROOM URLs).  This prevents a stolen token being abused by unathorized users to allocate new conference rooms in the system. Admin users are not required to provide a valid token which is used for example by Jicofo.
188
+JWT is currently checked in 2 places:
189
+
190
+- when a user connects to Prosody through BOSH or WebSocket. The token value is passed as the 'token' query parameter of 
191
+  the BOSH or WebSocket URL. User uses XMPP anonymous authentication method.
192
+- when a MUC room is being created/joined Prosody compares the 'room' claim with the actual name of the room. In
193
+  addition, the 'sub' claim is compare to either the tenant (for TENANT/ROOM URLs) or the base domain (for /ROOM URLs).
194
+  This prevents a stolen token being abused by unauthorized users to allocate new conference rooms in the system. Admin
195
+  users are not required to provide a valid token which is used for example by Jicofo.
89 196
 
90 197
 ### Lib-jitsi-meet options
91 198
 
92
-When JWT authentication is used with *lib-jitsi-meet* the token is passed to the *JitsiConference* constructor:
199
+When JWT authentication is used with _lib-jitsi-meet_ the token is passed to the _JitsiConference_ constructor:
93 200
 
94
-```
95
-var token = {token is provided by your application possibly after some authentication}
201
+```javascript
202
+var token = {token_is_provided_by_your_application_possibly_after_some_authentication}
96 203
 
97
-JitsiMeetJS.init(initOptions).then(function(){
204
+JitsiMeetJS.init(initOptions).then(function () {
98 205
     connection = new JitsiMeetJS.JitsiConnection(APP_ID, token, options);
99
-    ...
206
+    // ...
100 207
     connection.connect();
101 208
 });
102
-
103 209
 ```
104 210
 
105 211
 ### Jitsi-meet options
106 212
 
107 213
 In order to start a jitsi-meet conference with a token you need to specify the token as an URL param:
108
-```
109
-https://example.com/angrywhalesgrowhigh?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
110
-```
111
-At the current level of integration every user that joins the conference has to provide the token and not just the one who
112
-creates the room. It should be possible to change that by using a second anonymous domain, but that hasn't been tested
113
-yet.
114 214
 
215
+`
216
+https://example.com/angrywhalesgrowhigh?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
217
+`
115 218
 
219
+At the current level of integration every user that joins the conference has to provide the token and not just the one
220
+who creates the room. It should be possible to change that by using a second anonymous domain, but that hasn't been
221
+tested yet.
116 222
 
117 223
 ### Installing the token plugin
118 224
 
119
-Token authentication can be integrated automatically using a Debian package install. Once you have jitsi-meet installed
120
-just install 'jitsi-meet-tokens' on top of it. In order to have it configured automatically at least version 779 of
225
+Token authentication can be integrated automatically using a Debian package. Once you have `jitsi-meet` installed
226
+just install `jitsi-meet-tokens` on top of it. In order to have it configured automatically at least version 779 of
121 227
 jitsi-meet is required which comes with a special Prosody config template.
122 228
 
123
-```
229
+```bash
124 230
 apt-get install jitsi-meet-tokens
125 231
 ```
126 232
 
@@ -128,16 +234,18 @@ Check the "Prosody Version" that is used in the deployment.
128 234
 
129 235
 ### Prosody Version
130 236
 
131
-JWT tokens requires prosody 0.11.6 or higher.
237
+JWT authentication requires Prosody 0.11.6 or higher.
132 238
 
133
-Make sure that */etc/prosody/prosody.cfg.lua* contains the line below at the end to include meet host config. That's because Prosody nightly may come with slightly different default config:
239
+Make sure that */etc/prosody/prosody.cfg.lua* contains the line below at the end to include meet host config. That's
240
+because Prosody nightly may come with slightly different default config:
134 241
 
135
-```
242
+```lua
136 243
 Include "conf.d/*.cfg.lua"
137 244
 ```
138 245
 
139 246
 Restart the service to take the changes into account
140
-```
247
+
248
+```bash
141 249
 sudo /etc/init.d/prosody restart
142 250
 ```
143 251
 
@@ -147,43 +255,52 @@ sudo /etc/init.d/prosody restart
147 255
 
148 256
 Modify your Prosody config with these three steps:
149 257
 
150
-\1. Adjust *plugin_paths* to contain the path pointing to the jitsi meet Prosody plugins location. That's where plugins are copied on *jitsi-meet-token* package installation. This should be included in the global config section (possibly at the beginning of your host config file).
151
-
152
-```lua
153
-plugin_paths = { "/usr/share/jitsi-meet/prosody-plugins/" }
154
-```
155
-
156
-Also, you need to set the global settings for key authorization. Both these options used to default to the '*' parameter which means accept any issuer or audience string in incoming tokens, but that is no longer the case.
157
-```lua
158
-asap_accepted_issuers = { "*" }
159
-asap_accepted_audiences = { "*" }
160
-```
258
+1. Adjust _plugin_paths_ to contain the path pointing to the jitsi meet Prosody plugins location. That's where plugins
259
+   are copied on _jitsi-meet-token_ package installation. This should be included in the global config section (possibly
260
+   at the beginning of your host config file).
261
+
262
+    ```lua
263
+    plugin_paths = { "/usr/share/jitsi-meet/prosody-plugins/" }
264
+    ```
265
+    
266
+    Also, you need to set the global settings for token authorization. Both these options used to default to the '*' parameter
267
+    which means accept any issuer or audience string in incoming tokens, but that is no longer the case.
268
+    
269
+    ```lua
270
+    asap_accepted_issuers = { "*" }
271
+    asap_accepted_audiences = { "*" }
272
+    ```
273
+
274
+2. Under your domain config change `authentication` to `token` and provide the _application ID_ in `app_id`:
275
+
276
+    If you want to validate the token via **Shared Secret Validation** add the `app_secret` parameter
277
+    
278
+    ```lua
279
+    VirtualHost "jitmeet.example.com"
280
+        authentication    = "token";
281
+        app_id            = "example_app_id";         -- application identifier
282
+        app_secret        = "example_app_secret";     -- application secret known only to your token
283
+                                                      -- generator and the plugin
284
+        allow_empty_token = false;                    -- tokens are verified only if they are supplied by the client
285
+    ```
286
+
287
+   alternatively for the **Public Key Validation** you need to set an `asap_key_server` to the base URL where valid/accepted 
288
+    _public keys_ can be found by taking a sha256() of the `kid` field from the JWT header, and appending .pem to the end
289
+    
290
+    ```lua
291
+    VirtualHost "jitmeet.example.com"
292
+        authentication    = "token";
293
+        app_id            = "example_app_id";                       -- application identifier
294
+        asap_key_server   = "https://keyserver.example.com/asap";   -- URL for public keyserver storing keys by kid
295
+        allow_empty_token = false;                                  -- tokens are verified only if they are supplied
296
+    ```
297
+
298
+3. Enable the room name token verification plugin in your MUC component config section:
299
+
300
+    ```lua
301
+    Component "conference.jitmeet.example.com" "muc"
302
+        modules_enabled = { "token_verification" }
303
+    ```
161 304
 
162
-\2. Under your domain config change authentication to "token" and provide the application ID, secret and optionally the token lifetime:
163
-
164
-```lua
165
-VirtualHost "jitmeet.example.com"
166
-    authentication = "token";
167
-    app_id = "example_app_id";             -- application identifier
168
-    app_secret = "example_app_secret";     -- application secret known only to your token
169
-    									   -- generator and the plugin
170
-    allow_empty_token = false;             -- tokens are verified only if they are supplied by the client
171
-```
172
-
173
-Alternately instead of using a shared secret you can set an asap_key_server to the base URL where valid/accepted public keys can be found by taking a sha256() of the 'kid' field in the JWT token header, and appending .pem to the end
174
-
175
-```lua
176
-VirtualHost "jitmeet.example.com"
177
-    authentication = "token";
178
-    app_id = "example_app_id";                                  -- application identifier
179
-    asap_key_server = "https://keyserver.example.com/asap";     -- URL for public keyserver storing keys by kid
180
-    allow_empty_token = false;                                  -- tokens are verified only if they are supplied
181
-```
182
-
183
-
184
-\3. Enable the room name token verification plugin in your MUC component config section:
185
-
186
-```lua
187
-Component "conference.jitmeet.example.com" "muc"
188
-    modules_enabled = { "token_verification" }
189
-```
305
+[RFC7519]: https://tools.ietf.org/html/rfc7519
306
+[http://jwt.io/#libraries-io]: http://jwt.io/#libraries-io

Loading…
Cancel
Save