[CLOUD] Intercept query string (#204129)

## Summary

This PR in cloud https://github.com/elastic/cloud/pull/135346 is going
to pass an `onboarding_token` query string. I am just trying to
Intercept it and saved it. Therefore solution can streamline the Kibana
onboarding process for trial user.


### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Xavier Mouligneau 2025-01-13 18:09:50 -05:00 committed by GitHub
parent 13d4813151
commit 1d52062c2c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 1038 additions and 53 deletions

View file

@ -282,6 +282,7 @@ enabled:
- x-pack/test/functional/config.firefox.js
- x-pack/test/functional/config.upgrade_assistant.ts
- x-pack/test/functional_cloud/config.ts
- x-pack/test/functional_cloud/saml.config.ts
- x-pack/test/functional_solution_sidenav/config.ts
- x-pack/test/functional_search/config.ts
- x-pack/test/kubernetes_security/basic/config.ts
@ -379,3 +380,4 @@ enabled:
# stateful config files that run deployment-agnostic tests
- x-pack/test/api_integration/deployment_agnostic/configs/stateful/platform.stateful.config.ts
- x-pack/test/api_integration/apis/cloud/config.ts
- x-pack/test/api_integration/apis/cloud/saml.config.ts

View file

@ -0,0 +1,8 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export { persistTokenCloudData } from './persist_token';

View file

@ -0,0 +1,158 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { persistTokenCloudData } from './persist_token'; // Adjust the import based on the actual file path
import { Logger, SavedObjectsClientContract, SavedObjectsErrorHelpers } from '@kbn/core/server';
import { CLOUD_DATA_SAVED_OBJECT_TYPE } from '../saved_objects';
import { CLOUD_DATA_SAVED_OBJECT_ID } from '../routes/constants';
const mockSavedObjectsClient = {
get: jest.fn(),
create: jest.fn(),
update: jest.fn(),
} as unknown as SavedObjectsClientContract;
const mockLogger = {
error: jest.fn(),
} as unknown as Logger;
describe('persistTokenCloudData', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('creates a new saved object if none exists and onboardingToken is provided', async () => {
(mockSavedObjectsClient.get as jest.Mock).mockRejectedValue(
SavedObjectsErrorHelpers.createGenericNotFoundError()
);
await persistTokenCloudData(mockSavedObjectsClient, {
logger: mockLogger,
onboardingToken: 'test_token',
solutionType: 'test_solution',
});
expect(mockSavedObjectsClient.create).toHaveBeenCalledWith(
CLOUD_DATA_SAVED_OBJECT_TYPE,
{
onboardingData: {
solutionType: 'test_solution',
token: 'test_token',
},
},
{ id: CLOUD_DATA_SAVED_OBJECT_ID }
);
});
it('updates an existing saved object if onboardingToken is provided and different', async () => {
(mockSavedObjectsClient.get as jest.Mock).mockResolvedValue({
id: CLOUD_DATA_SAVED_OBJECT_ID,
attributes: {
onboardingData: {
token: 'old_token',
solutionType: 'test_solution',
},
},
});
await persistTokenCloudData(mockSavedObjectsClient, {
logger: mockLogger,
onboardingToken: 'new_token',
solutionType: 'test_solution',
});
expect(mockSavedObjectsClient.update).toHaveBeenCalledWith(
CLOUD_DATA_SAVED_OBJECT_TYPE,
CLOUD_DATA_SAVED_OBJECT_ID,
{
onboardingData: {
solutionType: 'test_solution',
token: 'new_token',
},
}
);
});
it('does nothing if onboardingToken is the same', async () => {
(mockSavedObjectsClient.get as jest.Mock).mockResolvedValue({
id: CLOUD_DATA_SAVED_OBJECT_ID,
attributes: {
onboardingData: {
token: 'same_token',
solutionType: 'test_solution',
},
},
});
await persistTokenCloudData(mockSavedObjectsClient, {
logger: mockLogger,
onboardingToken: 'same_token',
solutionType: 'test_solution',
});
expect(mockSavedObjectsClient.update).not.toHaveBeenCalled();
});
it('logs an error if get throws an unexpected error', async () => {
(mockSavedObjectsClient.get as jest.Mock).mockRejectedValue(
SavedObjectsErrorHelpers.createBadRequestError()
);
await persistTokenCloudData(mockSavedObjectsClient, {
logger: mockLogger,
onboardingToken: 'test_token',
solutionType: 'test_solution',
});
expect(mockLogger.error).toHaveBeenCalled();
});
it('throws an error if get throws an unexpected error and returnError is true', async () => {
(mockSavedObjectsClient.get as jest.Mock).mockRejectedValue(
SavedObjectsErrorHelpers.createBadRequestError()
);
await expect(
persistTokenCloudData(mockSavedObjectsClient, {
logger: mockLogger,
returnError: true,
onboardingToken: 'test_token',
solutionType: 'test_solution',
})
).rejects.toThrow();
});
it('logs an error if create throws an error', async () => {
(mockSavedObjectsClient.get as jest.Mock).mockRejectedValue(
SavedObjectsErrorHelpers.createGenericNotFoundError()
);
const error = new Error('Create error');
(mockSavedObjectsClient.create as jest.Mock).mockRejectedValue(error);
await persistTokenCloudData(mockSavedObjectsClient, {
logger: mockLogger,
onboardingToken: 'test_token',
solutionType: 'test_solution',
});
expect(mockLogger.error).toHaveBeenCalledWith(error);
});
it('throws an error if create throws an error and returnError is true', async () => {
(mockSavedObjectsClient.get as jest.Mock).mockRejectedValue(
SavedObjectsErrorHelpers.createGenericNotFoundError()
);
const error = new Error('Create error');
(mockSavedObjectsClient.create as jest.Mock).mockRejectedValue(error);
await expect(
persistTokenCloudData(mockSavedObjectsClient, {
logger: mockLogger,
returnError: true,
onboardingToken: 'test_token',
solutionType: 'test_solution',
})
).rejects.toThrow(error);
});
});

View file

@ -0,0 +1,81 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { Logger, SavedObjectsClientContract, SavedObjectsErrorHelpers } from '@kbn/core/server';
import { CloudDataAttributes, SolutionType } from '../routes/types';
import { CLOUD_DATA_SAVED_OBJECT_TYPE } from '../saved_objects';
import { CLOUD_DATA_SAVED_OBJECT_ID } from '../routes/constants';
export const persistTokenCloudData = async (
savedObjectsClient: SavedObjectsClientContract,
{
logger,
returnError,
onboardingToken,
solutionType,
}: {
logger?: Logger;
returnError?: boolean;
onboardingToken?: string;
solutionType?: string;
}
): Promise<void> => {
let cloudDataSo = null;
try {
cloudDataSo = await savedObjectsClient.get<CloudDataAttributes>(
CLOUD_DATA_SAVED_OBJECT_TYPE,
CLOUD_DATA_SAVED_OBJECT_ID
);
} catch (error) {
if (SavedObjectsErrorHelpers.isNotFoundError(error)) {
cloudDataSo = null;
} else {
if (returnError) {
throw error;
} else if (logger) {
logger.error(error);
}
}
}
try {
if (onboardingToken && cloudDataSo === null) {
await savedObjectsClient.create<CloudDataAttributes>(
CLOUD_DATA_SAVED_OBJECT_TYPE,
{
onboardingData: {
solutionType: solutionType as SolutionType,
token: onboardingToken,
},
},
{ id: CLOUD_DATA_SAVED_OBJECT_ID }
);
} else if (
onboardingToken &&
cloudDataSo?.attributes.onboardingData.token &&
cloudDataSo?.attributes.onboardingData.token !== onboardingToken
) {
await savedObjectsClient.update<CloudDataAttributes>(
CLOUD_DATA_SAVED_OBJECT_TYPE,
CLOUD_DATA_SAVED_OBJECT_ID,
{
onboardingData: {
solutionType:
(solutionType as SolutionType) ?? cloudDataSo?.attributes.onboardingData.solutionType,
token: onboardingToken,
},
}
);
}
} catch (error) {
if (returnError) {
throw error;
} else if (logger) {
logger.error(error);
}
}
};

View file

@ -20,3 +20,11 @@ jest.doMock('../common/decode_cloud_id', () => {
decodeCloudId: decodeCloudIdMock,
};
});
export const persistTokenCloudDataMock = jest.fn();
jest.doMock('./cloud_data', () => {
return {
persistTokenCloudData: persistTokenCloudDataMock,
};
});

View file

