@@ -12,31 +12,71 @@ The JSON file contains the following fields:
12
12
<table >
13
13
<thead>
14
14
<tr>
15
+ <th/>
15
16
<th>Field</th>
16
17
<th>Type</th>
17
18
<th>Description</th>
18
19
</tr>
19
20
</thead>
20
21
<tbody>
21
22
<tr>
23
+ <th rowspan="2">Common fields</th>
22
24
<td><code>mode</code></td>
23
25
<td>string</td>
24
26
<td>
25
27
<p>The auth mode to use. Not case-sensitive.</p>
26
28
Available options:
27
29
<ul>
28
30
<li><code>fixed</code></li>
31
+ <li><code>plugin</code></li>
29
32
</ul>
30
33
</td>
31
34
</tr>
32
35
<tr>
33
- <td><code>parameters</code></td>
36
+ <td><code>parameters</code> (optional; depends on mode) </td>
34
37
<td>object</td>
35
38
<td>
36
39
A structure containing mode-specific key-value configuration
37
40
fields, if applicable.
38
41
</td>
39
42
</tr>
43
+ <tr>
44
+ <th rowspan="3"><code>plugin</code>-specific fields</th>
45
+ <td><code>path</code></td>
46
+ <td>string</td>
47
+ <td>
48
+ The absolute path to the auth plugin <code>.so</code> file.
49
+ </td>
50
+ </tr>
51
+ <tr>
52
+ <td><code>initializer</code></td>
53
+ <td>string</td>
54
+ <td>
55
+ The name of the symbol within the plugin binary that can invoked
56
+ to create the <code>AuthMiddleware</code>. The initializer:
57
+ <ul>
58
+ <li>
59
+ Must have the signature
60
+ <code>func(json.RawMessage) (AuthMiddleware, error)</code>.
61
+ </li>
62
+ <li>
63
+ Must be exported in its package (i.e.,
64
+ <code>UpperCamelCase</code> name).
65
+ </li>
66
+ </ul>
67
+ See <a href="#plugin-mode">Plugin mode</a> for more details.
68
+ </td>
69
+ </tr>
70
+ <tr>
71
+ <td><code>sha256</code></td>
72
+ <td>string</td>
73
+ <td>
74
+ The SHA256 checksum of the plugin <code>.so</code> file,
75
+ rendered as a hex string. If the checksum does not match the
76
+ calculated checksum of the plugin file, the web server will
77
+ refuse to start.
78
+ </td>
79
+ </tr>
40
80
</tbody>
41
81
</table >
42
82
@@ -139,3 +179,86 @@ Invalid:
139
179
}
140
180
}
141
181
```
182
+
183
+ ## Plugin mode
184
+
185
+ ** Mode: ` plugin ` **
186
+
187
+ Plugin mode allows users to develop their custom auth middleware to serve a more
188
+ specific platform or need than the built-in modes (e.g., host-based federated
189
+ access). The bundle server makes use of Go's [ ` plugin ` ] [ plugin ] package to load
190
+ the plugin and create an instance of the specified middleware.
191
+
192
+ ### The plugin
193
+
194
+ The plugin is a ` .so ` shared library built using ` go build ` 's
195
+ ` -buildmode=plugin ` option. The custom auth middleware must implement the
196
+ ` AuthMiddleware ` interface defined in the exported ` auth ` package of this
197
+ repository. Additionally, the plugin must contain an initializer function that
198
+ creates and returns the custom ` AuthMiddleware ` interface. The function
199
+ signature of this initializer is:
200
+
201
+ ``` go
202
+ func (json .RawMessage ) (AuthMiddleware , error )
203
+ ```
204
+
205
+ - The `json.RawMessage` input is the raw bytes of the `parameters` object (empty
206
+ if `parameters` is not in the auth config JSON).
207
+ - The `AuthMiddleware` is an instance of the plugin's custom `AuthMiddleware`
208
+ implementation. If this is `nil` and `error` is not `nil`, the web server will
209
+ fail to start.
210
+ - If the `AuthMiddleware` cannot be initialized, the `error` captures the
211
+ context of the failure. If `error` is not `nil`, the web server will fail to
212
+ start.
213
+
214
+ > **Note**
215
+ >
216
+ > While this project is in a pre-release/alpha state, the `AuthMiddleware`
217
+ > and initializer interfaces may change, breaking older plugins.
218
+
219
+ After the `AuthMiddleware` is loaded, its `Authorize()` function will be called
220
+ for each valid route request. The `AuthResult` returned must be created with one
221
+ of `Accept()` or `Reject()`; an accepted request will continue on to the logic
222
+ for serving bundle server content, a rejected one will return immediately with
223
+ the specified code and headers.
224
+
225
+ Note that these requests may be processed in parallel, therefore **it is up to
226
+ the developer of the plugin to ensure their middleware's `Authorize()` function
227
+ is thread-safe**! Failure to do so could create race conditions and lead to
228
+ unexpected behavior.
229
+
230
+ ### The config
231
+
232
+ When using `plugin` mode in the auth config, there are a few additional fields
233
+ that must be specified that are not required for built-in modes: `path`,
234
+ `initializer`, `sha256`.
235
+
236
+ There are multiple ways to determine the SHA256 checksum of a file, but an
237
+ easy way to do so on the command line is:
238
+
239
+ ```bash
240
+ shasum -a 256 path/to/your/plugin.so
241
+ ```
242
+
243
+ > **Warning**
244
+ >
245
+ > In the current plugin-loading implementation, the SHA256 checksum of the
246
+ > specified is calculated and compared before reading in the plugin. This opens
247
+ > up the possibility of a [time-of-check/time-of-use][toctou] attack wherein a
248
+ > malicious actor replaces a valid plugin file with their own plugin _after_ the
249
+ > checksum verification of the "good" file but before the plugin is loaded into
250
+ > memory.
251
+ >
252
+ > To mitigate this risk, ensure 'write' permissions are disabled on your plugin
253
+ > file. And, as always, practice caution when running third party code that
254
+ > interacts with credentials and other sensitive information.
255
+
256
+ [plugin]: https:// pkg.go.dev/plugin
257
+ [toctou]: https:// en.wikipedia.org/wiki/Time-of-check_to_time-of-use
258
+
259
+ ### Examples
260
+
261
+ An example plugin and corresponding config can be found in the
262
+ [`examples/auth`][examples-dir] directory of this repository.
263
+
264
+ [examples-dir]: ../../examples/auth
0 commit comments