Browse Source

Refine the use of tokens in urls.

This still defaults to not using tokens in urls in the browser, but makes it a setting so it can be used if needed. This should still maintain the security fixes from #8813 and #8835.

Fixes #9070
Jason Grout 4 years ago
parent
commit
13c897f2de

+ 2 - 4
packages/services/examples/node/main.py

@@ -22,9 +22,7 @@ class NodeApp(ProcessApp):
 
     name = __name__
     serverapp_config = dict(
-        disable_check_xsrf = True,
-        allow_origin = "*",
-        token=""
+        allow_origin = "*"
     )
 
     def get_command(self):
@@ -33,7 +31,7 @@ class NodeApp(ProcessApp):
         # Run the node script with command arguments.
         config = dict(
             baseUrl='http://localhost:{}{}'.format(self.serverapp.port, self.settings['base_url']),
-            token="")
+            token=self.settings['token'])
 
         with open(osp.join(HERE, 'config.json'), 'w') as fid:
             json.dump(config, fid)

+ 6 - 0
packages/services/src/kernel/default.ts

@@ -1216,6 +1216,12 @@ export class KernelConnection implements Kernel.IKernelConnection {
       'channels?session_id=' + encodeURIComponent(this._clientId)
     );
 
+    // If token authentication is in use.
+    const token = settings.token;
+    if (settings.appendToken && token !== '') {
+      url = url + `&token=${encodeURIComponent(token)}`;
+    }
+
     this._ws = new settings.WebSocket(url);
 
     // Ensure incoming binary messages are not Blobs

+ 9 - 0
packages/services/src/serverconnection.ts

@@ -76,6 +76,12 @@ export namespace ServerConnection {
      */
     readonly token: string;
 
+    /**
+     * Whether to append a token to a Websocket url.  The default is `false` in the browser
+     * and `true` in node or jest.
+     */
+    readonly appendToken: boolean;
+
     /**
      * The `fetch` method to use.
      */
@@ -238,6 +244,9 @@ namespace Private {
       WebSocket: WEBSOCKET,
       token: PageConfig.getToken(),
       appUrl: PageConfig.getOption('appUrl'),
+      appendToken:
+        typeof window === 'undefined' ||
+        process.env.JEST_WORKER_ID !== undefined,
       ...options,
       baseUrl,
       wsUrl

+ 4 - 2
packages/services/src/terminal/default.ts

@@ -265,8 +265,10 @@ export class TerminalConnection implements Terminal.ITerminalConnection {
       encodeURIComponent(name)
     );
 
-    if (settings.token !== undefined) {
-      url += `?token=${encodeURIComponent(settings.token)}`;
+    // If token authentication is in use.
+    const token = settings.token;
+    if (settings.appendToken && token !== '') {
+      url = url + `?token=${encodeURIComponent(token)}`;
     }
 
     this._ws = new settings.WebSocket(url);

+ 5 - 6
testutils/src/start_jupyter_server.ts

@@ -5,7 +5,7 @@ import * as fs from 'fs';
 import * as path from 'path';
 
 import { PageConfig, URLExt } from '@jupyterlab/coreutils';
-import { PromiseDelegate } from '@lumino/coreutils';
+import { PromiseDelegate, UUID } from '@lumino/coreutils';
 import { sleep } from './common';
 
 /**
@@ -202,7 +202,8 @@ namespace Private {
    */
   export function handleConfig(): string {
     // Set up configuration.
-    PageConfig.setOption('token', '');
+    const token = UUID.uuid4();
+    PageConfig.setOption('token', token);
     PageConfig.setOption('terminalsAvailable', 'true');
 
     const configDir = mktempDir('config');
@@ -221,10 +222,8 @@ namespace Private {
         open_browser: false
       },
       ServerApp: {
-        token: '',
-        notebook_dir,
-        disable_check_xsrf: true,
-        allow_origin: '*'
+        token,
+        notebook_dir
       },
       MultiKernelManager: {
         default_kernel_name: 'echo'