Refactor logic for determining if we should use data plane RBAC (#2180)

* Refactor logic for determining if we should use data plane RBAC to a
common function.

* Move test function into test scope.
This commit is contained in:
jawelton74 2025-07-08 11:41:43 -07:00 committed by GitHub
parent e0edaf405c
commit f370507a27
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 90 additions and 5 deletions

View File

@ -4,12 +4,12 @@ import { CosmosDbArtifactType } from "Contracts/FabricMessagesContract";
import { AuthorizationToken } from "Contracts/FabricMessageTypes"; import { AuthorizationToken } from "Contracts/FabricMessageTypes";
import { checkDatabaseResourceTokensValidity, isFabricMirroredKey } from "Platform/Fabric/FabricUtil"; import { checkDatabaseResourceTokensValidity, isFabricMirroredKey } from "Platform/Fabric/FabricUtil";
import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility"; import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
import { useDataplaneRbacAuthorization } from "Utils/AuthorizationUtils";
import { AuthType } from "../AuthType"; import { AuthType } from "../AuthType";
import { PriorityLevel } from "../Common/Constants"; import { PriorityLevel } from "../Common/Constants";
import * as Logger from "../Common/Logger"; import * as Logger from "../Common/Logger";
import { Platform, configContext } from "../ConfigContext"; import { Platform, configContext } from "../ConfigContext";
import { FabricArtifactInfo, updateUserContext, userContext } from "../UserContext"; import { FabricArtifactInfo, updateUserContext, userContext } from "../UserContext";
import { isDataplaneRbacSupported } from "../Utils/APITypeUtils";
import { logConsoleError } from "../Utils/NotificationConsoleUtils"; import { logConsoleError } from "../Utils/NotificationConsoleUtils";
import * as PriorityBasedExecutionUtils from "../Utils/PriorityBasedExecutionUtils"; import * as PriorityBasedExecutionUtils from "../Utils/PriorityBasedExecutionUtils";
import { EmulatorMasterKey, HttpHeaders } from "./Constants"; import { EmulatorMasterKey, HttpHeaders } from "./Constants";
@ -20,8 +20,7 @@ const _global = typeof self === "undefined" ? window : self;
export const tokenProvider = async (requestInfo: Cosmos.RequestInfo) => { export const tokenProvider = async (requestInfo: Cosmos.RequestInfo) => {
const { verb, resourceId, resourceType, headers } = requestInfo; const { verb, resourceId, resourceType, headers } = requestInfo;
const dataPlaneRBACOptionEnabled = userContext.dataPlaneRbacEnabled && isDataplaneRbacSupported(userContext.apiType); if (useDataplaneRbacAuthorization(userContext)) {
if (userContext.features.enableAadDataPlane || dataPlaneRBACOptionEnabled) {
Logger.logInfo( Logger.logInfo(
`AAD Data Plane Feature flag set to ${userContext.features.enableAadDataPlane} for account with disable local auth ${userContext.databaseAccount.properties.disableLocalAuth} `, `AAD Data Plane Feature flag set to ${userContext.features.enableAadDataPlane} for account with disable local auth ${userContext.databaseAccount.properties.disableLocalAuth} `,
"Explorer/tokenProvider", "Explorer/tokenProvider",

View File

@ -1,10 +1,51 @@
import { AuthType } from "../AuthType"; import { AuthType } from "../AuthType";
import * as Constants from "../Common/Constants"; import * as Constants from "../Common/Constants";
import { updateUserContext } from "../UserContext"; import { ApiType, updateUserContext, userContext } from "../UserContext";
import * as AuthorizationUtils from "./AuthorizationUtils"; import * as AuthorizationUtils from "./AuthorizationUtils";
jest.mock("../Explorer/Explorer"); jest.mock("../Explorer/Explorer");
describe("AuthorizationUtils", () => { describe("AuthorizationUtils", () => {
const setAadDataPlane = (enabled: boolean) => {
updateUserContext({
features: {
enableAadDataPlane: enabled,
canExceedMaximumValue: false,
cosmosdb: false,
enableChangeFeedPolicy: false,
enableFixedCollectionWithSharedThroughput: false,
enableKOPanel: false,
enableNotebooks: false,
enableReactPane: false,
enableRightPanelV2: false,
enableSchema: false,
enableSDKoperations: false,
enableSpark: false,
enableTtl: false,
executeSproc: false,
enableResourceGraph: false,
enableKoResourceTree: false,
enableThroughputBuckets: false,
hostedDataExplorer: false,
sandboxNotebookOutputs: false,
showMinRUSurvey: false,
ttl90Days: false,
enableThroughputCap: false,
enableHierarchicalKeys: false,
enableCopilot: false,
disableCopilotPhoenixGateaway: false,
enableCopilotFullSchema: false,
copilotChatFixedMonacoEditorHeight: false,
enablePriorityBasedExecution: false,
disableConnectionStringLogin: false,
enableCloudShell: false,
autoscaleDefault: false,
partitionKeyDefault: false,
partitionKeyDefault2: false,
notebooksDownBanner: false,
},
});
};
describe("getAuthorizationHeader()", () => { describe("getAuthorizationHeader()", () => {
it("should return authorization header if authentication type is AAD", () => { it("should return authorization header if authentication type is AAD", () => {
updateUserContext({ updateUserContext({
@ -54,4 +95,41 @@ describe("AuthorizationUtils", () => {
).toBeDefined(); ).toBeDefined();
}); });
}); });
describe("useDataplaneRbacAuthorization()", () => {
it("should return true if enableAadDataPlane feature flag is set", () => {
setAadDataPlane(true);
expect(AuthorizationUtils.useDataplaneRbacAuthorization(userContext)).toBe(true);
});
it("should return true if dataPlaneRbacEnabled is set to true and API supports RBAC", () => {
setAadDataPlane(false);
["SQL", "Tables"].forEach((type) => {
updateUserContext({
dataPlaneRbacEnabled: true,
apiType: type as ApiType,
});
expect(AuthorizationUtils.useDataplaneRbacAuthorization(userContext)).toBe(true);
});
});
it("should return false if dataPlaneRbacEnabled is set to true and API does not support RBAC", () => {
setAadDataPlane(false);
["Mongo", "Gremlin", "Cassandra", "Postgres", "VCoreMongo"].forEach((type) => {
updateUserContext({
dataPlaneRbacEnabled: true,
apiType: type as ApiType,
});
expect(AuthorizationUtils.useDataplaneRbacAuthorization(userContext)).toBe(false);
});
});
it("should return false if dataPlaneRbacEnabled is set to false", () => {
setAadDataPlane(false);
updateUserContext({
dataPlaneRbacEnabled: false,
});
expect(AuthorizationUtils.useDataplaneRbacAuthorization(userContext)).toBe(false);
});
});
}); });

View File

@ -1,5 +1,6 @@
import * as msal from "@azure/msal-browser"; import * as msal from "@azure/msal-browser";
import { Action, ActionModifiers } from "Shared/Telemetry/TelemetryConstants"; import { Action, ActionModifiers } from "Shared/Telemetry/TelemetryConstants";
import { isDataplaneRbacSupported } from "Utils/APITypeUtils";
import { AuthType } from "../AuthType"; import { AuthType } from "../AuthType";
import * as Constants from "../Common/Constants"; import * as Constants from "../Common/Constants";
import * as Logger from "../Common/Logger"; import * as Logger from "../Common/Logger";
@ -7,7 +8,7 @@ import { configContext } from "../ConfigContext";
import { DatabaseAccount } from "../Contracts/DataModels"; import { DatabaseAccount } from "../Contracts/DataModels";
import * as ViewModels from "../Contracts/ViewModels"; import * as ViewModels from "../Contracts/ViewModels";
import { trace, traceFailure } from "../Shared/Telemetry/TelemetryProcessor"; import { trace, traceFailure } from "../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../UserContext"; import { UserContext, userContext } from "../UserContext";
export function getAuthorizationHeader(): ViewModels.AuthorizationTokenHeaderMetadata { export function getAuthorizationHeader(): ViewModels.AuthorizationTokenHeaderMetadata {
if (userContext.authType === AuthType.EncryptedToken) { if (userContext.authType === AuthType.EncryptedToken) {
@ -179,3 +180,10 @@ export async function acquireTokenWithMsal(
} }
} }
} }
export function useDataplaneRbacAuthorization(userContext: UserContext): boolean {
return (
userContext.features.enableAadDataPlane ||
(userContext.dataPlaneRbacEnabled && isDataplaneRbacSupported(userContext.apiType))
);
}