mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2024-11-25 15:06:55 +00:00
Implement retrieval of authorization token for Fabric via iframe rpc (#1647)
* For Fabric, send message to get Authorization token from iframe parent * tokenProvider: set date header and return token * Expect account endpoint on initialize message from Fabric * Fix format --------- Co-authored-by: artrejo <artrejo@microsoft.com>
This commit is contained in:
parent
f36fccd3ef
commit
dcd8d1637b
@ -1,13 +1,14 @@
|
||||
import * as Cosmos from "@azure/cosmos";
|
||||
import { configContext, Platform } from "../ConfigContext";
|
||||
import { sendCachedDataMessage } from "Common/MessageHandler";
|
||||
import { AuthorizationToken, MessageTypes } from "Contracts/MessageTypes";
|
||||
import { AuthType } from "../AuthType";
|
||||
import { PriorityLevel } from "../Common/Constants";
|
||||
import { Platform, configContext } from "../ConfigContext";
|
||||
import { userContext } from "../UserContext";
|
||||
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
|
||||
import * as PriorityBasedExecutionUtils from "../Utils/PriorityBasedExecutionUtils";
|
||||
import { EmulatorMasterKey, HttpHeaders } from "./Constants";
|
||||
import { getErrorMessage } from "./ErrorHandlingUtils";
|
||||
import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
|
||||
import { PriorityLevel } from "../Common/Constants";
|
||||
import * as PriorityBasedExecutionUtils from "../Utils/PriorityBasedExecutionUtils";
|
||||
import { AuthType } from "../AuthType";
|
||||
|
||||
const _global = typeof self === "undefined" ? window : self;
|
||||
|
||||
@ -26,6 +27,15 @@ export const tokenProvider = async (requestInfo: Cosmos.RequestInfo) => {
|
||||
return decodeURIComponent(headers.authorization);
|
||||
}
|
||||
|
||||
if (configContext.platform === Platform.Fabric) {
|
||||
const authorizationToken = await sendCachedDataMessage<AuthorizationToken>(MessageTypes.GetAuthorizationToken, [
|
||||
requestInfo,
|
||||
]);
|
||||
console.log("Response from Fabric: ", authorizationToken);
|
||||
headers[HttpHeaders.msDate] = authorizationToken.XDate;
|
||||
return authorizationToken.PrimaryReadWriteToken;
|
||||
}
|
||||
|
||||
if (userContext.masterKey) {
|
||||
// TODO This SDK method mutates the headers object. Find a better one or fix the SDK.
|
||||
await Cosmos.setAuthorizationTokenHeaderUsingMasterKey(verb, resourceId, resourceType, headers, EmulatorMasterKey);
|
||||
@ -56,7 +66,11 @@ export const endpoint = () => {
|
||||
return userContext.endpoint || userContext?.databaseAccount?.properties?.documentEndpoint;
|
||||
};
|
||||
|
||||
export async function getTokenFromAuthService(verb: string, resourceType: string, resourceId?: string): Promise<any> {
|
||||
export async function getTokenFromAuthService(
|
||||
verb: string,
|
||||
resourceType: string,
|
||||
resourceId?: string,
|
||||
): Promise<AuthorizationToken> {
|
||||
try {
|
||||
const host = configContext.BACKEND_ENDPOINT;
|
||||
const response = await _global.fetch(host + "/api/guest/runtimeproxy/authorizationTokens", {
|
||||
|
@ -22,7 +22,7 @@ export function handleCachedDataMessage(message: any): void {
|
||||
if (messageContent.error != null) {
|
||||
cachedDataPromise.deferred.reject(messageContent.error);
|
||||
} else {
|
||||
cachedDataPromise.deferred.resolve(JSON.parse(messageContent.data));
|
||||
cachedDataPromise.deferred.resolve(messageContent.data);
|
||||
}
|
||||
runGarbageCollector();
|
||||
}
|
||||
|
@ -1,46 +1,6 @@
|
||||
import { MessageTypes } from "Contracts/MessageTypes";
|
||||
import * as ActionContracts from "./ActionContracts";
|
||||
import * as Diagnostics from "./Diagnostics";
|
||||
import * as Versions from "./Versions";
|
||||
|
||||
/**
|
||||
* Messaging types used with Data Explorer <-> Portal communication
|
||||
* and Hosted <-> Explorer communication
|
||||
*/
|
||||
export enum MessageTypes {
|
||||
TelemetryInfo,
|
||||
LogInfo,
|
||||
RefreshResources,
|
||||
AllDatabases,
|
||||
CollectionsForDatabase,
|
||||
RefreshOffers,
|
||||
AllOffers,
|
||||
UpdateLocationHash,
|
||||
SingleOffer,
|
||||
RefreshOffer,
|
||||
UpdateAccountName,
|
||||
ForbiddenError,
|
||||
AadSignIn,
|
||||
GetAccessAadRequest,
|
||||
GetAccessAadResponse,
|
||||
UpdateAccountSwitch,
|
||||
UpdateDirectoryControl,
|
||||
SwitchAccount,
|
||||
SendNotification,
|
||||
ClearNotification,
|
||||
ExplorerClickEvent,
|
||||
LoadingStatus,
|
||||
GetArcadiaToken,
|
||||
CreateWorkspace,
|
||||
CreateSparkPool,
|
||||
RefreshDatabaseAccount,
|
||||
CloseTab,
|
||||
OpenQuickstartBlade,
|
||||
OpenPostgreSQLPasswordReset,
|
||||
OpenPostgresNetworkingBlade,
|
||||
OpenCosmosDBNetworkingBlade,
|
||||
DisplayNPSSurvey,
|
||||
OpenVCoreMongoNetworkingBlade,
|
||||
OpenVCoreMongoConnectionStringsBlade,
|
||||
}
|
||||
|
||||
export { ActionContracts, Diagnostics, Versions };
|
||||
export { ActionContracts, Diagnostics, MessageTypes, Versions };
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { AuthorizationToken, MessageTypes } from "./MessageTypes";
|
||||
|
||||
export type FabricMessage =
|
||||
| {
|
||||
type: "newContainer";
|
||||
@ -5,21 +7,52 @@ export type FabricMessage =
|
||||
}
|
||||
| {
|
||||
type: "initialize";
|
||||
connectionString: string | undefined;
|
||||
message: {
|
||||
endpoint: string | undefined;
|
||||
error: string | undefined;
|
||||
};
|
||||
}
|
||||
| {
|
||||
type: "openTab";
|
||||
databaseName: string;
|
||||
collectionName: string | undefined;
|
||||
}
|
||||
| {
|
||||
type: "authorizationToken";
|
||||
message: {
|
||||
id: string;
|
||||
error: string | undefined;
|
||||
data: AuthorizationToken | undefined;
|
||||
};
|
||||
};
|
||||
|
||||
export type DataExploreMessage =
|
||||
| "ready"
|
||||
| {
|
||||
type: number;
|
||||
type: MessageTypes.TelemetryInfo;
|
||||
data: {
|
||||
action: "LoadDatabases";
|
||||
actionModifier: "success" | "start";
|
||||
defaultExperience: "SQL";
|
||||
};
|
||||
}
|
||||
| {
|
||||
type: MessageTypes.GetAuthorizationToken;
|
||||
id: string;
|
||||
params: GetCosmosTokenMessageOptions[];
|
||||
};
|
||||
|
||||
export type GetCosmosTokenMessageOptions = {
|
||||
verb: "connect" | "delete" | "get" | "head" | "options" | "patch" | "post" | "put" | "trace";
|
||||
resourceType: "" | "dbs" | "colls" | "docs" | "sprocs" | "pkranges";
|
||||
resourceId: string;
|
||||
};
|
||||
|
||||
export type CosmosDBTokenResponse = {
|
||||
token: string;
|
||||
date: string;
|
||||
};
|
||||
|
||||
export type CosmosDBConnectionInfoResponse = {
|
||||
endpoint: string;
|
||||
};
|
||||
|
48
src/Contracts/MessageTypes.ts
Normal file
48
src/Contracts/MessageTypes.ts
Normal file
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Messaging types used with Data Explorer <-> Portal communication,
|
||||
* Hosted <-> Explorer communication and Data Explorer -> Fabric communication.
|
||||
*/
|
||||
export enum MessageTypes {
|
||||
TelemetryInfo,
|
||||
LogInfo,
|
||||
RefreshResources,
|
||||
AllDatabases,
|
||||
CollectionsForDatabase,
|
||||
RefreshOffers,
|
||||
AllOffers,
|
||||
UpdateLocationHash,
|
||||
SingleOffer,
|
||||
RefreshOffer,
|
||||
UpdateAccountName,
|
||||
ForbiddenError,
|
||||
AadSignIn,
|
||||
GetAccessAadRequest,
|
||||
GetAccessAadResponse,
|
||||
UpdateAccountSwitch,
|
||||
UpdateDirectoryControl,
|
||||
SwitchAccount,
|
||||
SendNotification,
|
||||
ClearNotification,
|
||||
ExplorerClickEvent,
|
||||
LoadingStatus,
|
||||
GetArcadiaToken,
|
||||
CreateWorkspace,
|
||||
CreateSparkPool,
|
||||
RefreshDatabaseAccount,
|
||||
CloseTab,
|
||||
OpenQuickstartBlade,
|
||||
OpenPostgreSQLPasswordReset,
|
||||
OpenPostgresNetworkingBlade,
|
||||
OpenCosmosDBNetworkingBlade,
|
||||
DisplayNPSSurvey,
|
||||
OpenVCoreMongoNetworkingBlade,
|
||||
OpenVCoreMongoConnectionStringsBlade,
|
||||
|
||||
// Data Explorer -> Fabric communication
|
||||
GetAuthorizationToken,
|
||||
}
|
||||
|
||||
export interface AuthorizationToken {
|
||||
XDate: string;
|
||||
PrimaryReadWriteToken: string;
|
||||
}
|
@ -2,15 +2,13 @@ import { createUri } from "Common/UrlUtility";
|
||||
import { FabricMessage } from "Contracts/FabricContract";
|
||||
import Explorer from "Explorer/Explorer";
|
||||
import { useSelectedNode } from "Explorer/useSelectedNode";
|
||||
import { fetchEncryptedToken } from "Platform/Hosted/Components/ConnectExplorer";
|
||||
import { getNetworkSettingsWarningMessage } from "Utils/NetworkUtility";
|
||||
import { fetchAccessData } from "hooks/usePortalAccessToken";
|
||||
import { ReactTabKind, useTabs } from "hooks/useTabs";
|
||||
import { useEffect, useState } from "react";
|
||||
import { AuthType } from "../AuthType";
|
||||
import { AccountKind, Flights } from "../Common/Constants";
|
||||
import { normalizeArmEndpoint } from "../Common/EnvironmentUtility";
|
||||
import { sendMessage, sendReadyMessage } from "../Common/MessageHandler";
|
||||
import { handleCachedDataMessage, sendMessage, sendReadyMessage } from "../Common/MessageHandler";
|
||||
import { Platform, configContext, updateConfigContext } from "../ConfigContext";
|
||||
import { ActionType, DataExplorerAction, TabKind } from "../Contracts/ActionContracts";
|
||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||
@ -107,23 +105,7 @@ async function configureFabric(): Promise<Explorer> {
|
||||
|
||||
switch (data.type) {
|
||||
case "initialize": {
|
||||
// TODO For now, retrieve info from session storage. Replace with info injected into Data Explorer
|
||||
const connectionString = data.connectionString ?? sessionStorage.getItem("connectionString");
|
||||
if (!connectionString) {
|
||||
console.error("No connection string found in session storage");
|
||||
return undefined;
|
||||
}
|
||||
const encryptedToken = await fetchEncryptedToken(connectionString);
|
||||
// TODO Duplicated from useTokenMetadata
|
||||
const encryptedTokenMetadata = await fetchAccessData(encryptedToken);
|
||||
|
||||
const hostedConfig: EncryptedToken = {
|
||||
authType: AuthType.EncryptedToken,
|
||||
encryptedToken,
|
||||
encryptedTokenMetadata,
|
||||
};
|
||||
|
||||
explorer = await configureWithEncryptedToken(hostedConfig);
|
||||
explorer = await configureWithFabric(data.message.endpoint);
|
||||
resolve(explorer);
|
||||
break;
|
||||
}
|
||||
@ -166,6 +148,10 @@ async function configureFabric(): Promise<Explorer> {
|
||||
|
||||
break;
|
||||
}
|
||||
case "authorizationToken": {
|
||||
handleCachedDataMessage(data);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console.error(`Unknown Fabric message type: ${JSON.stringify(data)}`);
|
||||
break;
|
||||
@ -315,6 +301,25 @@ function configureHostedWithResourceToken(config: ResourceToken): Explorer {
|
||||
return explorer;
|
||||
}
|
||||
|
||||
function configureWithFabric(documentEndpoint: string): Explorer {
|
||||
updateUserContext({
|
||||
authType: AuthType.ConnectionString,
|
||||
databaseAccount: {
|
||||
id: "",
|
||||
location: "",
|
||||
type: "",
|
||||
name: "Mounted",
|
||||
kind: AccountKind.Default,
|
||||
properties: {
|
||||
documentEndpoint,
|
||||
},
|
||||
},
|
||||
});
|
||||
const explorer = new Explorer();
|
||||
setTimeout(() => explorer.refreshAllDatabases(), 0);
|
||||
return explorer;
|
||||
}
|
||||
|
||||
function configureWithEncryptedToken(config: EncryptedToken): Explorer {
|
||||
const apiExperience = DefaultExperienceUtility.getDefaultExperienceFromApiKind(config.encryptedTokenMetadata.apiKind);
|
||||
updateUserContext({
|
||||
|
Loading…
Reference in New Issue
Block a user