Port ssl config fix (#8185)

This commit is contained in:
Charles Gagnon
2019-11-01 15:37:22 -07:00
committed by GitHub
parent 517b375395
commit 650ab3b800
15 changed files with 99 additions and 45 deletions

View File

@@ -139,7 +139,18 @@
"command": "bigDataClusters.command.deletemount", "command": "bigDataClusters.command.deletemount",
"title": "%command.deletemount.title%" "title": "%command.deletemount.title%"
} }
] ],
"configuration": {
"type": "object",
"title": "%bdc.configuration.title%",
"properties": {
"bigDataCluster.ignoreSslVerification": {
"type": "boolean",
"default": true,
"description": "%bdc.ignoreSslVerification.desc%"
}
}
}
}, },
"dependencies": { "dependencies": {
"kerberos": "^1.1.3", "kerberos": "^1.1.3",

View File

@@ -7,5 +7,7 @@
"command.manageController.title" : "Manage", "command.manageController.title" : "Manage",
"command.mount.title" : "Mount HDFS", "command.mount.title" : "Mount HDFS",
"command.refreshmount.title" : "Refresh Mount", "command.refreshmount.title" : "Refresh Mount",
"command.deletemount.title" : "Delete Mount" "command.deletemount.title" : "Delete Mount",
"bdc.configuration.title" : "Big Data Cluster",
"bdc.ignoreSslVerification.desc" : "Ignore SSL verification errors against SQL Server Big Data Cluster endpoints such as HDFS, Spark, and Controller if true"
} }

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
export enum BdcItemType { export enum BdcItemType {

View File

@@ -4,32 +4,30 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as request from 'request'; import * as request from 'request';
import { authenticateKerberos, getHostAndPortFromEndpoint } from '../auth'; import { authenticateKerberos, getHostAndPortFromEndpoint } from '../auth';
import { BdcRouterApi, Authentication, EndpointModel, BdcStatusModel, DefaultApi } from './apiGenerated'; import { BdcRouterApi, Authentication, EndpointModel, BdcStatusModel, DefaultApi } from './apiGenerated';
import { TokenRouterApi } from './clusterApiGenerated2'; import { TokenRouterApi } from './clusterApiGenerated2';
import { AuthType } from '../constants'; import { AuthType } from '../constants';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { ConnectControllerDialog, ConnectControllerModel } from '../dialog/connectControllerDialog'; import { ConnectControllerDialog, ConnectControllerModel } from '../dialog/connectControllerDialog';
import { getIgnoreSslVerificationConfigSetting } from '../utils';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
class SslAuth implements Authentication { class SslAuth implements Authentication {
constructor() { }
constructor(private _ignoreSslVerification: boolean) {
}
applyToRequest(requestOptions: request.Options): void { applyToRequest(requestOptions: request.Options): void {
requestOptions['agentOptions'] = { requestOptions['agentOptions'] = {
rejectUnauthorized: !this._ignoreSslVerification rejectUnauthorized: !getIgnoreSslVerificationConfigSetting()
}; };
} }
} }
export class KerberosAuth extends SslAuth implements Authentication { export class KerberosAuth extends SslAuth implements Authentication {
constructor(public kerberosToken: string, ignoreSslVerification: boolean) { constructor(public kerberosToken: string) {
super(ignoreSslVerification); super();
} }
applyToRequest(requestOptions: request.Options): void { applyToRequest(requestOptions: request.Options): void {
@@ -41,8 +39,8 @@ export class KerberosAuth extends SslAuth implements Authentication {
} }
} }
export class BasicAuth extends SslAuth implements Authentication { export class BasicAuth extends SslAuth implements Authentication {
constructor(public username: string, public password: string, ignoreSslVerification: boolean) { constructor(public username: string, public password: string) {
super(ignoreSslVerification); super();
} }
applyToRequest(requestOptions: request.Options): void { applyToRequest(requestOptions: request.Options): void {
@@ -96,17 +94,16 @@ export class ClusterController {
constructor(url: string, constructor(url: string,
private _authType: AuthType, private _authType: AuthType,
private _username?: string, private _username?: string,
private _password?: string, private _password?: string
ignoreSslVerification?: boolean
) { ) {
if (!url || (_authType === 'basic' && (!_username || !_password))) { if (!url || (_authType === 'basic' && (!_username || !_password))) {
throw new Error('Missing required inputs for Cluster controller API (URL, username, password)'); throw new Error('Missing required inputs for Cluster controller API (URL, username, password)');
} }
this._url = adjustUrl(url); this._url = adjustUrl(url);
if (this._authType === 'basic') { if (this._authType === 'basic') {
this._authPromise = Promise.resolve(new BasicAuth(_username, _password, !!ignoreSslVerification)); this._authPromise = Promise.resolve(new BasicAuth(_username, _password));
} else { } else {
this._authPromise = this.requestTokenUsingKerberos(ignoreSslVerification); this._authPromise = this.requestTokenUsingKerberos();
} }
this._dialog = new ConnectControllerDialog(new ConnectControllerModel( this._dialog = new ConnectControllerDialog(new ConnectControllerModel(
{ {
@@ -133,8 +130,8 @@ export class ClusterController {
return this._password; return this._password;
} }
private async requestTokenUsingKerberos(ignoreSslVerification?: boolean): Promise<Authentication> { private async requestTokenUsingKerberos(): Promise<Authentication> {
let supportsKerberos = await this.verifyKerberosSupported(ignoreSslVerification); let supportsKerberos = await this.verifyKerberosSupported();
if (!supportsKerberos) { if (!supportsKerberos) {
throw new Error(localize('error.no.activedirectory', "This cluster does not support Windows authentication")); throw new Error(localize('error.no.activedirectory', "This cluster does not support Windows authentication"));
} }
@@ -145,9 +142,9 @@ export class ClusterController {
let host = getHostAndPortFromEndpoint(this._url).host; let host = getHostAndPortFromEndpoint(this._url).host;
let kerberosToken = await authenticateKerberos(host); let kerberosToken = await authenticateKerberos(host);
let tokenApi = new TokenRouterApi(this._url); let tokenApi = new TokenRouterApi(this._url);
tokenApi.setDefaultAuthentication(new KerberosAuth(kerberosToken, !!ignoreSslVerification)); tokenApi.setDefaultAuthentication(new KerberosAuth(kerberosToken));
let result = await tokenApi.apiV1TokenPost(); let result = await tokenApi.apiV1TokenPost();
let auth = new OAuthWithSsl(ignoreSslVerification); let auth = new OAuthWithSsl();
auth.accessToken = result.body.accessToken; auth.accessToken = result.body.accessToken;
return auth; return auth;
} catch (error) { } catch (error) {
@@ -160,9 +157,9 @@ export class ClusterController {
} }
} }
private async verifyKerberosSupported(ignoreSslVerification: boolean): Promise<boolean> { private async verifyKerberosSupported(): Promise<boolean> {
let tokenApi = new TokenRouterApi(this._url); let tokenApi = new TokenRouterApi(this._url);
tokenApi.setDefaultAuthentication(new SslAuth(!!ignoreSslVerification)); tokenApi.setDefaultAuthentication(new SslAuth());
try { try {
await tokenApi.apiV1TokenPost(); await tokenApi.apiV1TokenPost();
// If we get to here, the route for endpoints doesn't require auth so state this is false // If we get to here, the route for endpoints doesn't require auth so state this is false

View File

@@ -70,7 +70,7 @@ export class AddControllerDialogModel {
} }
} }
// We pre-fetch the endpoints here to verify that the information entered is correct (the user is able to connect) // We pre-fetch the endpoints here to verify that the information entered is correct (the user is able to connect)
let controller = new ClusterController(url, auth, username, password, true); let controller = new ClusterController(url, auth, username, password);
let response = await controller.getEndPoints(); let response = await controller.getEndPoints();
if (response && response.endPoints) { if (response && response.endPoints) {
if (this._canceled) { if (this._canceled) {

View File

@@ -31,9 +31,9 @@ export class BdcDashboardModel {
public onDidUpdateBdcStatus = this._onDidUpdateBdcStatus.event; public onDidUpdateBdcStatus = this._onDidUpdateBdcStatus.event;
public onBdcError = this._onBdcError.event; public onBdcError = this._onBdcError.event;
constructor(private _options: BdcDashboardOptions, private _treeDataProvider: ControllerTreeDataProvider, ignoreSslVerification = true) { constructor(private _options: BdcDashboardOptions, private _treeDataProvider: ControllerTreeDataProvider) {
try { try {
this._clusterController = new ClusterController(_options.url, _options.auth, _options.username, _options.password, ignoreSslVerification); this._clusterController = new ClusterController(_options.url, _options.auth, _options.username, _options.password);
// tslint:disable-next-line:no-floating-promises // tslint:disable-next-line:no-floating-promises
this.refresh(); this.refresh();
} catch { } catch {

View File

@@ -80,7 +80,7 @@ export abstract class HdfsDialogModelBase<T extends HdfsDialogProperties, R> {
} }
protected createController(): ClusterController { protected createController(): ClusterController {
return new ClusterController(this.props.url, this.props.auth, this.props.username, this.props.password, true); return new ClusterController(this.props.url, this.props.auth, this.props.username, this.props.password);
} }
protected async createAndVerifyControllerConnection(): Promise<ClusterController> { protected async createAndVerifyControllerConnection(): Promise<ClusterController> {

View File

@@ -3,13 +3,11 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
'use strict';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
import * as constants from './constants'; import * as constants from './constants';
const localize = nls.loadMessageBundle();
export enum Endpoint { export enum Endpoint {
gateway = 'gateway', gateway = 'gateway',
@@ -273,3 +271,21 @@ export function getControllerEndpoint(serverInfo: azdata.ServerInfo): string | u
export function getBdcStatusErrorMessage(error: Error): string { export function getBdcStatusErrorMessage(error: Error): string {
return localize('endpointsError', "Unexpected error retrieving BDC Endpoints: {0}", error.message); return localize('endpointsError', "Unexpected error retrieving BDC Endpoints: {0}", error.message);
} }
export const bdcConfigSectionName = 'bigDataCluster';
export const ignoreSslConfigName = 'ignoreSslVerification';
/**
* Retrieves the current setting for whether to ignore SSL verification errors
*/
export function getIgnoreSslVerificationConfigSetting(): boolean {
try {
const config = vscode.workspace.getConfiguration(bdcConfigSectionName);
return config.get<boolean>(ignoreSslConfigName) || true;
} catch (error) {
console.error(`Unexpected error retrieving ${bdcConfigSectionName}.${ignoreSslConfigName} setting : ${error}`);
}
return true;
}

View File

@@ -780,10 +780,6 @@ export class WebHDFS {
stream.pipe(upload); stream.pipe(upload);
stream.resume(); stream.resume();
} }
if (error && !response) {
// request failed, and req is not accessible in this case.
throw this.parseError(undefined, undefined, error);
}
if (error || this.isError(response)) { if (error || this.isError(response)) {
emitError(req, this.parseError(response, body, error)); emitError(req, this.parseError(response, body, error));
} }

View File

@@ -18,6 +18,7 @@ import { WebHDFS, HdfsError } from '../hdfs/webhdfs';
import { PermissionStatus } from '../hdfs/aclEntry'; import { PermissionStatus } from '../hdfs/aclEntry';
import { Mount, MountStatus } from '../hdfs/mount'; import { Mount, MountStatus } from '../hdfs/mount';
import { FileStatus, hdfsFileTypeToFileType } from '../hdfs/fileStatus'; import { FileStatus, hdfsFileTypeToFileType } from '../hdfs/fileStatus';
import { getIgnoreSslVerificationConfigSetting } from '../util/auth';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
@@ -143,12 +144,11 @@ export class FileSourceFactory {
options = options && options.host ? FileSourceFactory.removePortFromHost(options) : options; options = options && options.host ? FileSourceFactory.removePortFromHost(options) : options;
let requestParams: IRequestParams = options.requestParams ? options.requestParams : {}; let requestParams: IRequestParams = options.requestParams ? options.requestParams : {};
if (requestParams.auth || requestParams.isKerberos) { if (requestParams.auth || requestParams.isKerberos) {
// TODO Remove handling of unsigned cert once we have real certs in our Knox service
let agentOptions = { let agentOptions = {
host: options.host, host: options.host,
port: options.port, port: options.port,
path: constants.hdfsRootPath, path: constants.hdfsRootPath,
rejectUnauthorized: false rejectUnauthorized: !getIgnoreSslVerificationConfigSetting()
}; };
let agent = new https.Agent(agentOptions); let agent = new https.Agent(agentOptions);
requestParams['agent'] = agent; requestParams['agent'] = agent;

View File

@@ -37,8 +37,7 @@ export class SparkJobSubmissionService {
uri: livyUrl, uri: livyUrl,
method: 'POST', method: 'POST',
json: true, json: true,
// TODO, change it back after service's authentication changed. rejectUnauthorized: !auth.getIgnoreSslVerificationConfigSetting(),
rejectUnauthorized: false,
body: { body: {
file: submissionArgs.sparkFile, file: submissionArgs.sparkFile,
proxyUser: submissionArgs.user, proxyUser: submissionArgs.user,
@@ -114,7 +113,7 @@ export class SparkJobSubmissionService {
uri: livyUrl, uri: livyUrl,
method: 'GET', method: 'GET',
json: true, json: true,
rejectUnauthorized: false, rejectUnauthorized: !auth.getIgnoreSslVerificationConfigSetting(),
// authentication headers // authentication headers
headers: headers headers: headers
}; };

View File

@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as kerberos from 'kerberos'; import * as kerberos from 'kerberos';
import * as vscode from 'vscode';
export enum AuthType { export enum AuthType {
Integrated = 'integrated', Integrated = 'integrated',
@@ -17,3 +18,20 @@ export async function authenticateKerberos(hostname: string): Promise<string> {
let response = await client.step(''); let response = await client.step('');
return response; return response;
} }
const bdcConfigSectionName = 'bigDataCluster';
const ignoreSslConfigName = 'ignoreSslVerification';
/**
* Retrieves the current setting for whether to ignore SSL verification errors
*/
export function getIgnoreSslVerificationConfigSetting(): boolean {
try {
const config = vscode.workspace.getConfiguration(bdcConfigSectionName);
return config.get<boolean>(ignoreSslConfigName) || true;
} catch (error) {
console.error(`Unexpected error retrieving ${bdcConfigSectionName}.${ignoreSslConfigName} setting : ${error}`);
}
return true;
}

View File

@@ -11,7 +11,6 @@
"url": "", "url": "",
"auth": "None" "auth": "None"
}, },
"ignore_ssl_errors": true,
"livy_session_startup_timeout_seconds": 100, "livy_session_startup_timeout_seconds": 100,
"logging_config": { "logging_config": {
"version": 1, "version": 1,

View File

@@ -246,3 +246,19 @@ export async function exists(path: string): Promise<boolean> {
return false; return false;
} }
} }
const bdcConfigSectionName = 'bigDataCluster';
const ignoreSslConfigName = 'ignoreSslVerification';
/**
* Retrieves the current setting for whether to ignore SSL verification errors
*/
export function getIgnoreSslVerificationConfigSetting(): boolean {
try {
const config = vscode.workspace.getConfiguration(bdcConfigSectionName);
return config.get<boolean>(ignoreSslConfigName) || true;
} catch (error) {
console.error(`Unexpected error retrieving ${bdcConfigSectionName}.${ignoreSslConfigName} setting : ${error}`);
}
return true;
}

View File

@@ -26,10 +26,6 @@ const configBase = {
'kernel_r_credentials': { 'kernel_r_credentials': {
'url': '' 'url': ''
}, },
'ignore_ssl_errors': true,
'livy_session_startup_timeout_seconds': 100,
'logging_config': { 'logging_config': {
'version': 1, 'version': 1,
'formatters': { 'formatters': {
@@ -172,7 +168,12 @@ export class JupyterSession implements nb.ISession {
private _messagesComplete: Deferred<void> = new Deferred<void>(); private _messagesComplete: Deferred<void> = new Deferred<void>();
constructor(private sessionImpl: Session.ISession, skipSettingEnvironmentVars?: boolean, private _pythonEnvVarPath?: string) { constructor(private sessionImpl: Session.ISession, skipSettingEnvironmentVars?: boolean, private _pythonEnvVarPath?: string) {
this.setEnvironmentVars(skipSettingEnvironmentVars); this.setEnvironmentVars(skipSettingEnvironmentVars).catch(error => {
console.error(`Unexpected exception setting Jupyter Session variables : ${error}`);
// We don't want callers to hang forever waiting - it's better to continue on even if we weren't
// able to set environment variables
this._messagesComplete.resolve();
});
} }
public get canChangeKernels(): boolean { public get canChangeKernels(): boolean {
@@ -309,6 +310,7 @@ export class JupyterSession implements nb.ISession {
config.kernel_scala_credentials = creds; config.kernel_scala_credentials = creds;
config.kernel_r_credentials = creds; config.kernel_r_credentials = creds;
config.logging_config.handlers.magicsHandler.home_path = homePath; config.logging_config.handlers.magicsHandler.home_path = homePath;
config.ignore_ssl_errors = utils.getIgnoreSslVerificationConfigSetting();
} }
private getKnoxPortOrDefault(connectionProfile: IConnectionProfile): string { private getKnoxPortOrDefault(connectionProfile: IConnectionProfile): string {