@ -10,8 +10,12 @@ import type { CoreSetup, Plugin, PluginInitializerContext } from '@kbn/core/serv
import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server';
import type { SolutionId } from '@kbn/core-chrome-browser';
import { registerCloudDeploymentMetadataAnalyticsContext } from '../common/register_cloud_deployment_id_analytics_context';
import { schema } from '@kbn/config-schema';
import { parseNextURL } from '@kbn/std';
import type { CloudConfigType } from './config';
import { registerCloudDeploymentMetadataAnalyticsContext } from '../common/register_cloud_deployment_id_analytics_context';
import { registerCloudUsageCollector } from './collectors';
import { getIsCloudEnabled } from '../common/is_cloud_enabled';
import { parseDeploymentIdFromDeploymentUrl } from '../common/parse_deployment_id_from_deployment_url';
@ -21,7 +25,8 @@ import { getFullCloudUrl } from '../common/utils';
import { readInstanceSizeMb } from './env';
import { defineRoutes } from './routes';
import { CloudRequestHandlerContext } from './routes/types';
import { setupSavedObjects } from './saved_objects';
import { CLOUD_DATA_SAVED_OBJECT_TYPE, setupSavedObjects } from './saved_objects';
import { persistTokenCloudData } from './cloud_data';
interface PluginsSetup {
usageCollection?: UsageCollectionSetup;
@ -200,6 +205,64 @@ export class CloudPlugin implements Plugin<CloudSetup, CloudStart> {
projectType,
orchestratorTarget,
});
const basePath = core.http.basePath.serverBasePath;
core.http.resources.register(
{
path: '/app/cloud/onboarding',
validate: {
query: schema.maybe(
schema.object(
{
next: schema.maybe(schema.string()),
onboarding_token: schema.maybe(schema.string()),
},
{ unknowns: 'ignore' }
)
),
},
security: {
authz: {
enabled: false,
reason:
'Authorization at the API level isnt required, as its implicitly enforced by the scoped `uiSettings` and `SavedObjects` clients used to handle the request.',
},
},
},
async (context, request, response) => {
const { uiSettings, savedObjects } = await context.core;
const defaultRoute = await uiSettings.client.get<string>('defaultRoute');
const nextCandidateRoute = parseNextURL(request.url.href);
const route = nextCandidateRoute === '/' ? defaultRoute : nextCandidateRoute;
// need to get reed of ../../ to make sure we will not be out of space basePath
const normalizedRoute = new URL(route, 'https://localhost');
const queryOnboardingToken = request.url.searchParams.get('onboarding_token');
const solutionType = this.config.onboarding?.default_solution;
if (queryOnboardingToken) {
core
.getStartServices()
.then(async ([coreStart]) => {
const soClient = savedObjects.getClient({
includedHiddenTypes: [CLOUD_DATA_SAVED_OBJECT_TYPE],
});
await persistTokenCloudData(soClient, {
logger: this.logger,
onboardingToken: queryOnboardingToken,
solutionType,
});
})
.catch((errorMsg) => this.logger.error(errorMsg));
}
// preserving of the hash is important for the navigation to work correctly with default route
return response.redirected({
headers: {
location: `${basePath}${normalizedRoute.pathname}${normalizedRoute.search}${normalizedRoute.hash}`,
},
});
}
);
let decodedId: DecodedCloudId | undefined;
if (this.config.id) {

View file

@ -6,11 +6,10 @@
*/
import { schema } from '@kbn/config-schema';
import { ReservedPrivilegesSet, SavedObjectsErrorHelpers } from '@kbn/core/server';
import { ReservedPrivilegesSet } from '@kbn/core/server';
import { RouteOptions } from '.';
import { CLOUD_DATA_SAVED_OBJECT_ID } from './constants';
import { CLOUD_DATA_SAVED_OBJECT_TYPE } from '../saved_objects';
import { CloudDataAttributes } from './types';
import { persistTokenCloudData } from '../cloud_data';
const createBodySchemaV1 = schema.object({
onboardingData: schema.object({
@ -50,40 +49,15 @@ export const setPostCloudSolutionDataRoute = ({ router }: RouteOptions) => {
const savedObjectsClient = coreContext.savedObjects.getClient({
includedHiddenTypes: [CLOUD_DATA_SAVED_OBJECT_TYPE],
});
let cloudDataSo = null;
try {
cloudDataSo = await savedObjectsClient.get<CloudDataAttributes>(
CLOUD_DATA_SAVED_OBJECT_TYPE,
CLOUD_DATA_SAVED_OBJECT_ID
);
} catch (error) {
if (SavedObjectsErrorHelpers.isNotFoundError(error)) {
cloudDataSo = null;
} else {
return response.customError(error);
}
}
try {
if (cloudDataSo === null) {
await savedObjectsClient.create<CloudDataAttributes>(
CLOUD_DATA_SAVED_OBJECT_TYPE,
{
onboardingData: request.body.onboardingData,
},
{ id: CLOUD_DATA_SAVED_OBJECT_ID }
);
} else {
await savedObjectsClient.update<CloudDataAttributes>(
CLOUD_DATA_SAVED_OBJECT_TYPE,
CLOUD_DATA_SAVED_OBJECT_ID,
{
onboardingData: request.body.onboardingData,
}
);
}
await persistTokenCloudData(savedObjectsClient, {
returnError: true,
solutionType: request.body.onboardingData.solutionType,
onboardingToken: request.body.onboardingData.token,
});
} catch (error) {
return response.badRequest(error);
return response.customError(error);
}
return response.ok();

View file

@ -11,10 +11,10 @@ import { CustomRequestHandlerContext } from '@kbn/core/server';
* @internal
*/
export type CloudRequestHandlerContext = CustomRequestHandlerContext<{}>;
export type SolutionType = 'search' | 'elasticsearch' | 'observability' | 'security';
export interface CloudDataAttributes {
onboardingData: {
solutionType: 'security' | 'observability' | 'search' | 'elasticsearch';
solutionType?: SolutionType;
token: string;
};
}

View file

@ -18,6 +18,7 @@
"@kbn/logging-mocks",
"@kbn/logging",
"@kbn/core-saved-objects-server",
"@kbn/std",
],
"exclude": [
"target/**/*",

View file

@ -57,7 +57,7 @@ describe('FeatureRegistry', () => {
app: ['app1'],
savedObject: {
all: ['space', 'etc', 'telemetry'],
read: ['canvas', 'config', 'config-global', 'url', 'tag'],
read: ['canvas', 'config', 'config-global', 'url', 'tag', 'cloud'],
},
api: ['someApiEndpointTag', 'anotherEndpointTag'],
ui: ['allowsFoo', 'showBar', 'showBaz'],
@ -65,7 +65,7 @@ describe('FeatureRegistry', () => {
read: {
savedObject: {
all: [],
read: ['config', 'config-global', 'url', 'telemetry', 'tag'],
read: ['config', 'config-global', 'url', 'telemetry', 'tag', 'cloud'],
},
ui: [],
},
@ -130,7 +130,7 @@ describe('FeatureRegistry', () => {
app: ['app1'],
savedObject: {
all: ['space', 'etc', 'telemetry'],
read: ['canvas', 'config', 'config-global', 'url', 'tag'],
read: ['canvas', 'config', 'config-global', 'url', 'tag', 'cloud'],
},
api: ['someApiEndpointTag', 'anotherEndpointTag'],
ui: ['allowsFoo', 'showBar', 'showBaz'],
@ -348,13 +348,20 @@ describe('FeatureRegistry', () => {
const allPrivilege = result[0].privileges?.all;
const readPrivilege = result[0].privileges?.read;
expect(allPrivilege?.savedObject.read).toEqual(['config', 'config-global', 'url', 'tag']);
expect(allPrivilege?.savedObject.read).toEqual([
'config',
'config-global',
'url',
'tag',
'cloud',
]);
expect(readPrivilege?.savedObject.read).toEqual([
'config',
'config-global',
'telemetry',
'url',
'tag',
'cloud',
]);
});
@ -389,7 +396,13 @@ describe('FeatureRegistry', () => {
const reservedPrivilege = result[0]!.reserved!.privileges[0].privilege;
expect(reservedPrivilege.savedObject.all).toEqual(['telemetry']);
expect(reservedPrivilege.savedObject.read).toEqual(['config', 'config-global', 'url', 'tag']);
expect(reservedPrivilege.savedObject.read).toEqual([
'config',
'config-global',
'url',
'tag',
'cloud',
]);
});
it(`does not duplicate the automatic grants if specified on the incoming feature`, () => {
@ -403,14 +416,14 @@ describe('FeatureRegistry', () => {
ui: [],
savedObject: {
all: ['telemetry'],
read: ['config', 'config-global', 'url', 'tag'],
read: ['config', 'config-global', 'url', 'tag', 'cloud'],
},
},
read: {
ui: [],
savedObject: {
all: [],
read: ['config', 'config-global', 'url', 'tag'],
read: ['config', 'config-global', 'url', 'tag', 'cloud'],
},
},
},
@ -427,12 +440,19 @@ describe('FeatureRegistry', () => {
const allPrivilege = result[0].privileges!.all;
const readPrivilege = result[0].privileges!.read;
expect(allPrivilege?.savedObject.all).toEqual(['telemetry']);
expect(allPrivilege?.savedObject.read).toEqual(['config', 'config-global', 'url', 'tag']);
expect(allPrivilege?.savedObject.read).toEqual([
'config',
'config-global',
'url',
'tag',
'cloud',
]);
expect(readPrivilege?.savedObject.read).toEqual([
'config',
'config-global',
'url',
'tag',
'cloud',
'telemetry',
]);
});
@ -2457,7 +2477,10 @@ describe('FeatureRegistry', () => {
expect(featureA.privileges).toEqual({
all: {
ui: [],
savedObject: { all: ['telemetry'], read: ['config', 'config-global', 'url', 'tag'] },
savedObject: {
all: ['telemetry'],
read: ['config', 'config-global', 'url', 'tag', 'cloud'],
},
composedOf: [
{ feature: 'featureC', privileges: ['subFeatureCOne'] },
{ feature: 'featureD', privileges: ['all'] },
@ -2465,7 +2488,10 @@ describe('FeatureRegistry', () => {
},
read: {
ui: [],
savedObject: { all: [], read: ['config', 'config-global', 'telemetry', 'url', 'tag'] },
savedObject: {
all: [],
read: ['config', 'config-global', 'telemetry', 'url', 'tag', 'cloud'],
},
composedOf: [{ feature: 'featureD', privileges: ['read'] }],
},
});
@ -2485,12 +2511,18 @@ describe('FeatureRegistry', () => {
expect(featureA.privileges).toEqual({
all: {
ui: [],
savedObject: { all: ['telemetry'], read: ['config', 'config-global', 'url', 'tag'] },
savedObject: {
all: ['telemetry'],
read: ['config', 'config-global', 'url', 'tag', 'cloud'],
},
composedOf: [{ feature: 'featureE', privileges: ['all'] }],
},
read: {
ui: [],
savedObject: { all: [], read: ['config', 'config-global', 'telemetry', 'url', 'tag'] },
savedObject: {
all: [],
read: ['config', 'config-global', 'telemetry', 'url', 'tag', 'cloud'],
},
},
});
});

View file

@ -341,6 +341,7 @@ function applyAutomaticAllPrivilegeGrants(
'config-global',
'url',
'tag',
'cloud',
]);
}
});
@ -358,6 +359,7 @@ function applyAutomaticReadPrivilegeGrants(
'telemetry',
'url',
'tag',
'cloud',
]);
}
});

View file

@ -169,6 +169,7 @@ describe('Features Plugin', () => {
"config-global",
"url",
"tag",
"cloud",
],
},
"ui": Array [],
@ -185,6 +186,7 @@ describe('Features Plugin', () => {
"telemetry",
"url",
"tag",
"cloud",
],
},
"ui": Array [],

View file

@ -12,7 +12,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
return {
...baseIntegrationTestsConfig.getAll(),
testFiles: [require.resolve('.')],
testFiles: [require.resolve('./tests/set_cloud_data_route')],
kbnTestServer: {
...baseIntegrationTestsConfig.get('kbnTestServer'),
serverArgs: [

View file

@ -0,0 +1,101 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { readFileSync } from 'fs';
import { CA_CERT_PATH, KBN_CERT_PATH, KBN_KEY_PATH } from '@kbn/dev-utils';
import type { FtrConfigProviderContext } from '@kbn/test';
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
const kibanaAPITestsConfig = await readConfigFile(
require.resolve('@kbn/test-suites-src/api_integration/config')
);
const xPackAPITestsConfig = await readConfigFile(require.resolve('../../config.ts'));
const kibanaPort = xPackAPITestsConfig.get('servers.kibana.port');
const saml1IdPMetadataPath = require.resolve(
'@kbn/security-api-integration-helpers/saml/idp_metadata.xml'
);
const servers = {
...xPackAPITestsConfig.get('servers'),
elasticsearch: {
...xPackAPITestsConfig.get('servers.elasticsearch'),
protocol: 'https',
},
kibana: {
...xPackAPITestsConfig.get('servers.kibana'),
protocol: 'https',
certificateAuthorities: [readFileSync(CA_CERT_PATH)],
},
};
return {
testFiles: [require.resolve('./tests/relay_state')],
servers,
security: { disableTestUser: true },
services: {
...kibanaAPITestsConfig.get('services'),
...xPackAPITestsConfig.get('services'),
},
junit: {
reportName: 'X-Pack Security API Integration Tests (Login Selector)',
},
esTestCluster: {
...xPackAPITestsConfig.get('esTestCluster'),
ssl: true,
serverArgs: [
...xPackAPITestsConfig.get('esTestCluster.serverArgs'),
'xpack.security.authc.token.enabled=true',
'xpack.security.authc.token.timeout=15s',
'xpack.security.authc.realms.saml.saml1.order=0',
`xpack.security.authc.realms.saml.saml1.idp.metadata.path=${saml1IdPMetadataPath}`,
'xpack.security.authc.realms.saml.saml1.idp.entity_id=http://www.elastic.co/saml1',
`xpack.security.authc.realms.saml.saml1.sp.entity_id=http://localhost:${kibanaPort}`,
`xpack.security.authc.realms.saml.saml1.sp.logout=http://localhost:${kibanaPort}/logout`,
`xpack.security.authc.realms.saml.saml1.sp.acs=http://localhost:${kibanaPort}/api/security/saml/callback`,
'xpack.security.authc.realms.saml.saml1.attributes.principal=urn:oid:0.0.7',
],
// We're going to use the same TGT multiple times and during a short period of time, so we
// have to disable replay cache so that ES doesn't complain about that.
esJavaOpts: `-Dsun.security.krb5.rcache=none`,
},
kbnTestServer: {
...xPackAPITestsConfig.get('kbnTestServer'),
serverArgs: [
...xPackAPITestsConfig.get('kbnTestServer.serverArgs'),
'--server.ssl.enabled=true',
`--server.ssl.key=${KBN_KEY_PATH}`,
`--server.ssl.certificate=${KBN_CERT_PATH}`,
`--server.ssl.certificateAuthorities=${JSON.stringify([CA_CERT_PATH])}`,
`--server.ssl.clientAuthentication=optional`,
`--elasticsearch.hosts=${servers.elasticsearch.protocol}://${servers.elasticsearch.hostname}:${servers.elasticsearch.port}`,
`--elasticsearch.ssl.certificateAuthorities=${CA_CERT_PATH}`,
`--xpack.security.authc.providers=${JSON.stringify({
basic: { basic1: { order: 0 } },
saml: {
saml1: {
order: 1,
realm: 'saml1',
maxRedirectURLSize: '100b',
useRelayStateDeepLink: true,
},
},
anonymous: {
anonymous1: {
order: 6,
credentials: { username: 'anonymous_user', password: 'changeme' },
},
},
})}`,
],
},
};
}

View file

@ -0,0 +1,14 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { FtrProviderContext } from '../../../../ftr_provider_context';
export default function ({ loadTestFile }: FtrProviderContext) {
describe('cloud data', function () {
loadTestFile(require.resolve('./relay_state'));
});
}

View file

@ -0,0 +1,126 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { readFileSync } from 'fs';
import type { Cookie } from 'tough-cookie';
import { parse as parseCookie } from 'tough-cookie';
import { CA_CERT_PATH } from '@kbn/dev-utils';
import expect from '@kbn/expect';
import { getSAMLResponse } from '@kbn/security-api-integration-helpers/saml/saml_tools';
import type { AuthenticationProvider } from '@kbn/security-plugin/common';
import type { FtrProviderContext } from '../../../../ftr_provider_context';
export default function ({ getService }: FtrProviderContext) {
const randomness = getService('randomness');
const supertest = getService('supertestWithoutAuth');
const config = getService('config');
const kibanaServerConfig = config.get('servers.kibana');
const CA_CERT = readFileSync(CA_CERT_PATH);
const CLIENT_CERT = readFileSync(
require.resolve('@kbn/security-api-integration-helpers/pki/first_client.p12')
);
async function checkSessionCookie(
sessionCookie: Cookie,
username: string,
provider: AuthenticationProvider,
authenticationRealm: { name: string; type: string } | null,
authenticationType: string
) {
expect(sessionCookie.key).to.be('sid');
expect(sessionCookie.value).to.not.be.empty();
expect(sessionCookie.path).to.be('/');
expect(sessionCookie.httpOnly).to.be(true);
const apiResponse = await supertest
.get('/internal/security/me')
.ca(CA_CERT)
.pfx(CLIENT_CERT)
.set('kbn-xsrf', 'xxx')
.set('Cookie', sessionCookie.cookieString())
.expect(200);
expect(apiResponse.body).to.have.keys([
'username',
'full_name',
'email',
'roles',
'metadata',
'enabled',
'authentication_realm',
'lookup_realm',
'authentication_provider',
'authentication_type',
'elastic_cloud_user',
]);
expect(apiResponse.body.username).to.be(username);
expect(apiResponse.body.authentication_provider).to.eql(provider);
if (authenticationRealm) {
expect(apiResponse.body.authentication_realm).to.eql(authenticationRealm);
}
expect(apiResponse.body.authentication_type).to.be(authenticationType);
}
describe('Relay State into onboarding flow', () => {
function createSAMLResponse(options = {}) {
return getSAMLResponse({
destination: `http://localhost:${kibanaServerConfig.port}/api/security/saml/callback`,
sessionIndex: String(randomness.naturalNumber()),
...options,
});
}
it('should redirect to URL from relay state and keeping query string', async () => {
for (const { providerName, redirectURL } of [
{
providerName: 'saml1',
redirectURL: `/app/cloud/onboarding?onboarding_token=vector&next=${encodeURIComponent(
'/app/enterprise_search/vector_search'
)}`,
},
{
providerName: 'saml1',
redirectURL: `/app/cloud/onboarding?onboarding_token=vector&next=${encodeURIComponent(
'/app/enterprise_search/vector_search'
)}#some=hash-value`,
},
]) {
const authenticationResponse = await supertest
.post('/api/security/saml/callback')
.ca(CA_CERT)
.type('form')
.send({
SAMLResponse: await createSAMLResponse({
issuer: `http://www.elastic.co/${providerName}`,
}),
})
.send({ RelayState: redirectURL })
.expect(302);
// User should be redirected to the base URL.
expect(authenticationResponse.headers.location).to.be(redirectURL);
const cookies = authenticationResponse.headers['set-cookie'];
expect(cookies).to.have.length(1);
await checkSessionCookie(
parseCookie(cookies[0])!,
'a@b.c',
{ type: 'saml', name: providerName },
{ name: providerName, type: 'saml' },
'token'
);
}
});
});
}

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { FtrProviderContext } from '../../ftr_provider_context';
import { FtrProviderContext } from '../../../../ftr_provider_context';
export default function ({ loadTestFile }: FtrProviderContext) {
describe('cloud data', function () {

View file

@ -6,7 +6,7 @@
*/
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../ftr_provider_context';
import { FtrProviderContext } from '../../../../ftr_provider_context';
export default function ({ getService }: FtrProviderContext) {
const supertest = getService('supertest');

View file

@ -0,0 +1,85 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { resolve } from 'path';
import type { FtrConfigProviderContext } from '@kbn/test';
import { pageObjects } from '../functional/page_objects';
import { services } from '../functional/services';
// the default export of config files must be a config provider
// that returns an object with the projects config values
export default async function ({ readConfigFile }: FtrConfigProviderContext) {
const kibanaCommonConfig = await readConfigFile(
require.resolve('@kbn/test-suites-src/common/config')
);
const kibanaFunctionalConfig = await readConfigFile(
require.resolve('@kbn/test-suites-src/functional/config.base')
);
const kibanaPort = kibanaFunctionalConfig.get('servers.kibana.port');
const idpPath = resolve(
__dirname,
'../security_api_integration/plugins/saml_provider/metadata.xml'
);
const samlIdPPlugin = resolve(__dirname, '../security_api_integration/plugins/saml_provider');
const testEndpointsPlugin = resolve(__dirname, '../security_functional/plugins/test_endpoints');
return {
testFiles: [resolve(__dirname, './tests/onboarding_token.ts')],
services,
pageObjects,
servers: kibanaFunctionalConfig.get('servers'),
esTestCluster: {
license: 'trial',
from: 'snapshot',
serverArgs: [
'xpack.security.authc.token.enabled=true',
'xpack.security.authc.realms.saml.saml1.order=0',
`xpack.security.authc.realms.saml.saml1.idp.metadata.path=${idpPath}`,
'xpack.security.authc.realms.saml.saml1.idp.entity_id=http://www.elastic.co/saml1',
`xpack.security.authc.realms.saml.saml1.sp.entity_id=http://localhost:${kibanaPort}`,
`xpack.security.authc.realms.saml.saml1.sp.logout=http://localhost:${kibanaPort}/logout`,
`xpack.security.authc.realms.saml.saml1.sp.acs=http://localhost:${kibanaPort}/api/security/saml/callback`,
'xpack.security.authc.realms.saml.saml1.attributes.principal=urn:oid:0.0.7',
],
},
kbnTestServer: {
...kibanaCommonConfig.get('kbnTestServer'),
serverArgs: [
...kibanaCommonConfig.get('kbnTestServer.serverArgs'),
`--plugin-path=${samlIdPPlugin}`,
`--plugin-path=${testEndpointsPlugin}`,
'--server.uuid=5b2de169-2785-441b-ae8c-186a1936b17d',
'--xpack.security.encryptionKey="wuGNaIhoMpk5sO4UBxgr3NyW1sFcLgIf"',
'--xpack.security.authc.selector.enabled=false',
'--xpack.security.authc.providers.saml.saml1.order=0',
'--xpack.security.authc.providers.saml.saml1.realm=saml1',
'--xpack.security.authc.providers.basic.basic1.order=1',
'--server.restrictInternalApis=false',
],
},
uiSettings: {
defaults: {
'accessibility:disableAnimations': true,
'dateFormat:tz': 'UTC',
},
},
apps: kibanaFunctionalConfig.get('apps'),
screenshots: { directory: resolve(__dirname, 'screenshots') },
junit: {
reportName: 'Chrome X-Pack Security Functional Tests (SAML)',
},
};
}

View file

@ -0,0 +1,68 @@
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
/*
* 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; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { parse } from 'url';
import expect from '@kbn/expect';
import type { FtrProviderContext } from '../../security_functional/ftr_provider_context';
export default function ({ getService, getPageObjects }: FtrProviderContext) {
const find = getService('find');
const browser = getService('browser');
const deployment = getService('deployment');
const PageObjects = getPageObjects(['common']);
const supertest = getService('supertest');
describe('onboarding token', function () {
this.tags('includeFirefox');
before(async () => {
await getService('esSupertest')
.post('/_security/role_mapping/saml1')
.send({ roles: ['superuser'], enabled: true, rules: { field: { 'realm.name': 'saml1' } } })
.expect(200);
});
afterEach(async () => {
await browser.get(deployment.getHostPort() + '/logout');
await PageObjects.common.waitUntilUrlIncludes('logged_out');
});
it('Redirect and save token', async () => {
await browser.get(
deployment.getHostPort() +
`/app/cloud/onboarding?onboarding_token=vector&next=${encodeURIComponent(
'/app/elasticsearch/vector_search'
)}#some=hash-value`
);
await find.byCssSelector('[data-test-subj="userMenuButton"]', 20000);
// We need to make sure that both path and hash are respected.
const currentURL = parse(await browser.getCurrentUrl());
expect(currentURL.pathname).to.eql('/app/elasticsearch/vector_search');
expect(currentURL.hash).to.eql('#some=hash-value');
const {
body: { onboardingData },
} = await supertest
.get('/internal/cloud/solution')
.set('kbn-xsrf', 'xxx')
.set('x-elastic-internal-origin', 'cloud')
.set('elastic-api-version', '1')
.expect(200);
expect(onboardingData).to.eql({ token: 'vector' });
});
});
}

View file

@ -99,6 +99,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:apm/show",
"ui:apm/save",
"ui:apm/alerting:show",
@ -1582,6 +1587,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:apm/show",
"ui:apm/save",
"ui:apm/alerting:show",
@ -3056,6 +3066,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:apm/show",
"ui:apm/alerting:show",
"alerting:apm.error_rate/apm/rule/get",
@ -3671,6 +3686,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:apm/show",
"ui:apm/alerting:show",
"alerting:apm.error_rate/apm/rule/get",
@ -4377,6 +4397,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:config-global/find",
"saved_object:config-global/open_point_in_time",
"saved_object:config-global/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:dashboard/createNew",
"ui:dashboard/show",
"ui:dashboard/showWriteControls",
@ -4538,6 +4563,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:url/find",
"saved_object:url/open_point_in_time",
"saved_object:url/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:dashboard/createNew",
"ui:dashboard/show",
"ui:dashboard/showWriteControls",
@ -4670,6 +4700,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:url/find",
"saved_object:url/open_point_in_time",
"saved_object:url/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:dashboard/show",
"app:maps",
"ui:catalogue/maps",
@ -4777,6 +4812,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:telemetry/find",
"saved_object:telemetry/open_point_in_time",
"saved_object:telemetry/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:dashboard/show",
"ui:dashboard/createShortUrl",
"app:maps",
@ -4921,6 +4961,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:discover/show",
"ui:discover/save",
"ui:discover/saveQuery",
@ -6133,6 +6178,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:discover/show",
"ui:discover/save",
"ui:discover/saveQuery",
@ -7313,6 +7363,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:discover/show",
"api:rac",
"app:observability",
@ -7817,6 +7872,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:discover/show",
"ui:discover/createShortUrl",
"api:rac",
@ -8924,6 +8984,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:fleetv2/read",
"ui:fleetv2/all",
"ui:fleetv2/agents_read",
@ -9420,6 +9485,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:fleetv2/read",
"ui:fleetv2/all",
"api:infra",
@ -9818,6 +9888,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:fleetv2/read",
"api:infra",
"api:rac",
@ -10042,6 +10117,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:fleetv2/read",
"ui:fleetv2/agents_read",
"ui:fleetv2/agent_policies_read",
@ -10467,6 +10547,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:infrastructure/show",
"ui:infrastructure/configureSource",
"ui:infrastructure/save",
@ -11990,6 +12075,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:infrastructure/show",
"ui:infrastructure/configureSource",
"ui:infrastructure/save",
@ -13492,6 +13582,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:infrastructure/show",
"alerting:metrics.alert.threshold/infrastructure/rule/get",
"alerting:metrics.alert.threshold/infrastructure/rule/getRuleState",
@ -14122,6 +14217,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:infrastructure/show",
"alerting:metrics.alert.threshold/infrastructure/rule/get",
"alerting:metrics.alert.threshold/infrastructure/rule/getRuleState",
@ -14735,6 +14835,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"api:downloadCsv",
"ui:management/insightsAndAlerting/reporting",
"ui:dashboard/downloadCsv",
@ -14775,6 +14880,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"api:downloadCsv",
"ui:management/insightsAndAlerting/reporting",
"ui:dashboard/downloadCsv",
@ -14808,6 +14918,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
],
"read": Array [
"login:",
@ -14836,6 +14951,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
],
},
"slo": Object {
@ -14906,6 +15026,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:slo/read",
"ui:slo/write",
"alerting:slo.rules.burnRate/slo/rule/get",
@ -16135,6 +16260,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:slo/read",
"ui:slo/write",
"alerting:slo.rules.burnRate/slo/rule/get",
@ -17342,6 +17472,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:slo/read",
"alerting:slo.rules.burnRate/slo/rule/get",
"alerting:slo.rules.burnRate/slo/rule/getRuleState",
@ -17847,6 +17982,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:slo/read",
"alerting:slo.rules.burnRate/slo/rule/get",
"alerting:slo.rules.burnRate/slo/rule/getRuleState",
@ -18440,6 +18580,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:uptime/save",
"ui:uptime/configureSettings",
"ui:uptime/show",
@ -19921,6 +20066,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:uptime/save",
"ui:uptime/configureSettings",
"ui:uptime/show",
@ -21324,6 +21474,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:uptime/show",
"ui:uptime/alerting:save",
"alerting:xpack.uptime.alerts.tls/uptime/rule/get",
@ -21924,6 +22079,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:uptime/show",
"ui:uptime/alerting:save",
"alerting:xpack.uptime.alerts.tls/uptime/rule/get",

View file

@ -164,6 +164,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:config-global/find",
"saved_object:config-global/open_point_in_time",
"saved_object:config-global/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:dashboard/createNew",
"ui:dashboard/show",
"ui:dashboard/showWriteControls",
@ -325,6 +330,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:url/find",
"saved_object:url/open_point_in_time",
"saved_object:url/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:dashboard/createNew",
"ui:dashboard/show",
"ui:dashboard/showWriteControls",
@ -457,6 +467,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:url/find",
"saved_object:url/open_point_in_time",
"saved_object:url/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:dashboard/show",
"app:maps",
"ui:catalogue/maps",
@ -564,6 +579,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:telemetry/find",
"saved_object:telemetry/open_point_in_time",
"saved_object:telemetry/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:dashboard/show",
"ui:dashboard/createShortUrl",
"app:maps",
@ -708,6 +728,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:discover/show",
"ui:discover/save",
"ui:discover/saveQuery",
@ -792,6 +817,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:discover/show",
"ui:discover/save",
"ui:discover/saveQuery",
@ -844,6 +874,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:discover/show",
],
"read": Array [
@ -901,6 +936,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:discover/show",
"ui:discover/createShortUrl",
],
@ -974,6 +1014,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"api:downloadCsv",
"ui:management/insightsAndAlerting/reporting",
"ui:dashboard/downloadCsv",
@ -1014,6 +1059,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"api:downloadCsv",
"ui:management/insightsAndAlerting/reporting",
"ui:dashboard/downloadCsv",
@ -1047,6 +1097,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
],
"read": Array [
"login:",
@ -1075,6 +1130,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
],
},
}

View file

@ -72,6 +72,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"api:downloadCsv",
"ui:management/insightsAndAlerting/reporting",
"ui:dashboard/downloadCsv",
@ -112,6 +117,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"api:downloadCsv",
"ui:management/insightsAndAlerting/reporting",
"ui:dashboard/downloadCsv",
@ -145,6 +155,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
],
"read": Array [
"login:",
@ -173,6 +188,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
],
},
"siem": Object {
@ -461,6 +481,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:siem/show",
"ui:siem/crud",
"ui:siem/entity-analytics",
@ -1320,6 +1345,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:siem/show",
"ui:siem/crud",
"ui:siem/entity-analytics",
@ -1901,6 +1931,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:siem/show",
"ui:siem/entity-analytics",
"ui:siem/investigation-guide",
@ -2268,6 +2303,11 @@ export default function ({ getService }: FtrProviderContext) {
"saved_object:tag/find",
"saved_object:tag/open_point_in_time",
"saved_object:tag/close_point_in_time",
"saved_object:cloud/bulk_get",
"saved_object:cloud/get",
"saved_object:cloud/find",
"saved_object:cloud/open_point_in_time",
"saved_object:cloud/close_point_in_time",
"ui:siem/show",
"ui:siem/entity-analytics",
"ui:siem/investigation-guide",