Rename viewer_user to viewer (#134294)

This commit is contained in:
Søren Louv-Jansen 2022-06-22 20:39:18 +02:00 committed by GitHub
parent 429c14991a
commit 60e7f1dcd1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 225 additions and 105 deletions

View file

@ -15,6 +15,8 @@ import {
// @ts-ignore not typed yet
} from './functional_tests/cli';
export { KbnClientRequesterError } from './kbn_client/kbn_client_requester_error';
// @internal
export { runTestsCli, processRunTestsCliOptions, startServersCli, processStartServersCliOptions };

View file

@ -13,6 +13,7 @@ import Qs from 'querystring';
import Axios, { AxiosResponse, ResponseType } from 'axios';
import { isAxiosRequestError, isAxiosResponseError } from '@kbn/dev-utils';
import { ToolingLog } from '@kbn/tooling-log';
import { KbnClientRequesterError } from './kbn_client_requester_error';
const isConcliftOnGetError = (error: any) => {
return (
@ -166,7 +167,7 @@ export class KbnClientRequester {
continue;
}
throw new Error(`${errorMessage} -- and ran out of retries`);
throw new KbnClientRequesterError(`${errorMessage} -- and ran out of retries`, error);
}
}
}

View file

@ -0,0 +1,21 @@
/*
* 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 { AxiosError } from 'axios';
export class KbnClientRequesterError extends Error {
axiosError?: AxiosError;
constructor(message: string, error: unknown) {
super(message);
this.name = 'KbnClientRequesterError';
if (error instanceof AxiosError) {
this.axiosError = error;
}
}
}

View file

@ -90,8 +90,8 @@ node x-pack/plugins/apm/scripts/create_apm_users.js --username admin --password
This will create:
- **viewer_user**: User with `viewer` role (read-only)
- **editor_user**: User with `editor` role (read/write)
- **viewer**: User with `viewer` role (read-only)
- **editor**: User with `editor` role (read/write)
# Debugging Elasticsearch queries

View file

@ -29,7 +29,7 @@ describe('No data screen', () => {
headers: {
'kbn-xsrf': true,
},
auth: { user: 'editor_user', pass: 'changeme' },
auth: { user: 'editor', pass: 'changeme' },
});
});
@ -57,7 +57,7 @@ describe('No data screen', () => {
metric: '',
},
headers: { 'kbn-xsrf': true },
auth: { user: 'editor_user', pass: 'changeme' },
auth: { user: 'editor', pass: 'changeme' },
});
});
});

View file

@ -11,11 +11,11 @@ import moment from 'moment';
import { AXE_CONFIG, AXE_OPTIONS } from '@kbn/axe-config';
Cypress.Commands.add('loginAsViewerUser', () => {
cy.loginAs({ username: 'viewer_user', password: 'changeme' });
cy.loginAs({ username: 'viewer', password: 'changeme' });
});
Cypress.Commands.add('loginAsEditorUser', () => {
cy.loginAs({ username: 'editor_user', password: 'changeme' });
cy.loginAs({ username: 'editor', password: 'changeme' });
});
Cypress.Commands.add(

View file

@ -7,8 +7,8 @@
/*
* This script will create two users
* - editor_user
* - viewer_user
* - editor
* - viewer
*
* Usage: node create-apm-users.js
******************************/

View file

