mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-10-13 15:28:05 +01:00
Use Config.json to Set Environment Specific AAD Auth Settings (#2184)
* Force hosted explorer to load config.json before calling useAADAuth. * Ensure AAD endpoint from config.json loads before useAADAuth. * Fix immediate linting errors and warnings. * Remove separate spinner for waiting on config to load. * Simplifying auth and reintroducing "No tokens for given scope, and no authorization code was passed to acquireToken." error. Blocking on login if incorrect AAD_ENDPOINT provided. * Fix linting errors. * Add error handling to prevent unhandled errors thrown when login prompt is cancelled prematurely.
This commit is contained in:
parent
08a51ca6b1
commit
6ec909a97b
@ -34,7 +34,8 @@ const App: React.FunctionComponent = () => {
|
|||||||
const [isOpen, { setTrue: openPanel, setFalse: dismissPanel }] = useBoolean(false);
|
const [isOpen, { setTrue: openPanel, setFalse: dismissPanel }] = useBoolean(false);
|
||||||
const config = useConfig();
|
const config = useConfig();
|
||||||
const { isLoggedIn, armToken, graphToken, account, tenantId, logout, login, switchTenant, authFailure } =
|
const { isLoggedIn, armToken, graphToken, account, tenantId, logout, login, switchTenant, authFailure } =
|
||||||
useAADAuth();
|
useAADAuth(config);
|
||||||
|
|
||||||
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>();
|
||||||
|
@ -1,12 +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 { configContext } from "../ConfigContext";
|
import { ConfigContext } from "../ConfigContext";
|
||||||
import { acquireTokenWithMsal, getMsalInstance } from "../Utils/AuthorizationUtils";
|
import { acquireTokenWithMsal, getMsalInstance } from "../Utils/AuthorizationUtils";
|
||||||
|
|
||||||
const msalInstance = await getMsalInstance();
|
|
||||||
|
|
||||||
const cachedAccount = msalInstance.getAllAccounts()?.[0];
|
|
||||||
const cachedTenantId = localStorage.getItem("cachedTenantId");
|
const cachedTenantId = localStorage.getItem("cachedTenantId");
|
||||||
|
|
||||||
interface ReturnType {
|
interface ReturnType {
|
||||||
@ -27,57 +24,97 @@ export interface AadAuthFailure {
|
|||||||
failureLinkAction?: () => void;
|
failureLinkAction?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useAADAuth(): ReturnType {
|
export function useAADAuth(config?: ConfigContext): ReturnType {
|
||||||
const [isLoggedIn, { setTrue: setLoggedIn, setFalse: setLoggedOut }] = useBoolean(
|
const [msalInstance, setMsalInstance] = React.useState<msal.PublicClientApplication | null>(null);
|
||||||
Boolean(cachedAccount && cachedTenantId) || false,
|
const [isLoggedIn, { setTrue: setLoggedIn, setFalse: setLoggedOut }] = useBoolean(false);
|
||||||
);
|
const [account, setAccount] = React.useState<msal.AccountInfo>(null);
|
||||||
const [account, setAccount] = React.useState<msal.AccountInfo>(cachedAccount);
|
|
||||||
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 [authFailure, setAuthFailure] = React.useState<AadAuthFailure>(undefined);
|
const [authFailure, setAuthFailure] = React.useState<AadAuthFailure>(undefined);
|
||||||
|
|
||||||
msalInstance.setActiveAccount(account);
|
// Initialize MSAL instance when config is available
|
||||||
const login = React.useCallback(async () => {
|
React.useEffect(() => {
|
||||||
const response = await msalInstance.loginPopup({
|
if (config && !msalInstance) {
|
||||||
redirectUri: configContext.msalRedirectURI,
|
getMsalInstance().then((instance) => {
|
||||||
scopes: [],
|
setMsalInstance(instance);
|
||||||
});
|
const cachedAccount = instance.getAllAccounts()?.[0];
|
||||||
setLoggedIn();
|
if (cachedAccount && cachedTenantId) {
|
||||||
setAccount(response.account);
|
setAccount(cachedAccount);
|
||||||
setTenantId(response.tenantId);
|
setLoggedIn();
|
||||||
localStorage.setItem("cachedTenantId", response.tenantId);
|
instance.setActiveAccount(cachedAccount);
|
||||||
}, []);
|
}
|
||||||
|
|
||||||
const logout = React.useCallback(() => {
|
|
||||||
setLoggedOut();
|
|
||||||
localStorage.removeItem("cachedTenantId");
|
|
||||||
msalInstance.logoutRedirect();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const switchTenant = React.useCallback(
|
|
||||||
async (id) => {
|
|
||||||
const response = await msalInstance.loginPopup({
|
|
||||||
redirectUri: configContext.msalRedirectURI,
|
|
||||||
authority: `${configContext.AAD_ENDPOINT}${id}`,
|
|
||||||
scopes: [],
|
|
||||||
});
|
});
|
||||||
setTenantId(response.tenantId);
|
}
|
||||||
setAccount(response.account);
|
}, [config, msalInstance]);
|
||||||
localStorage.setItem("cachedTenantId", response.tenantId);
|
|
||||||
},
|
|
||||||
[account, tenantId],
|
|
||||||
);
|
|
||||||
|
|
||||||
const acquireTokens = React.useCallback(async () => {
|
React.useEffect(() => {
|
||||||
if (!(account && tenantId)) {
|
if (msalInstance && account) {
|
||||||
|
msalInstance.setActiveAccount(account);
|
||||||
|
}
|
||||||
|
}, [msalInstance, account]);
|
||||||
|
|
||||||
|
const login = React.useCallback(async () => {
|
||||||
|
if (!msalInstance || !config) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await msalInstance.loginPopup({
|
||||||
|
redirectUri: config.msalRedirectURI,
|
||||||
|
scopes: [],
|
||||||
|
});
|
||||||
|
setLoggedIn();
|
||||||
|
setAccount(response.account);
|
||||||
|
setTenantId(response.tenantId);
|
||||||
|
localStorage.setItem("cachedTenantId", response.tenantId);
|
||||||
|
} catch (error) {
|
||||||
|
setAuthFailure({
|
||||||
|
failureMessage: `Login failed: ${JSON.stringify(error)}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [msalInstance, config]);
|
||||||
|
|
||||||
|
const logout = React.useCallback(() => {
|
||||||
|
if (!msalInstance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setLoggedOut();
|
||||||
|
localStorage.removeItem("cachedTenantId");
|
||||||
|
msalInstance.logoutRedirect();
|
||||||
|
}, [msalInstance]);
|
||||||
|
|
||||||
|
const switchTenant = React.useCallback(
|
||||||
|
async (id) => {
|
||||||
|
if (!msalInstance || !config) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const response = await msalInstance.loginPopup({
|
||||||
|
redirectUri: config.msalRedirectURI,
|
||||||
|
authority: `${config.AAD_ENDPOINT}${id}`,
|
||||||
|
scopes: [],
|
||||||
|
});
|
||||||
|
setTenantId(response.tenantId);
|
||||||
|
setAccount(response.account);
|
||||||
|
localStorage.setItem("cachedTenantId", response.tenantId);
|
||||||
|
} catch (error) {
|
||||||
|
setAuthFailure({
|
||||||
|
failureMessage: `Tenant switch failed: ${JSON.stringify(error)}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[msalInstance, config],
|
||||||
|
);
|
||||||
|
|
||||||
|
const acquireTokens = React.useCallback(async () => {
|
||||||
|
if (!(account && tenantId && msalInstance && config)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const armToken = await acquireTokenWithMsal(msalInstance, {
|
const armToken = await acquireTokenWithMsal(msalInstance, {
|
||||||
authority: `${configContext.AAD_ENDPOINT}${tenantId}`,
|
authority: `${config.AAD_ENDPOINT}${tenantId}`,
|
||||||
scopes: [`${configContext.ARM_ENDPOINT}/.default`],
|
scopes: [`${config.ARM_ENDPOINT}/.default`],
|
||||||
});
|
});
|
||||||
|
|
||||||
setArmToken(armToken);
|
setArmToken(armToken);
|
||||||
@ -105,8 +142,8 @@ export function useAADAuth(): ReturnType {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const graphToken = await acquireTokenWithMsal(msalInstance, {
|
const graphToken = await acquireTokenWithMsal(msalInstance, {
|
||||||
authority: `${configContext.AAD_ENDPOINT}${tenantId}`,
|
authority: `${config.AAD_ENDPOINT}${tenantId}`,
|
||||||
scopes: [`${configContext.GRAPH_ENDPOINT}/.default`],
|
scopes: [`${config.GRAPH_ENDPOINT}/.default`],
|
||||||
});
|
});
|
||||||
|
|
||||||
setGraphToken(graphToken);
|
setGraphToken(graphToken);
|
||||||
@ -115,7 +152,7 @@ export function useAADAuth(): ReturnType {
|
|||||||
// it's not critical if this fails.
|
// it's not critical if this fails.
|
||||||
console.warn("Error acquiring graph token: " + error);
|
console.warn("Error acquiring graph token: " + error);
|
||||||
}
|
}
|
||||||
}, [account, tenantId]);
|
}, [account, tenantId, msalInstance, config]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (account && tenantId && !authFailure) {
|
if (account && tenantId && !authFailure) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user