@@ -12,31 +12,71 @@ The JSON file contains the following fields:
1212 <table >
1313 <thead>
1414 <tr>
15+ <th/>
1516 <th>Field</th>
1617 <th>Type</th>
1718 <th>Description</th>
1819 </tr>
1920 </thead>
2021 <tbody>
2122 <tr>
23+ <th rowspan="2">Common fields</th>
2224 <td><code>mode</code></td>
2325 <td>string</td>
2426 <td>
2527 <p>The auth mode to use. Not case-sensitive.</p>
2628 Available options:
2729 <ul>
2830 <li><code>fixed</code></li>
31+ <li><code>plugin</code></li>
2932 </ul>
3033 </td>
3134 </tr>
3235 <tr>
33- <td><code>parameters</code></td>
36+ <td><code>parameters</code> (optional; depends on mode) </td>
3437 <td>object</td>
3538 <td>
3639 A structure containing mode-specific key-value configuration
3740 fields, if applicable.
3841 </td>
3942 </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>
4080 </tbody>
4181</table >
4282
@@ -139,3 +179,86 @@ Invalid:
139179 }
140180}
141181```
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