1
1
// Copyright (c) Microsoft Corporation. All rights reserved.
2
2
// Licensed under the MIT License.
3
3
'use strict' ;
4
+ import { Agent as HttpsAgent } from 'https' ;
4
5
import { inject , injectable } from 'inversify' ;
5
6
import * as nodeFetch from 'node-fetch' ;
6
7
import { URLSearchParams } from 'url' ;
@@ -19,7 +20,7 @@ export class JupyterPasswordConnect implements IJupyterPasswordConnect {
19
20
}
20
21
21
22
@captureTelemetry ( Telemetry . GetPasswordAttempt )
22
- public async getPasswordConnectionInfo ( url : string , fetchFunction ?: ( url : nodeFetch . RequestInfo , init ?: nodeFetch . RequestInit ) => Promise < nodeFetch . Response > ) : Promise < IJupyterPasswordConnectInfo | undefined > {
23
+ public async getPasswordConnectionInfo ( url : string , allowUnauthorized : boolean , fetchFunction ?: ( url : nodeFetch . RequestInfo , init ?: nodeFetch . RequestInit ) => Promise < nodeFetch . Response > ) : Promise < IJupyterPasswordConnectInfo | undefined > {
23
24
// For testing allow for our fetch function to be overridden
24
25
if ( ! fetchFunction ) {
25
26
fetchFunction = nodeFetch . default ;
@@ -44,11 +45,11 @@ export class JupyterPasswordConnect implements IJupyterPasswordConnect {
44
45
45
46
if ( userPassword ) {
46
47
// First get the xsrf cookie by hitting the initial login page
47
- xsrfCookie = await this . getXSRFToken ( url , fetchFunction ) ;
48
+ xsrfCookie = await this . getXSRFToken ( url , allowUnauthorized , fetchFunction ) ;
48
49
49
50
// Then get the session cookie by hitting that same page with the xsrftoken and the password
50
51
if ( xsrfCookie ) {
51
- const sessionResult = await this . getSessionCookie ( url , xsrfCookie , userPassword , fetchFunction ) ;
52
+ const sessionResult = await this . getSessionCookie ( url , allowUnauthorized , xsrfCookie , userPassword , fetchFunction ) ;
52
53
sessionCookieName = sessionResult . sessionCookieName ;
53
54
sessionCookieValue = sessionResult . sessionCookieValue ;
54
55
}
@@ -65,6 +66,16 @@ export class JupyterPasswordConnect implements IJupyterPasswordConnect {
65
66
}
66
67
}
67
68
69
+ // For HTTPS connections respect our allowUnauthorized setting by adding in an agent to enable that on the request
70
+ private addAllowUnauthorized ( url : string , allowUnauthorized : boolean , options : nodeFetch . RequestInit ) : nodeFetch . RequestInit {
71
+ if ( url . startsWith ( 'https' ) && allowUnauthorized ) {
72
+ const requestAgent = new HttpsAgent ( { rejectUnauthorized : false } ) ;
73
+ return { ...options , agent : requestAgent } ;
74
+ }
75
+
76
+ return options ;
77
+ }
78
+
68
79
private async getUserPassword ( ) : Promise < string | undefined > {
69
80
// First get the proposed URI from the user
70
81
return this . appShell . showInputBox ( {
@@ -74,14 +85,14 @@ export class JupyterPasswordConnect implements IJupyterPasswordConnect {
74
85
} ) ;
75
86
}
76
87
77
- private async getXSRFToken ( url : string , fetchFunction : ( url : nodeFetch . RequestInfo , init ?: nodeFetch . RequestInit ) => Promise < nodeFetch . Response > ) : Promise < string | undefined > {
88
+ private async getXSRFToken ( url : string , allowUnauthorized : boolean , fetchFunction : ( url : nodeFetch . RequestInfo , init ?: nodeFetch . RequestInit ) => Promise < nodeFetch . Response > ) : Promise < string | undefined > {
78
89
let xsrfCookie : string | undefined ;
79
90
80
- const response = await fetchFunction ( `${ url } login?` , {
91
+ const response = await fetchFunction ( `${ url } login?` , this . addAllowUnauthorized ( url , allowUnauthorized , {
81
92
method : 'get' ,
82
93
redirect : 'manual' ,
83
94
headers : { Connection : 'keep-alive' }
84
- } ) ;
95
+ } ) ) ;
85
96
86
97
if ( response . ok ) {
87
98
const cookies = this . getCookies ( response ) ;
@@ -98,6 +109,7 @@ export class JupyterPasswordConnect implements IJupyterPasswordConnect {
98
109
// First you need a get at the login page to get the xsrf token, then you send back that token along with the password in a post
99
110
// That will return back the session cookie. This session cookie then needs to be added to our requests and websockets for @jupyterlab /services
100
111
private async getSessionCookie ( url : string ,
112
+ allowUnauthorized : boolean ,
101
113
xsrfCookie : string ,
102
114
password : string ,
103
115
fetchFunction : ( url : nodeFetch . RequestInfo , init ?: nodeFetch . RequestInit ) => Promise < nodeFetch . Response > ) : Promise < { sessionCookieName : string | undefined ; sessionCookieValue : string | undefined } > {
@@ -108,12 +120,12 @@ export class JupyterPasswordConnect implements IJupyterPasswordConnect {
108
120
postParams . append ( '_xsrf' , xsrfCookie ) ;
109
121
postParams . append ( 'password' , password ) ;
110
122
111
- const response = await fetchFunction ( `${ url } login?` , {
123
+ const response = await fetchFunction ( `${ url } login?` , this . addAllowUnauthorized ( url , allowUnauthorized , {
112
124
method : 'post' ,
113
125
headers : { Cookie : `_xsrf=${ xsrfCookie } ` , Connection : 'keep-alive' , 'content-type' : 'application/x-www-form-urlencoded;charset=UTF-8' } ,
114
126
body : postParams . toString ( ) ,
115
127
redirect : 'manual'
116
- } ) ;
128
+ } ) ) ;
117
129
118
130
// Now from this result we need to extract the session cookie
119
131
if ( response . status === 302 ) {
0 commit comments