Add prompt for enabling Trust Server Certificate (#18147)
* Adding dialog to prompt for enabling Trust Server Certificate * generated loc files * adding ability to set flag in connection string * updated loc files * comments for regex
This commit is contained in:
Родитель
5b510caf9c
Коммит
0d3180de23
|
@ -194,6 +194,11 @@
|
|||
"Location": "Location",
|
||||
"Server": "Server",
|
||||
"Database": "Database",
|
||||
"Connection Error": "Connection Error",
|
||||
"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.": "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?": "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?",
|
||||
"Read more": "Read more",
|
||||
"Enable 'Trust Server Certificate'": "Enable 'Trust Server Certificate'",
|
||||
"Query {0}: Query cost (relative to the script): {1}%/{0} is the query number{1} is the query cost": {
|
||||
"message": "Query {0}: Query cost (relative to the script): {1}%",
|
||||
"comment": [
|
||||
|
@ -363,7 +368,6 @@
|
|||
"Mandatory (True)": "Mandatory (True)",
|
||||
"Mandatory (Recommended)": "Mandatory (Recommended)",
|
||||
"Enable Trust Server Certificate": "Enable Trust Server Certificate",
|
||||
"Read more": "Read more",
|
||||
"Copy code and open webpage": "Copy code and open webpage",
|
||||
"Choose a Microsoft Entra account": "Choose a Microsoft Entra account",
|
||||
"Add a Microsoft Entra account...": "Add a Microsoft Entra account...",
|
||||
|
@ -434,7 +438,7 @@
|
|||
"Refresh Credentials": "Refresh Credentials",
|
||||
"Failed to fetch user tokens.": "Failed to fetch user tokens.",
|
||||
"Error: Login failed. Retry using different credentials?": "Error: Login failed. Retry using different credentials?",
|
||||
"Encryption was enabled on this connection, review your SSL and certificate configuration for the target SQL Server, or set 'Trust server certificate' to 'true' in the settings file. 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?": "Encryption was enabled on this connection, review your SSL and certificate configuration for the target SQL Server, or set 'Trust server certificate' to 'true' in the settings file. 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?",
|
||||
"Encryption was enabled on this connection; review your SSL and certificate configuration for the target SQL Server, or set 'Trust server certificate' to 'true' in the settings file. 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?": "Encryption was enabled on this connection; review your SSL and certificate configuration for the target SQL Server, or set 'Trust server certificate' to 'true' in the settings file. 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?",
|
||||
"Your client IP address does not have access to the server. Add a Microsoft Entra account and create a new firewall rule to enable access.": "Your client IP address does not have access to the server. Add a Microsoft Entra account and create a new firewall rule to enable access.",
|
||||
"Your client IP Address '{0}' does not have access to the server '{1}' you're attempting to connect to. Would you like to create new firewall rule?/{0} is the client IP address{1} is the server name": {
|
||||
"message": "Your client IP Address '{0}' does not have access to the server '{1}' you're attempting to connect to. Would you like to create new firewall rule?",
|
||||
|
|
|
@ -262,6 +262,9 @@
|
|||
<trans-unit id="++CODE++dba530f818587a0d79d7bb8f59e07d372d10691f49c560e3e4c3d42d105fe9e7">
|
||||
<source xml:lang="en">Connection Dialog</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="++CODE++ddb621f87c5c0baf1158d527d62ad1bf9752e53483d2540591ce3ae35e06fd6b">
|
||||
<source xml:lang="en">Connection Error</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="++CODE++52d8d284995954ca5f68adbc705bb4ff2a930cc1ff2a3885a1002ff477394eee">
|
||||
<source xml:lang="en">Connection Errors</source>
|
||||
</trans-unit>
|
||||
|
@ -378,14 +381,20 @@
|
|||
<trans-unit id="++CODE++464c4ffd019e1e9691dcf0537c797353ef2b1c1d4833d3d463e5b74ae4547344">
|
||||
<source xml:lang="en">Edit</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="++CODE++1e71b5c8f3211f1f01b27341d3ddc6a2ad651800264b495c12b50867f998662c">
|
||||
<source xml:lang="en">Enable 'Trust Server Certificate'</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="++CODE++45e33ceba31737f1cb793c231fafc9dd99074ca1f26476a70b0c830ef155c9d3">
|
||||
<source xml:lang="en">Enable Trust Server Certificate</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="++CODE++4f03bf1cdf8e7d1882e5198384139c078fa527857e7371ac6cb2d030dede15a3">
|
||||
<source xml:lang="en">Encrypt</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="++CODE++476c508b94c7f515d2276689b1eb5c8d1eb0d109b274cced59a3e1a1e3a247c9">
|
||||
<source xml:lang="en">Encryption was enabled on this connection, review your SSL and certificate configuration for the target SQL Server, or set 'Trust server certificate' to 'true' in the settings file. 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?</source>
|
||||
<trans-unit id="++CODE++ac8fee089cebcddef6529d9c8b467120173dbd02a46992ecbaf62fe25c925ae0">
|
||||
<source xml:lang="en">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.</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="++CODE++a04452986b48c7c3c21f78712b31a68f2aecb85566c134d87d55348c7b16b9a8">
|
||||
<source xml:lang="en">Encryption was enabled on this connection; review your SSL and certificate configuration for the target SQL Server, or set 'Trust server certificate' to 'true' in the settings file. 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?</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="++CODE++6051d2070e8e51a99adfa6b3f5171cfa92107943f46417bcd51a8f5e995c881f">
|
||||
<source xml:lang="en">End IP Address</source>
|
||||
|
@ -775,6 +784,9 @@
|
|||
<trans-unit id="++CODE++ba35f0c47d862763dafa955d6716942f79b8bfe1d01d5968520db6f9ba665f6f">
|
||||
<source xml:lang="en">Not started</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="++CODE++07b555a4dd9446c56aae7bbe326905f8aabc205d5eee96191a71e15510fbb53f">
|
||||
<source xml:lang="en">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?</source>
|
||||
</trans-unit>
|
||||
<trans-unit id="++CODE++6091a3057f7b1b8140c1ad2fc9232cc4d483a484667f76fe8bb305d77ca3deb1">
|
||||
<source xml:lang="en">Number of Rows Read</source>
|
||||
</trans-unit>
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export const connectionCertValidationFailedErrorCode = -2146893019;
|
|
@ -49,6 +49,7 @@ import {
|
|||
import { getErrorMessage, listAllIterator } from "../utils/utils";
|
||||
import { l10n } from "vscode";
|
||||
import { UserSurvey } from "../nps/userSurvey";
|
||||
import { connectionCertValidationFailedErrorCode } from "./connectionConstants";
|
||||
|
||||
export class ConnectionDialogWebviewController extends ReactWebviewPanelController<
|
||||
ConnectionDialogWebviewState,
|
||||
|
@ -86,6 +87,7 @@ export class ConnectionDialogWebviewController extends ReactWebviewPanelControll
|
|||
formError: "",
|
||||
loadingAzureSubscriptionsStatus: ApiStatus.NotStarted,
|
||||
loadingAzureServersStatus: ApiStatus.NotStarted,
|
||||
trustServerCertError: undefined,
|
||||
}),
|
||||
vscode.ViewColumn.Active,
|
||||
{
|
||||
|
@ -903,7 +905,16 @@ export class ConnectionDialogWebviewController extends ReactWebviewPanelControll
|
|||
this.state.connectionProfile as any,
|
||||
);
|
||||
|
||||
if (result?.errorMessage) {
|
||||
if (result.errorMessage) {
|
||||
if (
|
||||
result.errorNumber ===
|
||||
connectionCertValidationFailedErrorCode
|
||||
) {
|
||||
this.state.connectionStatus = ApiStatus.Error;
|
||||
this.state.trustServerCertError =
|
||||
result.errorMessage;
|
||||
return state;
|
||||
}
|
||||
this.state.formError = result.errorMessage;
|
||||
this.state.connectionStatus = ApiStatus.Error;
|
||||
return state;
|
||||
|
@ -965,6 +976,11 @@ export class ConnectionDialogWebviewController extends ReactWebviewPanelControll
|
|||
return state;
|
||||
});
|
||||
|
||||
this.registerReducer("cancelTrustServerCertDialog", async (state) => {
|
||||
state.trustServerCertError = undefined;
|
||||
return state;
|
||||
});
|
||||
|
||||
this.registerReducer("refreshMruConnections", async (state) => {
|
||||
state.recentConnections = await this.loadRecentConnections();
|
||||
this.updateState();
|
||||
|
|
|
@ -282,7 +282,7 @@ export let msgPromptRetryConnectionDifferentCredentials = l10n.t(
|
|||
"Error: Login failed. Retry using different credentials?",
|
||||
);
|
||||
export let msgPromptSSLCertificateValidationFailed = l10n.t(
|
||||
"Encryption was enabled on this connection, review your SSL and certificate configuration for the target SQL Server, or set 'Trust server certificate' to 'true' in the settings file. 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?",
|
||||
"Encryption was enabled on this connection; review your SSL and certificate configuration for the target SQL Server, or set 'Trust server certificate' to 'true' in the settings file. 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?",
|
||||
);
|
||||
export let msgPromptRetryFirewallRuleNotSignedIn = l10n.t(
|
||||
"Your client IP address does not have access to the server. Add a Microsoft Entra account and create a new firewall rule to enable access.",
|
||||
|
|
|
@ -151,6 +151,18 @@ export class LocConstants {
|
|||
location: l10n.t("Location"),
|
||||
server: l10n.t("Server"),
|
||||
database: l10n.t("Database"),
|
||||
connectionErrorTitle: l10n.t("Connection Error"),
|
||||
trustServerCertMessage: l10n.t(
|
||||
"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.",
|
||||
),
|
||||
trustServerCertPrompt: l10n.t(
|
||||
"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?",
|
||||
),
|
||||
readMore: l10n.t("Read more"),
|
||||
enableTrustServerCertificateButton: l10n.t(
|
||||
"Enable 'Trust Server Certificate'",
|
||||
),
|
||||
close: l10n.t("Close"),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -140,6 +140,10 @@ export function VscodeWebviewProvider<State, Reducers>({
|
|||
setState(params as State);
|
||||
});
|
||||
|
||||
function isInitialized(): boolean {
|
||||
return state !== undefined;
|
||||
}
|
||||
|
||||
return (
|
||||
<VscodeWebviewContext.Provider
|
||||
value={{
|
||||
|
@ -158,7 +162,10 @@ export function VscodeWebviewProvider<State, Reducers>({
|
|||
}}
|
||||
theme={theme}
|
||||
>
|
||||
{children}
|
||||
{
|
||||
// don't render webview unless necessary dependencies are initialized
|
||||
isInitialized() && children
|
||||
}
|
||||
</FluentProvider>
|
||||
</VscodeWebviewContext.Provider>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { useContext } from "react";
|
||||
import { ConnectionDialogContext } from "../connectionDialogStateProvider";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogBody,
|
||||
DialogContent,
|
||||
DialogSurface,
|
||||
DialogTitle,
|
||||
Link,
|
||||
MessageBar,
|
||||
} from "@fluentui/react-components";
|
||||
|
||||
import { locConstants } from "../../../common/locConstants";
|
||||
import { connectionCertValidationReadMoreUrl } from "../connectionConstants";
|
||||
import { ConnectionInputMode } from "../../../../sharedInterfaces/connectionDialog";
|
||||
|
||||
export const TrustServerCertificateDialog = ({}) => {
|
||||
const context = useContext(ConnectionDialogContext)!;
|
||||
|
||||
return (
|
||||
<Dialog open={context.state.trustServerCertError !== undefined}>
|
||||
<DialogSurface>
|
||||
<DialogBody>
|
||||
<DialogTitle>
|
||||
{locConstants.connectionDialog.connectionErrorTitle}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<MessageBar
|
||||
intent="error"
|
||||
style={{ paddingRight: "12px" }}
|
||||
>
|
||||
{context.state.trustServerCertError}
|
||||
</MessageBar>
|
||||
<br />
|
||||
{locConstants.connectionDialog.trustServerCertMessage}
|
||||
<br />
|
||||
<br />
|
||||
{locConstants.connectionDialog.trustServerCertPrompt}
|
||||
{" " /* extra space before the 'Read More' link*/}
|
||||
<Link href={connectionCertValidationReadMoreUrl}>
|
||||
{locConstants.connectionDialog.readMore}
|
||||
</Link>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
appearance="primary"
|
||||
onClick={() => {
|
||||
context.cancelTrustServerCertDialog();
|
||||
if (
|
||||
context.state.selectedInputMode ===
|
||||
ConnectionInputMode.ConnectionString
|
||||
) {
|
||||
context.formAction({
|
||||
propertyName: "connectionString",
|
||||
value: setConnectionStringProperty(
|
||||
context.state.formState
|
||||
.connectionString ?? "",
|
||||
"trustServerCertificate",
|
||||
true,
|
||||
),
|
||||
isAction: false,
|
||||
});
|
||||
} else {
|
||||
context.formAction({
|
||||
propertyName: "trustServerCertificate",
|
||||
value: true,
|
||||
isAction: false,
|
||||
});
|
||||
}
|
||||
context.connect();
|
||||
}}
|
||||
>
|
||||
{
|
||||
locConstants.connectionDialog
|
||||
.enableTrustServerCertificateButton
|
||||
}
|
||||
</Button>
|
||||
<Button
|
||||
appearance="secondary"
|
||||
onClick={() => {
|
||||
context.cancelTrustServerCertDialog();
|
||||
}}
|
||||
>
|
||||
{locConstants.connectionDialog.close}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</DialogBody>
|
||||
</DialogSurface>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
function setConnectionStringProperty(
|
||||
connectionString: string,
|
||||
propertyName: string,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
value: any,
|
||||
): string {
|
||||
const regex = new RegExp(`${propertyName}\\s*=`); // check for existence of the property
|
||||
if (regex.test(connectionString)) {
|
||||
const valueRegex = new RegExp(`${propertyName}\\s*=\\s*[^;]*`); // grab the entirety of "propertyName=value"
|
||||
return connectionString.replace(valueRegex, `${propertyName}=${value}`);
|
||||
} else {
|
||||
return `${connectionString};${propertyName}=${value}`;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export const connectionCertValidationReadMoreUrl =
|
||||
"https://learn.microsoft.com/sql/database-engine/configure-windows/enable-encrypted-connections-to-the-database-engine";
|
|
@ -64,6 +64,11 @@ const ConnectionDialogStateProvider: React.FC<
|
|||
subscriptionId: subscriptionId,
|
||||
});
|
||||
},
|
||||
cancelTrustServerCertDialog: function (): void {
|
||||
webviewState?.extensionRpc.action(
|
||||
"cancelTrustServerCertDialog",
|
||||
);
|
||||
},
|
||||
refreshMruConnections: function (): void {
|
||||
webviewState.extensionRpc.action("refreshMruConnections");
|
||||
},
|
||||
|
|
|
@ -25,6 +25,7 @@ import { FormField, useFormStyles } from "../../common/forms/form.component";
|
|||
import { FormItemSpec } from "../../common/forms/form";
|
||||
import { locConstants } from "../../common/locConstants";
|
||||
import { AzureBrowsePage } from "./azureBrowsePage";
|
||||
import { TrustServerCertificateDialog } from "./components/trustServerCertificateDialog.component";
|
||||
|
||||
function renderContent(
|
||||
connectionDialogContext: ConnectionDialogContextProps,
|
||||
|
@ -40,28 +41,24 @@ function renderContent(
|
|||
}
|
||||
|
||||
export const ConnectionInfoFormContainer = () => {
|
||||
const connectionDialogContext = useContext(ConnectionDialogContext);
|
||||
const context = useContext(ConnectionDialogContext)!;
|
||||
const formStyles = useFormStyles();
|
||||
|
||||
if (!connectionDialogContext?.state) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={formStyles.formRoot}>
|
||||
<ConnectionHeader />
|
||||
|
||||
<div className={formStyles.formDiv} style={{ overflow: "auto" }}>
|
||||
{connectionDialogContext?.state.formError && (
|
||||
{context.state.formError && (
|
||||
<MessageBar intent="error">
|
||||
{connectionDialogContext.state.formError}
|
||||
{context.state.formError}
|
||||
</MessageBar>
|
||||
)}
|
||||
<TrustServerCertificateDialog />
|
||||
<FormField
|
||||
context={connectionDialogContext}
|
||||
context={context}
|
||||
component={
|
||||
connectionDialogContext.state.connectionComponents
|
||||
.components[
|
||||
context.state.connectionComponents.components[
|
||||
"profileName"
|
||||
] as FormItemSpec<IConnectionDialogProfile>
|
||||
}
|
||||
|
@ -73,13 +70,11 @@ export const ConnectionInfoFormContainer = () => {
|
|||
<Field label="Input type" orientation="horizontal">
|
||||
<RadioGroup
|
||||
onChange={(_, data) => {
|
||||
connectionDialogContext.setConnectionInputType(
|
||||
context.setConnectionInputType(
|
||||
data.value as ConnectionInputMode,
|
||||
);
|
||||
}}
|
||||
value={
|
||||
connectionDialogContext.state.selectedInputMode
|
||||
}
|
||||
value={context.state.selectedInputMode}
|
||||
>
|
||||
<Radio
|
||||
value={ConnectionInputMode.Parameters}
|
||||
|
@ -101,7 +96,7 @@ export const ConnectionInfoFormContainer = () => {
|
|||
</RadioGroup>
|
||||
</Field>
|
||||
</div>
|
||||
{renderContent(connectionDialogContext)}
|
||||
{renderContent(context)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -44,6 +44,7 @@ export class ConnectionDialogWebviewState
|
|||
public formError: string;
|
||||
public loadingAzureSubscriptionsStatus: ApiStatus;
|
||||
public loadingAzureServersStatus: ApiStatus;
|
||||
public trustServerCertError: string | undefined;
|
||||
|
||||
constructor({
|
||||
connectionProfile,
|
||||
|
@ -56,6 +57,7 @@ export class ConnectionDialogWebviewState
|
|||
formError,
|
||||
loadingAzureSubscriptionsStatus,
|
||||
loadingAzureServersStatus,
|
||||
trustServerCertError,
|
||||
}: {
|
||||
connectionProfile: IConnectionDialogProfile;
|
||||
selectedInputMode: ConnectionInputMode;
|
||||
|
@ -78,6 +80,7 @@ export class ConnectionDialogWebviewState
|
|||
formError: string;
|
||||
loadingAzureSubscriptionsStatus: ApiStatus;
|
||||
loadingAzureServersStatus: ApiStatus;
|
||||
trustServerCertError: string | undefined;
|
||||
}) {
|
||||
this.formState = connectionProfile;
|
||||
this.selectedInputMode = selectedInputMode;
|
||||
|
@ -89,6 +92,7 @@ export class ConnectionDialogWebviewState
|
|||
this.formError = formError;
|
||||
this.loadingAzureSubscriptionsStatus = loadingAzureSubscriptionsStatus;
|
||||
this.loadingAzureServersStatus = loadingAzureServersStatus;
|
||||
this.trustServerCertError = trustServerCertError;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,6 +142,7 @@ export interface ConnectionDialogContextProps
|
|||
setConnectionInputType: (inputType: ConnectionInputMode) => void;
|
||||
connect: () => void;
|
||||
loadAzureServers: (subscriptionId: string) => void;
|
||||
cancelTrustServerCertDialog: () => void;
|
||||
refreshMruConnections: () => void;
|
||||
}
|
||||
|
||||
|
@ -161,5 +166,6 @@ export interface ConnectionDialogReducers {
|
|||
loadAzureServers: {
|
||||
subscriptionId: string;
|
||||
};
|
||||
cancelTrustServerCertDialog: {};
|
||||
refreshMruConnections: {};
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче