Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions extensions/mssql/l10n/bundle.l10n.json
Original file line number Diff line number Diff line change
Expand Up @@ -1783,6 +1783,7 @@
"Integrated": "Integrated",
"SQL Login": "SQL Login",
"Microsoft Entra Id - Universal w/ MFA Support": "Microsoft Entra Id - Universal w/ MFA Support",
"Microsoft Entra Id - Default": "Microsoft Entra Id - Default",
"Azure Code Grant": "Azure Code Grant",
"Azure Device Code": "Azure Device Code",
"MSSQL - Azure Auth Logs": "MSSQL - Azure Auth Logs",
Expand Down Expand Up @@ -2230,8 +2231,8 @@
"Clear cache and refresh token": "Clear cache and refresh token",
"Clear token cache": "Clear token cache",
"No workspaces found. Please change Fabric account or tenant to view available workspaces.": "No workspaces found. Please change Fabric account or tenant to view available workspaces.",
"Unsupported authentication type in connection string: {0}. Only SQL Login, Integrated, and Azure MFA authentication are supported./{0} is the authentication type": {
"message": "Unsupported authentication type in connection string: {0}. Only SQL Login, Integrated, and Azure MFA authentication are supported.",
"Unsupported authentication type in connection string: {0}. Only SQL Login, Integrated, Azure MFA, and Active Directory Default authentication are supported./{0} is the authentication type": {
"message": "Unsupported authentication type in connection string: {0}. Only SQL Login, Integrated, Azure MFA, and Active Directory Default authentication are supported.",
"comment": ["{0} is the authentication type"]
},
"Add Firewall Rule to {0}/{0} is the server name": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,7 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
AuthenticationType.SqlLogin,
AuthenticationType.Integrated,
AuthenticationType.AzureMFA,
AuthenticationType.ActiveDirectoryDefault,
];

