From d07d2c7c0d4e7fdecdd8fc368c41290fa246b563 Mon Sep 17 00:00:00 2001 From: sindhuba <122321535+sindhuba@users.noreply.github.com> Date: Fri, 19 Jul 2024 08:02:44 -0700 Subject: [PATCH] Add readOnlyKeys call to support accounts with Reader role (#1916) * Fix API endpoint for CassandraProxy query API * activate Mongo Proxy and Cassandra Proxy in Prod * Add CP Prod endpoint * Run npm format and tests * Revert code * fix bug that blocked local mongo proxy and cassandra proxy development * Add prod endpoint * fix pr check tests * Remove prod * Remove prod endpoint * Remove dev endpoint * Support data plane RBAC * Support data plane RBAC * Add additional changes for Portal RBAC functionality * Remove unnecessary code * Remove unnecessary code * Add code to fix VCoreMongo/PG bug * Address feedback * Add more logs for RBAC feature * Add more logs for RBAC features * Add readOnlyKeys call for accounts with Reader role * Resolve conflicts --------- Co-authored-by: Asier Isayas --- .../Panes/SettingsPane/SettingsPane.tsx | 28 +++++++++------ src/hooks/useKnockoutExplorer.ts | 36 +++++++++++-------- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/Explorer/Panes/SettingsPane/SettingsPane.tsx b/src/Explorer/Panes/SettingsPane/SettingsPane.tsx index ef277b53f..216deda25 100644 --- a/src/Explorer/Panes/SettingsPane/SettingsPane.tsx +++ b/src/Explorer/Panes/SettingsPane/SettingsPane.tsx @@ -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; @@ -172,18 +171,25 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({ }); const { databaseAccount: account, subscriptionId, resourceGroup } = userContext; if (!userContext.features.enableAadDataPlane && !userContext.masterKey) { + let keys; try { - const keys: DatabaseAccountListKeysResult = await listKeys(subscriptionId, resourceGroup, account.name); - - if (keys.primaryMasterKey) { - updateUserContext({ masterKey: keys.primaryMasterKey }); - - useDataPlaneRbac.setState({ dataPlaneRbacEnabled: false }); - } + keys = await listKeys(subscriptionId, resourceGroup, account.name); + updateUserContext({ + masterKey: keys.primaryMasterKey, + }); } catch (error) { - logConsoleError(`Error occurred fetching keys for the account." ${error.message}`); - throw 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 8a0bfa149..fcf1d314e 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"; @@ -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; + } } }