mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-31 12:39:01 +00:00
* fix(#10190): entities permissions cache issue * chore: update handler name * fix: component name typo * fix: minor issue * add unit test * chore: revert the reset entities permissions changes * chore: reset everything for permissions on logout * test: add unit test * update unit test
This commit is contained in:
parent
be7e6254d9
commit
12a846e35b
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
import ApplicationConfigProvider from 'components/ApplicationConfigProvider/ApplicationConfigProvider';
|
import ApplicationConfigProvider from 'components/ApplicationConfigProvider/ApplicationConfigProvider';
|
||||||
import { AuthProvider } from 'components/authentication/auth-provider/AuthProvider';
|
import { AuthProvider } from 'components/authentication/auth-provider/AuthProvider';
|
||||||
import ErrorBoundry from 'components/ErrorBoundry/ErrorBoundry';
|
import ErrorBoundary from 'components/ErrorBoundary/ErrorBoundary';
|
||||||
import GlobalSearchProvider from 'components/GlobalSearchProvider/GlobalSearchProvider';
|
import GlobalSearchProvider from 'components/GlobalSearchProvider/GlobalSearchProvider';
|
||||||
import PermissionProvider from 'components/PermissionProvider/PermissionProvider';
|
import PermissionProvider from 'components/PermissionProvider/PermissionProvider';
|
||||||
import AppRouter from 'components/router/AppRouter';
|
import AppRouter from 'components/router/AppRouter';
|
||||||
@ -34,7 +34,7 @@ const App: FunctionComponent = () => {
|
|||||||
<div className="content-wrapper" data-testid="content-wrapper">
|
<div className="content-wrapper" data-testid="content-wrapper">
|
||||||
<Router>
|
<Router>
|
||||||
<I18nextProvider i18n={i18n}>
|
<I18nextProvider i18n={i18n}>
|
||||||
<ErrorBoundry>
|
<ErrorBoundary>
|
||||||
<ApplicationConfigProvider>
|
<ApplicationConfigProvider>
|
||||||
<AuthProvider childComponentType={AppRouter}>
|
<AuthProvider childComponentType={AppRouter}>
|
||||||
<HelmetProvider>
|
<HelmetProvider>
|
||||||
@ -50,7 +50,7 @@ const App: FunctionComponent = () => {
|
|||||||
</HelmetProvider>
|
</HelmetProvider>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
</ApplicationConfigProvider>
|
</ApplicationConfigProvider>
|
||||||
</ErrorBoundry>
|
</ErrorBoundary>
|
||||||
</I18nextProvider>
|
</I18nextProvider>
|
||||||
</Router>
|
</Router>
|
||||||
<ToastContainer {...TOAST_OPTIONS} newestOnTop />
|
<ToastContainer {...TOAST_OPTIONS} newestOnTop />
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ErrorBoundary } from 'react-error-boundary';
|
import { ErrorBoundary as ErrorBoundaryWrapper } from 'react-error-boundary';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import { ROUTES } from '../../constants/constants';
|
import { ROUTES } from '../../constants/constants';
|
||||||
import ErrorFallback from './ErrorFallback';
|
import ErrorFallback from './ErrorFallback';
|
||||||
@ -21,7 +21,7 @@ interface Props {
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ErrorBoundry: React.FC<Props> = ({ children }) => {
|
const ErrorBoundary: React.FC<Props> = ({ children }) => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
const onErrorReset = () => {
|
const onErrorReset = () => {
|
||||||
@ -29,10 +29,12 @@ const ErrorBoundry: React.FC<Props> = ({ children }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorBoundary FallbackComponent={ErrorFallback} onReset={onErrorReset}>
|
<ErrorBoundaryWrapper
|
||||||
|
FallbackComponent={ErrorFallback}
|
||||||
|
onReset={onErrorReset}>
|
||||||
{children}
|
{children}
|
||||||
</ErrorBoundary>
|
</ErrorBoundaryWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ErrorBoundry;
|
export default ErrorBoundary;
|
@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { CookieStorage } from 'cookie-storage';
|
import { CookieStorage } from 'cookie-storage';
|
||||||
|
import { isEmpty, isUndefined } from 'lodash';
|
||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import React, {
|
import React, {
|
||||||
createContext,
|
createContext,
|
||||||
@ -166,10 +167,19 @@ const PermissionProvider: FC<PermissionProviderProps> = ({ children }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const resetPermissions = () => {
|
||||||
|
setEntitiesPermission({} as EntityPermissionMap);
|
||||||
|
setPermissions({} as UIPermission);
|
||||||
|
setResourcesPermission({} as UIPermission);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isProtectedRoute(location.pathname)) {
|
if (isProtectedRoute(location.pathname)) {
|
||||||
fetchLoggedInUserPermissions();
|
fetchLoggedInUserPermissions();
|
||||||
}
|
}
|
||||||
|
if (isUndefined(currentUser) || isEmpty(currentUser)) {
|
||||||
|
resetPermissions();
|
||||||
|
}
|
||||||
}, [currentUser]);
|
}, [currentUser]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Collate.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import {
|
||||||
|
act,
|
||||||
|
render,
|
||||||
|
screen,
|
||||||
|
waitForElementToBeRemoved,
|
||||||
|
} from '@testing-library/react';
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import AppState from 'AppState';
|
||||||
|
import React from 'react';
|
||||||
|
import AuthProvider, { useAuthContext } from './AuthProvider';
|
||||||
|
|
||||||
|
jest.mock('react-router-dom', () => ({
|
||||||
|
useHistory: jest.fn().mockReturnValue({ push: jest.fn(), listen: jest.fn() }),
|
||||||
|
useLocation: jest.fn().mockReturnValue({ pathname: 'pathname' }),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('rest/miscAPI', () => ({
|
||||||
|
fetchAuthenticationConfig: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => Promise.resolve()),
|
||||||
|
fetchAuthorizerConfig: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||||
|
}));
|
||||||
|
|
||||||
|
jest.mock('rest/userAPI', () => ({
|
||||||
|
getLoggedInUser: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||||
|
updateUser: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('Test auth provider', () => {
|
||||||
|
it('Logout handler should call the "updateUserDetails" method', async () => {
|
||||||
|
const mockUpdateUserDetails = jest.spyOn(AppState, 'updateUserDetails');
|
||||||
|
const ConsumerComponent = () => {
|
||||||
|
const { onLogoutHandler } = useAuthContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button data-testid="logout-button" onClick={onLogoutHandler}>
|
||||||
|
Logout
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
render(
|
||||||
|
<AuthProvider childComponentType={ConsumerComponent}>
|
||||||
|
<ConsumerComponent />
|
||||||
|
</AuthProvider>
|
||||||
|
);
|
||||||
|
|
||||||
|
await waitForElementToBeRemoved(() => screen.getByTestId('loader'));
|
||||||
|
|
||||||
|
const logoutButton = screen.getByTestId('logout-button');
|
||||||
|
|
||||||
|
expect(logoutButton).toBeInTheDocument();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
userEvent.click(logoutButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockUpdateUserDetails).toHaveBeenCalled();
|
||||||
|
expect(mockUpdateUserDetails).toHaveBeenCalledWith({});
|
||||||
|
});
|
||||||
|
});
|
@ -16,6 +16,7 @@ import { Auth0Provider } from '@auth0/auth0-react';
|
|||||||
import { Configuration } from '@azure/msal-browser';
|
import { Configuration } from '@azure/msal-browser';
|
||||||
import { MsalProvider } from '@azure/msal-react';
|
import { MsalProvider } from '@azure/msal-react';
|
||||||
import { LoginCallback } from '@okta/okta-react';
|
import { LoginCallback } from '@okta/okta-react';
|
||||||
|
import appState from 'AppState';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import { CookieStorage } from 'cookie-storage';
|
import { CookieStorage } from 'cookie-storage';
|
||||||
import { AuthorizerConfiguration } from 'generated/configuration/authorizerConfiguration';
|
import { AuthorizerConfiguration } from 'generated/configuration/authorizerConfiguration';
|
||||||
@ -36,7 +37,6 @@ import { useHistory, useLocation } from 'react-router-dom';
|
|||||||
import axiosClient from 'rest/index';
|
import axiosClient from 'rest/index';
|
||||||
import { fetchAuthenticationConfig, fetchAuthorizerConfig } from 'rest/miscAPI';
|
import { fetchAuthenticationConfig, fetchAuthorizerConfig } from 'rest/miscAPI';
|
||||||
import { getLoggedInUser, updateUser } from 'rest/userAPI';
|
import { getLoggedInUser, updateUser } from 'rest/userAPI';
|
||||||
import appState from '../../../AppState';
|
|
||||||
import { NO_AUTH } from '../../../constants/auth.constants';
|
import { NO_AUTH } from '../../../constants/auth.constants';
|
||||||
import { REDIRECT_PATHNAME, ROUTES } from '../../../constants/constants';
|
import { REDIRECT_PATHNAME, ROUTES } from '../../../constants/constants';
|
||||||
import { ClientErrors } from '../../../enums/axios.enum';
|
import { ClientErrors } from '../../../enums/axios.enum';
|
||||||
@ -133,10 +133,13 @@ export const AuthProvider = ({
|
|||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
authenticatorRef.current?.invokeLogout();
|
authenticatorRef.current?.invokeLogout();
|
||||||
|
|
||||||
|
// reset the user details on logout
|
||||||
|
appState.updateUserDetails({} as User);
|
||||||
|
|
||||||
// remove analytics session on logout
|
// remove analytics session on logout
|
||||||
removeSession();
|
removeSession();
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}, [timeoutId]);
|
}, [timeoutId, appState]);
|
||||||
|
|
||||||
const onRenewIdTokenHandler = () => {
|
const onRenewIdTokenHandler = () => {
|
||||||
return authenticatorRef.current?.renewIdToken();
|
return authenticatorRef.current?.renewIdToken();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user