mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-26 18:06:03 +00:00
fix(ui): MSAL popup auth issue (#18125)
(cherry picked from commit e44c8d4f3143831c0aa95fe31d89f93b7b0da638)
This commit is contained in:
parent
6a36355d3e
commit
a1a9b91a1e
@ -45,8 +45,8 @@
|
|||||||
"@ant-design/icons": "^4.7.0",
|
"@ant-design/icons": "^4.7.0",
|
||||||
"@apidevtools/json-schema-ref-parser": "^9.0.9",
|
"@apidevtools/json-schema-ref-parser": "^9.0.9",
|
||||||
"@auth0/auth0-react": "^1.9.0",
|
"@auth0/auth0-react": "^1.9.0",
|
||||||
"@azure/msal-browser": "^3.10.0",
|
"@azure/msal-browser": "^3.25.0",
|
||||||
"@azure/msal-react": "^2.0.12",
|
"@azure/msal-react": "^2.1.1",
|
||||||
"@dagrejs/dagre": "^1.1.2",
|
"@dagrejs/dagre": "^1.1.2",
|
||||||
"@deuex-solutions/react-tour": "^1.2.6",
|
"@deuex-solutions/react-tour": "^1.2.6",
|
||||||
"@fontsource/poppins": "^5.0.0",
|
"@fontsource/poppins": "^5.0.0",
|
||||||
|
@ -12,27 +12,29 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AuthenticationResult,
|
|
||||||
InteractionRequiredAuthError,
|
InteractionRequiredAuthError,
|
||||||
|
InteractionStatus,
|
||||||
} from '@azure/msal-browser';
|
} from '@azure/msal-browser';
|
||||||
import { useAccount, useMsal } from '@azure/msal-react';
|
import { useAccount, useMsal } from '@azure/msal-react';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import { get } from 'lodash';
|
|
||||||
import React, {
|
import React, {
|
||||||
forwardRef,
|
forwardRef,
|
||||||
Fragment,
|
Fragment,
|
||||||
ReactNode,
|
ReactNode,
|
||||||
|
useEffect,
|
||||||
useImperativeHandle,
|
useImperativeHandle,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { useApplicationStore } from '../../../hooks/useApplicationStore';
|
import {
|
||||||
import { msalLoginRequest } from '../../../utils/AuthProvider.util';
|
msalLoginRequest,
|
||||||
|
parseMSALResponse,
|
||||||
|
} from '../../../utils/AuthProvider.util';
|
||||||
import { getPopupSettingLink } from '../../../utils/BrowserUtils';
|
import { getPopupSettingLink } from '../../../utils/BrowserUtils';
|
||||||
import { Transi18next } from '../../../utils/CommonUtils';
|
import { Transi18next } from '../../../utils/CommonUtils';
|
||||||
|
import Loader from '../../common/Loader/Loader';
|
||||||
import {
|
import {
|
||||||
AuthenticatorRef,
|
AuthenticatorRef,
|
||||||
OidcUser,
|
OidcUser,
|
||||||
UserProfile,
|
|
||||||
} from '../AuthProviders/AuthProvider.interface';
|
} from '../AuthProviders/AuthProvider.interface';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -47,36 +49,10 @@ const MsalAuthenticator = forwardRef<AuthenticatorRef, Props>(
|
|||||||
{ children, onLoginSuccess, onLogoutSuccess, onLoginFailure }: Props,
|
{ children, onLoginSuccess, onLogoutSuccess, onLoginFailure }: Props,
|
||||||
ref
|
ref
|
||||||
) => {
|
) => {
|
||||||
const { setOidcToken } = useApplicationStore();
|
const { instance, accounts, inProgress } = useMsal();
|
||||||
const { instance, accounts } = useMsal();
|
|
||||||
const account = useAccount(accounts[0] || {});
|
const account = useAccount(accounts[0] || {});
|
||||||
|
|
||||||
const parseResponse = (response: AuthenticationResult): OidcUser => {
|
const handleOnLogoutSuccess = async () => {
|
||||||
// Call your API with the access token and return the data you need to save in state
|
|
||||||
const { idToken, scopes, account } = response;
|
|
||||||
|
|
||||||
const user = {
|
|
||||||
id_token: idToken,
|
|
||||||
scope: scopes.join(),
|
|
||||||
profile: {
|
|
||||||
email: get(account, 'idTokenClaims.email', ''),
|
|
||||||
name: account?.name || '',
|
|
||||||
picture: '',
|
|
||||||
preferred_username: get(
|
|
||||||
account,
|
|
||||||
'idTokenClaims.preferred_username',
|
|
||||||
''
|
|
||||||
),
|
|
||||||
sub: get(account, 'idTokenClaims.sub', ''),
|
|
||||||
} as UserProfile,
|
|
||||||
};
|
|
||||||
|
|
||||||
setOidcToken(idToken);
|
|
||||||
|
|
||||||
return user;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOnLogoutSuccess = () => {
|
|
||||||
for (const key in localStorage) {
|
for (const key in localStorage) {
|
||||||
if (key.includes('-login.windows.net-') || key.startsWith('msal.')) {
|
if (key.includes('-login.windows.net-') || key.startsWith('msal.')) {
|
||||||
localStorage.removeItem(key);
|
localStorage.removeItem(key);
|
||||||
@ -87,9 +63,8 @@ const MsalAuthenticator = forwardRef<AuthenticatorRef, Props>(
|
|||||||
|
|
||||||
const login = async () => {
|
const login = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await instance.loginPopup(msalLoginRequest);
|
// Use login with redirect to avoid popup issue with maximized browser window
|
||||||
|
await instance.loginRedirect();
|
||||||
onLoginSuccess(parseResponse(response));
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
onLoginFailure(error as AxiosError);
|
onLoginFailure(error as AxiosError);
|
||||||
}
|
}
|
||||||
@ -109,7 +84,7 @@ const MsalAuthenticator = forwardRef<AuthenticatorRef, Props>(
|
|||||||
try {
|
try {
|
||||||
const response = await instance.ssoSilent(tokenRequest);
|
const response = await instance.ssoSilent(tokenRequest);
|
||||||
|
|
||||||
return parseResponse(response);
|
return parseMSALResponse(response);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (
|
if (
|
||||||
error instanceof InteractionRequiredAuthError &&
|
error instanceof InteractionRequiredAuthError &&
|
||||||
@ -138,7 +113,7 @@ const MsalAuthenticator = forwardRef<AuthenticatorRef, Props>(
|
|||||||
throw e;
|
throw e;
|
||||||
});
|
});
|
||||||
|
|
||||||
return parseResponse(response);
|
return parseMSALResponse(response);
|
||||||
} else {
|
} else {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@ -160,6 +135,32 @@ const MsalAuthenticator = forwardRef<AuthenticatorRef, Props>(
|
|||||||
renewIdToken: renewIdToken,
|
renewIdToken: renewIdToken,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// Need to capture redirect and parse ID token
|
||||||
|
// Call login success callback
|
||||||
|
const handleRedirect = async () => {
|
||||||
|
try {
|
||||||
|
const response = await instance.handleRedirectPromise();
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
const user = parseMSALResponse(response);
|
||||||
|
|
||||||
|
onLoginSuccess(user);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
onLoginFailure(error as AxiosError);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// To add redirect callback
|
||||||
|
useEffect(() => {
|
||||||
|
instance && handleRedirect();
|
||||||
|
}, [instance]);
|
||||||
|
|
||||||
|
// Show loader until the interaction is completed
|
||||||
|
if (inProgress !== InteractionStatus.None) {
|
||||||
|
return <Loader />;
|
||||||
|
}
|
||||||
|
|
||||||
return <Fragment>{children}</Fragment>;
|
return <Fragment>{children}</Fragment>;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -459,16 +459,21 @@ export const AuthProvider = ({
|
|||||||
}
|
}
|
||||||
}, [location.pathname, storeRedirectPath]);
|
}, [location.pathname, storeRedirectPath]);
|
||||||
|
|
||||||
const updateAuthInstance = (configJson: AuthenticationConfiguration) => {
|
const updateAuthInstance = async (
|
||||||
|
configJson: AuthenticationConfiguration
|
||||||
|
) => {
|
||||||
const { provider, ...otherConfigs } = configJson;
|
const { provider, ...otherConfigs } = configJson;
|
||||||
switch (provider) {
|
switch (provider) {
|
||||||
case AuthProviderEnum.Azure:
|
case AuthProviderEnum.Azure:
|
||||||
{
|
{
|
||||||
setMsalInstance(
|
const instance = new PublicClientApplication(
|
||||||
new PublicClientApplication(
|
otherConfigs as unknown as Configuration
|
||||||
otherConfigs as unknown as Configuration
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Need to initialize the instance before setting it
|
||||||
|
await instance.initialize();
|
||||||
|
|
||||||
|
setMsalInstance(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
AuthenticationResult,
|
||||||
BrowserCacheLocation,
|
BrowserCacheLocation,
|
||||||
Configuration,
|
Configuration,
|
||||||
PopupRequest,
|
PopupRequest,
|
||||||
@ -32,6 +33,7 @@ import {
|
|||||||
ClientType,
|
ClientType,
|
||||||
} from '../generated/configuration/authenticationConfiguration';
|
} from '../generated/configuration/authenticationConfiguration';
|
||||||
import { AuthProvider } from '../generated/settings/settings';
|
import { AuthProvider } from '../generated/settings/settings';
|
||||||
|
import { useApplicationStore } from '../hooks/useApplicationStore';
|
||||||
import { isDev } from './EnvironmentUtils';
|
import { isDev } from './EnvironmentUtils';
|
||||||
|
|
||||||
const cookieStorage = new CookieStorage();
|
const cookieStorage = new CookieStorage();
|
||||||
@ -412,3 +414,26 @@ export const prepareUserProfileFromClaims = ({
|
|||||||
|
|
||||||
return newUser;
|
return newUser;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Responsible for parsing the response from MSAL AuthenticationResult
|
||||||
|
export const parseMSALResponse = (response: AuthenticationResult): OidcUser => {
|
||||||
|
// Call your API with the access token and return the data you need to save in state
|
||||||
|
const { idToken, scopes, account } = response;
|
||||||
|
const { setOidcToken } = useApplicationStore.getState();
|
||||||
|
|
||||||
|
const user = {
|
||||||
|
id_token: idToken,
|
||||||
|
scope: scopes.join(),
|
||||||
|
profile: {
|
||||||
|
email: get(account, 'idTokenClaims.email', ''),
|
||||||
|
name: account?.name ?? '',
|
||||||
|
picture: '',
|
||||||
|
preferred_username: get(account, 'idTokenClaims.preferred_username', ''),
|
||||||
|
sub: get(account, 'idTokenClaims.sub', ''),
|
||||||
|
} as UserProfile,
|
||||||
|
};
|
||||||
|
|
||||||
|
setOidcToken(idToken);
|
||||||
|
|
||||||
|
return user;
|
||||||
|
};
|
||||||
|
@ -160,22 +160,22 @@
|
|||||||
promise-polyfill "^8.2.1"
|
promise-polyfill "^8.2.1"
|
||||||
unfetch "^4.2.0"
|
unfetch "^4.2.0"
|
||||||
|
|
||||||
"@azure/msal-browser@^3.10.0":
|
"@azure/msal-browser@^3.25.0":
|
||||||
version "3.10.0"
|
version "3.25.0"
|
||||||
resolved "https://registry.yarnpkg.com/@azure/msal-browser/-/msal-browser-3.10.0.tgz#8925659e8d1a4bd21e389cca4683eb52658c778e"
|
resolved "https://registry.yarnpkg.com/@azure/msal-browser/-/msal-browser-3.25.0.tgz#7ce0949977bc9e0c58319f7090c44fe5537104d4"
|
||||||
integrity sha512-mnmi8dCXVNZI+AGRq0jKQ3YiodlIC4W9npr6FCB9WN6NQT+6rq+cIlxgUb//BjLyzKsnYo+i4LROGeMyU+6v1A==
|
integrity sha512-a0Y7pmSy8SC1s9bvwr+REvyAA1nQcITlZvkElM2gNUPYFTTNUTEdcpg73TmawNucyMdZ9xb/GFcuhrLOqYAzwg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@azure/msal-common" "14.7.1"
|
"@azure/msal-common" "14.15.0"
|
||||||
|
|
||||||
"@azure/msal-common@14.7.1":
|
"@azure/msal-common@14.15.0":
|
||||||
version "14.7.1"
|
version "14.15.0"
|
||||||
resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-14.7.1.tgz#b13443fbacc87ce2019a91e81a6582ea73847c75"
|
resolved "https://registry.yarnpkg.com/@azure/msal-common/-/msal-common-14.15.0.tgz#0e27ac0bb88fe100f4f8d1605b64d5c268636a55"
|
||||||
integrity sha512-v96btzjM7KrAu4NSEdOkhQSTGOuNUIIsUdB8wlyB9cdgl5KqEKnTonHUZ8+khvZ6Ap542FCErbnTyDWl8lZ2rA==
|
integrity sha512-ImAQHxmpMneJ/4S8BRFhjt1MZ3bppmpRPYYNyzeQPeFN288YKbb8TmmISQEbtfkQ1BPASvYZU5doIZOPBAqENQ==
|
||||||
|
|
||||||
"@azure/msal-react@^2.0.12":
|
"@azure/msal-react@^2.1.1":
|
||||||
version "2.0.12"
|
version "2.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/@azure/msal-react/-/msal-react-2.0.12.tgz#f33c84a57663307fcf3707ca17d9ce2d7934a048"
|
resolved "https://registry.yarnpkg.com/@azure/msal-react/-/msal-react-2.1.1.tgz#d61cd8698d3963ffff685377ece487d7ad5bc111"
|
||||||
integrity sha512-23HKdajBWQ5SSzcwwFKHAWaOCpq4UCthoOBgKpab3UoHx0OuFMQiq6CrNBzBKtBFdyxCjadBGzWshRgl0Nvk1g==
|
integrity sha512-XOBgAR0fbkfUUkQZyhIlwAZiy8WIzNWxAAFacJgyL8LiE2Y5pgM9var9X0Jh7Oz/1Oy5lhTQDtCYWSMHmTZ84Q==
|
||||||
|
|
||||||
"@babel/code-frame@7.12.11":
|
"@babel/code-frame@7.12.11":
|
||||||
version "7.12.11"
|
version "7.12.11"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user