Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add access control #10222

Merged
merged 182 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
182 commits
Select commit Hold shift + click to select a range
c929cec
Add useCanAccess hook
djhi Sep 18, 2024
0c3e8f5
Add access control to resource views
djhi Sep 18, 2024
af8dab3
Cleanup tests output
djhi Sep 18, 2024
3d1f48e
Add access control to ResourceMenuItem
djhi Sep 18, 2024
85dc156
Fix first resource detection
djhi Sep 18, 2024
80cf005
Reorganize stories
djhi Sep 19, 2024
2931d3c
Add tests for first resource detection
djhi Sep 19, 2024
2685254
Fix Admin documentation
djhi Sep 19, 2024
7dbc256
Add <CanAccess>
djhi Sep 19, 2024
69678c6
Apply suggestions from code review
djhi Sep 19, 2024
2b63cfe
Refactor useFirstResourceWithListAccess
djhi Sep 19, 2024
769cdfb
Reorganize Resource tests
djhi Sep 19, 2024
7323384
Improve ResourceMenuItem stories
djhi Sep 19, 2024
4d25054
Add default Unauthorized component to ra-ui-materialui
djhi Sep 19, 2024
484f728
Handle errors in canAccess hooks
djhi Sep 19, 2024
469ae82
Update authProvider documentation
djhi Sep 19, 2024
47e6836
Add missing export
djhi Sep 19, 2024
a5b0d45
Improve typings on useCanAccess & useCanAccessResources
djhi Sep 20, 2024
0b1252e
Add access control to views buttons
djhi Sep 20, 2024
6f13406
Pass the current record when available
djhi Sep 20, 2024
a789e19
Add documentation
djhi Sep 20, 2024
33fc627
Add CreateButton tests
djhi Sep 20, 2024
0c71f04
Improve canAccess hooks types
djhi Sep 20, 2024
e6e435e
Add EditButton tests
djhi Sep 20, 2024
c158c88
Add ShowButton tests
djhi Sep 20, 2024
9d730d6
Add ListButton tests
djhi Sep 20, 2024
c23e4f5
Add access control to DeleteButton
djhi Sep 20, 2024
a8be1f3
Fix other buttons stories
djhi Sep 20, 2024
afd578d
Add DeleteButton tests
djhi Sep 20, 2024
4472472
Apply suggestions from code review
djhi Sep 20, 2024
582b3de
Fix build
djhi Sep 23, 2024
fd77b62
Fix Unauthorized
djhi Sep 23, 2024
9cdc380
Fix useCanAccessResources documentation
djhi Sep 23, 2024
538c461
Fix CanAccess tests
djhi Sep 23, 2024
5861e9e
Fix types and exports
djhi Sep 23, 2024
97bdba1
Remove unnecessary fragment
djhi Sep 23, 2024
95485f0
Fix auth documentation
djhi Sep 23, 2024
76f32b2
Update Unauthorized design
djhi Sep 23, 2024
b40d39c
Apply suggestions from code review
djhi Sep 23, 2024
5c4251e
Update useCanAccess documentation
djhi Sep 23, 2024
82d33a0
Update useCanAccessResources documentation
djhi Sep 23, 2024
98336dc
Refactor canAccess hooks
djhi Sep 23, 2024
1d70577
Remove wrong prop
djhi Sep 23, 2024
5918515
Pessimistic authentication checks
djhi Sep 25, 2024
08258c9
Better design of authenticationError
djhi Sep 25, 2024
7d21e19
Update Admin documentation
djhi Sep 25, 2024
e6992b2
Fix default AuthenticationError and Unauthorized design and API
djhi Sep 25, 2024
680ee68
Update AuthenticationError documentation screenshot
djhi Sep 25, 2024
0a9ad7d
Simplify useListController auth check
djhi Sep 25, 2024
2cdea62
Fix useListController security story
djhi Sep 25, 2024
bff6f96
useListController security story design
djhi Sep 25, 2024
bb42e52
Avoid a rerender with useAuthState when no AuthProvider is set
djhi Sep 25, 2024
09505c4
Add authentication check to useEditController
djhi Sep 25, 2024
805a7c4
Add authentication check to useInfiniteListController
djhi Sep 25, 2024
b4c97c0
Add authentication check to useShowController
djhi Sep 25, 2024
21661bb
Simplify stories
djhi Sep 25, 2024
b2c828b
Fix typo in tests
djhi Sep 25, 2024
8455d7d
Improve tests
djhi Sep 25, 2024
b2f759b
Don't set logoutOnFailure to its default
djhi Sep 25, 2024
93099ef
Fix disableAuthentication
djhi Sep 25, 2024
2c8ce0b
Restore Resource access control
djhi Sep 25, 2024
1b84ccf
Apply suggestions from code review
fzaninotto Sep 26, 2024
87e65ba
Fix linter warnings
fzaninotto Sep 26, 2024
12d762e
Merge pull request #10238 from marmelab/pessimistic-authentication-ch…
fzaninotto Sep 26, 2024
98cf688
Introduce useRequireAccess
djhi Sep 27, 2024
ea857f0
Move access control from Resource to useShowController
djhi Sep 27, 2024
dace0e9
Move access control from Resource to useEditController
djhi Sep 27, 2024
eb61992
Move access control from Resource to useListController
djhi Sep 27, 2024
c02f540
Move access control from Resource to useCreateController
djhi Sep 27, 2024
079f4f5
Remove unnecessary contexts
djhi Sep 30, 2024
a78a2aa
Refactor CanAccess
djhi Sep 30, 2024
28d2b02
Add access control to useInfiniteController
djhi Sep 30, 2024
b1f0e00
Fix CanAccess js docs
djhi Sep 30, 2024
782b485
Avoid redirecting to /authentication-error in useCanAccess
djhi Sep 30, 2024
a552b5f
Remove old canAccess documentation
djhi Sep 30, 2024
97e85fa
Fix CanAccess documentation
djhi Sep 30, 2024
dafdc56
Update documentation
djhi Sep 30, 2024
f595820
Handle errors in <CanAccess>
djhi Sep 30, 2024
12f0777
Better useRequireAccess example
djhi Sep 30, 2024
009b852
Improve useRequireAccess tests
djhi Sep 30, 2024
de52132
Improve useRequireAccess jsDoc
djhi Sep 30, 2024
d3804d3
Revert unnecessary changes
djhi Sep 30, 2024
b4ca86b
Set the default unauthorized prop in ra-ui-materialui
djhi Sep 30, 2024
c429d46
Apply suggestions from code review
djhi Oct 1, 2024
53b24e8
Remove premium icons for non enterprise features
djhi Oct 1, 2024
766c5b5
Rename unauthorized to accessDenied
djhi Oct 1, 2024
a8adf6e
Make access control calls dependant on auth check calls
djhi Oct 1, 2024
36ec547
Rename image
djhi Oct 1, 2024
34b1c1c
Fix useRequireAccess documentation
djhi Oct 1, 2024
00e33cf
Simplify stories
djhi Oct 1, 2024
c0b26e0
Merge pull request #10247 from marmelab/access-control-controllers
fzaninotto Oct 1, 2024
4b04c41
Merge branch 'access-control-resources' into access-control-buttons
djhi Oct 1, 2024
a6df775
Improve stories names
djhi Oct 1, 2024
738b273
Merge branch 'access-control-buttons' into access-control-delete-buttons
djhi Oct 1, 2024
2b718fb
Add access control to `<Datagrid rowClick>`
djhi Sep 20, 2024
e238966
Use Record<string, any> instead of RaRecord
djhi Oct 1, 2024
b37cf6d
Merge branch 'access-control-buttons' into access-control-rowclick
djhi Oct 1, 2024
2419a2e
Fix useCanAccessCallback
djhi Oct 1, 2024
c84dff7
Merge pull request #10225 from marmelab/access-control-buttons
fzaninotto Oct 1, 2024
b569075
Merge pull request #10226 from marmelab/access-control-delete-buttons
fzaninotto Oct 1, 2024
9267276
[Doc] Rewrite access control documentation
fzaninotto Sep 30, 2024
a866f3a
Review
fzaninotto Oct 1, 2024
6556df4
Document access control in views
fzaninotto Oct 1, 2024
7ebb52f
Document controllers
fzaninotto Oct 1, 2024
c083814
Fix build
fzaninotto Oct 1, 2024
b2e2eeb
Add mention of built-in access control in action buttons
fzaninotto Oct 1, 2024
f2bc053
Merge branch 'next' into access-control-resources
fzaninotto Oct 1, 2024
d0172f9
Document buttons
fzaninotto Oct 1, 2024
38f2d17
Fix buttons doc
fzaninotto Oct 1, 2024
c88e259
Make Authenticated component secure by default
fzaninotto Oct 1, 2024
6b82a78
Fix useCanAccess result type
djhi Oct 2, 2024
8347890
Merge branch 'access-control-resources' into access-control-rowclick
djhi Oct 2, 2024
0053e0f
Update navigation and reference
djhi Oct 2, 2024
2202c9c
Apply suggestions from code review
fzaninotto Oct 2, 2024
259d6f0
Remove unnecessary canAccess calls in useGetPathForRecord
djhi Oct 2, 2024
6fb0f3a
Add tests and stories
djhi Oct 2, 2024
71f74d4
Add tests and stories for ReferenceField
djhi Oct 2, 2024
b5edf22
Merge pull request #10251 from marmelab/authenticated-pessimistic
djhi Oct 2, 2024
31934d7
Only check access rights for inferred link types
djhi Oct 2, 2024
bababb4
Revert unnecessary changes on useGetPathForRecord
djhi Oct 2, 2024
b5dabbf
Introduce `<NavigateToFirstResource>`
djhi Oct 2, 2024
c0549b4
Better formatting in documentation
djhi Oct 2, 2024
f789795
Add mention of authentication
fzaninotto Oct 3, 2024
1a43739
Merge pull request #10250 from marmelab/access-control-doc
fzaninotto Oct 3, 2024
e7c8541
Fix ShowBase should accept a ReactNode
djhi Oct 3, 2024
dfcbfe9
Reuse HintedString in useCreatePath
djhi Oct 3, 2024
10a1c76
Refactor useGetPathForRecord to leverage react-query
djhi Oct 3, 2024
439ab27
Add tests and stories for useGetPathForRecordCallback and improve can…
djhi Oct 3, 2024
3a05c9c
Improve ReferenceField tests and stories
djhi Oct 3, 2024
04fffab
Apply review suggestions
djhi Oct 3, 2024
fe49131
Merge branch 'access-control-first-resource' of github.com:marmelab/r…
djhi Oct 3, 2024
61b14c8
Export NavigateToFirstResource
djhi Oct 3, 2024
0481fb0
Reintroduce CreatePathType
djhi Oct 3, 2024
b7cfad2
Improve tests and stories
djhi Oct 3, 2024
2b76791
Add Datagrid story
djhi Oct 3, 2024
ed77a48
Add documentation
djhi Oct 3, 2024
2246a5d
Throw an error when no resources are found
djhi Oct 3, 2024
cffa9b4
Mibor tweaks
fzaninotto Oct 3, 2024
bdf0c99
Revert change on useGetPathForRecord and explain in comments
djhi Oct 3, 2024
8d02eda
Merge pull request #10227 from marmelab/access-control-rowclick
fzaninotto Oct 3, 2024
ad12e41
Remove the error
djhi Oct 3, 2024
d1be9bb
Merge pull request #10255 from marmelab/access-control-first-resource
fzaninotto Oct 3, 2024
44dc614
[Doc] Overhaul Auth introduction and auth provider writing chapters
fzaninotto Oct 3, 2024
4bdcf84
Reorganize auth doc
fzaninotto Oct 3, 2024
54b3522
Fix Admin authenticationError documentation
fzaninotto Oct 3, 2024
68c4066
Make authProvider.getPermissions optional
djhi Oct 4, 2024
c53bc86
Cleanup
djhi Oct 4, 2024
ec56f9f
Add story and screencast
fzaninotto Oct 4, 2024
86f1474
Merge pull request #10257 from marmelab/optional-authprovider-getperm…
fzaninotto Oct 4, 2024
40adf7d
Introduce useIsAuthPending
djhi Oct 4, 2024
18620e6
Ensure List check auth states pessimistically
djhi Oct 4, 2024
483d84c
Ensure InfiniteList check auth states pessimistically
djhi Oct 4, 2024
99ab061
Ensure Create check auth states pessimistically
djhi Oct 4, 2024
bb78db5
Ensure Edit check auth states pessimistically
djhi Oct 4, 2024
75c9ba5
Ensure Show check auth states pessimistically
djhi Oct 4, 2024
515c326
[Doc] Update requireAuth explanation
fzaninotto Oct 4, 2024
e6b2df3
[doc] Clarify that `getPermissions` is now optional
fzaninotto Oct 4, 2024
ecd4461
Proofreading
fzaninotto Oct 4, 2024
6076cf4
Ensure devs can provide their own loading
djhi Oct 4, 2024
41e9853
Ensure a ResourceContext is added only when needed
djhi Oct 4, 2024
abd28a2
Fix Resource documentation
fzaninotto Oct 4, 2024
d09d409
Fix missing export
fzaninotto Oct 4, 2024
ee520bb
Remove links to deleted chapters
fzaninotto Oct 4, 2024
581ac7a
Fix typo
fzaninotto Oct 4, 2024
842cd2f
Proofreading
fzaninotto Oct 4, 2024
5a2df6c
Add stories and tests for ListBase
djhi Oct 4, 2024
4e98cb6
Add stories and tests for InfiniteListBase
djhi Oct 4, 2024
fa587fd
Fix useAuthState is optimistic
fzaninotto Oct 4, 2024
68b92d5
Fix mention of optimistic default auth
fzaninotto Oct 4, 2024
8370f97
Add message to future me
fzaninotto Oct 4, 2024
5b4a06c
Update docs/CustomRoutes.md
fzaninotto Oct 4, 2024
6b984f1
Fix type
fzaninotto Oct 4, 2024
ff5b916
Fix useCanAccessResources should not log out on error
fzaninotto Oct 4, 2024
7008b31
Add stories and tests for Create
djhi Oct 4, 2024
34dfce2
Fix useCreateController isPending is always true if disableAuthentica…
fzaninotto Oct 4, 2024
0fee4fd
Add stories and tests for Edit
djhi Oct 4, 2024
3a6c3a8
Add stories and tests for Show
djhi Oct 4, 2024
8a8cead
Fix new auth error pages can't be overridden
fzaninotto Oct 4, 2024
a60d5e6
Ensure dashboard waits for all auth calls resolutions
djhi Oct 4, 2024
30924a4
Merge pull request #10258 from marmelab/access-control-views-loading
fzaninotto Oct 4, 2024
5e26e1f
Fix message key
fzaninotto Oct 4, 2024
452253d
Allow requireAuth to use react-query cache
djhi Oct 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add default Unauthorized component to ra-ui-materialui
  • Loading branch information
