diff --git a/src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.tsx b/src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.tsx index 8ab643e3a..25ed4ea4f 100644 --- a/src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.tsx +++ b/src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.tsx @@ -19,10 +19,16 @@ import { AuthType } from "../../../AuthType"; import * as Constants from "../../../Common/Constants"; import { Platform, configContext } from "../../../ConfigContext"; import * as ViewModels from "../../../Contracts/ViewModels"; -import { userContext } from "../../../UserContext"; +import { + userContext, + isVCoreMongoNativeAuthDisabled, + VCoreMongoNativeAuthDisabledMessage, + VCoreMongoNativeAuthLearnMoreUrl, +} from "../../../UserContext"; import { isRunningOnNationalCloud } from "../../../Utils/CloudUtils"; import { useSidePanel } from "../../../hooks/useSidePanel"; import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent"; +import { useDialog } from "../../Controls/Dialog"; import Explorer from "../../Explorer"; import { useNotebook } from "../../Notebook/useNotebook"; import { BrowseQueriesPane } from "../../Panes/BrowseQueriesPane/BrowseQueriesPane"; @@ -499,12 +505,21 @@ function createOpenTerminalButtonByKind( const label = `Open ${terminalFriendlyName()} shell`; const tooltip = "This feature is not yet available in your account's region. View supported regions here: https://aka.ms/cosmos-enable-notebooks."; + const isNativeAuthDisabled = terminalKind === ViewModels.TerminalKind.VCoreMongo && isVCoreMongoNativeAuthDisabled(); const disableButton = - !useNotebook.getState().isNotebooksEnabledForAccount && !useNotebook.getState().isNotebookEnabled; + (!useNotebook.getState().isNotebooksEnabledForAccount && !useNotebook.getState().isNotebookEnabled) || + isNativeAuthDisabled; return { iconSrc: HostedTerminalIcon, iconAlt: label, onCommandClick: () => { + if (isNativeAuthDisabled) { + useDialog.getState().showOkModalDialog("Native Authentication Disabled", VCoreMongoNativeAuthDisabledMessage, { + linkText: "Learn more", + linkUrl: VCoreMongoNativeAuthLearnMoreUrl, + }); + return; + } if (useNotebook.getState().isNotebookEnabled || userContext.features.enableCloudShell) { container.openNotebookTerminal(terminalKind); } @@ -513,7 +528,7 @@ function createOpenTerminalButtonByKind( hasPopup: false, disabled: disableButton, ariaLabel: label, - tooltipText: !disableButton ? "" : tooltip, + tooltipText: isNativeAuthDisabled ? VCoreMongoNativeAuthDisabledMessage : !disableButton ? "" : tooltip, }; } diff --git a/src/Explorer/SplashScreen/SplashScreen.tsx b/src/Explorer/SplashScreen/SplashScreen.tsx index 8d7749f79..aeb599f67 100644 --- a/src/Explorer/SplashScreen/SplashScreen.tsx +++ b/src/Explorer/SplashScreen/SplashScreen.tsx @@ -33,8 +33,14 @@ import QuickStartIcon from "../../../images/Quickstart_Lightning.svg"; import VisualStudioIcon from "../../../images/VisualStudio.svg"; import CollectionIcon from "../../../images/tree-collection.svg"; import * as Constants from "../../Common/Constants"; -import { userContext } from "../../UserContext"; +import { + isVCoreMongoNativeAuthDisabled, + userContext, + VCoreMongoNativeAuthDisabledMessage, + VCoreMongoNativeAuthLearnMoreUrl, +} from "../../UserContext"; import { getCollectionName } from "../../Utils/APITypeUtils"; +import { useDialog } from "../Controls/Dialog"; import Explorer from "../Explorer"; import * as MostRecentActivity from "../MostRecentActivity/MostRecentActivity"; import { useNotebook } from "../Notebook/useNotebook"; @@ -413,11 +419,23 @@ export const SplashScreen: React.FC = ({ explorer }) => { } if (userContext.apiType === "VCoreMongo") { + const isNativeAuthDisabled = isVCoreMongoNativeAuthDisabled(); return { iconSrc: PowerShellIcon, title: t(Keys.splashScreen.shell.vcoreMongo.title), description: t(Keys.splashScreen.shell.vcoreMongo.description), - onClick: () => container.openNotebookTerminal(TerminalKind.VCoreMongo), + onClick: () => { + if (isNativeAuthDisabled) { + useDialog + .getState() + .showOkModalDialog("Native Authentication Disabled", VCoreMongoNativeAuthDisabledMessage, { + linkText: "Learn more", + linkUrl: VCoreMongoNativeAuthLearnMoreUrl, + }); + } else { + container.openNotebookTerminal(TerminalKind.VCoreMongo); + } + }, }; } diff --git a/src/Explorer/Tabs/VCoreMongoQuickstartTab.tsx b/src/Explorer/Tabs/VCoreMongoQuickstartTab.tsx index 6cbcb856a..72c38e15b 100644 --- a/src/Explorer/Tabs/VCoreMongoQuickstartTab.tsx +++ b/src/Explorer/Tabs/VCoreMongoQuickstartTab.tsx @@ -1,24 +1,44 @@ -import { Stack } from "@fluentui/react"; +import { Link, MessageBar, MessageBarType, Stack, Text } from "@fluentui/react"; import { TerminalKind } from "Contracts/ViewModels"; import { VcoreMongoQuickstartGuide } from "Explorer/Quickstart/VCoreMongoQuickstartGuide"; import { CloudShellTerminalComponent } from "Explorer/Tabs/CloudShellTab/CloudShellTerminalComponent"; -import { userContext } from "UserContext"; +import { + isVCoreMongoNativeAuthDisabled, + userContext, + VCoreMongoNativeAuthDisabledMessage, + VCoreMongoNativeAuthLearnMoreUrl, +} from "UserContext"; import React from "react"; export const VcoreMongoQuickstartTab: React.FC = (): JSX.Element => { + const isNativeAuthDisabled = isVCoreMongoNativeAuthDisabled(); + return ( - + {isNativeAuthDisabled ? ( + + + + {VCoreMongoNativeAuthDisabledMessage}{" "} + + Learn more + + + + + ) : ( + + )} ); diff --git a/src/Platform/Hosted/extractFeatures.ts b/src/Platform/Hosted/extractFeatures.ts index ee1855818..88aaac1ca 100644 --- a/src/Platform/Hosted/extractFeatures.ts +++ b/src/Platform/Hosted/extractFeatures.ts @@ -36,6 +36,7 @@ export type Features = { readonly enableContainerCopy: boolean; readonly enableCloudShell: boolean; readonly enableRestoreContainer: boolean; // only for Fabric + readonly mongoDisableNativeAuth: boolean; // can be set via both flight and feature flag autoscaleDefault: boolean; @@ -103,6 +104,7 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear enableContainerCopy: "true" === get("enablecontainercopy"), enableRestoreContainer: "true" === get("enablerestorecontainer"), enableCloudShell: true, + mongoDisableNativeAuth: "true" === get("mongodisablenativeauth"), }; } diff --git a/src/UserContext.ts b/src/UserContext.ts index 5c83341fd..036ed322e 100644 --- a/src/UserContext.ts +++ b/src/UserContext.ts @@ -42,9 +42,37 @@ export interface PostgresConnectionStrParams { isFreeTier: boolean; } +export type VCoreMongoAuthMode = "NativeAuth" | "MicrosoftEntraID"; + +export interface VCoreMongoAuthConfig { + allowedModes?: VCoreMongoAuthMode[]; +} + export interface VCoreMongoConnectionParams { adminLogin: string; connectionString: string; + authConfig?: VCoreMongoAuthConfig; + isNativeAuthDisabled?: boolean; +} + +export const VCoreMongoNativeAuthLearnMoreUrl = "https://go.microsoft.com/fwlink/?linkid=2340100"; + +export const VCoreMongoNativeAuthDisabledMessage = + "Native DocumentDB authentication is disabled on this cluster. You can use MongoDB Shell with Entra ID authentication outside of the Azure portal."; + +export function isVCoreMongoNativeAuthDisabled(): boolean { + if (userContext.features?.mongoDisableNativeAuth) { + return true; + } + const params = userContext.vcoreMongoConnectionParams; + if (!params) { + return false; + } + if (params.isNativeAuthDisabled) { + return true; + } + const allowedModes = params.authConfig?.allowedModes || []; + return allowedModes.length > 0 && !allowedModes.includes("NativeAuth"); } export interface FabricArtifactInfo { diff --git a/src/Utils/AuthorizationUtils.test.ts b/src/Utils/AuthorizationUtils.test.ts index 6eb5f761f..68d448ba7 100644 --- a/src/Utils/AuthorizationUtils.test.ts +++ b/src/Utils/AuthorizationUtils.test.ts @@ -48,6 +48,7 @@ describe("AuthorizationUtils", () => { partitionKeyDefault2: false, notebooksDownBanner: false, enableRestoreContainer: false, + mongoDisableNativeAuth: false, }, }); };