if (
Expand Down Expand Up @@ -925,9 +926,24 @@ export class ConnectionDialogWebviewController extends FormWebviewController<
async updateItemVisibility() {
let hiddenProperties: (keyof IConnectionDialogProfile)[] = [];

if (
this.state.connectionProfile.authenticationType !== AuthenticationType.SqlLogin &&
this.state.connectionProfile.authenticationType !==
AuthenticationType.ActiveDirectoryDefault
) {
hiddenProperties.push("user");
}
if (this.state.connectionProfile.authenticationType !== AuthenticationType.SqlLogin) {
hiddenProperties.push("user", "password", "savePassword");
hiddenProperties.push("password", "savePassword");
}

const userComponent = this.state.formComponents["user"];
if (userComponent) {
// userId is required for SQL Login, optional for AD Default, and hidden (above) for everything else
userComponent.required =
this.state.connectionProfile.authenticationType === AuthenticationType.SqlLogin;
}

if (this.state.connectionProfile.authenticationType !== AuthenticationType.AzureMFA) {
hiddenProperties.push("accountId", "tenantId");
}
Expand Down
3 changes: 2 additions & 1 deletion extensions/mssql/src/constants/locConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ export let authTypeName = l10n.t("authenticationType");
export let authTypeIntegrated = l10n.t("Integrated");
export let authTypeSql = l10n.t("SQL Login");
export let authTypeAzureActiveDirectory = l10n.t("Microsoft Entra Id - Universal w/ MFA Support");
export let authTypeAzureActiveDirectoryDefault = l10n.t("Microsoft Entra Id - Default");
export let azureAuthTypeCodeGrant = l10n.t("Azure Code Grant");
export let azureAuthTypeDeviceCode = l10n.t("Azure Device Code");
export let azureLogChannelName = l10n.t("MSSQL - Azure Auth Logs");
Expand Down Expand Up @@ -972,7 +973,7 @@ export class ConnectionDialog {
public static unsupportedAuthType(authenticationType: string) {
return l10n.t({
message:
"Unsupported authentication type in connection string: {0}. Only SQL Login, Integrated, and Azure MFA authentication are supported.",
"Unsupported authentication type in connection string: {0}. Only SQL Login, Integrated, Azure MFA, and Active Directory Default authentication are supported.",
args: [authenticationType],
comment: ["{0} is the authentication type"],
});
Expand Down
4 changes: 3 additions & 1 deletion extensions/mssql/src/controllers/connectionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1333,6 +1333,8 @@ export default class ConnectionManager {
connectionSource: connectionSource,
},
undefined,
credentials,
undefined,
true, // include call stack
);

Expand Down Expand Up @@ -1404,7 +1406,7 @@ export default class ConnectionManager {
*/
connectionActivity.endFailed(
error,
false, // Do not include error message as it might contain sensitive info
false, // includeErrorMessage
);
return false;
}
Expand Down
26 changes: 17 additions & 9 deletions extensions/mssql/src/controllers/queryRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,12 @@ export default class QueryRunner {
const cancelQueryActivity = startActivity(
TelemetryViews.QueryEditor,
TelemetryActions.CancelQuery,
undefined,
undefined,
undefined,
true, // Include call stack
undefined, // correlationId
undefined, // startActivityAdditionalProps
undefined, // startActivityAdditionalMeasurements
undefined, // connectionInfo
undefined, // serverInfo
true, // include callstack in telemetry
);
const cancelParams: QueryCancelParams = { ownerUri: this._ownerUri };
let cancelRequestCompleted = false;
Expand Down Expand Up @@ -316,12 +318,14 @@ export default class QueryRunner {
const runStatementActivity = startActivity(
TelemetryViews.QueryEditor,
TelemetryActions.RunQuery,
undefined,
undefined, // correlationId
{
executionType: "statement",
hasExecutionPlan: executionPlanOptions ? "true" : "false",
},
undefined,
undefined, // startActivityAdditionalMeasurements
undefined, // connectionInfo
undefined, // serverInfo
true, // Include call stack
);
let runStatementRequestCompleted = false;
Expand Down Expand Up @@ -392,7 +396,9 @@ export default class QueryRunner {
executionType: queryType,
hasExecutionPlan: executionPlanOptions ? "true" : "false",
},
undefined,
undefined, // startActivityAdditionalMeasurements
undefined, // connectionInfo
undefined, // serverInfo
true, // Include call stack
);

Expand Down Expand Up @@ -640,11 +646,13 @@ export default class QueryRunner {
const rowsFetchActivity = startActivity(
TelemetryViews.QueryEditor,
TelemetryActions.GetResultRowsSubset,
undefined,
undefined,
undefined, // correlationId
undefined, // startActivityAdditionalProps
{
rowCount: bucketizeRowCount(numberOfRows),
},
undefined, // connectionInfo
undefined, // serverInfo
true, // Include call stack
);
try {
Expand Down
12 changes: 8 additions & 4 deletions extensions/mssql/src/controllers/webviewBaseController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,12 +366,14 @@ export abstract class WebviewBaseController<State, Reducers> implements vscode.D
const reducerActivity = startActivity(
TelemetryViews.WebviewController,
TelemetryActions.Reducer,
undefined,
undefined, // correlationId
{
type: action.type as string,
webviewId: this._sourceFile,
},
undefined,
undefined, // startActivityAdditionalMeasurements
undefined, // connectionInfo
undefined, // serverInfo
true, // include call stack
);
const reducer = this._reducerHandlers.get(action.type);
Expand Down Expand Up @@ -440,12 +442,14 @@ export abstract class WebviewBaseController<State, Reducers> implements vscode.D
const handlerActivity = startActivity(
TelemetryViews.WebviewController,
TelemetryActions.OnRequest,
undefined,
undefined, // correlationId
{
type: type.method,
webviewId: this._sourceFile,
},
undefined,
undefined, // startActivityAdditionalMeasurements
undefined, // connectionInfo
undefined, // serverInfo
true, // include call stack
);
try {
Expand Down
4 changes: 4 additions & 0 deletions extensions/mssql/src/models/connectionCredentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ export class ConnectionCredentials implements IConnectionInfo {
name: LocalizedConstants.authTypeAzureActiveDirectory,
value: utils.authTypeToString(AuthenticationTypes.AzureMFA),
},
{
name: LocalizedConstants.authTypeAzureActiveDirectoryDefault,
value: utils.authTypeToString(AuthenticationTypes.ActiveDirectoryDefault),
},
];

return choices;
Expand Down
4 changes: 3 additions & 1 deletion extensions/mssql/src/models/connectionProfile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ export class ConnectionProfile extends ConnectionCredentials implements IConnect
if (this.authenticationType) {
if (
this.authenticationType === AuthenticationTypes[AuthenticationTypes.Integrated] ||
this.authenticationType === AuthenticationTypes[AuthenticationTypes.AzureMFA]
this.authenticationType === AuthenticationTypes[AuthenticationTypes.AzureMFA] ||
this.authenticationType ===
AuthenticationTypes[AuthenticationTypes.ActiveDirectoryDefault]
) {
return utils.isNotEmpty(this.server);
} else {
Expand Down
1 change: 1 addition & 0 deletions extensions/mssql/src/models/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export enum AuthenticationTypes {
Integrated = 1,
SqlLogin = 2,
AzureMFA = 3,
ActiveDirectoryDefault = 4,
}

export enum EncryptOptions {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,7 @@ export class ObjectExplorerService {
);
if (choice === LocalizedConstants.ObjectExplorer.FailedOEConnectionErrorSignIn) {
try {
await VsCodeAzureHelper.signIn(); // User chose to sign in to the missing account; try again.
await VsCodeAzureHelper.signIn(true); // User chose to sign in to the missing account; try again.
return await prepareConnectionProfile();
} catch (retryError) {
this._logger.error(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,11 @@ export class SchemaDesignerWebviewController extends WebviewPanelController<
const schemaDesignerInitActivity = startActivity(
TelemetryViews.SchemaDesigner,
TelemetryActions.Initialize,
undefined,
undefined,
undefined,
undefined, // correlationId
undefined, // startActivityAdditionalProps
undefined, // startActivityAdditionalMeasurements
undefined, // connectionInfo
undefined, // serverInfo
true, // include callstack in telemetry
);
try {
Expand Down
4 changes: 4 additions & 0 deletions extensions/mssql/src/sharedInterfaces/connectionDialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,10 @@ export enum AuthenticationType {
* Microsoft Entra Id - Universal with MFA support
*/
AzureMFA = "AzureMFA",
/**
* Microsoft Entra Id - Default
*/
ActiveDirectoryDefault = "ActiveDirectoryDefault",
/**
* Microsoft Entra Id - Password
*/
Expand Down
4 changes: 2 additions & 2 deletions extensions/mssql/src/sharedInterfaces/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ export type FinishActivity = (
activityStatus: Exclude<ActivityStatus, ActivityStatus.Failed>,
additionalProperties?: Record<string, string>,
additionalMeasurements?: Record<string, number>,
connectionProfile?: any, //TODO fix any with IConnectionProfile
connectionProfile?: vscodeMssql.IConnectionInfo,
serverInfo?: vscodeMssql.IServerInfo,
) => void;

Expand All @@ -310,7 +310,7 @@ export type FinishActivityFailed = (
export type UpdateActivity = (
additionalProperties?: Record<string, string>,
additionalMeasurements?: Record<string, number>,
connectionProfile?: any, //TODO fix any with IConnectionProfile
connectionProfile?: vscodeMssql.IConnectionInfo,
serverInfo?: vscodeMssql.IServerInfo,
) => void;

Expand Down
6 changes: 5 additions & 1 deletion extensions/mssql/src/telemetry/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export function sendActionEvent(
telemetryAction: TelemetryActions,
additionalProps: TelemetryEventProperties | { [key: string]: string } = {},
additionalMeasurements: TelemetryEventMeasures | { [key: string]: number } = {},
connectionInfo?: IConnectionProfile,
connectionInfo?: vscodeMssql.IConnectionInfo,
serverInfo?: vscodeMssql.IServerInfo,
includeCallStack: boolean = false,
): void {
Expand Down Expand Up @@ -188,6 +188,8 @@ export function startActivity(
correlationId?: string,
startActivityAdditionalProps: TelemetryEventProperties = {},
startActivityAdditionalMeasurements: TelemetryEventMeasures = {},
connectionInfo?: vscodeMssql.IConnectionInfo,
serverInfo?: vscodeMssql.IServerInfo,
includeCallStack: boolean = false,
): ActivityObject {
const startTime = performance.now();
Expand All @@ -209,6 +211,8 @@ export function startActivity(
...startActivityAdditionalMeasurements,
startTime: Math.round(startTime),
},
connectionInfo,
serverInfo,
);

const activityUpdateAdditionalPropsBase: TelemetryEventProperties = {
Expand Down
15 changes: 15 additions & 0 deletions extensions/mssql/test/unit/connectionCredentials.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,5 +124,20 @@ suite("ConnectionCredentials Tests", () => {
).to.equal(originalConnInfo[key as keyof IConnectionInfo]);
}
});

test("createConnectionInfo preserves ActiveDirectoryDefault auth type", () => {
const connDetails: ConnectionDetails = {
options: {
server: "someServer",
authenticationType:
AuthenticationTypes[AuthenticationTypes.ActiveDirectoryDefault],
},
};

const connInfo = ConnectionCredentials.createConnectionInfo(connDetails);
expect(connInfo.authenticationType).to.equal(
AuthenticationTypes[AuthenticationTypes.ActiveDirectoryDefault],
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,19 @@ suite("ConnectionDialogWebviewController Tests", () => {
expect(controller.state.isEditingConnection).to.be.true;
expect(controller.state.editingConnectionDisplayName).to.not.be.undefined;
});

test("should show optional user and hide password fields for ActiveDirectoryDefault", async () => {
controller.state.connectionProfile.authenticationType =
AuthenticationType.ActiveDirectoryDefault;

await controller.updateItemVisibility();

expect(controller.state.formComponents.user.hidden).to.not.be.true;
expect(controller.state.formComponents.password.hidden).to.be.true;
expect(controller.state.formComponents.savePassword.hidden).to.be.true;
expect(controller.state.formComponents.accountId.hidden).to.be.true;
expect(controller.state.formComponents.tenantId.hidden).to.be.true;
});
});

suite("Reducers", () => {
Expand Down Expand Up @@ -920,6 +933,25 @@ suite("ConnectionDialogWebviewController Tests", () => {
expect(controller.state.dialog, "dialog should be closed").to.be.undefined;
});

test("should load connection details from connection string with ActiveDirectoryDefault", async () => {
const parsedDetails = {
options: {
server: "myServer",
database: "myDB",
authenticationType: AuthenticationType.ActiveDirectoryDefault,
},
} as ConnectionDetails;

await runConnectionStringScenario(parsedDetails);

expect(controller.state.connectionProfile.server).to.equal("myServer");
expect(controller.state.connectionProfile.database).to.equal("myDB");
expect(controller.state.connectionProfile.authenticationType).to.equal(
AuthenticationType.ActiveDirectoryDefault,
);
expect(controller.state.dialog, "dialog should be closed").to.be.undefined;
});

test("should display error message if connection string has unsupported authentication type", async () => {
const parsedDetails = {
options: {
Expand Down
10 changes: 10 additions & 0 deletions extensions/mssql/test/unit/connectionProfile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import * as sinon from "sinon";
import { IConnectionInfo } from "vscode-mssql";
import { ConnectionCredentials } from "../../src/models/connectionCredentials";
import { ConnectionProfile } from "../../src/models/connectionProfile";
import { AuthenticationTypes } from "../../src/models/interfaces";
import { expect } from "chai";

Expand Down Expand Up @@ -115,4 +116,13 @@ suite("Connection Profile tests", () => {
expect(details.options["user"]).to.not.be.undefined;
expect(details.options["workstationId"]).to.not.be.undefined;
});

test("ActiveDirectoryDefault profile only requires server", () => {
const profile = new ConnectionProfile();
profile.server = "my-server";
profile.authenticationType =
AuthenticationTypes[AuthenticationTypes.ActiveDirectoryDefault];

expect(profile.isValidProfile()).to.be.true;
});
});
1 change: 1 addition & 0 deletions extensions/mssql/test/unit/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export function buildCapabilitiesResult(): CapabilitiesResult {
AuthenticationType.SqlLogin,
AuthenticationType.Integrated,
AuthenticationType.AzureMFA,
AuthenticationType.ActiveDirectoryDefault,
],
},
{
Expand Down
Loading
Loading