mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-21 09:35:38 -05:00
Migrate cert validation error handling to mssql extension (#21829)
This commit is contained in:
@@ -27,8 +27,7 @@ import * as types from 'vs/base/common/types';
|
||||
import { trim } from 'vs/base/common/strings';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
|
||||
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
|
||||
import { TelemetryView } from 'sql/platform/telemetry/common/telemetryKeys';
|
||||
import { CmsConnectionController } from 'sql/workbench/services/connection/browser/cmsConnectionController';
|
||||
import { entries } from 'sql/base/common/collections';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
@@ -91,7 +90,6 @@ export class ConnectionDialogService implements IConnectionDialogService {
|
||||
@IClipboardService private _clipboardService: IClipboardService,
|
||||
@ICommandService private _commandService: ICommandService,
|
||||
@ILogService private _logService: ILogService,
|
||||
@IAdsTelemetryService private _telemetryService: IAdsTelemetryService
|
||||
) {
|
||||
this.initializeConnectionProviders();
|
||||
}
|
||||
@@ -285,7 +283,7 @@ export class ConnectionDialogService implements IConnectionDialogService {
|
||||
this._logService.debug(`ConnectionDialogService: Error handled and connection reset - Error: ${connectionResult.errorMessage}`);
|
||||
} else {
|
||||
this._connectionDialog.resetConnection();
|
||||
this.showErrorDialog(Severity.Error, this._connectionErrorTitle, connectionResult.errorMessage, connectionResult.callStack, connectionResult.errorCode);
|
||||
this.showErrorDialog(Severity.Error, this._connectionErrorTitle, connectionResult.errorMessage, connectionResult.messageDetails);
|
||||
this._logService.debug(`ConnectionDialogService: Connection error: ${connectionResult.errorMessage}`);
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -471,7 +469,7 @@ export class ConnectionDialogService implements IConnectionDialogService {
|
||||
await this.showDialogWithModel();
|
||||
|
||||
if (connectionResult && connectionResult.errorMessage) {
|
||||
this.showErrorDialog(Severity.Error, this._connectionErrorTitle, connectionResult.errorMessage, connectionResult.callStack, connectionResult.errorCode);
|
||||
this.showErrorDialog(Severity.Error, this._connectionErrorTitle, connectionResult.errorMessage, connectionResult.messageDetails);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,8 +501,7 @@ export class ConnectionDialogService implements IConnectionDialogService {
|
||||
recentConnections.forEach(conn => conn.dispose());
|
||||
}
|
||||
|
||||
|
||||
private showErrorDialog(severity: Severity, headerTitle: string, message: string, messageDetails?: string, errorCode?: number): void {
|
||||
private showErrorDialog(severity: Severity, headerTitle: string, message: string, messageDetails?: string): void {
|
||||
// Kerberos errors are currently very hard to understand, so adding handling of these to solve the common scenario
|
||||
// note that ideally we would have an extensible service to handle errors by error code and provider, but for now
|
||||
// this solves the most common "hard error" that we've noticed
|
||||
@@ -532,22 +529,6 @@ export class ConnectionDialogService implements IConnectionDialogService {
|
||||
|
||||
this._logService.error(message);
|
||||
|
||||
// Set instructionText for MSSQL Provider Encryption error code -2146893019 thrown by SqlClient when certificate validation fails.
|
||||
if (errorCode === -2146893019) {
|
||||
let enableTrustServerCert = localize('enableTrustServerCertificate', "Enable Trust server certificate");
|
||||
let instructionText = localize('trustServerCertInstructionText', `Encryption was enabled on this connection, review your SSL and certificate configuration for the target SQL Server, or enable 'Trust server certificate' in the connection dialog.
|
||||
|
||||
Note: A self-signed certificate offers only limited protection and is not a recommended practice for production environments. Do you want to enable 'Trust server certificate' on this connection and retry? `);
|
||||
let readMoreLink = "https://learn.microsoft.com/sql/database-engine/configure-windows/enable-encrypted-connections-to-the-database-engine"
|
||||
actions.push(new Action('trustServerCert', enableTrustServerCert, undefined, true, async () => {
|
||||
this._telemetryService.sendActionEvent(TelemetryKeys.TelemetryView.ConnectionDialog, TelemetryKeys.TelemetryAction.EnableTrustServerCertificate);
|
||||
this._model.options[Constants.trustServerCertificate] = true;
|
||||
await this.handleOnConnect(this._connectionDialog.newConnectionParams, this._model as IConnectionProfile);
|
||||
return;
|
||||
}));
|
||||
this._errorMessageService.showDialog(severity, headerTitle, message, messageDetails, actions, instructionText, readMoreLink);
|
||||
} else {
|
||||
this._errorMessageService.showDialog(severity, headerTitle, message, messageDetails, actions);
|
||||
}
|
||||
this._errorMessageService.showDialog(severity, headerTitle, message, messageDetails, TelemetryView.ConnectionErrorDialog, actions, undefined, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ export class ConnectionDialogWidget extends Modal {
|
||||
private connect(element?: IConnectionProfile): void {
|
||||
this.logService.debug('ConnectionDialogWidget: Connect button is clicked');
|
||||
if (this._connectButton.enabled) {
|
||||
this._telemetryService.createActionEvent(TelemetryKeys.TelemetryView.ConnectionDialog, TelemetryKeys.TelemetryAction.ConnectToServer).withAdditionalProperties(
|
||||
this._telemetryService.createActionEvent(TelemetryKeys.TelemetryView.ConnectionErrorDialog, TelemetryKeys.TelemetryAction.ConnectToServer).withAdditionalProperties(
|
||||
{ [TelemetryKeys.TelemetryPropertyName.ConnectionSource]: this._connectionSource }
|
||||
).send();
|
||||
this._connecting = true;
|
||||
|
||||
@@ -329,7 +329,7 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
|
||||
// If the password is required and still not loaded show the dialog
|
||||
if ((!foundPassword && this._connectionStore.isPasswordRequired(newConnection) && !newConnection.password) || !tokenFillSuccess) {
|
||||
return this.showConnectionDialogOnError(connection, owner, { connected: false, errorMessage: undefined, callStack: undefined, errorCode: undefined }, options);
|
||||
return this.showConnectionDialogOnError(connection, owner, { connected: false, errorMessage: undefined, messageDetails: undefined, errorCode: undefined }, options);
|
||||
} else {
|
||||
// Try to connect
|
||||
return this.connectWithOptions(newConnection, owner.uri, options, owner).then(connectionResult => {
|
||||
@@ -564,14 +564,22 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
return this.connectWithOptions(connection, uri, options, callbacks);
|
||||
}
|
||||
else {
|
||||
let connectionErrorHandled = await this._errorDiagnosticsService.tryHandleConnectionError(connectionResult.errorCode, connectionResult.errorMessage, connection.providerName, connection);
|
||||
if (connectionErrorHandled.handled) {
|
||||
let connectionErrorHandleResult = await this._errorDiagnosticsService.tryHandleConnectionError(connectionResult, connection.providerName, connection);
|
||||
if (connectionErrorHandleResult.handled) {
|
||||
connectionResult.errorHandled = true;
|
||||
if (connectionErrorHandled.options) {
|
||||
if (connectionErrorHandleResult.options) {
|
||||
//copy over altered connection options from the result if provided.
|
||||
connection.options = connectionErrorHandled.options;
|
||||
connection.options = connectionErrorHandleResult.options;
|
||||
}
|
||||
if (connectionErrorHandleResult.reconnect) {
|
||||
// Attempt reconnect if requested by provider
|
||||
return this.connectWithOptions(connection, uri, options, callbacks);
|
||||
} else {
|
||||
if (callbacks.onConnectCanceled) {
|
||||
callbacks.onConnectCanceled();
|
||||
}
|
||||
return connectionResult;
|
||||
}
|
||||
return this.connectWithOptions(connection, uri, options, callbacks);
|
||||
}
|
||||
else {
|
||||
// Error not handled by any registered providers so fail the connection
|
||||
@@ -1299,18 +1307,18 @@ export class ConnectionManagementService extends Disposable implements IConnecti
|
||||
if (connectionMngInfo && connectionMngInfo.deleted) {
|
||||
this._logService.info(`Found deleted connection management info for ${uri} - removing`);
|
||||
this._connectionStatusManager.deleteConnection(uri);
|
||||
resolve({ connected: connectResult, errorMessage: undefined, errorCode: undefined, callStack: undefined, errorHandled: true, connectionProfile: connection });
|
||||
resolve({ connected: connectResult, errorMessage: undefined, errorCode: undefined, messageDetails: undefined, errorHandled: true, connectionProfile: connection });
|
||||
} else {
|
||||
if (errorMessage) {
|
||||
// Connection to the server failed
|
||||
this._logService.info(`Error occurred while connecting, removing connection management info for ${uri}`);
|
||||
this._connectionStatusManager.deleteConnection(uri);
|
||||
resolve({ connected: connectResult, errorMessage: errorMessage, errorCode: errorCode, callStack: callStack, connectionProfile: connection });
|
||||
resolve({ connected: connectResult, errorMessage: errorMessage, errorCode: errorCode, messageDetails: callStack, connectionProfile: connection });
|
||||
} else {
|
||||
if (connectionMngInfo.serverInfo) {
|
||||
connection.options.isCloud = connectionMngInfo.serverInfo.isCloud;
|
||||
}
|
||||
resolve({ connected: connectResult, errorMessage: errorMessage, errorCode: errorCode, callStack: callStack, connectionProfile: connection });
|
||||
resolve({ connected: connectResult, errorMessage: errorMessage, errorCode: errorCode, messageDetails: callStack, connectionProfile: connection });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user