djhi committed Sep 19, 2024
commit 4d25054471fc6ff7f0a61157f01649bf3642197a
2 changes: 2 additions & 0 deletions docs/Admin.md
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,8 @@ const MyTitle = () => {

When using an authProvider that supports [the `canAccess` method](./AuthProviderWriting.md#canaccess), react-admin will check whether users can access a resource page and display the `unauthorized` component when they can't.

fzaninotto marked this conversation as resolved.
Show resolved Hide resolved
![Default unauthorized component](./img/unauthorized.png)

You can replace the default "unauthorized" screen by passing a custom component as the `unauthorized` prop:

```tsx
Expand Down
Binary file added docs/img/unauthorized.png
fzaninotto marked this conversation as resolved.
Show resolved Hide resolved
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 1 addition & 2 deletions packages/ra-core/src/core/CoreAdminContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
DashboardComponent,
LegacyDataProvider,
LoadingComponent,
UnauthorizedComponent,
} from '../types';
import { LoadingContextProvider } from './LoadingContextProvider';
import { UnauthorizedContextProvider } from './UnauthorizedContextProvider';
Expand Down Expand Up @@ -203,7 +202,7 @@ export interface CoreAdminContextProps {
* </Admin>
* );
*/
unauthorized?: UnauthorizedComponent;
unauthorized?: React.ComponentType;
}

export const CoreAdminContext = (props: CoreAdminContextProps) => {
Expand Down
7 changes: 2 additions & 5 deletions packages/ra-core/src/core/UnauthorizedContext.tsx
fzaninotto marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import { createContext } from 'react';
import { UnauthorizedComponent } from '../types';
import { ComponentType, createContext } from 'react';

export const UnauthorizedContext = createContext<UnauthorizedComponent>(
() => null
);
export const UnauthorizedContext = createContext<ComponentType>(() => null);
1 change: 0 additions & 1 deletion packages/ra-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,6 @@ export type AdminChildren =

export type TitleComponent = string | ReactElement<any>;
export type CatchAllComponent = ComponentType<{ title?: TitleComponent }>;
export type UnauthorizedComponent = ComponentType<{ title?: TitleComponent }>;

export type LoginComponent = ComponentType<{}> | ReactElement<any>;
export type DashboardComponent = ComponentType<WithPermissionsChildrenParams>;
Expand Down
3 changes: 3 additions & 0 deletions packages/ra-language-english/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const englishMessages: TranslationMessages = {
show: '%{name} %{recordRepresentation}',
empty: 'No %{name} yet.',
invite: 'Do you want to add one?',
unauthorized: 'Unauthorized',
},
input: {
file: {
Expand Down Expand Up @@ -110,6 +111,8 @@ const englishMessages: TranslationMessages = {
yes: 'Yes',
unsaved_changes:
"Some of your changes weren't saved. Are you sure you want to ignore them?",
unauthorized:
"You don't have the right permissions to access this page",
},
navigation: {
clear_filters: 'Clear filters',
Expand Down
2 changes: 2 additions & 0 deletions packages/ra-language-french/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const frenchMessages: TranslationMessages = {
show: '%{name} %{recordRepresentation}',
empty: 'Pas encore de %{name}.',
invite: 'Voulez-vous en créer un ?',
unauthorized: 'Non autorisé',
},
input: {
file: {
Expand Down Expand Up @@ -115,6 +116,7 @@ const frenchMessages: TranslationMessages = {
yes: 'Oui',
unsaved_changes:
"Certains changements n'ont pas été enregistrés. Êtes-vous sûr(e) de vouloir quitter cette page ?",
unauthorized: "Vous n'avez pas les droits d'accès à cette page",
},
navigation: {
clear_filters: 'Effacer les filtres',
Expand Down
4 changes: 3 additions & 1 deletion packages/ra-ui-materialui/src/AdminContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
defaultLightTheme,
defaultDarkTheme,
} from './theme';
import { Unauthorized } from './layout/Unauthorized';

export const AdminContext = (props: AdminContextProps) => {
const {
Expand All @@ -16,10 +17,11 @@ export const AdminContext = (props: AdminContextProps) => {
darkTheme,
defaultTheme,
children,
unauthorized = Unauthorized,
...rest
} = props;
return (
<CoreAdminContext {...rest}>
<CoreAdminContext unauthorized={unauthorized} {...rest}>
<ThemesContext.Provider
value={{
lightTheme: theme || lightTheme,
Expand Down
74 changes: 74 additions & 0 deletions packages/ra-ui-materialui/src/layout/Unauthorized.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import * as React from 'react';
import polyglotI18nProvider from 'ra-i18n-polyglot';
import englishMessages from 'ra-language-english';
import frenchMessages from 'ra-language-french';
import {
I18nContextProvider,
Resource,
testDataProvider,
TestMemoryRouter,
} from 'ra-core';

import { AdminContext } from '../AdminContext';
import { AdminUI } from '../AdminUI';
import { Unauthorized } from './Unauthorized';
import { Link } from 'react-router-dom';

export default {
title: 'ra-ui-materialui/layout/Unauthorized',
};

const i18nProvider = polyglotI18nProvider(
locale => (locale === 'fr' ? frenchMessages : englishMessages),
'en',
[
{ locale: 'en', name: 'English' },
{ locale: 'fr', name: 'Français' },
]
);

export const Basic = () => <Unauthorized />;

export const I18N = () => {
return (
<TestMemoryRouter>
<I18nContextProvider value={i18nProvider}>
<Unauthorized />
</I18nContextProvider>
</TestMemoryRouter>
);
};

const authProvider = {
login: () => Promise.resolve(),
logout: () => Promise.resolve(),
checkAuth: () => Promise.resolve(),
checkError: () => Promise.resolve(),
getPermissions: () => Promise.resolve(),
canAccess: ({ resource }) => Promise.resolve(resource === 'posts'),
};

export const FullApp = () => (
fzaninotto marked this conversation as resolved.
Show resolved Hide resolved
<TestMemoryRouter>
<AdminContext
dataProvider={testDataProvider()}
authProvider={authProvider}
i18nProvider={i18nProvider}
>
<AdminUI>
<Resource name="users" list={UserList} />
<Resource name="posts" list={PostList} />
</AdminUI>
</AdminContext>
</TestMemoryRouter>
);

const UserList = () => <div style={{ marginTop: 10 }}>User list</div>;
const PostList = () => (
<div style={{ marginTop: 10 }}>
<div>Post list</div>
<div>
<Link to="/users">User list</Link>
</div>
</div>
);
59 changes: 59 additions & 0 deletions packages/ra-ui-materialui/src/layout/Unauthorized.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import * as React from 'react';
import { styled } from '@mui/material/styles';
import { Typography, SxProps } from '@mui/material';
import { useTranslate } from 'ra-core';

export const Unauthorized = (props: UnauthorizedProps) => {
const {
className,
unauthorizedPrimary = 'ra.page.unauthorized',
unauthorizedSecondary = 'ra.message.unauthorized',
fzaninotto marked this conversation as resolved.
Show resolved Hide resolved
...rest
} = props;
const translate = useTranslate();
return (
<Root className={className} {...rest}>
<div className={UnauthorizedClasses.message}>
<Typography variant="h5" mt={3} color="text.secondary">
{translate(unauthorizedPrimary, { _: unauthorizedPrimary })}
</Typography>
<Typography variant="body2">
{translate(unauthorizedSecondary, {
_: unauthorizedSecondary,
})}
</Typography>
</div>
</Root>
);
};

export interface UnauthorizedProps {
className?: string;
unauthorizedPrimary?: string;
unauthorizedSecondary?: string;
sx?: SxProps;
}

const PREFIX = 'RaUnauthorized';

export const UnauthorizedClasses = {
root: `${PREFIX}-root`,
fzaninotto marked this conversation as resolved.
Show resolved Hide resolved
message: `${PREFIX}-message`,
};

const Root = styled('div', {
name: PREFIX,
overridesResolver: (props, styles) => styles.root,
})(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
height: '100%',
[`& .${UnauthorizedClasses.message}`]: {
textAlign: 'center',
fontFamily: 'Roboto, sans-serif',
fzaninotto marked this conversation as resolved.
Show resolved Hide resolved
color: theme.palette.text.disabled,
fzaninotto marked this conversation as resolved.
Show resolved Hide resolved
paddingTop: '1em',
paddingBottom: '1em',
},
}));
Loading