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 Mock IDP login page and role switcher #172257

Merged
merged 51 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
92686f3
Add Mock IDP login page and role switcher
thomheymann Nov 30, 2023
f1eb108
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Nov 30, 2023
f0a38eb
Separate mock IDP package
thomheymann Nov 30, 2023
58e2e2b
Merge branch 'serverless-role-selector-ui' of https://github.com/thom…
thomheymann Nov 30, 2023
eb34508
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Nov 30, 2023
f1d598f
[CI] Auto-commit changed files from 'node scripts/generate codeowners'
kibanamachine Nov 30, 2023
2e47f43
Update limits
thomheymann Nov 30, 2023
a704a2d
Merge branch 'serverless-role-selector-ui' of https://github.com/thom…
thomheymann Nov 30, 2023
75755eb
Remove translations
thomheymann Nov 30, 2023
a458759
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Nov 30, 2023
0501827
Fix plugin path
thomheymann Nov 30, 2023
84d52cd
Merge branch 'serverless-role-selector-ui' of https://github.com/thom…
thomheymann Nov 30, 2023
f2c74a1
Fix snapshot test
thomheymann Nov 30, 2023
40259a9
Fix offset
thomheymann Nov 30, 2023
848ec7c
Merge branch 'main' of https://github.com/elastic/kibana into serverl…
thomheymann Nov 30, 2023
d6a7623
Fix application usage test
thomheymann Nov 30, 2023
0da9c1c
.
thomheymann Nov 30, 2023
3e2ed38
Only show relevant roles
thomheymann Dec 1, 2023
15ee54a
Merge branch 'main' of https://github.com/elastic/kibana into serverl…
thomheymann Dec 1, 2023
86827f2
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Dec 1, 2023
d341fb5
Fix functional test
thomheymann Dec 1, 2023
0ea1ae3
Merge branch 'serverless-role-selector-ui' of https://github.com/thom…
thomheymann Dec 1, 2023
1f26219
Merge branch 'main' of https://github.com/elastic/kibana into serverl…
thomheymann Dec 1, 2023
933e225
Fix dynamic imports
thomheymann Dec 12, 2023
374d518
Merge branch 'main' of https://github.com/elastic/kibana into serverl…
thomheymann Dec 12, 2023
6805755
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Dec 12, 2023
aaa7c72
Fix cyclic dependencies
thomheymann Dec 12, 2023
10edd06
Merge branch 'serverless-role-selector-ui' of https://github.com/thom…
thomheymann Dec 12, 2023
e52244e
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine Dec 12, 2023
7dd3e44
Fix types
thomheymann Dec 12, 2023
aaece90
Merge branch 'main' into serverless-role-selector-ui
thomheymann Dec 12, 2023
a5f30a9
Merge branch 'main' into pr-172257-mock-idp
azasypkin Jan 3, 2024
d9d2b34
Merge branch 'main' into pr-172257-mock-idp
azasypkin Jan 3, 2024
404d4ab
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Jan 3, 2024
3f6db79
[will be reverted] add debug info
pgayvallet Jan 3, 2024
b14d5ee
Revert "[will be reverted] add debug info"
pgayvallet Jan 3, 2024
a759611
Exclude dev-only packages from `package-map.json`.
azasypkin Jan 3, 2024
65df3a3
Revert unnecessary test/telemetry changes.
azasypkin Jan 3, 2024
5b788e0
Merge branch 'main' into pr-172257-mock-idp
azasypkin Jan 4, 2024
b1cd8ab
Add workaround for missing `mock_idp` plugin in serverless tests.
azasypkin Jan 4, 2024
2aafc3b
Register fake root only in production mode to please Cypress tests th…
azasypkin Jan 4, 2024
b9ab6fa
Merge branch 'main' into serverless-role-selector-ui
kibanamachine Jan 5, 2024
6f6b5af
Apply builkite patch from @delanni
azasypkin Jan 5, 2024
e4c508d
Merge branch 'main' into serverless-role-selector-ui
kibanamachine Jan 5, 2024
b9a3298
Merge branch 'main' into pr-172257-mock-idp
azasypkin Jan 5, 2024
4239759
Merge branch 'main' into pr-172257-mock-idp
azasypkin Jan 11, 2024
ae6aabf
A few minor tweaks.
azasypkin Jan 11, 2024
eaba0ef
Few more tweaks.
azasypkin Jan 11, 2024
a5a08e2
Merge branch 'main' into pr-172257-mock-idp
azasypkin Jan 12, 2024
8294235
Merge branch 'main' into pr-172257-mock-idp
azasypkin Jan 12, 2024
f979aa7
Review#1: move `isDevOnly` check to `getDistPackagesFromRepo`.
azasypkin Jan 12, 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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,7 @@ x-pack/packages/ml/trained_models_utils @elastic/ml-ui
x-pack/packages/ml/ui_actions @elastic/ml-ui
x-pack/packages/ml/url_state @elastic/ml-ui
packages/kbn-mock-idp-plugin @elastic/kibana-security
packages/kbn-mock-idp-utils @elastic/kibana-security
packages/kbn-monaco @elastic/appex-sharedux
x-pack/plugins/monitoring_collection @elastic/obs-ux-infra_services-team
x-pack/plugins/monitoring @elastic/obs-ux-infra_services-team
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1269,6 +1269,7 @@
"@kbn/managed-vscode-config-cli": "link:packages/kbn-managed-vscode-config-cli",
"@kbn/management-storybook-config": "link:packages/kbn-management/storybook/config",
"@kbn/mock-idp-plugin": "link:packages/kbn-mock-idp-plugin",
"@kbn/mock-idp-utils": "link:packages/kbn-mock-idp-utils",
"@kbn/openapi-bundler": "link:packages/kbn-openapi-bundler",
"@kbn/openapi-generator": "link:packages/kbn-openapi-generator",
"@kbn/optimizer": "link:packages/kbn-optimizer",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ export type HttpResourcesResponseOptions = HttpResponseOptions;
export interface HttpResourcesServiceToolkit {
/** To respond with HTML page bootstrapping Kibana application. */
renderCoreApp: (options?: HttpResourcesRenderOptions) => Promise<IKibanaResponse>;
/** To respond with HTML page bootstrapping Kibana application without retrieving user-specific information. */
/**
* To respond with HTML page bootstrapping Kibana application without retrieving user-specific information.
* **Note:**
* - Your client-side JavaScript bundle will only be loaded on an anonymous page if `plugin.enabledOnAnonymousPages` is enabled in your plugin's `kibana.jsonc` manifest file.
* - You will also need to register the route serving your anonymous app with the `coreSetup.http.anonymousPaths` service in your plugin's client-side `setup` method.
* */
Comment on lines +50 to +55
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can feel the pain and suffering in this comment addition 😄

renderAnonymousCoreApp: (options?: HttpResourcesRenderOptions) => Promise<IKibanaResponse>;
/** To respond with a custom HTML page. */
renderHtml: (options: HttpResourcesResponseOptions) => IKibanaResponse;
Expand Down
4 changes: 2 additions & 2 deletions packages/kbn-es/src/utils/docker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import {
} from '../paths';
import * as waitClusterUtil from './wait_until_cluster_ready';
import * as waitForSecurityIndexUtil from './wait_for_security_index';
import * as mockIdpPluginUtil from '@kbn/mock-idp-plugin/common';
import * as mockIdpPluginUtil from '@kbn/mock-idp-utils';

jest.mock('execa');
const execa = jest.requireMock('execa');
Expand All @@ -59,7 +59,7 @@ jest.mock('./wait_for_security_index', () => ({
waitForSecurityIndex: jest.fn(),
}));

jest.mock('@kbn/mock-idp-plugin/common');
jest.mock('@kbn/mock-idp-utils');

const log = new ToolingLog();
const logWriter = new ToolingLogCollectingWriter();
Expand Down
2 changes: 1 addition & 1 deletion packages/kbn-es/src/utils/docker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
MOCK_IDP_ATTRIBUTE_NAME,
ensureSAMLRoleMapping,
createMockIdpMetadata,
} from '@kbn/mock-idp-plugin/common';
} from '@kbn/mock-idp-utils';

