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 * 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 { userContext } from "../UserContext";
|
||||||
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
|
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
|
||||||
|
import * as PriorityBasedExecutionUtils from "../Utils/PriorityBasedExecutionUtils";
|
||||||
import { EmulatorMasterKey, HttpHeaders } from "./Constants";
|
import { EmulatorMasterKey, HttpHeaders } from "./Constants";
|
||||||
import { getErrorMessage } from "./ErrorHandlingUtils";
|
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;
|
const _global = typeof self === "undefined" ? window : self;
|
||||||
|
|
||||||
|
@ -26,6 +27,15 @@ export const tokenProvider = async (requestInfo: Cosmos.RequestInfo) => {
|
||||||
return decodeURIComponent(headers.authorization);
|
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) {
|
if (userContext.masterKey) {
|
||||||
// TODO This SDK method mutates the headers object. Find a better one or fix the SDK.
|
// TODO This SDK method mutates the headers object. Find a better one or fix the SDK.
|
||||||
await Cosmos.setAuthorizationTokenHeaderUsingMasterKey(verb, resourceId, resourceType, headers, EmulatorMasterKey);
|
await Cosmos.setAuthorizationTokenHeaderUsingMasterKey(verb, resourceId, resourceType, headers, EmulatorMasterKey);
|
||||||
|
@ -56,7 +66,11 @@ export const endpoint = () => {
|
||||||
return userContext.endpoint || userContext?.databaseAccount?.properties?.documentEndpoint;
|
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 {
|
try {
|
||||||
const host = configContext.BACKEND_ENDPOINT;
|
const host = configContext.BACKEND_ENDPOINT;
|
||||||
const response = await _global.fetch(host + "/api/guest/runtimeproxy/authorizationTokens", {
|
const response = await _global.fetch(host + "/api/guest/runtimeproxy/authorizationTokens", {
|
||||||
|
|
|
@ -22,7 +22,7 @@ export function handleCachedDataMessage(message: any): void {
|
||||||
if (messageContent.error != null) {
|
if (messageContent.error != null) {
|
||||||
cachedDataPromise.deferred.reject(messageContent.error);
|
cachedDataPromise.deferred.reject(messageContent.error);
|
||||||
} else {
|
} else {
|
||||||
cachedDataPromise.deferred.resolve(JSON.parse(messageContent.data));
|
cachedDataPromise.deferred.resolve(messageContent.data);
|
||||||
}
|
}
|
||||||
runGarbageCollector();
|
runGarbageCollector();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,46 +1,6 @@
|
||||||
|
import { MessageTypes } from "Contracts/MessageTypes";
|
||||||
import * as ActionContracts from "./ActionContracts";
|
import * as ActionContracts from "./ActionContracts";
|
||||||
import * as Diagnostics from "./Diagnostics";
|
import * as Diagnostics from "./Diagnostics";
|
||||||
import * as Versions from "./Versions";
|
import * as Versions from "./Versions";
|
||||||
|
|
||||||
/**
|
export { ActionContracts, Diagnostics, MessageTypes, 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 };
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { AuthorizationToken, MessageTypes } from "./MessageTypes";
|
||||||
|
|
||||||
export type FabricMessage =
|
export type FabricMessage =
|
||||||
| {
|
| {
|
||||||
type: "newContainer";
|
type: "newContainer";
|
||||||
|
@ -5,21 +7,52 @@ export type FabricMessage =
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: "initialize";
|
type: "initialize";
|
||||||
connectionString: string | undefined;
|
message: {
|
||||||
|
endpoint: string | undefined;
|
||||||
|
error: string | undefined;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: "openTab";
|
type: "openTab";
|
||||||
databaseName: string;
|
databaseName: string;
|
||||||
collectionName: string | undefined;
|
collectionName: string | undefined;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: "authorizationToken";
|
||||||
|
message: {
|
||||||
|
id: string;
|
||||||
|
error: string | undefined;
|
||||||
|
data: AuthorizationToken | undefined;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DataExploreMessage =
|
export type DataExploreMessage =
|
||||||
| "ready"
|
| "ready"
|
||||||
| {
|
| {
|
||||||
type: number;
|
type: MessageTypes.TelemetryInfo;
|
||||||
data: {
|
data: {
|
||||||
action: "LoadDatabases";
|
action: "LoadDatabases";
|
||||||
actionModifier: "success" | "start";
|
actionModifier: "success" | "start";
|
||||||
defaultExperience: "SQL";
|
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;
|
||||||
|
};
|
||||||
|
|
|
@ -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 { FabricMessage } from "Contracts/FabricContract";
|
||||||
import Explorer from "Explorer/Explorer";
|
import Explorer from "Explorer/Explorer";
|
||||||
import { useSelectedNode } from "Explorer/useSelectedNode";
|
import { useSelectedNode } from "Explorer/useSelectedNode";
|
||||||
import { fetchEncryptedToken } from "Platform/Hosted/Components/ConnectExplorer";
|
|
||||||
import { getNetworkSettingsWarningMessage } from "Utils/NetworkUtility";
|
import { getNetworkSettingsWarningMessage } from "Utils/NetworkUtility";
|
||||||
import { fetchAccessData } from "hooks/usePortalAccessToken";
|
|
||||||
import { ReactTabKind, useTabs } from "hooks/useTabs";
|
import { ReactTabKind, useTabs } from "hooks/useTabs";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { AuthType } from "../AuthType";
|
import { AuthType } from "../AuthType";
|
||||||
import { AccountKind, Flights } from "../Common/Constants";
|
import { AccountKind, Flights } from "../Common/Constants";
|
||||||
import { normalizeArmEndpoint } from "../Common/EnvironmentUtility";
|
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 { Platform, configContext, updateConfigContext } from "../ConfigContext";
|
||||||
import { ActionType, DataExplorerAction, TabKind } from "../Contracts/ActionContracts";
|
import { ActionType, DataExplorerAction, TabKind } from "../Contracts/ActionContracts";
|
||||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||||
|
@ -107,23 +105,7 @@ async function configureFabric(): Promise<Explorer> {
|
||||||
|
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case "initialize": {
|
case "initialize": {
|
||||||
// TODO For now, retrieve info from session storage. Replace with info injected into Data Explorer
|
explorer = await configureWithFabric(data.message.endpoint);
|
||||||
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);
|
|
||||||
resolve(explorer);
|
resolve(explorer);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -166,6 +148,10 @@ async function configureFabric(): Promise<Explorer> {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "authorizationToken": {
|
||||||
|
handleCachedDataMessage(data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
console.error(`Unknown Fabric message type: ${JSON.stringify(data)}`);
|
console.error(`Unknown Fabric message type: ${JSON.stringify(data)}`);
|
||||||
break;
|
break;
|
||||||
|
@ -315,6 +301,25 @@ function configureHostedWithResourceToken(config: ResourceToken): Explorer {
|
||||||
return 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 {
|
function configureWithEncryptedToken(config: EncryptedToken): Explorer {
|
||||||
const apiExperience = DefaultExperienceUtility.getDefaultExperienceFromApiKind(config.encryptedTokenMetadata.apiKind);
|
const apiExperience = DefaultExperienceUtility.getDefaultExperienceFromApiKind(config.encryptedTokenMetadata.apiKind);
|
||||||
updateUserContext({
|
updateUserContext({
|
||||||
|
|
Loading…
Reference in New Issue