From 40283ff7f174ab83b7df5446afdd881a07c186bc Mon Sep 17 00:00:00 2001 From: Senthamil Sindhu Date: Fri, 19 Jul 2024 07:28:39 -0700 Subject: [PATCH 1/5] Add readOnlyKeys call for accounts with Reader role --- .../Panes/SettingsPane/SettingsPane.tsx | 31 +++++++++++----- src/hooks/useKnockoutExplorer.ts | 37 +++++++++++-------- 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/src/Explorer/Panes/SettingsPane/SettingsPane.tsx b/src/Explorer/Panes/SettingsPane/SettingsPane.tsx index bb1435077..216deda25 100644 --- a/src/Explorer/Panes/SettingsPane/SettingsPane.tsx +++ b/src/Explorer/Panes/SettingsPane/SettingsPane.tsx @@ -27,7 +27,7 @@ import { } from "Shared/StorageUtility"; import * as StringUtility from "Shared/StringUtility"; import { updateUserContext, userContext } from "UserContext"; -import { logConsoleInfo } from "Utils/NotificationConsoleUtils"; +import { logConsoleError, logConsoleInfo } from "Utils/NotificationConsoleUtils"; import * as PriorityBasedExecutionUtils from "Utils/PriorityBasedExecutionUtils"; import { useQueryCopilot } from "hooks/useQueryCopilot"; import { useSidePanel } from "hooks/useSidePanel"; @@ -36,8 +36,7 @@ import Explorer from "../../Explorer"; import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm"; import { AuthType } from "AuthType"; import create, { UseStore } from "zustand"; -import { DatabaseAccountListKeysResult } from "@azure/arm-cosmosdb/esm/models"; -import { listKeys } from "Utils/arm/generatedClients/cosmos/databaseAccounts"; +import { getReadOnlyKeys, listKeys } from "Utils/arm/generatedClients/cosmos/databaseAccounts"; export interface DataPlaneRbacState { dataPlaneRbacEnabled: boolean; @@ -171,14 +170,26 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({ hasDataPlaneRbacSettingChanged: true, }); const { databaseAccount: account, subscriptionId, resourceGroup } = userContext; - if (!userContext.features.enableAadDataPlane) { - const keys: DatabaseAccountListKeysResult = await listKeys(subscriptionId, resourceGroup, account.name); - - if (keys.primaryMasterKey) { - updateUserContext({ masterKey: keys.primaryMasterKey }); - - useDataPlaneRbac.setState({ dataPlaneRbacEnabled: false }); + if (!userContext.features.enableAadDataPlane && !userContext.masterKey) { + let keys; + try { + keys = await listKeys(subscriptionId, resourceGroup, account.name); + updateUserContext({ + masterKey: keys.primaryMasterKey, + }); + } catch (error) { + // if listKeys fail because of permissions issue, then make call to get ReadOnlyKeys + if (error.code === "AuthorizationFailed") { + keys = await getReadOnlyKeys(subscriptionId, resourceGroup, account.name); + updateUserContext({ + masterKey: keys.primaryReadonlyMasterKey, + }); + } else { + logConsoleError(`Error occurred fetching keys for the account." ${error.message}`); + throw error; + } } + useDataPlaneRbac.setState({ dataPlaneRbacEnabled: false }); } } diff --git a/src/hooks/useKnockoutExplorer.ts b/src/hooks/useKnockoutExplorer.ts index 22cc0b51d..fa4e5ca7f 100644 --- a/src/hooks/useKnockoutExplorer.ts +++ b/src/hooks/useKnockoutExplorer.ts @@ -40,7 +40,7 @@ import { DefaultExperienceUtility } from "../Shared/DefaultExperienceUtility"; import { Node, PortalEnv, updateUserContext, userContext } from "../UserContext"; import { acquireTokenWithMsal, getAuthorizationHeader, getMsalInstance } from "../Utils/AuthorizationUtils"; import { isInvalidParentFrameOrigin, shouldProcessMessage } from "../Utils/MessageValidation"; -import { listKeys } from "../Utils/arm/generatedClients/cosmos/databaseAccounts"; +import { getReadOnlyKeys, listKeys } from "../Utils/arm/generatedClients/cosmos/databaseAccounts"; import { applyExplorerBindings } from "../applyExplorerBindings"; import { useDataPlaneRbac } from "Explorer/Panes/SettingsPane/SettingsPane"; import * as Logger from "../Common/Logger"; @@ -465,26 +465,33 @@ function configureEmulator(): Explorer { return explorer; } -async function fetchAndUpdateKeys(subscriptionId: string, resourceGroup: string, account: string) { +export async function fetchAndUpdateKeys(subscriptionId: string, resourceGroup: string, account: string) { + Logger.logInfo(`Fetching keys for ${userContext.apiType} account ${account}`, "Explorer/fetchAndUpdateKeys"); + let keys; try { - Logger.logInfo(`Fetching keys for ${userContext.apiType} account ${account}`, "Explorer/fetchAndUpdateKeys"); - const keys = await listKeys(subscriptionId, resourceGroup, account); + keys = await listKeys(subscriptionId, resourceGroup, account); Logger.logInfo(`Keys fetched for ${userContext.apiType} account ${account}`, "Explorer/fetchAndUpdateKeys"); - updateUserContext({ masterKey: keys.primaryMasterKey, }); - Logger.logInfo( - `User context updated with Master key for ${userContext.apiType} account ${account}`, - "Explorer/fetchAndUpdateKeys", - ); } catch (error) { - console.error("Error during fetching keys or updating user context:", error); - Logger.logError( - `Error during fetching keys or updating user context: ${error} for ${userContext.apiType} account ${account}`, - "Explorer/fetchAndUpdateKeys", - ); - throw error; + if (error.code === "AuthorizationFailed") { + keys = await getReadOnlyKeys(subscriptionId, resourceGroup, account); + Logger.logInfo( + `Read only Keys fetched for ${userContext.apiType} account ${account}`, + "Explorer/fetchAndUpdateKeys", + ); + updateUserContext({ + masterKey: keys.primaryReadonlyMasterKey, + }); + } else { + logConsoleError(`Error occurred fetching keys for the account." ${error.message}`); + Logger.logError( + `Error during fetching keys or updating user context: ${error} for ${userContext.apiType} account ${account}`, + "Explorer/fetchAndUpdateKeys", + ); + throw error; + } } } From 521ff39eb00df1e3475d09c1b776fc55ae475edd Mon Sep 17 00:00:00 2001 From: Senthamil Sindhu Date: Fri, 19 Jul 2024 07:48:12 -0700 Subject: [PATCH 2/5] Resolve conflicts --- src/hooks/useKnockoutExplorer.ts | 34 ++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/hooks/useKnockoutExplorer.ts b/src/hooks/useKnockoutExplorer.ts index e261dfbf5..fcf1d314e 100644 --- a/src/hooks/useKnockoutExplorer.ts +++ b/src/hooks/useKnockoutExplorer.ts @@ -453,25 +453,33 @@ function configureEmulator(): Explorer { return explorer; } -async function fetchAndUpdateKeys(subscriptionId: string, resourceGroup: string, account: string) { +export async function fetchAndUpdateKeys(subscriptionId: string, resourceGroup: string, account: string) { + Logger.logInfo(`Fetching keys for ${userContext.apiType} account ${account}`, "Explorer/fetchAndUpdateKeys"); + let keys; try { - Logger.logInfo(`Fetching keys for ${userContext.apiType} account ${account}`, "Explorer/fetchAndUpdateKeys"); - const keys = await listKeys(subscriptionId, resourceGroup, account); + keys = await listKeys(subscriptionId, resourceGroup, account); Logger.logInfo(`Keys fetched for ${userContext.apiType} account ${account}`, "Explorer/fetchAndUpdateKeys"); updateUserContext({ masterKey: keys.primaryMasterKey, }); - Logger.logInfo( - `User context updated with Master key for ${userContext.apiType} account ${account}`, - "Explorer/fetchAndUpdateKeys", - ); } catch (error) { - logConsoleError(`Error occurred fetching keys for the account." ${error.message}`); - Logger.logError( - `Error during fetching keys or updating user context: ${error} for ${userContext.apiType} account ${account}`, - "Explorer/fetchAndUpdateKeys", - ); - throw error; + if (error.code === "AuthorizationFailed") { + keys = await getReadOnlyKeys(subscriptionId, resourceGroup, account); + Logger.logInfo( + `Read only Keys fetched for ${userContext.apiType} account ${account}`, + "Explorer/fetchAndUpdateKeys", + ); + updateUserContext({ + masterKey: keys.primaryReadonlyMasterKey, + }); + } else { + logConsoleError(`Error occurred fetching keys for the account." ${error.message}`); + Logger.logError( + `Error during fetching keys or updating user context: ${error} for ${userContext.apiType} account ${account}`, + "Explorer/fetchAndUpdateKeys", + ); + throw error; + } } } From 3b86a9477fe8257e5b9483eff2c848f05e321776 Mon Sep 17 00:00:00 2001 From: Senthamil Sindhu Date: Tue, 23 Jul 2024 11:14:19 -0700 Subject: [PATCH 3/5] Add code for arm token refresh --- src/hooks/useDatabaseAccounts.tsx | 66 ++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/src/hooks/useDatabaseAccounts.tsx b/src/hooks/useDatabaseAccounts.tsx index f517b2e30..4cdb36bca 100644 --- a/src/hooks/useDatabaseAccounts.tsx +++ b/src/hooks/useDatabaseAccounts.tsx @@ -3,6 +3,8 @@ import { QueryRequestOptions, QueryResponse } from "Contracts/AzureResourceGraph import useSWR from "swr"; import { configContext } from "../ConfigContext"; import { DatabaseAccount } from "../Contracts/DataModels"; +import { acquireTokenWithMsal, getMsalInstance } from "Utils/AuthorizationUtils"; +import React from "react"; /* eslint-disable @typescript-eslint/no-explicit-any */ interface AccountListResult { @@ -72,14 +74,24 @@ export async function fetchDatabaseAccountsFromGraph( }); if (!response.ok) { - throw new Error(await response.text()); - } + // throw new Error(await response.text()); + // } const queryResponse: QueryResponse = (await response.json()) as QueryResponse; skipToken = queryResponse.$skipToken; queryResponse.data?.map((databaseAccount: any) => { databaseAccounts.push(databaseAccount as DatabaseAccount); }); + } else { + try{ + console.log("Token expired"); + await acquireNewTokenAndRetry(body); + } + catch (error) { + throw new Error(error); + } + + } } while (skipToken); return databaseAccounts.sort((a, b) => a.name.localeCompare(b.name)); @@ -92,3 +104,53 @@ export function useDatabaseAccounts(subscriptionId: string, armToken: string): D ); return data; } + +async function acquireNewTokenAndRetry(body: any) { + try { + const msalInstance = await getMsalInstance(); + +const cachedAccount = msalInstance.getAllAccounts()?.[0]; +const cachedTenantId = localStorage.getItem("cachedTenantId"); + + // const [tenantId, setTenantId] = React.useState(cachedTenantId); + + + msalInstance.setActiveAccount(cachedAccount); + + const newAccessToken = await acquireTokenWithMsal(msalInstance, { + authority: `${configContext.AAD_ENDPOINT}${cachedTenantId}`, + scopes: [`${configContext.ARM_ENDPOINT}/.default`], + }); + const newBearer = `Bearer ${newAccessToken}`; + const newHeaders = new Headers(); + newHeaders.append("Authorization", newBearer); + newHeaders.append(HttpHeaders.contentType, "application/json"); + const apiVersion = "2021-03-01"; + const managementResourceGraphAPIURL = `${configContext.ARM_ENDPOINT}providers/Microsoft.ResourceGraph/resources?api-version=${apiVersion}`; + + const databaseAccounts: DatabaseAccount[] = []; + let skipToken: string; + + + // Retry the request with the new token + const response = await fetch(managementResourceGraphAPIURL, { + method: "POST", + headers: newHeaders, + body: JSON.stringify(body), + }); + + if (response.ok) { + // Handle successful response with new token + const queryResponse: QueryResponse = await response.json(); + skipToken = queryResponse.$skipToken; + queryResponse.data?.forEach((databaseAccount: any) => { + databaseAccounts.push(databaseAccount as DatabaseAccount); + }); + } else { + throw new Error(`Failed to fetch data after acquiring new token. Status: ${response.status}, ${await response.text()}`); + } + } catch (error) { + console.error("Error acquiring new token and retrying:", error); + throw error; + } +} From 9203276a246065179c08da00470388b5447f0a11 Mon Sep 17 00:00:00 2001 From: Senthamil Sindhu Date: Mon, 5 Aug 2024 09:57:54 -0700 Subject: [PATCH 4/5] Add common code for ARM token refresh --- src/UserContext.ts | 1 + src/hooks/useAADAuth.ts | 3 +- src/hooks/useDatabaseAccounts.tsx | 130 ++++++++++++++++++++++++------ src/hooks/useSubscriptions.tsx | 3 + 4 files changed, 113 insertions(+), 24 deletions(-) diff --git a/src/UserContext.ts b/src/UserContext.ts index ac534029a..8bd44ca1c 100644 --- a/src/UserContext.ts +++ b/src/UserContext.ts @@ -79,6 +79,7 @@ export interface UserContext { readonly endpoint?: string; readonly aadToken?: string; readonly accessToken?: string; + readonly armToken?: string; readonly authorizationToken?: string; readonly resourceToken?: string; readonly subscriptionType?: SubscriptionType; diff --git a/src/hooks/useAADAuth.ts b/src/hooks/useAADAuth.ts index c20f953f7..8b8abf006 100644 --- a/src/hooks/useAADAuth.ts +++ b/src/hooks/useAADAuth.ts @@ -3,6 +3,7 @@ import { useBoolean } from "@fluentui/react-hooks"; import * as React from "react"; import { configContext } from "../ConfigContext"; import { acquireTokenWithMsal, getMsalInstance } from "../Utils/AuthorizationUtils"; +import { updateUserContext } from "UserContext"; const msalInstance = await getMsalInstance(); @@ -79,7 +80,7 @@ export function useAADAuth(): ReturnType { authority: `${configContext.AAD_ENDPOINT}${tenantId}`, scopes: [`${configContext.ARM_ENDPOINT}/.default`], }); - + updateUserContext({ armToken: armToken}); setArmToken(armToken); setAuthFailure(null); } catch (error) { diff --git a/src/hooks/useDatabaseAccounts.tsx b/src/hooks/useDatabaseAccounts.tsx index 4cdb36bca..3a280728a 100644 --- a/src/hooks/useDatabaseAccounts.tsx +++ b/src/hooks/useDatabaseAccounts.tsx @@ -1,10 +1,8 @@ import { HttpHeaders } from "Common/Constants"; -import { QueryRequestOptions, QueryResponse } from "Contracts/AzureResourceGraph"; import useSWR from "swr"; -import { configContext } from "../ConfigContext"; -import { DatabaseAccount } from "../Contracts/DataModels"; import { acquireTokenWithMsal, getMsalInstance } from "Utils/AuthorizationUtils"; import React from "react"; +import { updateUserContext, userContext } from "UserContext"; /* eslint-disable @typescript-eslint/no-explicit-any */ interface AccountListResult { @@ -36,11 +34,10 @@ export async function fetchDatabaseAccounts(subscriptionId: string, accessToken: } export async function fetchDatabaseAccountsFromGraph( - subscriptionId: string, - accessToken: string, + subscriptionId: string ): Promise { const headers = new Headers(); - const bearer = `Bearer ${accessToken}`; + const bearer = `Bearer ${userContext.armToken}`; headers.append("Authorization", bearer); headers.append(HttpHeaders.contentType, "application/json"); @@ -48,8 +45,9 @@ export async function fetchDatabaseAccountsFromGraph( const apiVersion = "2021-03-01"; const managementResourceGraphAPIURL = `${configContext.ARM_ENDPOINT}providers/Microsoft.ResourceGraph/resources?api-version=${apiVersion}`; - const databaseAccounts: DatabaseAccount[] = []; + let databaseAccounts: DatabaseAccount[] = []; let skipToken: string; + console.log("Old ARM Token", userContext.armToken); do { const body = { query: databaseAccountsQuery, @@ -74,38 +72,121 @@ export async function fetchDatabaseAccountsFromGraph( }); if (!response.ok) { - // throw new Error(await response.text()); - // } + throw new Error(await response.text()); + } + const queryResponse: QueryResponse = (await response.json()) as QueryResponse; skipToken = queryResponse.$skipToken; queryResponse.data?.map((databaseAccount: any) => { databaseAccounts.push(databaseAccount as DatabaseAccount); }); - } else { - try{ - console.log("Token expired"); - await acquireNewTokenAndRetry(body); - } - catch (error) { - throw new Error(error); - } - } + // else { + // try{ + // console.log("Token expired"); + // databaseAccounts = await acquireNewTokenAndRetry(body); + // } + // catch (error) { + // throw new Error(error); + // } + + //} } while (skipToken); - return databaseAccounts.sort((a, b) => a.name.localeCompare(b.name)); } -export function useDatabaseAccounts(subscriptionId: string, armToken: string): DatabaseAccount[] | undefined { +export function useDatabaseAccounts(subscriptionId: string): DatabaseAccount[] | undefined { const { data } = useSWR( - () => (armToken && subscriptionId ? ["databaseAccounts", subscriptionId, armToken] : undefined), - (_, subscriptionId, armToken) => fetchDatabaseAccountsFromGraph(subscriptionId, armToken), + () => ( subscriptionId ? ["databaseAccounts", subscriptionId] : undefined), + (_, subscriptionId) => runCommand(fetchDatabaseAccountsFromGraph, subscriptionId), ); return data; } -async function acquireNewTokenAndRetry(body: any) { + + +// Define the types for your responses +interface DatabaseAccount { + name: string; + id: string; + // Add other relevant fields as per your use case +} + +interface Subscription { + displayName: string; + subscriptionId: string; + state: string; +} + +interface QueryRequestOptions { + $top?: number; + $skipToken?: string; + $allowPartialScopes?: boolean; +} + +// Define the configuration context and headers if not already defined +const configContext = { + ARM_ENDPOINT: 'https://management.azure.com/', + AAD_ENDPOINT: 'https://login.microsoftonline.com/' +}; + +interface QueryResponse { + data?: any[]; + $skipToken?: string; +} + +// Define a generic runCommand function +export async function runCommand( + fn: (...args: any[]) => Promise, + ...args: any[] +): Promise { + try { + // Attempt to execute the function passed as an argument + const result = await fn(...args); + console.log('Successfully executed function:', result); + return result; + + } catch (error) { + // Handle any error that is thrown during the execution of the function + //(error.code === "ExpiredAuthenticationToken") + if(error) { + console.log('Creating new token'); + const msalInstance = await getMsalInstance(); + + const cachedAccount = msalInstance.getAllAccounts()?.[0]; + const cachedTenantId = localStorage.getItem("cachedTenantId"); + + + msalInstance.setActiveAccount(cachedAccount); + + const newAccessToken = await acquireTokenWithMsal(msalInstance, { + authority: `${configContext.AAD_ENDPOINT}${cachedTenantId}`, + scopes: [`${configContext.ARM_ENDPOINT}/.default`], + }); + + console.log("Latest ARM Token", userContext.armToken); + updateUserContext({armToken: newAccessToken}); + const result = await fn(...args); + return result; + } + else { + console.error('An error occurred:', error.message); + throw new error; + } + + } +} + +// Running the functions using runCommand + +const accessToken = 'your-access-token'; +const subscriptionId = 'your-subscription-id'; + +//runCommand(fetchDatabaseAccountsFromGraph, subscriptionId, accessToken); +//runCommand(fetchSubscriptionsFromGraph, accessToken); + +async function acquireNewTokenAndRetry(body: any) : Promise { try { const msalInstance = await getMsalInstance(); @@ -121,6 +202,7 @@ const cachedTenantId = localStorage.getItem("cachedTenantId"); authority: `${configContext.AAD_ENDPOINT}${cachedTenantId}`, scopes: [`${configContext.ARM_ENDPOINT}/.default`], }); + console.log("New ARM Token", newAccessToken); const newBearer = `Bearer ${newAccessToken}`; const newHeaders = new Headers(); newHeaders.append("Authorization", newBearer); @@ -146,6 +228,7 @@ const cachedTenantId = localStorage.getItem("cachedTenantId"); queryResponse.data?.forEach((databaseAccount: any) => { databaseAccounts.push(databaseAccount as DatabaseAccount); }); + return databaseAccounts; } else { throw new Error(`Failed to fetch data after acquiring new token. Status: ${response.status}, ${await response.text()}`); } @@ -154,3 +237,4 @@ const cachedTenantId = localStorage.getItem("cachedTenantId"); throw error; } } + diff --git a/src/hooks/useSubscriptions.tsx b/src/hooks/useSubscriptions.tsx index ca80a87f5..0b1633c36 100644 --- a/src/hooks/useSubscriptions.tsx +++ b/src/hooks/useSubscriptions.tsx @@ -3,6 +3,7 @@ import { QueryRequestOptions, QueryResponse } from "Contracts/AzureResourceGraph import useSWR from "swr"; import { configContext } from "../ConfigContext"; import { Subscription } from "../Contracts/DataModels"; +import { acquireTokenWithMsal, getMsalInstance } from "Utils/AuthorizationUtils"; /* eslint-disable @typescript-eslint/no-explicit-any */ interface SubscriptionListResult { @@ -92,3 +93,5 @@ export function useSubscriptions(armToken: string): Subscription[] | undefined { ); return data; } + + From 311cf9aa5aace63689a92218da87aa83a9508ef3 Mon Sep 17 00:00:00 2001 From: Senthamil Sindhu Date: Wed, 21 Aug 2024 10:08:55 -0700 Subject: [PATCH 5/5] Add AAD endpoints for all environments --- src/Common/Constants.ts | 6 ++++++ src/ConfigContext.ts | 4 +++- src/Utils/EndpointUtils.ts | 5 ++++- src/hooks/useKnockoutExplorer.ts | 29 +++++++++++++++++++++++++++-- 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/Common/Constants.ts b/src/Common/Constants.ts index cde5e9462..ce0042890 100644 --- a/src/Common/Constants.ts +++ b/src/Common/Constants.ts @@ -183,6 +183,12 @@ export class CassandraProxyAPIs { public static readonly connectionStringSchemaApi: string = "api/connectionstring/cassandra/schema"; } +export class AadEndpoints { + public static readonly Prod: string = "https://login.microsoftonline.com/"; + public static readonly Fairfax: string = "https://login.microsoftonline.us/"; + public static readonly Mooncake: string = "https://login.partner.microsoftonline.cn/"; +} + export class Queries { public static CustomPageOption: string = "custom"; public static UnlimitedPageOption: string = "unlimited"; diff --git a/src/ConfigContext.ts b/src/ConfigContext.ts index 8db033788..49cd6fb60 100644 --- a/src/ConfigContext.ts +++ b/src/ConfigContext.ts @@ -5,6 +5,7 @@ import { MongoProxyEndpoints, PortalBackendEndpoints, } from "Common/Constants"; +import { userContext } from "UserContext"; import { allowedAadEndpoints, allowedArcadiaEndpoints, @@ -36,6 +37,7 @@ export interface ConfigContext { gitSha?: string; proxyPath?: string; AAD_ENDPOINT: string; + ENVIRONMENT: string; ARM_AUTH_AREA: string; ARM_ENDPOINT: string; EMULATOR_ENDPOINT?: string; @@ -91,7 +93,7 @@ let configContext: Readonly = { ], // Webpack injects this at build time gitSha: process.env.GIT_SHA, hostedExplorerURL: "https://cosmos.azure.com/", - AAD_ENDPOINT: "https://login.microsoftonline.com/", + AAD_ENDPOINT: "", ARM_AUTH_AREA: "https://management.azure.com/", ARM_ENDPOINT: "https://management.azure.com/", ARM_API_VERSION: "2016-06-01", diff --git a/src/Utils/EndpointUtils.ts b/src/Utils/EndpointUtils.ts index b685dc71a..fb505a431 100644 --- a/src/Utils/EndpointUtils.ts +++ b/src/Utils/EndpointUtils.ts @@ -52,7 +52,10 @@ export const defaultAllowedArmEndpoints: ReadonlyArray = [ "https://management.chinacloudapi.cn", ]; -export const allowedAadEndpoints: ReadonlyArray = ["https://login.microsoftonline.com/"]; +export const allowedAadEndpoints: ReadonlyArray = ["https://login.microsoftonline.com/", + "https://login.microsoftonline.us/", + "https://login.partner.microsoftonline.cn/" +]; export const defaultAllowedBackendEndpoints: ReadonlyArray = [ "https://main.documentdb.ext.azure.com", diff --git a/src/hooks/useKnockoutExplorer.ts b/src/hooks/useKnockoutExplorer.ts index fcf1d314e..ae0b36988 100644 --- a/src/hooks/useKnockoutExplorer.ts +++ b/src/hooks/useKnockoutExplorer.ts @@ -4,6 +4,7 @@ import { DATA_EXPLORER_RPC_VERSION } from "Contracts/DataExplorerMessagesContrac import { FabricMessageTypes } from "Contracts/FabricMessageTypes"; import { FABRIC_RPC_VERSION, FabricMessageV2 } from "Contracts/FabricMessagesContract"; import Explorer from "Explorer/Explorer"; +import { useDataPlaneRbac } from "Explorer/Panes/SettingsPane/SettingsPane"; import { useSelectedNode } from "Explorer/useSelectedNode"; import { scheduleRefreshDatabaseResourceToken } from "Platform/Fabric/FabricUtil"; import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility"; @@ -15,6 +16,7 @@ import { useEffect, useState } from "react"; import { AuthType } from "../AuthType"; import { AccountKind, Flights } from "../Common/Constants"; import { normalizeArmEndpoint } from "../Common/EnvironmentUtility"; +import * as Logger from "../Common/Logger"; import { handleCachedDataMessage, sendMessage, sendReadyMessage } from "../Common/MessageHandler"; import { Platform, configContext, updateConfigContext } from "../ConfigContext"; import { ActionType, DataExplorerAction, TabKind } from "../Contracts/ActionContracts"; @@ -42,8 +44,6 @@ import { acquireTokenWithMsal, getAuthorizationHeader, getMsalInstance } from ". import { isInvalidParentFrameOrigin, shouldProcessMessage } from "../Utils/MessageValidation"; import { getReadOnlyKeys, listKeys } from "../Utils/arm/generatedClients/cosmos/databaseAccounts"; import { applyExplorerBindings } from "../applyExplorerBindings"; -import { useDataPlaneRbac } from "Explorer/Panes/SettingsPane/SettingsPane"; -import * as Logger from "../Common/Logger"; // This hook will create a new instance of Explorer.ts and bind it to the DOM // This hook has a LOT of magic, but ideally we can delete it once we have removed KO and switched entirely to React @@ -642,6 +642,31 @@ function updateContextsFromPortalMessage(inputs: DataExplorerInputsFrame) { PORTAL_BACKEND_ENDPOINT: inputs.portalBackendEndpoint, }); + const portalEnv = inputs.serverId as PortalEnv; + + switch (portalEnv) { + case "prod1": + case "prod": + updateConfigContext({ + AAD_ENDPOINT: Constants.AadEndpoints.Prod + }); + break; + case "fairfax": + updateConfigContext({ + AAD_ENDPOINT: Constants.AadEndpoints.Fairfax + }); + break; + case "mooncake": + updateConfigContext({ + AAD_ENDPOINT: Constants.AadEndpoints.Mooncake + }); + break; + + default: + console.warn(`Unknown portal environment: ${portalEnv}`); + break; + } + updateUserContext({ authorizationToken, databaseAccount,