import { waitForSecurityIndex } from './wait_for_security_index';
import { createCliError } from '../errors';
Expand Down
2 changes: 1 addition & 1 deletion packages/kbn-es/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"@kbn/dev-utils",
"@kbn/dev-proc-runner",
"@kbn/ci-stats-reporter",
"@kbn/mock-idp-plugin",
"@kbn/mock-idp-utils",
"@kbn/jest-serializers",
"@kbn/repo-info"
]
Expand Down
20 changes: 1 addition & 19 deletions packages/kbn-mock-idp-plugin/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,4 @@
* Side Public License, v 1.
*/

export {
MOCK_IDP_PLUGIN_PATH,
MOCK_IDP_METADATA_PATH,
MOCK_IDP_LOGIN_PATH,
MOCK_IDP_LOGOUT_PATH,
MOCK_IDP_REALM_NAME,
MOCK_IDP_ENTITY_ID,
MOCK_IDP_ROLE_MAPPING_NAME,
MOCK_IDP_ATTRIBUTE_PRINCIPAL,
MOCK_IDP_ATTRIBUTE_ROLES,
MOCK_IDP_ATTRIBUTE_EMAIL,
MOCK_IDP_ATTRIBUTE_NAME,
} from './constants';
export {
createMockIdpMetadata,
createSAMLResponse,
ensureSAMLRoleMapping,
parseSAMLAuthnRequest,
} from './utils';
export { MOCK_IDP_REALM_NAME } from '@kbn/mock-idp-utils';
9 changes: 8 additions & 1 deletion packages/kbn-mock-idp-plugin/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
"plugin": {
"id": "mockIdpPlugin",
"server": true,
"browser": false
"browser": true,
"enabledOnAnonymousPages": true,
"requiredPlugins": [
"cloud"
],
"requiredBundles": [
"kibanaReact"
]
}
}
9 changes: 9 additions & 0 deletions packages/kbn-mock-idp-plugin/public/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

