mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[7.x] Migrate config deprecations and ShieldUser
functionality to the New Platform (#54004)
This commit is contained in:
parent
d7789f20d9
commit
12f47611ee
28 changed files with 329 additions and 211 deletions
|
@ -11,6 +11,8 @@ import * as React from 'react';
|
|||
import * as ReactDOM from 'react-dom';
|
||||
import { UIRoutes } from 'ui/routes';
|
||||
import { isLeft } from 'fp-ts/lib/Either';
|
||||
import { npSetup } from 'ui/new_platform';
|
||||
import { SecurityPluginSetup } from '../../../../../../../plugins/security/public';
|
||||
import { BufferedKibanaServiceCall, KibanaAdapterServiceRefs, KibanaUIConfig } from '../../types';
|
||||
import {
|
||||
FrameworkAdapter,
|
||||
|
@ -58,7 +60,7 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter {
|
|||
};
|
||||
|
||||
public async waitUntilFrameworkReady(): Promise<void> {
|
||||
const $injector = await this.onKibanaReady();
|
||||
await this.onKibanaReady();
|
||||
const xpackInfo: any = this.xpackInfoService;
|
||||
let xpackInfoUnpacked: FrameworkInfo;
|
||||
|
||||
|
@ -95,8 +97,10 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter {
|
|||
}
|
||||
this.xpackInfo = xpackInfoUnpacked;
|
||||
|
||||
const securitySetup = ((npSetup.plugins as unknown) as { security?: SecurityPluginSetup })
|
||||
.security;
|
||||
try {
|
||||
this.shieldUser = await $injector.get('ShieldUser').getCurrent().$promise;
|
||||
this.shieldUser = (await securitySetup?.authc.getCurrentUser()) || null;
|
||||
const assertUser = RuntimeFrameworkUser.decode(this.shieldUser);
|
||||
|
||||
if (isLeft(assertUser)) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import React from 'react';
|
|||
import { render } from 'react-dom';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import { npSetup } from 'ui/new_platform';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import { PipelineEditor } from '../../../../components/pipeline_editor';
|
||||
|
@ -21,7 +22,6 @@ app.directive('pipelineEdit', function($injector) {
|
|||
const pipelineService = $injector.get('pipelineService');
|
||||
const licenseService = $injector.get('logstashLicenseService');
|
||||
const kbnUrl = $injector.get('kbnUrl');
|
||||
const shieldUser = $injector.get('ShieldUser');
|
||||
const $route = $injector.get('$route');
|
||||
|
||||
return {
|
||||
|
@ -32,7 +32,7 @@ app.directive('pipelineEdit', function($injector) {
|
|||
scope.$evalAsync(kbnUrl.change(`/management/logstash/pipelines/${id}/edit`));
|
||||
|
||||
const userResource = logstashSecurity.isSecurityEnabled()
|
||||
? await shieldUser.getCurrent().$promise
|
||||
? await npSetup.plugins.security.authc.getCurrentUser()
|
||||
: null;
|
||||
|
||||
render(
|
||||
|
|
|
@ -29,18 +29,11 @@ export const security = kibana =>
|
|||
enabled: Joi.boolean().default(true),
|
||||
cookieName: HANDLED_IN_NEW_PLATFORM,
|
||||
encryptionKey: HANDLED_IN_NEW_PLATFORM,
|
||||
session: Joi.object({
|
||||
idleTimeout: HANDLED_IN_NEW_PLATFORM,
|
||||
lifespan: HANDLED_IN_NEW_PLATFORM,
|
||||
}).default(),
|
||||
session: HANDLED_IN_NEW_PLATFORM,
|
||||
secureCookies: HANDLED_IN_NEW_PLATFORM,
|
||||
public: HANDLED_IN_NEW_PLATFORM,
|
||||
loginAssistanceMessage: HANDLED_IN_NEW_PLATFORM,
|
||||
authorization: Joi.object({
|
||||
legacyFallback: Joi.object({
|
||||
enabled: Joi.boolean().default(true), // deprecated
|
||||
}).default(),
|
||||
}).default(),
|
||||
authorization: HANDLED_IN_NEW_PLATFORM,
|
||||
audit: Joi.object({
|
||||
enabled: Joi.boolean().default(false),
|
||||
}).default(),
|
||||
|
@ -48,10 +41,8 @@ export const security = kibana =>
|
|||
}).default();
|
||||
},
|
||||
|
||||
deprecations: function({ rename, unused }) {
|
||||
deprecations: function({ rename }) {
|
||||
return [
|
||||
unused('authorization.legacyFallback.enabled'),
|
||||
rename('sessionTimeout', 'session.idleTimeout'),
|
||||
rename('authProviders', 'authc.providers'),
|
||||
(settings, log) => {
|
||||
const hasSAMLProvider = get(settings, 'authc.providers', []).includes('saml');
|
||||
|
|
|
@ -5,16 +5,12 @@
|
|||
*/
|
||||
|
||||
import { kfetch } from 'ui/kfetch';
|
||||
import { AuthenticatedUser, Role, User, EditUser } from '../../common/model';
|
||||
import { Role, User, EditUser } from '../../common/model';
|
||||
|
||||
const usersUrl = '/internal/security/users';
|
||||
const rolesUrl = '/api/security/role';
|
||||
|
||||
export class UserAPIClient {
|
||||
public async getCurrentUser(): Promise<AuthenticatedUser> {
|
||||
return await kfetch({ pathname: `/internal/security/me` });
|
||||
}
|
||||
|
||||
public async getUsers(): Promise<User[]> {
|
||||
return await kfetch({ pathname: usersUrl });
|
||||
}
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import 'angular-resource';
|
||||
import angular from 'angular';
|
||||
import { uiModules } from 'ui/modules';
|
||||
|
||||
const module = uiModules.get('security', ['ngResource']);
|
||||
module.service('ShieldUser', ($resource, chrome) => {
|
||||
const baseUrl = chrome.addBasePath('/internal/security/users/:username');
|
||||
const ShieldUser = $resource(
|
||||
baseUrl,
|
||||
{
|
||||
username: '@username',
|
||||
},
|
||||
{
|
||||
changePassword: {
|
||||
method: 'POST',
|
||||
url: `${baseUrl}/password`,
|
||||
transformRequest: ({ password, newPassword }) => angular.toJson({ password, newPassword }),
|
||||
},
|
||||
getCurrent: {
|
||||
method: 'GET',
|
||||
url: chrome.addBasePath('/internal/security/me'),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
return ShieldUser;
|
||||
});
|
|
@ -6,22 +6,13 @@
|
|||
|
||||
import routes from 'ui/routes';
|
||||
import template from './account.html';
|
||||
import '../../services/shield_user';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import { npSetup } from 'ui/new_platform';
|
||||
import { AccountManagementPage } from './components';
|
||||
import React from 'react';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
|
||||
const renderReact = (elem, user) => {
|
||||
render(
|
||||
<I18nContext>
|
||||
<AccountManagementPage user={user} />
|
||||
</I18nContext>,
|
||||
elem
|
||||
);
|
||||
};
|
||||
|
||||
routes.when('/account', {
|
||||
template,
|
||||
k7Breadcrumbs: () => [
|
||||
|
@ -31,13 +22,8 @@ routes.when('/account', {
|
|||
}),
|
||||
},
|
||||
],
|
||||
resolve: {
|
||||
user(ShieldUser) {
|
||||
return ShieldUser.getCurrent().$promise;
|
||||
},
|
||||
},
|
||||
controllerAs: 'accountController',
|
||||
controller($scope, $route) {
|
||||
controller($scope) {
|
||||
$scope.$on('$destroy', () => {
|
||||
const elem = document.getElementById('userProfileReactRoot');
|
||||
if (elem) {
|
||||
|
@ -45,8 +31,12 @@ routes.when('/account', {
|
|||
}
|
||||
});
|
||||
$scope.$$postDigest(() => {
|
||||
const elem = document.getElementById('userProfileReactRoot');
|
||||
renderReact(elem, $route.current.locals.user);
|
||||
render(
|
||||
<I18nContext>
|
||||
<AccountManagementPage securitySetup={npSetup.plugins.security} />
|
||||
</I18nContext>,
|
||||
document.getElementById('userProfileReactRoot')
|
||||
);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
@ -4,8 +4,11 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { mountWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import { act } from '@testing-library/react';
|
||||
import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers';
|
||||
import { securityMock } from '../../../../../../../plugins/security/public/mocks';
|
||||
import { AccountManagementPage } from './account_management_page';
|
||||
import { AuthenticatedUser } from '../../../../common/model';
|
||||
|
||||
jest.mock('ui/kfetch');
|
||||
|
||||
|
@ -32,10 +35,24 @@ const createUser = ({ withFullName = true, withEmail = true, realm = 'native' }:
|
|||
};
|
||||
};
|
||||
|
||||
function getSecuritySetupMock({ currentUser }: { currentUser: AuthenticatedUser }) {
|
||||
const securitySetupMock = securityMock.createSetup();
|
||||
securitySetupMock.authc.getCurrentUser.mockResolvedValue(currentUser);
|
||||
return securitySetupMock;
|
||||
}
|
||||
|
||||
describe('<AccountManagementPage>', () => {
|
||||
it(`displays users full name, username, and email address`, () => {
|
||||
it(`displays users full name, username, and email address`, async () => {
|
||||
const user = createUser();
|
||||
const wrapper = mountWithIntl(<AccountManagementPage user={user} />);
|
||||
const wrapper = mountWithIntl(
|
||||
<AccountManagementPage securitySetup={getSecuritySetupMock({ currentUser: user })} />
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
expect(wrapper.find('EuiText[data-test-subj="userDisplayName"]').text()).toEqual(
|
||||
user.full_name
|
||||
);
|
||||
|
@ -43,28 +60,60 @@ describe('<AccountManagementPage>', () => {
|
|||
expect(wrapper.find('[data-test-subj="email"]').text()).toEqual(user.email);
|
||||
});
|
||||
|
||||
it(`displays username when full_name is not provided`, () => {
|
||||
it(`displays username when full_name is not provided`, async () => {
|
||||
const user = createUser({ withFullName: false });
|
||||
const wrapper = mountWithIntl(<AccountManagementPage user={user} />);
|
||||
const wrapper = mountWithIntl(
|
||||
<AccountManagementPage securitySetup={getSecuritySetupMock({ currentUser: user })} />
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
expect(wrapper.find('EuiText[data-test-subj="userDisplayName"]').text()).toEqual(user.username);
|
||||
});
|
||||
|
||||
it(`displays a placeholder when no email address is provided`, () => {
|
||||
it(`displays a placeholder when no email address is provided`, async () => {
|
||||
const user = createUser({ withEmail: false });
|
||||
const wrapper = mountWithIntl(<AccountManagementPage user={user} />);
|
||||
const wrapper = mountWithIntl(
|
||||
<AccountManagementPage securitySetup={getSecuritySetupMock({ currentUser: user })} />
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
expect(wrapper.find('[data-test-subj="email"]').text()).toEqual('no email address');
|
||||
});
|
||||
|
||||
it(`displays change password form for users in the native realm`, () => {
|
||||
it(`displays change password form for users in the native realm`, async () => {
|
||||
const user = createUser();
|
||||
const wrapper = mountWithIntl(<AccountManagementPage user={user} />);
|
||||
const wrapper = mountWithIntl(
|
||||
<AccountManagementPage securitySetup={getSecuritySetupMock({ currentUser: user })} />
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
expect(wrapper.find('EuiFieldText[data-test-subj="currentPassword"]')).toHaveLength(1);
|
||||
expect(wrapper.find('EuiFieldText[data-test-subj="newPassword"]')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it(`does not display change password form for users in the saml realm`, () => {
|
||||
it(`does not display change password form for users in the saml realm`, async () => {
|
||||
const user = createUser({ realm: 'saml' });
|
||||
const wrapper = mountWithIntl(<AccountManagementPage user={user} />);
|
||||
const wrapper = mountWithIntl(
|
||||
<AccountManagementPage securitySetup={getSecuritySetupMock({ currentUser: user })} />
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
expect(wrapper.find('EuiFieldText[data-test-subj="currentPassword"]')).toHaveLength(0);
|
||||
expect(wrapper.find('EuiFieldText[data-test-subj="newPassword"]')).toHaveLength(0);
|
||||
});
|
||||
|
|
|
@ -4,29 +4,41 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import { EuiPage, EuiPageBody, EuiPanel, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { SecurityPluginSetup } from '../../../../../../../plugins/security/public';
|
||||
import { getUserDisplayName, AuthenticatedUser } from '../../../../common/model';
|
||||
import { ChangePassword } from './change_password';
|
||||
import { PersonalInfo } from './personal_info';
|
||||
|
||||
interface Props {
|
||||
user: AuthenticatedUser;
|
||||
securitySetup: SecurityPluginSetup;
|
||||
}
|
||||
|
||||
export const AccountManagementPage: React.FC<Props> = props => (
|
||||
<EuiPage>
|
||||
<EuiPageBody restrictWidth>
|
||||
<EuiPanel>
|
||||
<EuiText data-test-subj={'userDisplayName'}>
|
||||
<h1>{getUserDisplayName(props.user)}</h1>
|
||||
</EuiText>
|
||||
export const AccountManagementPage = (props: Props) => {
|
||||
const [currentUser, setCurrentUser] = useState<AuthenticatedUser | null>(null);
|
||||
useEffect(() => {
|
||||
props.securitySetup.authc.getCurrentUser().then(setCurrentUser);
|
||||
}, [props]);
|
||||
|
||||
<EuiSpacer size="xl" />
|
||||
if (!currentUser) {
|
||||
return null;
|
||||
}
|
||||
|
||||
<PersonalInfo user={props.user} />
|
||||
return (
|
||||
<EuiPage>
|
||||
<EuiPageBody restrictWidth>
|
||||
<EuiPanel>
|
||||
<EuiText data-test-subj={'userDisplayName'}>
|
||||
<h1>{getUserDisplayName(currentUser)}</h1>
|
||||
</EuiText>
|
||||
|
||||
<ChangePassword user={props.user} />
|
||||
</EuiPanel>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
);
|
||||
<EuiSpacer size="xl" />
|
||||
|
||||
<PersonalInfo user={currentUser} />
|
||||
|
||||
<ChangePassword user={currentUser} />
|
||||
</EuiPanel>
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -11,10 +11,10 @@ import { kfetch } from 'ui/kfetch';
|
|||
import { fatalError, toastNotifications } from 'ui/notify';
|
||||
import { npStart } from 'ui/new_platform';
|
||||
import template from 'plugins/security/views/management/edit_role/edit_role.html';
|
||||
import 'plugins/security/services/shield_user';
|
||||
import 'plugins/security/services/shield_role';
|
||||
import 'plugins/security/services/shield_indices';
|
||||
import { xpackInfo } from 'plugins/xpack_main/services/xpack_info';
|
||||
import { UserAPIClient } from '../../../lib/api';
|
||||
import { ROLES_PATH, CLONE_ROLES_PATH, EDIT_ROLES_PATH } from '../management_urls';
|
||||
import { getEditRoleBreadcrumbs, getCreateRoleBreadcrumbs } from '../breadcrumbs';
|
||||
|
||||
|
@ -69,9 +69,8 @@ const routeDefinition = action => ({
|
|||
|
||||
return role.then(res => res.toJSON());
|
||||
},
|
||||
users(ShieldUser) {
|
||||
// $promise is used here because the result is an ngResource, not a promise itself
|
||||
return ShieldUser.query().$promise.then(users => _.map(users, 'username'));
|
||||
users() {
|
||||
return new UserAPIClient().getUsers().then(users => _.map(users, 'username'));
|
||||
},
|
||||
indexPatterns() {
|
||||
return npStart.plugins.data.indexPatterns.getTitles();
|
||||
|
|
|
@ -4,38 +4,42 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { mountWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import { act } from '@testing-library/react';
|
||||
import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers';
|
||||
import { EditUserPage } from './edit_user_page';
|
||||
import React from 'react';
|
||||
import { securityMock } from '../../../../../../../../plugins/security/public/mocks';
|
||||
import { UserAPIClient } from '../../../../lib/api';
|
||||
import { User, Role } from '../../../../../common/model';
|
||||
import { ReactWrapper } from 'enzyme';
|
||||
import { mockAuthenticatedUser } from '../../../../../../../../plugins/security/common/model/authenticated_user.mock';
|
||||
|
||||
jest.mock('ui/kfetch');
|
||||
|
||||
const createUser = (username: string) => {
|
||||
const user: User = {
|
||||
username,
|
||||
full_name: 'my full name',
|
||||
email: 'foo@bar.com',
|
||||
roles: ['idk', 'something'],
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
if (username === 'reserved_user') {
|
||||
user.metadata = {
|
||||
_reserved: true,
|
||||
};
|
||||
}
|
||||
|
||||
return user;
|
||||
};
|
||||
|
||||
const buildClient = () => {
|
||||
const apiClient = new UserAPIClient();
|
||||
|
||||
const createUser = (username: string) => {
|
||||
const user: User = {
|
||||
username,
|
||||
full_name: 'my full name',
|
||||
email: 'foo@bar.com',
|
||||
roles: ['idk', 'something'],
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
if (username === 'reserved_user') {
|
||||
user.metadata = {
|
||||
_reserved: true,
|
||||
};
|
||||
}
|
||||
|
||||
return Promise.resolve(user);
|
||||
};
|
||||
|
||||
apiClient.getUser = jest.fn().mockImplementation(createUser);
|
||||
apiClient.getCurrentUser = jest.fn().mockImplementation(() => createUser('current_user'));
|
||||
apiClient.getUser = jest
|
||||
.fn()
|
||||
.mockImplementation(async (username: string) => createUser(username));
|
||||
|
||||
apiClient.getRoles = jest.fn().mockImplementation(() => {
|
||||
return Promise.resolve([
|
||||
|
@ -63,6 +67,14 @@ const buildClient = () => {
|
|||
return apiClient;
|
||||
};
|
||||
|
||||
function buildSecuritySetup() {
|
||||
const securitySetupMock = securityMock.createSetup();
|
||||
securitySetupMock.authc.getCurrentUser.mockResolvedValue(
|
||||
mockAuthenticatedUser(createUser('current_user'))
|
||||
);
|
||||
return securitySetupMock;
|
||||
}
|
||||
|
||||
function expectSaveButton(wrapper: ReactWrapper<any, any>) {
|
||||
expect(wrapper.find('EuiButton[data-test-subj="userFormSaveButton"]')).toHaveLength(1);
|
||||
}
|
||||
|
@ -74,10 +86,12 @@ function expectMissingSaveButton(wrapper: ReactWrapper<any, any>) {
|
|||
describe('EditUserPage', () => {
|
||||
it('allows reserved users to be viewed', async () => {
|
||||
const apiClient = buildClient();
|
||||
const securitySetup = buildSecuritySetup();
|
||||
const wrapper = mountWithIntl(
|
||||
<EditUserPage.WrappedComponent
|
||||
username={'reserved_user'}
|
||||
apiClient={apiClient}
|
||||
securitySetup={securitySetup}
|
||||
changeUrl={path => path}
|
||||
intl={null as any}
|
||||
/>
|
||||
|
@ -86,17 +100,19 @@ describe('EditUserPage', () => {
|
|||
await waitForRender(wrapper);
|
||||
|
||||
expect(apiClient.getUser).toBeCalledTimes(1);
|
||||
expect(apiClient.getCurrentUser).toBeCalledTimes(1);
|
||||
expect(securitySetup.authc.getCurrentUser).toBeCalledTimes(1);
|
||||
|
||||
expectMissingSaveButton(wrapper);
|
||||
});
|
||||
|
||||
it('allows new users to be created', async () => {
|
||||
const apiClient = buildClient();
|
||||
const securitySetup = buildSecuritySetup();
|
||||
const wrapper = mountWithIntl(
|
||||
<EditUserPage.WrappedComponent
|
||||
username={''}
|
||||
apiClient={apiClient}
|
||||
securitySetup={securitySetup}
|
||||
changeUrl={path => path}
|
||||
intl={null as any}
|
||||
/>
|
||||
|
@ -105,17 +121,19 @@ describe('EditUserPage', () => {
|
|||
await waitForRender(wrapper);
|
||||
|
||||
expect(apiClient.getUser).toBeCalledTimes(0);
|
||||
expect(apiClient.getCurrentUser).toBeCalledTimes(0);
|
||||
expect(securitySetup.authc.getCurrentUser).toBeCalledTimes(0);
|
||||
|
||||
expectSaveButton(wrapper);
|
||||
});
|
||||
|
||||
it('allows existing users to be edited', async () => {
|
||||
const apiClient = buildClient();
|
||||
const securitySetup = buildSecuritySetup();
|
||||
const wrapper = mountWithIntl(
|
||||
<EditUserPage.WrappedComponent
|
||||
username={'existing_user'}
|
||||
apiClient={apiClient}
|
||||
securitySetup={securitySetup}
|
||||
changeUrl={path => path}
|
||||
intl={null as any}
|
||||
/>
|
||||
|
@ -124,16 +142,15 @@ describe('EditUserPage', () => {
|
|||
await waitForRender(wrapper);
|
||||
|
||||
expect(apiClient.getUser).toBeCalledTimes(1);
|
||||
expect(apiClient.getCurrentUser).toBeCalledTimes(1);
|
||||
expect(securitySetup.authc.getCurrentUser).toBeCalledTimes(1);
|
||||
|
||||
expectSaveButton(wrapper);
|
||||
});
|
||||
});
|
||||
|
||||
async function waitForRender(wrapper: ReactWrapper<any, any>) {
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
wrapper.update();
|
||||
await act(async () => {
|
||||
await nextTick();
|
||||
wrapper.update();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
import { FormattedMessage, injectI18n, InjectedIntl } from '@kbn/i18n/react';
|
||||
import { SecurityPluginSetup } from '../../../../../../../../plugins/security/public';
|
||||
import { UserValidator, UserValidationResult } from '../../../../lib/validate_user';
|
||||
import { User, EditUser, Role } from '../../../../../common/model';
|
||||
import { USERS_PATH } from '../../../../views/management/management_urls';
|
||||
|
@ -40,6 +41,7 @@ interface Props {
|
|||
intl: InjectedIntl;
|
||||
changeUrl: (path: string) => void;
|
||||
apiClient: UserAPIClient;
|
||||
securitySetup: SecurityPluginSetup;
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -82,7 +84,7 @@ class EditUserPageUI extends Component<Props, State> {
|
|||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const { username, apiClient } = this.props;
|
||||
const { username, apiClient, securitySetup } = this.props;
|
||||
let { user, currentUser } = this.state;
|
||||
if (username) {
|
||||
try {
|
||||
|
@ -91,7 +93,7 @@ class EditUserPageUI extends Component<Props, State> {
|
|||
password: '',
|
||||
confirmPassword: '',
|
||||
};
|
||||
currentUser = await apiClient.getCurrentUser();
|
||||
currentUser = await securitySetup.authc.getCurrentUser();
|
||||
} catch (err) {
|
||||
toastNotifications.addDanger({
|
||||
title: this.props.intl.formatMessage({
|
||||
|
|
|
@ -7,7 +7,6 @@ import routes from 'ui/routes';
|
|||
import template from 'plugins/security/views/management/edit_user/edit_user.html';
|
||||
import 'angular-resource';
|
||||
import 'ui/angular_ui_select';
|
||||
import 'plugins/security/services/shield_user';
|
||||
import 'plugins/security/services/shield_role';
|
||||
import { EDIT_USERS_PATH } from '../management_urls';
|
||||
import { EditUserPage } from './components';
|
||||
|
@ -15,12 +14,18 @@ import { UserAPIClient } from '../../../lib/api';
|
|||
import React from 'react';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import { npSetup } from 'ui/new_platform';
|
||||
import { getEditUserBreadcrumbs, getCreateUserBreadcrumbs } from '../breadcrumbs';
|
||||
|
||||
const renderReact = (elem, changeUrl, username) => {
|
||||
render(
|
||||
<I18nContext>
|
||||
<EditUserPage changeUrl={changeUrl} username={username} apiClient={new UserAPIClient()} />
|
||||
<EditUserPage
|
||||
changeUrl={changeUrl}
|
||||
username={username}
|
||||
apiClient={new UserAPIClient()}
|
||||
securitySetup={npSetup.plugins.security}
|
||||
/>
|
||||
</I18nContext>,
|
||||
elem
|
||||
);
|
||||
|
|
|
@ -13,10 +13,10 @@ import 'plugins/security/views/management/edit_user/edit_user';
|
|||
import 'plugins/security/views/management/edit_role/index';
|
||||
import routes from 'ui/routes';
|
||||
import { xpackInfo } from 'plugins/xpack_main/services/xpack_info';
|
||||
import '../../services/shield_user';
|
||||
import { ROLES_PATH, USERS_PATH, API_KEYS_PATH } from './management_urls';
|
||||
|
||||
import { management } from 'ui/management';
|
||||
import { npSetup } from 'ui/new_platform';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
|
||||
|
@ -36,7 +36,7 @@ routes
|
|||
})
|
||||
.defaults(/\/management/, {
|
||||
resolve: {
|
||||
securityManagementSection: function(ShieldUser) {
|
||||
securityManagementSection: function() {
|
||||
const showSecurityLinks = xpackInfo.get('features.security.showLinks');
|
||||
|
||||
function deregisterSecurity() {
|
||||
|
@ -93,12 +93,11 @@ routes
|
|||
if (!showSecurityLinks) {
|
||||
deregisterSecurity();
|
||||
} else {
|
||||
// getCurrent will reject if there is no authenticated user, so we prevent them from seeing the security
|
||||
// management screens
|
||||
//
|
||||
// $promise is used here because the result is an ngResource, not a promise itself
|
||||
return ShieldUser.getCurrent()
|
||||
.$promise.then(ensureSecurityRegistered)
|
||||
// getCurrentUser will reject if there is no authenticated user, so we prevent them from
|
||||
// seeing the security management screens.
|
||||
return npSetup.plugins.security.authc
|
||||
.getCurrentUser()
|
||||
.then(ensureSecurityRegistered)
|
||||
.catch(deregisterSecurity);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -8,7 +8,6 @@ import React from 'react';
|
|||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import routes from 'ui/routes';
|
||||
import template from 'plugins/security/views/management/users_grid/users.html';
|
||||
import 'plugins/security/services/shield_user';
|
||||
import { SECURITY_PATH, USERS_PATH } from '../management_urls';
|
||||
import { UsersListPage } from './components';
|
||||
import { UserAPIClient } from '../../../lib/api';
|
||||
|
|
|
@ -10,36 +10,40 @@ import React from 'react';
|
|||
import { render } from 'react-dom';
|
||||
import chrome from 'ui/chrome';
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import { npSetup } from 'ui/new_platform';
|
||||
import { SecurityPluginSetup } from '../../../../../../plugins/security/public';
|
||||
import { AuthenticatedUser } from '../../../common/model';
|
||||
import { AuthenticationStatePage } from '../../components/authentication_state_page';
|
||||
|
||||
chrome
|
||||
.setVisible(false)
|
||||
.setRootTemplate('<div id="reactOverwrittenSessionRoot" />')
|
||||
.setRootController('overwritten_session', ($scope: any, ShieldUser: any) => {
|
||||
.setRootController('overwritten_session', ($scope: any) => {
|
||||
$scope.$$postDigest(() => {
|
||||
ShieldUser.getCurrent().$promise.then((user: AuthenticatedUser) => {
|
||||
const overwrittenSessionPage = (
|
||||
<I18nContext>
|
||||
<AuthenticationStatePage
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.security.overwrittenSession.title"
|
||||
defaultMessage="You previously logged in as a different user."
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiButton href={chrome.addBasePath('/')}>
|
||||
<FormattedMessage
|
||||
id="xpack.security.overwrittenSession.continueAsUserText"
|
||||
defaultMessage="Continue as {username}"
|
||||
values={{ username: user.username }}
|
||||
/>
|
||||
</EuiButton>
|
||||
</AuthenticationStatePage>
|
||||
</I18nContext>
|
||||
);
|
||||
render(overwrittenSessionPage, document.getElementById('reactOverwrittenSessionRoot'));
|
||||
});
|
||||
((npSetup.plugins as unknown) as { security: SecurityPluginSetup }).security.authc
|
||||
.getCurrentUser()
|
||||
.then((user: AuthenticatedUser) => {
|
||||
const overwrittenSessionPage = (
|
||||
<I18nContext>
|
||||
<AuthenticationStatePage
|
||||
title={
|
||||
<FormattedMessage
|
||||
id="xpack.security.overwrittenSession.title"
|
||||
defaultMessage="You previously logged in as a different user."
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EuiButton href={chrome.addBasePath('/')}>
|
||||
<FormattedMessage
|
||||
id="xpack.security.overwrittenSession.continueAsUserText"
|
||||
defaultMessage="Continue as {username}"
|
||||
values={{ username: user.username }}
|
||||
/>
|
||||
</EuiButton>
|
||||
</AuthenticationStatePage>
|
||||
</I18nContext>
|
||||
);
|
||||
render(overwrittenSessionPage, document.getElementById('reactOverwrittenSessionRoot'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { HttpSetup } from 'src/core/public';
|
||||
import { AuthenticatedUser } from '../../common/model';
|
||||
|
||||
interface SetupParams {
|
||||
http: HttpSetup;
|
||||
}
|
||||
|
||||
export interface AuthenticationServiceSetup {
|
||||
/**
|
||||
* Returns currently authenticated user and throws if current user isn't authenticated.
|
||||
*/
|
||||
getCurrentUser: () => Promise<AuthenticatedUser>;
|
||||
}
|
||||
|
||||
export class AuthenticationService {
|
||||
public setup({ http }: SetupParams): AuthenticationServiceSetup {
|
||||
return {
|
||||
async getCurrentUser() {
|
||||
return (await http.get('/internal/security/me', {
|
||||
headers: { 'kbn-system-api': true },
|
||||
})) as AuthenticatedUser;
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
13
x-pack/plugins/security/public/authentication/index.mock.ts
Normal file
13
x-pack/plugins/security/public/authentication/index.mock.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { AuthenticationServiceSetup } from './authentication_service';
|
||||
|
||||
export const authenticationMock = {
|
||||
createSetup: (): jest.Mocked<AuthenticationServiceSetup> => ({
|
||||
getCurrentUser: jest.fn(),
|
||||
}),
|
||||
};
|
7
x-pack/plugins/security/public/authentication/index.ts
Normal file
7
x-pack/plugins/security/public/authentication/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export { AuthenticationService, AuthenticationServiceSetup } from './authentication_service';
|
|
@ -6,7 +6,10 @@
|
|||
|
||||
import { PluginInitializer } from 'src/core/public';
|
||||
import { SecurityPlugin, SecurityPluginSetup, SecurityPluginStart } from './plugin';
|
||||
|
||||
export { SecurityPluginSetup, SecurityPluginStart };
|
||||
export { SessionInfo } from './types';
|
||||
export { AuthenticatedUser } from '../common/model';
|
||||
|
||||
export const plugin: PluginInitializer<SecurityPluginSetup, SecurityPluginStart> = () =>
|
||||
new SecurityPlugin();
|
||||
|
|
19
x-pack/plugins/security/public/mocks.ts
Normal file
19
x-pack/plugins/security/public/mocks.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { authenticationMock } from './authentication/index.mock';
|
||||
import { createSessionTimeoutMock } from './session/session_timeout.mock';
|
||||
|
||||
function createSetupMock() {
|
||||
return {
|
||||
authc: authenticationMock.createSetup(),
|
||||
sessionTimeout: createSessionTimeoutMock(),
|
||||
};
|
||||
}
|
||||
|
||||
export const securityMock = {
|
||||
createSetup: createSetupMock,
|
||||
};
|
|
@ -10,6 +10,8 @@ import { ILicense } from '../../../licensing/public';
|
|||
import { SecurityNavControlService } from '.';
|
||||
import { SecurityLicenseService } from '../../common/licensing';
|
||||
import { nextTick } from 'test_utils/enzyme_helpers';
|
||||
import { securityMock } from '../mocks';
|
||||
import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock';
|
||||
|
||||
const validLicense = {
|
||||
isAvailable: true,
|
||||
|
@ -29,13 +31,17 @@ describe('SecurityNavControlService', () => {
|
|||
const license$ = new BehaviorSubject<ILicense>(validLicense);
|
||||
|
||||
const navControlService = new SecurityNavControlService();
|
||||
const mockSecuritySetup = securityMock.createSetup();
|
||||
mockSecuritySetup.authc.getCurrentUser.mockResolvedValue(
|
||||
mockAuthenticatedUser({ username: 'some-user', full_name: undefined })
|
||||
);
|
||||
navControlService.setup({
|
||||
securityLicense: new SecurityLicenseService().setup({ license$ }).license,
|
||||
authc: mockSecuritySetup.authc,
|
||||
});
|
||||
|
||||
const coreStart = coreMock.createStart();
|
||||
coreStart.chrome.navControls.registerRight = jest.fn();
|
||||
coreStart.http.get.mockResolvedValue({ username: 'some-user' });
|
||||
|
||||
navControlService.start({ core: coreStart });
|
||||
expect(coreStart.chrome.navControls.registerRight).toHaveBeenCalledTimes(1);
|
||||
|
@ -93,6 +99,7 @@ describe('SecurityNavControlService', () => {
|
|||
const navControlService = new SecurityNavControlService();
|
||||
navControlService.setup({
|
||||
securityLicense: new SecurityLicenseService().setup({ license$ }).license,
|
||||
authc: securityMock.createSetup().authc,
|
||||
});
|
||||
|
||||
const coreStart = coreMock.createStart();
|
||||
|
@ -111,6 +118,7 @@ describe('SecurityNavControlService', () => {
|
|||
const navControlService = new SecurityNavControlService();
|
||||
navControlService.setup({
|
||||
securityLicense: new SecurityLicenseService().setup({ license$ }).license,
|
||||
authc: securityMock.createSetup().authc,
|
||||
});
|
||||
|
||||
const coreStart = coreMock.createStart();
|
||||
|
@ -126,6 +134,7 @@ describe('SecurityNavControlService', () => {
|
|||
const navControlService = new SecurityNavControlService();
|
||||
navControlService.setup({
|
||||
securityLicense: new SecurityLicenseService().setup({ license$ }).license,
|
||||
authc: securityMock.createSetup().authc,
|
||||
});
|
||||
|
||||
const coreStart = coreMock.createStart();
|
||||
|
@ -146,6 +155,7 @@ describe('SecurityNavControlService', () => {
|
|||
const navControlService = new SecurityNavControlService();
|
||||
navControlService.setup({
|
||||
securityLicense: new SecurityLicenseService().setup({ license$ }).license,
|
||||
authc: securityMock.createSetup().authc,
|
||||
});
|
||||
|
||||
const coreStart = coreMock.createStart();
|
||||
|
|
|
@ -9,11 +9,12 @@ import { CoreStart } from 'src/core/public';
|
|||
import ReactDOM from 'react-dom';
|
||||
import React from 'react';
|
||||
import { SecurityLicense } from '../../common/licensing';
|
||||
import { AuthenticatedUser } from '../../common/model';
|
||||
import { SecurityNavControl } from './nav_control_component';
|
||||
import { AuthenticationServiceSetup } from '../authentication';
|
||||
|
||||
interface SetupDeps {
|
||||
securityLicense: SecurityLicense;
|
||||
authc: AuthenticationServiceSetup;
|
||||
}
|
||||
|
||||
interface StartDeps {
|
||||
|
@ -22,13 +23,15 @@ interface StartDeps {
|
|||
|
||||
export class SecurityNavControlService {
|
||||
private securityLicense!: SecurityLicense;
|
||||
private authc!: AuthenticationServiceSetup;
|
||||
|
||||
private navControlRegistered!: boolean;
|
||||
|
||||
private securityFeaturesSubscription?: Subscription;
|
||||
|
||||
public setup({ securityLicense }: SetupDeps) {
|
||||
public setup({ securityLicense, authc }: SetupDeps) {
|
||||
this.securityLicense = securityLicense;
|
||||
this.authc = authc;
|
||||
}
|
||||
|
||||
public start({ core }: StartDeps) {
|
||||
|
@ -38,14 +41,8 @@ export class SecurityNavControlService {
|
|||
|
||||
const shouldRegisterNavControl =
|
||||
!isAnonymousPath && showLinks && !this.navControlRegistered;
|
||||
|
||||
if (shouldRegisterNavControl) {
|
||||
const user = core.http.get('/internal/security/me', {
|
||||
headers: {
|
||||
'kbn-system-api': true,
|
||||
},
|
||||
}) as Promise<AuthenticatedUser>;
|
||||
this.registerSecurityNavControl(core, user);
|
||||
this.registerSecurityNavControl(core);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -60,16 +57,16 @@ export class SecurityNavControlService {
|
|||
}
|
||||
|
||||
private registerSecurityNavControl(
|
||||
core: Pick<CoreStart, 'chrome' | 'http' | 'i18n' | 'application'>,
|
||||
user: Promise<AuthenticatedUser>
|
||||
core: Pick<CoreStart, 'chrome' | 'http' | 'i18n' | 'application'>
|
||||
) {
|
||||
const currentUserPromise = this.authc.getCurrentUser();
|
||||
core.chrome.navControls.registerRight({
|
||||
order: 2000,
|
||||
mount: (el: HTMLElement) => {
|
||||
const I18nContext = core.i18n.Context;
|
||||
|
||||
const props = {
|
||||
user,
|
||||
user: currentUserPromise,
|
||||
editProfileUrl: core.http.basePath.prepend('/app/kibana#/account'),
|
||||
logoutUrl: core.http.basePath.prepend(`/logout`),
|
||||
};
|
||||
|
|
|
@ -9,18 +9,20 @@ import { LicensingPluginSetup } from '../../licensing/public';
|
|||
import {
|
||||
SessionExpired,
|
||||
SessionTimeout,
|
||||
ISessionTimeout,
|
||||
SessionTimeoutHttpInterceptor,
|
||||
UnauthorizedResponseHttpInterceptor,
|
||||
} from './session';
|
||||
import { SecurityLicenseService } from '../common/licensing';
|
||||
import { SecurityNavControlService } from './nav_control';
|
||||
import { AuthenticationService } from './authentication';
|
||||
|
||||
export interface PluginSetupDependencies {
|
||||
licensing: LicensingPluginSetup;
|
||||
}
|
||||
|
||||
export class SecurityPlugin implements Plugin<SecurityPluginSetup, SecurityPluginStart> {
|
||||
private sessionTimeout!: SessionTimeout;
|
||||
private sessionTimeout!: ISessionTimeout;
|
||||
|
||||
private navControlService!: SecurityNavControlService;
|
||||
|
||||
|
@ -43,12 +45,15 @@ export class SecurityPlugin implements Plugin<SecurityPluginSetup, SecurityPlugi
|
|||
this.securityLicenseService = new SecurityLicenseService();
|
||||
const { license } = this.securityLicenseService.setup({ license$: licensing.license$ });
|
||||
|
||||
const authc = new AuthenticationService().setup({ http: core.http });
|
||||
|
||||
this.navControlService.setup({
|
||||
securityLicense: license,
|
||||
authc,
|
||||
});
|
||||
|
||||
return {
|
||||
anonymousPaths,
|
||||
authc,
|
||||
sessionTimeout: this.sessionTimeout,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,6 +5,6 @@
|
|||
*/
|
||||
|
||||
export { SessionExpired } from './session_expired';
|
||||
export { SessionTimeout } from './session_timeout';
|
||||
export { SessionTimeout, ISessionTimeout } from './session_timeout';
|
||||
export { SessionTimeoutHttpInterceptor } from './session_timeout_http_interceptor';
|
||||
export { UnauthorizedResponseHttpInterceptor } from './unauthorized_response_http_interceptor';
|
||||
|
|
|
@ -41,7 +41,7 @@ export interface ISessionTimeout {
|
|||
extend(url: string): void;
|
||||
}
|
||||
|
||||
export class SessionTimeout {
|
||||
export class SessionTimeout implements ISessionTimeout {
|
||||
private channel?: BroadcastChannel<SessionInfo>;
|
||||
private sessionInfo?: SessionInfo;
|
||||
private fetchTimer?: number;
|
||||
|
|
|
@ -8,7 +8,6 @@ import crypto from 'crypto';
|
|||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { schema, Type, TypeOf } from '@kbn/config-schema';
|
||||
import { duration } from 'moment';
|
||||
import { PluginInitializerContext } from '../../../../src/core/server';
|
||||
|
||||
export type ConfigType = ReturnType<typeof createConfig$> extends Observable<infer P>
|
||||
|
@ -35,7 +34,6 @@ export const ConfigSchema = schema.object(
|
|||
schema.maybe(schema.string({ minLength: 32 })),
|
||||
schema.string({ minLength: 32, defaultValue: 'a'.repeat(32) })
|
||||
),
|
||||
sessionTimeout: schema.maybe(schema.nullable(schema.number())), // DEPRECATED
|
||||
session: schema.object({
|
||||
idleTimeout: schema.nullable(schema.duration()),
|
||||
lifespan: schema.nullable(schema.duration()),
|
||||
|
@ -112,22 +110,11 @@ export function createConfig$(context: PluginInitializerContext, isTLSEnabled: b
|
|||
secureCookies = true;
|
||||
}
|
||||
|
||||
// "sessionTimeout" is deprecated and replaced with "session.idleTimeout"
|
||||
// however, NP does not yet have a mechanism to automatically rename deprecated keys
|
||||
// for the time being, we'll do it manually:
|
||||
const deprecatedSessionTimeout =
|
||||
typeof config.sessionTimeout === 'number' ? duration(config.sessionTimeout) : null;
|
||||
const val = {
|
||||
return {
|
||||
...config,
|
||||
encryptionKey,
|
||||
secureCookies,
|
||||
session: {
|
||||
...config.session,
|
||||
idleTimeout: config.session.idleTimeout || deprecatedSessionTimeout,
|
||||
},
|
||||
};
|
||||
delete val.sessionTimeout; // DEPRECATED
|
||||
return val;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,9 +4,15 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { PluginInitializerContext } from '../../../../src/core/server';
|
||||
import { TypeOf } from '@kbn/config-schema';
|
||||
import {
|
||||
PluginConfigDescriptor,
|
||||
PluginInitializer,
|
||||
PluginInitializerContext,
|
||||
RecursiveReadonly,
|
||||
} from '../../../../src/core/server';
|
||||
import { ConfigSchema } from './config';
|
||||
import { Plugin } from './plugin';
|
||||
import { Plugin, PluginSetupContract, PluginSetupDependencies } from './plugin';
|
||||
|
||||
// These exports are part of public Security plugin contract, any change in signature of exported
|
||||
// functions or removal of exports should be considered as a breaking change.
|
||||
|
@ -17,8 +23,17 @@ export {
|
|||
InvalidateAPIKeyParams,
|
||||
InvalidateAPIKeyResult,
|
||||
} from './authentication';
|
||||
export { PluginSetupContract } from './plugin';
|
||||
export { PluginSetupContract };
|
||||
|
||||
export const config = { schema: ConfigSchema };
|
||||
export const plugin = (initializerContext: PluginInitializerContext) =>
|
||||
new Plugin(initializerContext);
|
||||
export const config: PluginConfigDescriptor<TypeOf<typeof ConfigSchema>> = {
|
||||
schema: ConfigSchema,
|
||||
deprecations: ({ rename, unused }) => [
|
||||
rename('sessionTimeout', 'session.idleTimeout'),
|
||||
unused('authorization.legacyFallback.enabled'),
|
||||
],
|
||||
};
|
||||
export const plugin: PluginInitializer<
|
||||
RecursiveReadonly<PluginSetupContract>,
|
||||
void,
|
||||
PluginSetupDependencies
|
||||
> = (initializerContext: PluginInitializerContext) => new Plugin(initializerContext);
|
||||
|
|
|
@ -111,10 +111,7 @@ export class Plugin {
|
|||
this.logger = this.initializerContext.logger.get();
|
||||
}
|
||||
|
||||
public async setup(
|
||||
core: CoreSetup,
|
||||
{ features, licensing }: PluginSetupDependencies
|
||||
): Promise<RecursiveReadonly<PluginSetupContract>> {
|
||||
public async setup(core: CoreSetup, { features, licensing }: PluginSetupDependencies) {
|
||||
const [config, legacyConfig] = await combineLatest([
|
||||
createConfig$(this.initializerContext, core.http.isTlsEnabled),
|
||||
this.initializerContext.config.legacy.globalConfig$,
|
||||
|
@ -170,7 +167,7 @@ export class Plugin {
|
|||
csp: core.http.csp,
|
||||
});
|
||||
|
||||
return deepFreeze({
|
||||
return deepFreeze<PluginSetupContract>({
|
||||
authc,
|
||||
|
||||
authz: {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue