mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2024-11-25 15:06:55 +00:00
Redo user endpoint dynamic token (#827)
* Redo user endpoint dynamic token * Fixes aad endpoint race condition, tenant switching, and account permissions * Export const msalInstance * Format * fix import * format * Redo getMsalInstance * format again * Check for doc endpoint
This commit is contained in:
parent
75d01f655f
commit
e41b52e265
@ -1,5 +1,5 @@
|
|||||||
import { useBoolean } from "@fluentui/react-hooks";
|
|
||||||
import { initializeIcons } from "@fluentui/react";
|
import { initializeIcons } from "@fluentui/react";
|
||||||
|
import { useBoolean } from "@fluentui/react-hooks";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { render } from "react-dom";
|
import { render } from "react-dom";
|
||||||
import ChevronRight from "../images/chevron-right.svg";
|
import ChevronRight from "../images/chevron-right.svg";
|
||||||
@ -31,7 +31,7 @@ const App: React.FunctionComponent = () => {
|
|||||||
// For showing/hiding panel
|
// For showing/hiding panel
|
||||||
const [isOpen, { setTrue: openPanel, setFalse: dismissPanel }] = useBoolean(false);
|
const [isOpen, { setTrue: openPanel, setFalse: dismissPanel }] = useBoolean(false);
|
||||||
|
|
||||||
const { isLoggedIn, armToken, graphToken, aadToken, account, tenantId, logout, login, switchTenant } = useAADAuth();
|
const { isLoggedIn, armToken, graphToken, account, tenantId, logout, login, switchTenant } = useAADAuth();
|
||||||
const [databaseAccount, setDatabaseAccount] = React.useState<DatabaseAccount>();
|
const [databaseAccount, setDatabaseAccount] = React.useState<DatabaseAccount>();
|
||||||
const [authType, setAuthType] = React.useState<AuthType>(encryptedToken ? AuthType.EncryptedToken : undefined);
|
const [authType, setAuthType] = React.useState<AuthType>(encryptedToken ? AuthType.EncryptedToken : undefined);
|
||||||
const [connectionString, setConnectionString] = React.useState<string>();
|
const [connectionString, setConnectionString] = React.useState<string>();
|
||||||
@ -50,7 +50,6 @@ const App: React.FunctionComponent = () => {
|
|||||||
authType: AuthType.AAD,
|
authType: AuthType.AAD,
|
||||||
databaseAccount,
|
databaseAccount,
|
||||||
authorizationToken: armToken,
|
authorizationToken: armToken,
|
||||||
aadToken,
|
|
||||||
};
|
};
|
||||||
} else if (authType === AuthType.EncryptedToken) {
|
} else if (authType === AuthType.EncryptedToken) {
|
||||||
frameWindow.hostedConfig = {
|
frameWindow.hostedConfig = {
|
||||||
|
@ -7,7 +7,6 @@ export interface HostedExplorerChildFrame extends Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface AAD {
|
export interface AAD {
|
||||||
aadToken: string;
|
|
||||||
authType: AuthType.AAD;
|
authType: AuthType.AAD;
|
||||||
databaseAccount: DatabaseAccount;
|
databaseAccount: DatabaseAccount;
|
||||||
authorizationToken: string;
|
authorizationToken: string;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import * as msal from "@azure/msal-browser";
|
||||||
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";
|
||||||
@ -40,3 +41,21 @@ export function decryptJWTToken(token: string) {
|
|||||||
|
|
||||||
return JSON.parse(tokenPayload);
|
return JSON.parse(tokenPayload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getMsalInstance() {
|
||||||
|
const config: msal.Configuration = {
|
||||||
|
cache: {
|
||||||
|
cacheLocation: "localStorage",
|
||||||
|
},
|
||||||
|
auth: {
|
||||||
|
authority: "https://login.microsoftonline.com/common",
|
||||||
|
clientId: "203f1145-856a-4232-83d4-a43568fba23d",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === "development") {
|
||||||
|
config.auth.redirectUri = "https://dataexplorer-dev.azurewebsites.net";
|
||||||
|
}
|
||||||
|
const msalInstance = new msal.PublicClientApplication(config);
|
||||||
|
return msalInstance;
|
||||||
|
}
|
||||||
|
@ -1,22 +1,9 @@
|
|||||||
import * as msal from "@azure/msal-browser";
|
import * as msal from "@azure/msal-browser";
|
||||||
import { useBoolean } from "@fluentui/react-hooks";
|
import { useBoolean } from "@fluentui/react-hooks";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import { getMsalInstance } from "../Utils/AuthorizationUtils";
|
||||||
|
|
||||||
const config: msal.Configuration = {
|
const msalInstance = getMsalInstance();
|
||||||
cache: {
|
|
||||||
cacheLocation: "localStorage",
|
|
||||||
},
|
|
||||||
auth: {
|
|
||||||
authority: "https://login.microsoftonline.com/common",
|
|
||||||
clientId: "203f1145-856a-4232-83d4-a43568fba23d",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV === "development") {
|
|
||||||
config.auth.redirectUri = "https://dataexplorer-dev.azurewebsites.net";
|
|
||||||
}
|
|
||||||
|
|
||||||
const msalInstance = new msal.PublicClientApplication(config);
|
|
||||||
|
|
||||||
const cachedAccount = msalInstance.getAllAccounts()?.[0];
|
const cachedAccount = msalInstance.getAllAccounts()?.[0];
|
||||||
const cachedTenantId = localStorage.getItem("cachedTenantId");
|
const cachedTenantId = localStorage.getItem("cachedTenantId");
|
||||||
@ -25,7 +12,6 @@ interface ReturnType {
|
|||||||
isLoggedIn: boolean;
|
isLoggedIn: boolean;
|
||||||
graphToken: string;
|
graphToken: string;
|
||||||
armToken: string;
|
armToken: string;
|
||||||
aadToken: string;
|
|
||||||
login: () => void;
|
login: () => void;
|
||||||
logout: () => void;
|
logout: () => void;
|
||||||
tenantId: string;
|
tenantId: string;
|
||||||
@ -41,7 +27,6 @@ export function useAADAuth(): ReturnType {
|
|||||||
const [tenantId, setTenantId] = React.useState<string>(cachedTenantId);
|
const [tenantId, setTenantId] = React.useState<string>(cachedTenantId);
|
||||||
const [graphToken, setGraphToken] = React.useState<string>();
|
const [graphToken, setGraphToken] = React.useState<string>();
|
||||||
const [armToken, setArmToken] = React.useState<string>();
|
const [armToken, setArmToken] = React.useState<string>();
|
||||||
const [aadToken, setAadToken] = React.useState<string>();
|
|
||||||
|
|
||||||
msalInstance.setActiveAccount(account);
|
msalInstance.setActiveAccount(account);
|
||||||
const login = React.useCallback(async () => {
|
const login = React.useCallback(async () => {
|
||||||
@ -81,13 +66,9 @@ export function useAADAuth(): ReturnType {
|
|||||||
authority: `https://login.microsoftonline.com/${tenantId}`,
|
authority: `https://login.microsoftonline.com/${tenantId}`,
|
||||||
scopes: ["https://management.azure.com//.default"],
|
scopes: ["https://management.azure.com//.default"],
|
||||||
}),
|
}),
|
||||||
msalInstance.acquireTokenSilent({
|
]).then(([graphTokenResponse, armTokenResponse]) => {
|
||||||
scopes: ["https://cosmos.azure.com/.default"],
|
|
||||||
}),
|
|
||||||
]).then(([graphTokenResponse, armTokenResponse, aadTokenResponse]) => {
|
|
||||||
setGraphToken(graphTokenResponse.accessToken);
|
setGraphToken(graphTokenResponse.accessToken);
|
||||||
setArmToken(armTokenResponse.accessToken);
|
setArmToken(armTokenResponse.accessToken);
|
||||||
setAadToken(aadTokenResponse.accessToken);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [account, tenantId]);
|
}, [account, tenantId]);
|
||||||
@ -98,7 +79,6 @@ export function useAADAuth(): ReturnType {
|
|||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
graphToken,
|
graphToken,
|
||||||
armToken,
|
armToken,
|
||||||
aadToken,
|
|
||||||
login,
|
login,
|
||||||
logout,
|
logout,
|
||||||
switchTenant,
|
switchTenant,
|
||||||
|
@ -28,11 +28,13 @@ import { CollectionCreation } from "../Shared/Constants";
|
|||||||
import { DefaultExperienceUtility } from "../Shared/DefaultExperienceUtility";
|
import { DefaultExperienceUtility } from "../Shared/DefaultExperienceUtility";
|
||||||
import { PortalEnv, updateUserContext, userContext } from "../UserContext";
|
import { PortalEnv, updateUserContext, userContext } from "../UserContext";
|
||||||
import { listKeys } from "../Utils/arm/generatedClients/cosmos/databaseAccounts";
|
import { listKeys } from "../Utils/arm/generatedClients/cosmos/databaseAccounts";
|
||||||
|
import { DatabaseAccountListKeysResult } from "../Utils/arm/generatedClients/cosmos/types";
|
||||||
|
import { getMsalInstance } from "../Utils/AuthorizationUtils";
|
||||||
import { isInvalidParentFrameOrigin } from "../Utils/MessageValidation";
|
import { isInvalidParentFrameOrigin } from "../Utils/MessageValidation";
|
||||||
|
|
||||||
// This hook will create a new instance of Explorer.ts and bind it to the DOM
|
// 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
|
// This hook has a LOT of magic, but ideally we can delete it once we have removed KO and switched entirely to React
|
||||||
// Pleas tread carefully :)
|
// Please tread carefully :)
|
||||||
|
|
||||||
export function useKnockoutExplorer(platform: Platform, explorerParams: ExplorerParams): Explorer {
|
export function useKnockoutExplorer(platform: Platform, explorerParams: ExplorerParams): Explorer {
|
||||||
const [explorer, setExplorer] = useState<Explorer>();
|
const [explorer, setExplorer] = useState<Explorer>();
|
||||||
@ -83,16 +85,33 @@ async function configureHostedWithAAD(config: AAD, explorerParams: ExplorerParam
|
|||||||
updateUserContext({
|
updateUserContext({
|
||||||
authType: AuthType.AAD,
|
authType: AuthType.AAD,
|
||||||
authorizationToken: `Bearer ${config.authorizationToken}`,
|
authorizationToken: `Bearer ${config.authorizationToken}`,
|
||||||
aadToken: config.aadToken,
|
|
||||||
});
|
});
|
||||||
const account = config.databaseAccount;
|
const account = config.databaseAccount;
|
||||||
const accountResourceId = account.id;
|
const accountResourceId = account.id;
|
||||||
const subscriptionId = accountResourceId && accountResourceId.split("subscriptions/")[1].split("/")[0];
|
const subscriptionId = accountResourceId && accountResourceId.split("subscriptions/")[1].split("/")[0];
|
||||||
const resourceGroup = accountResourceId && accountResourceId.split("resourceGroups/")[1].split("/")[0];
|
const resourceGroup = accountResourceId && accountResourceId.split("resourceGroups/")[1].split("/")[0];
|
||||||
const keys = await listKeys(subscriptionId, resourceGroup, account.name);
|
let aadToken;
|
||||||
|
let keys: DatabaseAccountListKeysResult = {};
|
||||||
|
if (account.properties?.documentEndpoint) {
|
||||||
|
const hrefEndpoint = new URL(account.properties.documentEndpoint).href.replace(/\/$/, "/.default");
|
||||||
|
const msalInstance = getMsalInstance();
|
||||||
|
const cachedAccount = msalInstance.getAllAccounts()?.[0];
|
||||||
|
msalInstance.setActiveAccount(cachedAccount);
|
||||||
|
const aadTokenResponse = await msalInstance.acquireTokenSilent({
|
||||||
|
forceRefresh: true,
|
||||||
|
scopes: [hrefEndpoint],
|
||||||
|
});
|
||||||
|
aadToken = aadTokenResponse.accessToken;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
keys = await listKeys(subscriptionId, resourceGroup, account.name);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e);
|
||||||
|
}
|
||||||
updateUserContext({
|
updateUserContext({
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
|
aadToken,
|
||||||
databaseAccount: config.databaseAccount,
|
databaseAccount: config.databaseAccount,
|
||||||
masterKey: keys.primaryMasterKey,
|
masterKey: keys.primaryMasterKey,
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user