[6.8][Security] Add message to login page. (#64158)

This commit is contained in:
Aleh Zasypkin 2020-04-23 08:16:55 +02:00 committed by GitHub
parent 0aea444da8
commit 2baa83bc4b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 163 additions and 12 deletions

View file

@ -54,3 +54,6 @@ routing requests through a load balancer or proxy).
Sets the session duration (in milliseconds). By default, sessions stay active
until the browser is closed. When this is set to an explicit timeout, closing the
browser still requires the user to log back in to {kib}.
`xpack.security.loginAssistanceMessage`::
Adds a message to the login screen. Useful for displaying information about maintenance windows, links to corporate sign up pages etc.

View file

@ -158,6 +158,7 @@ kibana_vars=(
xpack.security.encryptionKey
xpack.security.secureCookies
xpack.security.sessionTimeout
xpack.security.loginAssistanceMessage
xpack.xpack_main.telemetry.enabled
)

View file

@ -38,6 +38,7 @@ export const security = (kibana) => new kibana.Plugin({
encryptionKey: Joi.string(),
sessionTimeout: Joi.number().allow(null).default(null),
secureCookies: Joi.boolean().default(false),
loginAssistanceMessage: Joi.string(),
public: Joi.object({
protocol: Joi.string().valid(['http', 'https']),
hostname: Joi.string().hostname(),
@ -178,6 +179,7 @@ export const security = (kibana) => new kibana.Plugin({
const { showLogin, loginMessage, allowLogin, layout = 'form' } = xpackInfo.feature(plugin.id).getLicenseCheckResults() || {};
return {
loginAssistanceMessage: config.get('xpack.security.loginAssistanceMessage') || '',
loginState: {
showLogin,
allowLogin,

View file

@ -2,6 +2,18 @@
exports[`BasicLoginForm renders as expected 1`] = `
<Fragment>
<EuiText
grow={true}
size="s"
>
<ReactMarkdown
escapeHtml={true}
renderers={Object {}}
skipHtml={false}
source=""
transformLinkUri={[Function]}
/>
</EuiText>
<EuiPanel
grow={true}
hasShadow={false}

View file

@ -50,6 +50,7 @@ describe('BasicLoginForm', () => {
loginState={loginState}
next={''}
intl={null as any}
loginAssistanceMessage=""
/>
)
).toMatchSnapshot();
@ -68,6 +69,7 @@ describe('BasicLoginForm', () => {
next={''}
infoMessage={'Hey this is an info message'}
intl={null as any}
loginAssistanceMessage=""
/>
);
@ -86,6 +88,7 @@ describe('BasicLoginForm', () => {
loginState={loginState}
next={''}
intl={null as any}
loginAssistanceMessage=""
/>
);

View file

@ -4,9 +4,18 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { EuiButton, EuiCallOut, EuiFieldText, EuiFormRow, EuiPanel, EuiSpacer } from '@elastic/eui';
import {
EuiButton,
EuiCallOut,
EuiFieldText,
EuiFormRow,
EuiPanel,
EuiSpacer,
EuiText,
} from '@elastic/eui';
import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
import React, { ChangeEvent, Component, FormEvent, Fragment, MouseEvent } from 'react';
import ReactMarkdown from 'react-markdown';
import { LoginState } from '../../../../../common/login_state';
interface Props {
@ -14,6 +23,7 @@ interface Props {
window: any;
infoMessage?: string;
loginState: LoginState;
loginAssistanceMessage: string;
next: string;
intl: InjectedIntl;
}
@ -38,6 +48,7 @@ class BasicLoginFormUI extends Component<Props, State> {
public render() {
return (
<Fragment>
{this.renderLoginAssistanceMessage()}
{this.renderMessage()}
<EuiPanel>
<form onSubmit={this.submit}>
@ -102,6 +113,16 @@ class BasicLoginFormUI extends Component<Props, State> {
);
}
private renderLoginAssistanceMessage = () => {
return (
<Fragment>
<EuiText size="s">
<ReactMarkdown source={this.props.loginAssistanceMessage} />
</EuiText>
</Fragment>
);
};
private renderMessage = () => {
if (this.state.message) {
return (
@ -132,6 +153,7 @@ class BasicLoginFormUI extends Component<Props, State> {
</Fragment>
);
}
return null;
};

View file

@ -182,6 +182,100 @@ exports[`LoginPage disabled form states renders as expected when an unknown logi
</div>
`;
exports[`LoginPage disabled form states renders as expected when loginAssistanceMessage is set 1`] = `
<div
className="loginWelcome login-form"
>
<header
className="loginWelcome__header"
>
<div
className="loginWelcome__content eui-textCenter"
>
<EuiSpacer
size="xxl"
/>
<span
className="loginWelcome__logo"
>
<EuiIcon
size="xxl"
type="logoKibana"
/>
</span>
<EuiTitle
className="loginWelcome__title"
size="l"
textTransform="none"
>
<h1>
<FormattedMessage
defaultMessage="Welcome to Kibana"
id="xpack.security.loginPage.welcomeTitle"
values={Object {}}
/>
</h1>
</EuiTitle>
<EuiText
className="loginWelcome__subtitle"
color="subdued"
grow={true}
size="s"
>
<p>
<FormattedMessage
defaultMessage="Your window into the Elastic Stack"
id="xpack.security.loginPage.welcomeDescription"
values={Object {}}
/>
</p>
</EuiText>
<EuiSpacer
size="xl"
/>
</div>
</header>
<div
className="loginWelcome__content loginWelcome-body"
>
<EuiFlexGroup
alignItems="stretch"
component="div"
direction="row"
gutterSize="l"
justifyContent="flexStart"
responsive={true}
wrap={false}
>
<EuiFlexItem
component="div"
grow={true}
>
<InjectIntl(BasicLoginFormUI)
http={
Object {
"post": [MockFunction],
}
}
isSecureConnection={false}
loginAssistanceMessage="This is an *important* message"
loginState={
Object {
"allowLogin": true,
"layout": "form",
"loginMessage": "",
}
}
next=""
requiresSecureConnection={false}
window={Object {}}
/>
</EuiFlexItem>
</EuiFlexGroup>
</div>
</div>
`;
exports[`LoginPage disabled form states renders as expected when secure cookies are required but not present 1`] = `
<div
className="loginWelcome login-form"
@ -440,6 +534,7 @@ exports[`LoginPage enabled form state renders as expected 1`] = `
}
}
isSecureConnection={false}
loginAssistanceMessage=""
loginState={
Object {
"allowLogin": true,

View file

@ -46,6 +46,7 @@ describe('LoginPage', () => {
loginState: createLoginState(),
isSecureConnection: false,
requiresSecureConnection: true,
loginAssistanceMessage: '',
};
expect(shallow(<LoginPage {...props} />)).toMatchSnapshot();
@ -61,6 +62,7 @@ describe('LoginPage', () => {
}),
isSecureConnection: false,
requiresSecureConnection: false,
loginAssistanceMessage: '',
};
expect(shallow(<LoginPage {...props} />)).toMatchSnapshot();
@ -76,6 +78,7 @@ describe('LoginPage', () => {
}),
isSecureConnection: false,
requiresSecureConnection: false,
loginAssistanceMessage: '',
};
expect(shallow(<LoginPage {...props} />)).toMatchSnapshot();
@ -91,6 +94,21 @@ describe('LoginPage', () => {
}),
isSecureConnection: false,
requiresSecureConnection: false,
loginAssistanceMessage: '',
};
expect(shallow(<LoginPage {...props} />)).toMatchSnapshot();
});
it('renders as expected when loginAssistanceMessage is set', () => {
const props = {
http: createMockHttp(),
window: {},
next: '',
loginState: createLoginState(),
isSecureConnection: false,
requiresSecureConnection: false,
loginAssistanceMessage: 'This is an *important* message',
};
expect(shallow(<LoginPage {...props} />)).toMatchSnapshot();
@ -106,6 +124,7 @@ describe('LoginPage', () => {
loginState: createLoginState(),
isSecureConnection: false,
requiresSecureConnection: false,
loginAssistanceMessage: '',
};
expect(shallow(<LoginPage {...props} />)).toMatchSnapshot();

View file

@ -8,16 +8,7 @@ import React, { Component } from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import {
// @ts-ignore
EuiCard,
EuiFlexGroup,
EuiFlexItem,
EuiIcon,
EuiSpacer,
EuiText,
EuiTitle,
} from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui';
import classNames from 'classnames';
import { LoginState } from '../../../../../common/login_state';
import { BasicLoginForm } from '../basic_login_form';
@ -31,6 +22,7 @@ interface Props {
loginState: LoginState;
isSecureConnection: boolean;
requiresSecureConnection: boolean;
loginAssistanceMessage: string;
}
export class LoginPage extends Component<Props, {}> {

View file

@ -38,7 +38,8 @@ interface AnyObject {
$http: AnyObject,
$window: AnyObject,
secureCookies: boolean,
loginState: LoginState
loginState: LoginState,
loginAssistanceMessage: string
) => {
const basePath = chrome.getBasePath();
const next = parseNext($window.location.href, basePath);
@ -58,6 +59,7 @@ interface AnyObject {
loginState={loginState}
isSecureConnection={isSecure}
requiresSecureConnection={secureCookies}
loginAssistanceMessage={loginAssistanceMessage}
next={next}
/>
</I18nContext>,