Auth: Auth Drawer (#83910)

* add drawer for auth settings

* add auth drawer component

* include AuthDrawer component in auth providers page

* protect the feature as enterprise only

* add unit test
This commit is contained in:
linoman 2024-03-06 10:27:55 -06:00 committed by GitHub
parent 6731aacea9
commit 6287e1f8ed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 141 additions and 2 deletions

View File

@ -0,0 +1,22 @@
import { render, screen } from '@testing-library/react';
import React from 'react';
import { AuthDrawer, Props } from './AuthDrawer';
const defaultProps: Props = {
onClose: jest.fn(),
};
async function getTestContext(overrides: Partial<Props> = {}) {
jest.clearAllMocks();
const props = { ...defaultProps, ...overrides };
const { rerender } = render(<AuthDrawer {...props} />);
return { rerender, props };
}
it('should render with default props', async () => {
await getTestContext({});
expect(screen.getByText(/Enable insecure email lookup/i)).toBeInTheDocument();
});

View File

@ -0,0 +1,104 @@
import { css } from '@emotion/css';
import React, { useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
import { Button, Drawer, Text, TextLink, Switch, useStyles2 } from '@grafana/ui';
export interface Props {
onClose: () => void;
}
const SETTINGS_URL = '/api/admin/settings';
export const AuthDrawer = ({ onClose }: Props) => {
const [isOauthAllowInsecureEmailLookup, setOauthAllowInsecureEmailLookup] = useState(false);
const getSettings = async () => {
try {
const response = await getBackendSrv().get(SETTINGS_URL);
setOauthAllowInsecureEmailLookup(response.auth.oauth_allow_insecure_email_lookup?.toLowerCase?.() === 'true');
} catch (error) {}
};
const updateSettings = async (property: boolean) => {
try {
const body = {
updates: {
auth: {
oauth_allow_insecure_email_lookup: '' + property,
},
},
};
await getBackendSrv().put(SETTINGS_URL, body);
} catch (error) {}
};
const resetButtonOnClick = async () => {
try {
const body = {
removals: {
auth: ['oauth_allow_insecure_email_lookup'],
},
};
await getBackendSrv().put(SETTINGS_URL, body);
getSettings();
} catch (error) {}
};
const oauthAllowInsecureEmailLookupOnChange = async () => {
updateSettings(!isOauthAllowInsecureEmailLookup);
setOauthAllowInsecureEmailLookup(!isOauthAllowInsecureEmailLookup);
};
const subtitle = (
<>
Configure auth settings. Find out more in our{' '}
<TextLink
external={true}
href="https://grafana.com/docs/grafana/next/setup-grafana/configure-security/configure-authentication/#settings"
>
documentation
</TextLink>
.
</>
);
const styles = useStyles2(getStyles);
getSettings();
return (
<Drawer title="Auth Settings" subtitle={subtitle} size="md" onClose={onClose}>
<div className={styles.advancedAuth}>
<Text variant="h4">Advanced Auth</Text>
<Text variant="h5">Enable insecure email lookup</Text>
<Text variant="body" color="secondary">
Allow users to use the same email address to log into Grafana with different identity providers.
</Text>
<Switch value={isOauthAllowInsecureEmailLookup} onChange={oauthAllowInsecureEmailLookupOnChange} />
</div>
<Button
size="md"
variant="secondary"
className={styles.button}
onClick={resetButtonOnClick}
tooltip="This action will disregard any saved changes and load the configuration from the configuration file."
>
Reset
</Button>
</Drawer>
);
};
const getStyles = (theme: GrafanaTheme2) => {
return {
advancedAuth: css({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(1),
}),
button: css({
marginTop: theme.spacing(2),
}),
};
};

View File

@ -1,11 +1,14 @@
import React, { JSX, useEffect } from 'react';
import React, { JSX, useEffect, useState } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { GrafanaEdition } from '@grafana/data/src/types/config';
import { reportInteraction } from '@grafana/runtime';
import { Grid, TextLink } from '@grafana/ui';
import { Grid, TextLink, ToolbarButton } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page';
import { config } from 'app/core/config';
import { StoreState } from 'app/types';
import { AuthDrawer } from './AuthDrawer';
import ConfigureAuthCTA from './components/ConfigureAuthCTA';
import { ProviderCard } from './components/ProviderCard';
import { loadSettings } from './state/actions';
@ -41,6 +44,8 @@ export const AuthConfigPageUnconnected = ({
loadSettings();
}, [loadSettings]);
const [showDrawer, setShowDrawer] = useState(false);
const authProviders = getRegisteredAuthProviders();
const availableProviders = authProviders.filter((p) => !providerStatuses[p.id]?.hide);
const onProviderCardClick = (providerType: string, enabled: boolean) => {
@ -71,6 +76,13 @@ export const AuthConfigPageUnconnected = ({
.
</>
}
actions={
config.buildInfo.edition !== GrafanaEdition.OpenSource && (
<ToolbarButton icon="cog" variant="canvas" onClick={() => setShowDrawer(true)}>
Auth settings
</ToolbarButton>
)
}
>
<Page.Contents isLoading={isLoading}>
{!providerList.length ? (
@ -91,6 +103,7 @@ export const AuthConfigPageUnconnected = ({
configPath={settings.configPath}
/>
))}
{showDrawer && <AuthDrawer onClose={() => setShowDrawer(false)}></AuthDrawer>}
</Grid>
)}
</Page.Contents>