export { plugin } from './plugin';
152 changes: 152 additions & 0 deletions packages/kbn-mock-idp-plugin/public/login_page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import {
EuiButton,
EuiPageTemplate,
EuiEmptyPrompt,
EuiComboBox,
EuiInlineEditTitle,
EuiFormRow,
EuiSpacer,
EuiComboBoxOptionOption,
EuiButtonEmpty,
} from '@elastic/eui';
import React, { ChangeEvent, FunctionComponent } from 'react';
import { FormikProvider, useFormik, Field, Form } from 'formik';

import {
MOCK_IDP_SECURITY_ROLE_NAMES,
MOCK_IDP_OBSERVABILITY_ROLE_NAMES,
MOCK_IDP_SEARCH_ROLE_NAMES,
} from '@kbn/mock-idp-utils/src/constants';
import { useAuthenticator } from './role_switcher';

export interface LoginPageProps {
projectType?: string;
}

export const LoginPage: FunctionComponent<LoginPageProps> = ({ projectType }) => {
const roles =
projectType === 'security'
? MOCK_IDP_SECURITY_ROLE_NAMES
: projectType === 'observability'
? MOCK_IDP_OBSERVABILITY_ROLE_NAMES
: MOCK_IDP_SEARCH_ROLE_NAMES;

const [, switchCurrentUser] = useAuthenticator(true);
const formik = useFormik({
initialValues: {
full_name: 'Test User',
role: roles[0],
},
async onSubmit(values) {
await switchCurrentUser({
username: sanitizeUsername(values.full_name),
full_name: values.full_name,
email: sanitizeEmail(values.full_name),
roles: [values.role],
});
},
});

return (
<FormikProvider value={formik}>
<EuiPageTemplate panelled={false}>
<EuiPageTemplate.Section alignment="center">
<Form>
<EuiEmptyPrompt
iconType="user"
layout="vertical"
color="plain"
body={
<>
<Field
as={EuiInlineEditTitle}
name="full_name"
heading="h2"
inputAriaLabel="Edit name inline"
value={formik.values.full_name}
onChange={(event: ChangeEvent<HTMLInputElement>) => {
formik.setFieldValue('full_name', event.target.value);
}}
onCancel={(previousValue: string) => {
formik.setFieldValue('full_name', previousValue);
}}
isReadOnly={formik.isSubmitting}
editModeProps={{
formRowProps: {
error: formik.errors.full_name,
},
}}
validate={(value: string) => {
if (value.trim().length === 0) {
return 'Name cannot be empty';
}
}}
isInvalid={!!formik.errors.full_name}
placeholder="Enter your name"
css={{ width: 350 }}
/>
<EuiSpacer size="m" />

<EuiFormRow error={formik.errors.role} isInvalid={!!formik.errors.role}>
<Field
as={EuiComboBox}
name="role"
placeholder="Select your role"
singleSelection={{ asPlainText: true }}
options={roles.map((role) => ({ label: role }))}
selectedOptions={
formik.values.role ? [{ label: formik.values.role }] : undefined
}
onCreateOption={(value: string) => {
formik.setFieldValue('role', value);
}}
onChange={(selectedOptions: EuiComboBoxOptionOption[]) => {
formik.setFieldValue(
'role',
selectedOptions.length === 0 ? '' : selectedOptions[0].label
);
}}
validate={(value: string) => {
if (value.trim().length === 0) {
return 'Role cannot be empty';
}
}}
isInvalid={!!formik.errors.role}
isClearable={false}
fullWidth
/>
</EuiFormRow>
</>
}
actions={[
<EuiButton
type="submit"
disabled={!formik.isValid}
isLoading={formik.isSubmitting}
fill
>
Log in
</EuiButton>,
<EuiButtonEmpty size="xs" href="/">
More login options
</EuiButtonEmpty>,
]}
/>
</Form>
</EuiPageTemplate.Section>
</EuiPageTemplate>
</FormikProvider>
);
};