@ -42,8 +42,8 @@ export async function createApmUsers({
// user definitions
const users = [
{ username: 'viewer_user', roles: ['viewer'] },
{ username: 'editor_user', roles: ['editor'] },
{ username: 'viewer', roles: ['viewer'] },
{ username: 'editor', roles: ['editor'] },
];
// create users

View file

@ -38,7 +38,7 @@ journey('DataViewPermissions', async ({ page, params }) => {
await page.goto(`${baseUrl}?${queryParams}`, {
waitUntil: 'networkidle',
});
await login.loginToKibana('viewer_user', 'changeme');
await login.loginToKibana('viewer', 'changeme');
});
step('Click explore data button', async () => {

View file

@ -57,7 +57,7 @@ journey(
});
step('login to Kibana', async () => {
await uptime.loginToKibana('editor_user', 'changeme');
await uptime.loginToKibana('editor', 'changeme');
const invalid = await page.locator(
`text=Username or password is incorrect. Please try again.`
);

View file

@ -23,7 +23,7 @@ journey(
});
step('login to Kibana', async () => {
await uptime.loginToKibana('viewer_user', 'changeme');
await uptime.loginToKibana('viewer', 'changeme');
});
step('Adding monitor is disabled', async () => {

View file

@ -24,7 +24,7 @@ export function loginPageProvider({
await page.waitForTimeout(5 * 1000);
}
},
async loginToKibana(usernameT?: string, passwordT?: string) {
async loginToKibana(usernameT?: 'editor' | 'viewer', passwordT?: string) {
if (isRemote) {
await page.click('text="Log in with Elasticsearch"');
}

View file

@ -29,7 +29,7 @@ journey('Core Web Vitals', async ({ page, params }) => {
});
await loginToKibana({
page,
user: { username: 'viewer_user', password: 'changeme' },
user: { username: 'viewer', password: 'changeme' },
});
});

View file

@ -29,7 +29,7 @@ journey('UX URL Query', async ({ page, params }) => {
});
await loginToKibana({
page,
user: { username: 'viewer_user', password: 'changeme' },
user: { username: 'viewer', password: 'changeme' },
});
});

View file

@ -34,7 +34,7 @@ journey('UX JsErrors', async ({ page, params }) => {
});
await loginToKibana({
page,
user: { username: 'viewer_user', password: 'changeme' },
user: { username: 'viewer', password: 'changeme' },
});
});

View file

@ -7,25 +7,33 @@
import { Client } from '@elastic/elasticsearch';
import { PrivilegeType } from '@kbn/apm-plugin/common/privilege_type';
import { ToolingLog } from '@kbn/tooling-log';
import { omit } from 'lodash';
import { KbnClientRequesterError } from '@kbn/test';
import { AxiosError } from 'axios';
import { SecurityServiceProvider } from '../../../../test/common/services/security';
type SecurityService = Awaited<ReturnType<typeof SecurityServiceProvider>>;
export enum ApmUser {
export enum ApmUsername {
noAccessUser = 'no_access_user',
viewerUser = 'viewer_user',
editorUser = 'editor_user',
viewerUser = 'viewer',
editorUser = 'editor',
apmAnnotationsWriteUser = 'apm_annotations_write_user',
apmReadUserWithoutMlAccess = 'apm_read_user_without_ml_access',
apmManageOwnAgentKeys = 'apm_manage_own_agent_keys',
apmManageOwnAndCreateAgentKeys = 'apm_manage_own_and_create_agent_keys',
}
const roles = {
[ApmUser.noAccessUser]: {},
[ApmUser.viewerUser]: {},
[ApmUser.editorUser]: {},
[ApmUser.apmReadUserWithoutMlAccess]: {
export enum ApmCustomRolename {
apmReadUserWithoutMlAccess = 'apm_read_user_without_ml_access',
apmAnnotationsWriteUser = 'apm_annotations_write_user',
apmManageOwnAgentKeys = 'apm_manage_own_agent_keys',
apmManageOwnAndCreateAgentKeys = 'apm_manage_own_and_create_agent_keys',
}
const customRoles = {
[ApmCustomRolename.apmReadUserWithoutMlAccess]: {
elasticsearch: {
cluster: [],
indices: [
@ -43,7 +51,7 @@ const roles = {
},
],
},
[ApmUser.apmAnnotationsWriteUser]: {
[ApmCustomRolename.apmAnnotationsWriteUser]: {
elasticsearch: {
cluster: [],
indices: [
@ -61,12 +69,12 @@ const roles = {
],
},
},
[ApmUser.apmManageOwnAgentKeys]: {
[ApmCustomRolename.apmManageOwnAgentKeys]: {
elasticsearch: {
cluster: ['manage_own_api_key'],
},
},
[ApmUser.apmManageOwnAndCreateAgentKeys]: {
[ApmCustomRolename.apmManageOwnAndCreateAgentKeys]: {
applications: [
{
application: 'apm',
@ -77,55 +85,101 @@ const roles = {
},
};
const users = {
[ApmUser.noAccessUser]: {
roles: [],
const users: Record<
ApmUsername,
{ builtInRoleNames?: string[]; customRoleNames?: ApmCustomRolename[] }
> = {
[ApmUsername.noAccessUser]: {},
[ApmUsername.viewerUser]: {
builtInRoleNames: ['viewer'],
},
[ApmUser.viewerUser]: {
roles: ['viewer'],
[ApmUsername.editorUser]: {
builtInRoleNames: ['editor'],
},
[ApmUser.editorUser]: {
roles: ['editor'],
[ApmUsername.apmReadUserWithoutMlAccess]: {
customRoleNames: [ApmCustomRolename.apmReadUserWithoutMlAccess],
},
[ApmUser.apmReadUserWithoutMlAccess]: {
roles: [ApmUser.apmReadUserWithoutMlAccess],
[ApmUsername.apmAnnotationsWriteUser]: {
builtInRoleNames: ['editor'],
customRoleNames: [ApmCustomRolename.apmAnnotationsWriteUser],
},
[ApmUser.apmAnnotationsWriteUser]: {
roles: ['editor', ApmUser.apmAnnotationsWriteUser],
[ApmUsername.apmManageOwnAgentKeys]: {
builtInRoleNames: ['editor'],
customRoleNames: [ApmCustomRolename.apmManageOwnAgentKeys],
},
[ApmUser.apmManageOwnAgentKeys]: {
roles: ['editor', ApmUser.apmManageOwnAgentKeys],
},
[ApmUser.apmManageOwnAndCreateAgentKeys]: {
roles: ['editor', ApmUser.apmManageOwnAgentKeys, ApmUser.apmManageOwnAndCreateAgentKeys],
[ApmUsername.apmManageOwnAndCreateAgentKeys]: {
builtInRoleNames: ['editor'],
customRoleNames: [
ApmCustomRolename.apmManageOwnAgentKeys,
ApmCustomRolename.apmManageOwnAndCreateAgentKeys,
],
},
};
export async function createApmUser(security: SecurityService, apmUser: ApmUser, es: Client) {
const role = roles[apmUser];
const user = users[apmUser];
function logErrorResponse(logger: ToolingLog, e: Error) {
if (e instanceof KbnClientRequesterError) {
logger.error(`KbnClientRequesterError: ${JSON.stringify(e.axiosError?.response?.data)}`);
} else if (e instanceof AxiosError) {
logger.error(`AxiosError: ${JSON.stringify(e.response?.data)}`);
} else {
logger.error(`Unknown error: ${e.constructor.name}`);
}
}
if (!role || !user) {
throw new Error(`No configuration found for ${apmUser}`);
export async function createApmUser({
username,
security,
es,
logger,
}: {
username: ApmUsername;
security: SecurityService;
es: Client;
logger: ToolingLog;
}) {
const user = users[username];
if (!user) {
throw new Error(`No configuration found for ${username}`);
}
if ('applications' in role) {
// Add application privileges with es client as they are not supported by
// security.user.create. They are preserved when updating the role below
await es.security.putRole({
name: apmUser,
body: role,
const { builtInRoleNames = [], customRoleNames = [] } = user;
try {
// create custom roles
await Promise.all(
customRoleNames.map(async (roleName) => createCustomRole({ roleName, security, es }))
);
// create user
await security.user.create(username, {
full_name: username,
password: APM_TEST_PASSWORD,
roles: [...builtInRoleNames, ...customRoleNames],
});
delete (role as any).applications;
} catch (e) {
logErrorResponse(logger, e);
throw e;
}
}
await security.role.create(apmUser, role);
async function createCustomRole({
roleName,
security,
es,
}: {
roleName: ApmCustomRolename;
security: SecurityService;
es: Client;
}) {
const role = customRoles[roleName];
await security.user.create(apmUser, {
full_name: apmUser,
password: APM_TEST_PASSWORD,
roles: user.roles,
});
// Add application privileges with es client as they are not supported by
// security.user.create. They are preserved when updating the role below
if ('applications' in role) {
await es.security.putRole({ name: roleName, body: role });
}
await security.role.create(roleName, omit(role, 'applications'));
}
export const APM_TEST_PASSWORD = 'changeme';

View file

@ -9,9 +9,10 @@ import { FtrConfigProviderContext } from '@kbn/test';
import supertest from 'supertest';
import { format, UrlObject } from 'url';
import { Client } from '@elastic/elasticsearch';
import { ToolingLog } from '@kbn/tooling-log';
import { SecurityServiceProvider } from '../../../../test/common/services/security';
import { InheritedFtrProviderContext, InheritedServices } from './ftr_provider_context';
import { createApmUser, APM_TEST_PASSWORD, ApmUser } from './authentication';
import { createApmUser, APM_TEST_PASSWORD, ApmUsername } from './authentication';
import { APMFtrConfigName } from '../configs';
import { createApmApiClient } from './apm_api_supertest';
import { RegistryProvider } from './registry';
@ -26,34 +27,42 @@ export interface ApmFtrConfig {
type SecurityService = Awaited<ReturnType<typeof SecurityServiceProvider>>;
function getLegacySupertestClient(kibanaServer: UrlObject, apmUser: ApmUser) {
function getLegacySupertestClient(kibanaServer: UrlObject, username: ApmUsername) {
return async (context: InheritedFtrProviderContext) => {
const security = context.getService('security');
const es = context.getService('es');
const logger = context.getService('log');
await security.init();
await createApmUser(security, apmUser, es);
await createApmUser({ security, username, es, logger });
const url = format({
...kibanaServer,
auth: `${apmUser}:${APM_TEST_PASSWORD}`,
auth: `${username}:${APM_TEST_PASSWORD}`,
});
return supertest(url);
};
}
async function getApmApiClient(
kibanaServer: UrlObject,
security: SecurityService,
apmUser: ApmUser,
es: Client
) {
await createApmUser(security, apmUser, es);
async function getApmApiClient({
kibanaServer,
security,
username,
es,
logger,
}: {
kibanaServer: UrlObject;
security: SecurityService;
username: ApmUsername;
es: Client;
logger: ToolingLog;
}) {
await createApmUser({ security, username, es, logger });
const url = format({
...kibanaServer,
auth: `${apmUser}:${APM_TEST_PASSWORD}`,
auth: `${username}:${APM_TEST_PASSWORD}`,
});
return createApmApiClient(supertest(url));
@ -85,50 +94,83 @@ export function createTestConfig(config: ApmFtrConfig) {
apmApiClient: async (context: InheritedFtrProviderContext) => {
const security = context.getService('security');
const es = context.getService('es');
const logger = context.getService('log');
await security.init();
return {
noAccessUser: await getApmApiClient(servers.kibana, security, ApmUser.noAccessUser, es),
readUser: await getApmApiClient(servers.kibana, security, ApmUser.viewerUser, es),
writeUser: await getApmApiClient(servers.kibana, security, ApmUser.editorUser, es),
annotationWriterUser: await getApmApiClient(
servers.kibana,
noAccessUser: await getApmApiClient({
kibanaServer: servers.kibana,
security,
ApmUser.apmAnnotationsWriteUser,
es
),
noMlAccessUser: await getApmApiClient(
servers.kibana,
username: ApmUsername.noAccessUser,
es,
logger,
}),
readUser: await getApmApiClient({
kibanaServer: servers.kibana,
security,
ApmUser.apmReadUserWithoutMlAccess,
es
),
manageOwnAgentKeysUser: await getApmApiClient(
servers.kibana,
username: ApmUsername.viewerUser,
es,
logger,
}),
writeUser: await getApmApiClient({
kibanaServer: servers.kibana,
security,
ApmUser.apmManageOwnAgentKeys,
es
),
createAndAllAgentKeysUser: await getApmApiClient(
servers.kibana,
username: ApmUsername.editorUser,
es,
logger,
}),
annotationWriterUser: await getApmApiClient({
kibanaServer: servers.kibana,
security,
ApmUser.apmManageOwnAndCreateAgentKeys,
es
),
username: ApmUsername.apmAnnotationsWriteUser,
es,
logger,
}),
noMlAccessUser: await getApmApiClient({
kibanaServer: servers.kibana,
security,
username: ApmUsername.apmReadUserWithoutMlAccess,
es,
logger,
}),
manageOwnAgentKeysUser: await getApmApiClient({
kibanaServer: servers.kibana,
security,
username: ApmUsername.apmManageOwnAgentKeys,
es,
logger,
}),
createAndAllAgentKeysUser: await getApmApiClient({
kibanaServer: servers.kibana,
security,
username: ApmUsername.apmManageOwnAndCreateAgentKeys,
es,
logger,
}),
};
},
ml: MachineLearningAPIProvider,
// legacy clients
legacySupertestAsNoAccessUser: getLegacySupertestClient(kibanaServer, ApmUser.noAccessUser),
legacySupertestAsApmReadUser: getLegacySupertestClient(kibanaServer, ApmUser.viewerUser),
legacySupertestAsApmWriteUser: getLegacySupertestClient(kibanaServer, ApmUser.editorUser),
legacySupertestAsNoAccessUser: getLegacySupertestClient(
kibanaServer,
ApmUsername.noAccessUser
),
legacySupertestAsApmReadUser: getLegacySupertestClient(
kibanaServer,
ApmUsername.viewerUser
),
legacySupertestAsApmWriteUser: getLegacySupertestClient(
kibanaServer,
ApmUsername.editorUser
),
legacySupertestAsApmAnnotationsWriteUser: getLegacySupertestClient(
kibanaServer,
ApmUser.apmAnnotationsWriteUser
ApmUsername.apmAnnotationsWriteUser
),
legacySupertestAsApmReadUserWithoutMlAccess: getLegacySupertestClient(
kibanaServer,
ApmUser.apmReadUserWithoutMlAccess
ApmUsername.apmReadUserWithoutMlAccess
),
},
junit: {

View file

@ -9,7 +9,7 @@ import { first } from 'lodash';
import { PrivilegeType } from '@kbn/apm-plugin/common/privilege_type';
import { FtrProviderContext } from '../../../common/ftr_provider_context';
import { ApmApiError, ApmApiSupertest } from '../../../common/apm_api_supertest';
import { ApmUser } from '../../../common/authentication';
import { ApmUsername } from '../../../common/authentication';
export default function ApiTest({ getService }: FtrProviderContext) {
const registry = getService('registry');
@ -92,7 +92,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
() => {
afterEach(async () => {
await esClient.security.invalidateApiKey({
username: ApmUser.apmManageOwnAndCreateAgentKeys,
username: ApmUsername.apmManageOwnAndCreateAgentKeys,
});
});