const sanitizeUsername = (username: string) =>
username.replace(/[^a-zA-Z0-9_]/g, '_').toLowerCase();
const sanitizeEmail = (email: string) => `${sanitizeUsername(email)}@elastic.co`;
84 changes: 84 additions & 0 deletions packages/kbn-mock-idp-plugin/public/plugin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import type { PluginInitializer } from '@kbn/core-plugins-browser';
import { AppNavLinkStatus } from '@kbn/core-application-browser';
import React from 'react';
import ReactDOM from 'react-dom';
import { KibanaThemeProvider } from '@kbn/react-kibana-context-theme';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { I18nProvider } from '@kbn/i18n-react';
import { MOCK_IDP_LOGIN_PATH } from '@kbn/mock-idp-utils/src/constants';
import type { CloudStart, CloudSetup } from '@kbn/cloud-plugin/public';
import { RoleSwitcher } from './role_switcher';

export interface PluginSetupDependencies {
cloud?: CloudSetup;
}

export interface PluginStartDependencies {
cloud?: CloudStart;
}

export const plugin: PluginInitializer<
void,
void,
PluginSetupDependencies,
PluginStartDependencies
> = () => ({
setup(coreSetup, plugins) {
// Register Mock IDP login page
coreSetup.http.anonymousPaths.register(MOCK_IDP_LOGIN_PATH);
coreSetup.application.register({
id: 'mock_idp',
title: 'Mock IDP',
chromeless: true,
appRoute: MOCK_IDP_LOGIN_PATH,
navLinkStatus: AppNavLinkStatus.hidden,
mount: async (params) => {
const [[coreStart], { LoginPage }] = await Promise.all([
coreSetup.getStartServices(),
import('./login_page'),
]);

ReactDOM.render(
<KibanaThemeProvider theme={coreStart.theme}>
<KibanaContextProvider services={coreStart}>
<I18nProvider>
<LoginPage projectType={plugins.cloud?.serverless.projectType} />
</I18nProvider>
</KibanaContextProvider>
</KibanaThemeProvider>,
params.element
);

return () => ReactDOM.unmountComponentAtNode(params.element);
},
});
},
start(coreStart, plugins) {
// Register role switcher dropdown menu in the top right navigation of the Kibana UI
coreStart.chrome.navControls.registerRight({
order: 4000 + 1, // Make sure it comes after the user menu
mount: (element: HTMLElement) => {
ReactDOM.render(
<KibanaThemeProvider theme={coreStart.theme}>
<KibanaContextProvider services={coreStart}>
<I18nProvider>
<RoleSwitcher projectType={plugins.cloud?.serverless.projectType} />
</I18nProvider>
</KibanaContextProvider>
</KibanaThemeProvider>,
element
);
return () => ReactDOM.unmountComponentAtNode(element);
},
});
},
stop() {},
});
Loading