mirror of
https://github.com/elastic/kibana.git
synced 2025-06-27 18:51:07 -04:00
[HTTP] Allow for internal requests to also specify special query param elasticInternalOrigin
(#163796)
## Summary Closes https://github.com/elastic/kibana/issues/163678 * Raise the notion of "internal" into `CoreKibanaRequest`. This enables us to share this with lifecycle handlers and control validation of query params * Added new `isInternalRequest` alongside `isSystemRequest` and `isFakeRequest` * Slight simplification to existing internal restriction check * Some other chores and minor fixes ## Test * Start ES with `yarn es serverless` and Kibana with `yarn start --serverless --server.restrictInternalApis=true` * Add the service account token to `kibana.dev.yml`: `elasticsearch.serviceAccountToken: <SAT>` * Send a request to an internal endpoint like: `curl -XPOST -uelastic:changeme http://localhost:5601/<base-path>/api/files/find -H 'kbn-xsrf: foo' -H 'content-type: application/json' -d '{}'` * Should give you a 400 result * message like `{"statusCode":400,"error":"Bad Request","message":"uri [http://localhost:5603/api/files/find] with method [post] exists but is not available with the current configuration"}` * Send the same request, but include the query param: `elasticInternalOrigin=true` * Should give you a 200 result --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
bc988f22c6
commit
23d39555e0
16 changed files with 242 additions and 171 deletions
|
@ -12,5 +12,6 @@ export type { ApiVersion } from './src/versioning';
|
||||||
export {
|
export {
|
||||||
ELASTIC_HTTP_VERSION_HEADER,
|
ELASTIC_HTTP_VERSION_HEADER,
|
||||||
ELASTIC_HTTP_VERSION_QUERY_PARAM,
|
ELASTIC_HTTP_VERSION_QUERY_PARAM,
|
||||||
|
ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM,
|
||||||
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||||
} from './src/constants';
|
} from './src/constants';
|
||||||
|
|
|
@ -9,5 +9,5 @@
|
||||||
/** @public */
|
/** @public */
|
||||||
export const ELASTIC_HTTP_VERSION_HEADER = 'elastic-api-version' as const;
|
export const ELASTIC_HTTP_VERSION_HEADER = 'elastic-api-version' as const;
|
||||||
export const ELASTIC_HTTP_VERSION_QUERY_PARAM = 'apiVersion' as const;
|
export const ELASTIC_HTTP_VERSION_QUERY_PARAM = 'apiVersion' as const;
|
||||||
|
export const ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM = 'elasticInternalOrigin' as const;
|
||||||
export const X_ELASTIC_INTERNAL_ORIGIN_REQUEST = 'x-elastic-internal-origin' as const;
|
export const X_ELASTIC_INTERNAL_ORIGIN_REQUEST = 'x-elastic-internal-origin' as const;
|
||||||
|
|
|
@ -15,6 +15,10 @@ import { hapiMocks } from '@kbn/hapi-mocks';
|
||||||
import type { FakeRawRequest } from '@kbn/core-http-server';
|
import type { FakeRawRequest } from '@kbn/core-http-server';
|
||||||
import { CoreKibanaRequest } from './request';
|
import { CoreKibanaRequest } from './request';
|
||||||
import { schema } from '@kbn/config-schema';
|
import { schema } from '@kbn/config-schema';
|
||||||
|
import {
|
||||||
|
ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM,
|
||||||
|
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||||
|
} from '@kbn/core-http-common';
|
||||||
|
|
||||||
describe('CoreKibanaRequest', () => {
|
describe('CoreKibanaRequest', () => {
|
||||||
describe('using real requests', () => {
|
describe('using real requests', () => {
|
||||||
|
@ -145,6 +149,58 @@ describe('CoreKibanaRequest', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('isInternalApiRequest property', () => {
|
||||||
|
it('is true when header is set', () => {
|
||||||
|
const request = hapiMocks.createRequest({
|
||||||
|
headers: { [X_ELASTIC_INTERNAL_ORIGIN_REQUEST]: 'true' },
|
||||||
|
});
|
||||||
|
const kibanaRequest = CoreKibanaRequest.from(request);
|
||||||
|
expect(kibanaRequest.isInternalApiRequest).toBe(true);
|
||||||
|
});
|
||||||
|
it('is true when query param is set', () => {
|
||||||
|
const request = hapiMocks.createRequest({
|
||||||
|
query: { [ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM]: 'true' },
|
||||||
|
});
|
||||||
|
const kibanaRequest = CoreKibanaRequest.from(request);
|
||||||
|
expect(kibanaRequest.isInternalApiRequest).toBe(true);
|
||||||
|
});
|
||||||
|
it('is true when both header and query param is set', () => {
|
||||||
|
const request = hapiMocks.createRequest({
|
||||||
|
headers: { [X_ELASTIC_INTERNAL_ORIGIN_REQUEST]: 'true' },
|
||||||
|
query: { [ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM]: 'true' },
|
||||||
|
});
|
||||||
|
const kibanaRequest = CoreKibanaRequest.from(request);
|
||||||
|
expect(kibanaRequest.isInternalApiRequest).toBe(true);
|
||||||
|
});
|
||||||
|
it('is false when neither header nor query param is set', () => {
|
||||||
|
const request = hapiMocks.createRequest();
|
||||||
|
const kibanaRequest = CoreKibanaRequest.from(request);
|
||||||
|
expect(kibanaRequest.isInternalApiRequest).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('sanitize input', () => {
|
||||||
|
it('does not pass the reserved query parameter to consumers', () => {
|
||||||
|
const request = hapiMocks.createRequest({
|
||||||
|
query: { [ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM]: 'true', myCoolValue: 'cool!' },
|
||||||
|
});
|
||||||
|
const kibanaRequest = CoreKibanaRequest.from(request, {
|
||||||
|
query: schema.object({ myCoolValue: schema.string() }),
|
||||||
|
});
|
||||||
|
expect(kibanaRequest.query).toEqual({ myCoolValue: 'cool!' });
|
||||||
|
});
|
||||||
|
it('pass nothing if only the reserved query param is present', () => {
|
||||||
|
const request = hapiMocks.createRequest({
|
||||||
|
query: { [ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM]: 'true' },
|
||||||
|
});
|
||||||
|
expect(() =>
|
||||||
|
CoreKibanaRequest.from(request, {
|
||||||
|
query: schema.object({}, { unknowns: 'forbid' }), // we require an empty object
|
||||||
|
})
|
||||||
|
).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('route.options.authRequired property', () => {
|
describe('route.options.authRequired property', () => {
|
||||||
it('handles required auth: undefined', () => {
|
it('handles required auth: undefined', () => {
|
||||||
const auth: RouteOptions['auth'] = undefined;
|
const auth: RouteOptions['auth'] = undefined;
|
||||||
|
|
|
@ -29,6 +29,10 @@ import {
|
||||||
RawRequest,
|
RawRequest,
|
||||||
FakeRawRequest,
|
FakeRawRequest,
|
||||||
} from '@kbn/core-http-server';
|
} from '@kbn/core-http-server';
|
||||||
|
import {
|
||||||
|
ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM,
|
||||||
|
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
|
||||||
|
} from '@kbn/core-http-common';
|
||||||
import { RouteValidator } from './validator';
|
import { RouteValidator } from './validator';
|
||||||
import { isSafeMethod } from './route';
|
import { isSafeMethod } from './route';
|
||||||
import { KibanaSocket } from './socket';
|
import { KibanaSocket } from './socket';
|
||||||
|
@ -59,7 +63,13 @@ export class CoreKibanaRequest<
|
||||||
withoutSecretHeaders: boolean = true
|
withoutSecretHeaders: boolean = true
|
||||||
) {
|
) {
|
||||||
const routeValidator = RouteValidator.from<P, Q, B>(routeSchemas);
|
const routeValidator = RouteValidator.from<P, Q, B>(routeSchemas);
|
||||||
const requestParts = CoreKibanaRequest.validate(req, routeValidator);
|
let requestParts: { params: P; query: Q; body: B };
|
||||||
|
if (isFakeRawRequest(req)) {
|
||||||
|
requestParts = { query: {} as Q, params: {} as P, body: {} as B };
|
||||||
|
} else {
|
||||||
|
const rawParts = CoreKibanaRequest.sanitizeRequest(req);
|
||||||
|
requestParts = CoreKibanaRequest.validate(rawParts, routeValidator);
|
||||||
|
}
|
||||||
return new CoreKibanaRequest(
|
return new CoreKibanaRequest(
|
||||||
req,
|
req,
|
||||||
requestParts.params,
|
requestParts.params,
|
||||||
|
@ -69,6 +79,22 @@ export class CoreKibanaRequest<
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We have certain values that may be passed via query params that we want to
|
||||||
|
* exclude from further processing like validation. This method removes those
|
||||||
|
* internal values.
|
||||||
|
*/
|
||||||
|
private static sanitizeRequest<P, Q, B>(
|
||||||
|
req: Request
|
||||||
|
): { query: unknown; params: unknown; body: unknown } {
|
||||||
|
const { [ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM]: __, ...query } = req.query ?? {};
|
||||||
|
return {
|
||||||
|
query,
|
||||||
|
params: req.params,
|
||||||
|
body: req.payload,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the different parts of a request based on the schemas defined for
|
* Validates the different parts of a request based on the schemas defined for
|
||||||
* the route. Builds up the actual params, query and body object that will be
|
* the route. Builds up the actual params, query and body object that will be
|
||||||
|
@ -76,43 +102,42 @@ export class CoreKibanaRequest<
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
private static validate<P, Q, B>(
|
private static validate<P, Q, B>(
|
||||||
req: RawRequest,
|
raw: { params: unknown; query: unknown; body: unknown },
|
||||||
routeValidator: RouteValidator<P, Q, B>
|
routeValidator: RouteValidator<P, Q, B>
|
||||||
): {
|
): {
|
||||||
params: P;
|
params: P;
|
||||||
query: Q;
|
query: Q;
|
||||||
body: B;
|
body: B;
|
||||||
} {
|
} {
|
||||||
if (isFakeRawRequest(req)) {
|
const params = routeValidator.getParams(raw.params, 'request params');
|
||||||
return { query: {} as Q, params: {} as P, body: {} as B };
|
const query = routeValidator.getQuery(raw.query, 'request query');
|
||||||
}
|
const body = routeValidator.getBody(raw.body, 'request body');
|
||||||
const params = routeValidator.getParams(req.params, 'request params');
|
|
||||||
const query = routeValidator.getQuery(req.query, 'request query');
|
|
||||||
const body = routeValidator.getBody(req.payload, 'request body');
|
|
||||||
return { query, params, body };
|
return { query, params, body };
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc IKibanaRequest.id} */
|
/** {@inheritDoc KibanaRequest.id} */
|
||||||
public readonly id: string;
|
public readonly id: string;
|
||||||
/** {@inheritDoc IKibanaRequest.uuid} */
|
/** {@inheritDoc KibanaRequest.uuid} */
|
||||||
public readonly uuid: string;
|
public readonly uuid: string;
|
||||||
/** {@inheritDoc IKibanaRequest.url} */
|
/** {@inheritDoc KibanaRequest.url} */
|
||||||
public readonly url: URL;
|
public readonly url: URL;
|
||||||
/** {@inheritDoc IKibanaRequest.route} */
|
/** {@inheritDoc KibanaRequest.route} */
|
||||||
public readonly route: RecursiveReadonly<KibanaRequestRoute<Method>>;
|
public readonly route: RecursiveReadonly<KibanaRequestRoute<Method>>;
|
||||||
/** {@inheritDoc IKibanaRequest.headers} */
|
/** {@inheritDoc KibanaRequest.headers} */
|
||||||
public readonly headers: Headers;
|
public readonly headers: Headers;
|
||||||
/** {@inheritDoc IKibanaRequest.isSystemRequest} */
|
/** {@inheritDoc KibanaRequest.isSystemRequest} */
|
||||||
public readonly isSystemRequest: boolean;
|
public readonly isSystemRequest: boolean;
|
||||||
/** {@inheritDoc IKibanaRequest.socket} */
|
/** {@inheritDoc KibanaRequest.socket} */
|
||||||
public readonly socket: IKibanaSocket;
|
public readonly socket: IKibanaSocket;
|
||||||
/** {@inheritDoc IKibanaRequest.events} */
|
/** {@inheritDoc KibanaRequest.events} */
|
||||||
public readonly events: KibanaRequestEvents;
|
public readonly events: KibanaRequestEvents;
|
||||||
/** {@inheritDoc IKibanaRequest.auth} */
|
/** {@inheritDoc KibanaRequest.auth} */
|
||||||
public readonly auth: KibanaRequestAuth;
|
public readonly auth: KibanaRequestAuth;
|
||||||
/** {@inheritDoc IKibanaRequest.isFakeRequest} */
|
/** {@inheritDoc KibanaRequest.isFakeRequest} */
|
||||||
public readonly isFakeRequest: boolean;
|
public readonly isFakeRequest: boolean;
|
||||||
/** {@inheritDoc IKibanaRequest.rewrittenUrl} */
|
/** {@inheritDoc KibanaRequest.isInternalApiRequest} */
|
||||||
|
public readonly isInternalApiRequest: boolean;
|
||||||
|
/** {@inheritDoc KibanaRequest.rewrittenUrl} */
|
||||||
public readonly rewrittenUrl?: URL;
|
public readonly rewrittenUrl?: URL;
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
|
@ -139,7 +164,9 @@ export class CoreKibanaRequest<
|
||||||
this.headers = isRealRawRequest(request) ? deepFreeze({ ...request.headers }) : request.headers;
|
this.headers = isRealRawRequest(request) ? deepFreeze({ ...request.headers }) : request.headers;
|
||||||
this.isSystemRequest = this.headers['kbn-system-request'] === 'true';
|
this.isSystemRequest = this.headers['kbn-system-request'] === 'true';
|
||||||
this.isFakeRequest = isFakeRawRequest(request);
|
this.isFakeRequest = isFakeRawRequest(request);
|
||||||
|
this.isInternalApiRequest =
|
||||||
|
X_ELASTIC_INTERNAL_ORIGIN_REQUEST in this.headers ||
|
||||||
|
Boolean(this.url?.searchParams?.has(ELASTIC_INTERNAL_ORIGIN_QUERY_PARAM));
|
||||||
// prevent Symbol exposure via Object.getOwnPropertySymbols()
|
// prevent Symbol exposure via Object.getOwnPropertySymbols()
|
||||||
Object.defineProperty(this, requestSymbol, {
|
Object.defineProperty(this, requestSymbol, {
|
||||||
value: request,
|
value: request,
|
||||||
|
|
|
@ -39,11 +39,13 @@ const createToolkit = (): ToolkitMock => {
|
||||||
|
|
||||||
const forgeRequest = ({
|
const forgeRequest = ({
|
||||||
headers = {},
|
headers = {},
|
||||||
|
query = {},
|
||||||
path = '/',
|
path = '/',
|
||||||
method = 'get',
|
method = 'get',
|
||||||
kibanaRouteOptions,
|
kibanaRouteOptions,
|
||||||
}: Partial<{
|
}: Partial<{
|
||||||
headers: Record<string, string>;
|
headers: Record<string, string>;
|
||||||
|
query: Record<string, string>;
|
||||||
path: string;
|
path: string;
|
||||||
method: RouteMethod;
|
method: RouteMethod;
|
||||||
kibanaRouteOptions: KibanaRouteOptions;
|
kibanaRouteOptions: KibanaRouteOptions;
|
||||||
|
@ -51,6 +53,7 @@ const forgeRequest = ({
|
||||||
return mockRouter.createKibanaRequest({
|
return mockRouter.createKibanaRequest({
|
||||||
headers,
|
headers,
|
||||||
path,
|
path,
|
||||||
|
query,
|
||||||
method,
|
method,
|
||||||
kibanaRouteOptions,
|
kibanaRouteOptions,
|
||||||
});
|
});
|
||||||
|
@ -259,11 +262,13 @@ describe('restrictInternal post-auth handler', () => {
|
||||||
});
|
});
|
||||||
const createForgeRequest = (
|
const createForgeRequest = (
|
||||||
access: 'internal' | 'public',
|
access: 'internal' | 'public',
|
||||||
headers: Record<string, string> | undefined = {}
|
headers: Record<string, string> | undefined = {},
|
||||||
|
query: Record<string, string> | undefined = {}
|
||||||
) => {
|
) => {
|
||||||
return forgeRequest({
|
return forgeRequest({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
headers,
|
headers,
|
||||||
|
query,
|
||||||
path: `/${access}/some-path`,
|
path: `/${access}/some-path`,
|
||||||
kibanaRouteOptions: {
|
kibanaRouteOptions: {
|
||||||
xsrfRequired: false,
|
xsrfRequired: false,
|
||||||
|
@ -318,6 +323,24 @@ describe('restrictInternal post-auth handler', () => {
|
||||||
const request = createForgeRequest('public');
|
const request = createForgeRequest('public');
|
||||||
createForwardSuccess(handler, request);
|
createForwardSuccess(handler, request);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('forward the request to the next interceptor if called with internal origin query param for internal API', () => {
|
||||||
|
const handler = createRestrictInternalRoutesPostAuthHandler(config as HttpConfig);
|
||||||
|
const request = createForgeRequest('internal', undefined, { elasticInternalOrigin: 'true' });
|
||||||
|
createForwardSuccess(handler, request);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('forward the request to the next interceptor if called with internal origin query param for public APIs', () => {
|
||||||
|
const handler = createRestrictInternalRoutesPostAuthHandler(config as HttpConfig);
|
||||||
|
const request = createForgeRequest('internal', undefined, { elasticInternalOrigin: 'true' });
|
||||||
|
createForwardSuccess(handler, request);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('forward the request to the next interceptor if called without internal origin query param for public APIs', () => {
|
||||||
|
const handler = createRestrictInternalRoutesPostAuthHandler(config as HttpConfig);
|
||||||
|
const request = createForgeRequest('public');
|
||||||
|
createForwardSuccess(handler, request);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when restriction is not enabled', () => {
|
describe('when restriction is not enabled', () => {
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
import type { OnPostAuthHandler, OnPreResponseHandler } from '@kbn/core-http-server';
|
import type { OnPostAuthHandler, OnPreResponseHandler } from '@kbn/core-http-server';
|
||||||
import { isSafeMethod } from '@kbn/core-http-router-server-internal';
|
import { isSafeMethod } from '@kbn/core-http-router-server-internal';
|
||||||
import { X_ELASTIC_INTERNAL_ORIGIN_REQUEST } from '@kbn/core-http-common/src/constants';
|
|
||||||
import { HttpConfig } from './http_config';
|
import { HttpConfig } from './http_config';
|
||||||
|
|
||||||
const VERSION_HEADER = 'kbn-version';
|
const VERSION_HEADER = 'kbn-version';
|
||||||
|
@ -45,11 +44,7 @@ export const createRestrictInternalRoutesPostAuthHandler = (
|
||||||
|
|
||||||
return (request, response, toolkit) => {
|
return (request, response, toolkit) => {
|
||||||
const isInternalRoute = request.route.options.access === 'internal';
|
const isInternalRoute = request.route.options.access === 'internal';
|
||||||
|
if (isRestrictionEnabled && isInternalRoute && !request.isInternalApiRequest) {
|
||||||
// only check if the header is present, not it's content.
|
|
||||||
const hasInternalKibanaRequestHeader = X_ELASTIC_INTERNAL_ORIGIN_REQUEST in request.headers;
|
|
||||||
|
|
||||||
if (isRestrictionEnabled && isInternalRoute && !hasInternalKibanaRequestHeader) {
|
|
||||||
// throw 400
|
// throw 400
|
||||||
return response.badRequest({
|
return response.badRequest({
|
||||||
body: `uri [${request.url}] with method [${request.route.method}] exists but is not available with the current configuration`,
|
body: `uri [${request.url}] with method [${request.route.method}] exists but is not available with the current configuration`,
|
||||||
|
@ -75,7 +70,6 @@ export const createVersionCheckPostAuthHandler = (kibanaVersion: string): OnPost
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return toolkit.next();
|
return toolkit.next();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -135,6 +135,12 @@ export interface KibanaRequest<
|
||||||
*/
|
*/
|
||||||
readonly isFakeRequest: boolean;
|
readonly isFakeRequest: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An internal request has access to internal routes.
|
||||||
|
* @note See the {@link KibanaRequestRouteOptions#access} route option.
|
||||||
|
*/
|
||||||
|
readonly isInternalApiRequest: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The socket associated with this request.
|
* The socket associated with this request.
|
||||||
* See {@link IKibanaSocket}.
|
* See {@link IKibanaSocket}.
|
||||||
|
|
|
@ -18,6 +18,11 @@ export const createRequestMock = (customization: DeepPartial<Request> = {}): Req
|
||||||
formatUrl(Object.assign({ pathname, path, href: path }, customization.url)),
|
formatUrl(Object.assign({ pathname, path, href: path }, customization.url)),
|
||||||
'http://localhost'
|
'http://localhost'
|
||||||
);
|
);
|
||||||
|
if (customization.query) {
|
||||||
|
Object.entries(customization.query).forEach(([key, value]) => {
|
||||||
|
url.searchParams.set(key, value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return merge(
|
return merge(
|
||||||
{},
|
{},
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { contextServiceMock } from '@kbn/core-http-context-server-mocks';
|
||||||
import { createConfigService, createHttpServer } from '@kbn/core-http-server-mocks';
|
import { createConfigService, createHttpServer } from '@kbn/core-http-server-mocks';
|
||||||
import { HttpService, HttpServerSetup } from '@kbn/core-http-server-internal';
|
import { HttpService, HttpServerSetup } from '@kbn/core-http-server-internal';
|
||||||
import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks';
|
import { executionContextServiceMock } from '@kbn/core-execution-context-server-mocks';
|
||||||
|
import { schema } from '@kbn/config-schema';
|
||||||
|
|
||||||
const actualVersion = kibanaPackageJson.version;
|
const actualVersion = kibanaPackageJson.version;
|
||||||
const versionHeader = 'kbn-version';
|
const versionHeader = 'kbn-version';
|
||||||
|
@ -22,37 +23,39 @@ const allowlistedTestPath = '/xsrf/test/route/whitelisted';
|
||||||
const xsrfDisabledTestPath = '/xsrf/test/route/disabled';
|
const xsrfDisabledTestPath = '/xsrf/test/route/disabled';
|
||||||
const kibanaName = 'my-kibana-name';
|
const kibanaName = 'my-kibana-name';
|
||||||
const internalProductHeader = 'x-elastic-internal-origin';
|
const internalProductHeader = 'x-elastic-internal-origin';
|
||||||
|
const internalProductQueryParam = 'elasticInternalOrigin';
|
||||||
const setupDeps = {
|
const setupDeps = {
|
||||||
context: contextServiceMock.createSetupContract(),
|
context: contextServiceMock.createSetupContract(),
|
||||||
executionContext: executionContextServiceMock.createInternalSetupContract(),
|
executionContext: executionContextServiceMock.createInternalSetupContract(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const testConfig: Parameters<typeof createConfigService>[0] = {
|
||||||
|
server: {
|
||||||
|
name: kibanaName,
|
||||||
|
securityResponseHeaders: {
|
||||||
|
// reflects default config
|
||||||
|
strictTransportSecurity: null,
|
||||||
|
xContentTypeOptions: 'nosniff',
|
||||||
|
referrerPolicy: 'strict-origin-when-cross-origin',
|
||||||
|
permissionsPolicy: null,
|
||||||
|
crossOriginOpenerPolicy: 'same-origin',
|
||||||
|
} as any,
|
||||||
|
customResponseHeaders: {
|
||||||
|
'some-header': 'some-value',
|
||||||
|
'referrer-policy': 'strict-origin', // overrides a header that is defined by securityResponseHeaders
|
||||||
|
},
|
||||||
|
xsrf: { disableProtection: false, allowlist: [allowlistedTestPath] },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
describe('core lifecycle handlers', () => {
|
describe('core lifecycle handlers', () => {
|
||||||
let server: HttpService;
|
let server: HttpService;
|
||||||
let innerServer: HttpServerSetup['server'];
|
let innerServer: HttpServerSetup['server'];
|
||||||
let router: IRouter;
|
let router: IRouter;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const configService = createConfigService({
|
const configService = createConfigService(testConfig);
|
||||||
server: {
|
|
||||||
name: kibanaName,
|
|
||||||
securityResponseHeaders: {
|
|
||||||
// reflects default config
|
|
||||||
strictTransportSecurity: null,
|
|
||||||
xContentTypeOptions: 'nosniff',
|
|
||||||
referrerPolicy: 'strict-origin-when-cross-origin',
|
|
||||||
permissionsPolicy: null,
|
|
||||||
crossOriginOpenerPolicy: 'same-origin',
|
|
||||||
} as any,
|
|
||||||
customResponseHeaders: {
|
|
||||||
'some-header': 'some-value',
|
|
||||||
'referrer-policy': 'strict-origin', // overrides a header that is defined by securityResponseHeaders
|
|
||||||
},
|
|
||||||
xsrf: { disableProtection: false, allowlist: [allowlistedTestPath] },
|
|
||||||
},
|
|
||||||
});
|
|
||||||
server = createHttpServer({ configService });
|
server = createHttpServer({ configService });
|
||||||
|
|
||||||
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||||
const serverSetup = await server.setup(setupDeps);
|
const serverSetup = await server.setup(setupDeps);
|
||||||
router = serverSetup.createRouter('/');
|
router = serverSetup.createRouter('/');
|
||||||
|
@ -217,15 +220,36 @@ describe('core lifecycle handlers', () => {
|
||||||
describe('restrictInternalRoutes post-auth handler', () => {
|
describe('restrictInternalRoutes post-auth handler', () => {
|
||||||
const testInternalRoute = '/restrict_internal_routes/test/route_internal';
|
const testInternalRoute = '/restrict_internal_routes/test/route_internal';
|
||||||
const testPublicRoute = '/restrict_internal_routes/test/route_public';
|
const testPublicRoute = '/restrict_internal_routes/test/route_public';
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
await server?.stop();
|
||||||
|
const configService = createConfigService({
|
||||||
|
server: {
|
||||||
|
...testConfig.server,
|
||||||
|
restrictInternalApis: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
server = createHttpServer({ configService });
|
||||||
|
await server.preboot({ context: contextServiceMock.createPrebootContract() });
|
||||||
|
const serverSetup = await server.setup(setupDeps);
|
||||||
|
router = serverSetup.createRouter('/');
|
||||||
|
innerServer = serverSetup.server;
|
||||||
router.get(
|
router.get(
|
||||||
{ path: testInternalRoute, validate: false, options: { access: 'internal' } },
|
{
|
||||||
|
path: testInternalRoute,
|
||||||
|
validate: { query: schema.object({ myValue: schema.string() }) },
|
||||||
|
options: { access: 'internal' },
|
||||||
|
},
|
||||||
(context, req, res) => {
|
(context, req, res) => {
|
||||||
return res.ok({ body: 'ok()' });
|
return res.ok({ body: 'ok()' });
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
router.get(
|
router.get(
|
||||||
{ path: testPublicRoute, validate: false, options: { access: 'public' } },
|
{
|
||||||
|
path: testPublicRoute,
|
||||||
|
validate: { query: schema.object({ myValue: schema.string() }) },
|
||||||
|
options: { access: 'public' },
|
||||||
|
},
|
||||||
(context, req, res) => {
|
(context, req, res) => {
|
||||||
return res.ok({ body: 'ok()' });
|
return res.ok({ body: 'ok()' });
|
||||||
}
|
}
|
||||||
|
@ -233,10 +257,18 @@ describe('core lifecycle handlers', () => {
|
||||||
await server.start();
|
await server.start();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('rejects requests to internal routes without special values', async () => {
|
||||||
|
await supertest(innerServer.listener)
|
||||||
|
.get(testInternalRoute)
|
||||||
|
.query({ myValue: 'test' })
|
||||||
|
.expect(400);
|
||||||
|
});
|
||||||
|
|
||||||
it('accepts requests with the internal product header to internal routes', async () => {
|
it('accepts requests with the internal product header to internal routes', async () => {
|
||||||
await supertest(innerServer.listener)
|
await supertest(innerServer.listener)
|
||||||
.get(testInternalRoute)
|
.get(testInternalRoute)
|
||||||
.set(internalProductHeader, 'anything')
|
.set(internalProductHeader, 'anything')
|
||||||
|
.query({ myValue: 'test' })
|
||||||
.expect(200, 'ok()');
|
.expect(200, 'ok()');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -244,6 +276,21 @@ describe('core lifecycle handlers', () => {
|
||||||
await supertest(innerServer.listener)
|
await supertest(innerServer.listener)
|
||||||
.get(testPublicRoute)
|
.get(testPublicRoute)
|
||||||
.set(internalProductHeader, 'anything')
|
.set(internalProductHeader, 'anything')
|
||||||
|
.query({ myValue: 'test' })
|
||||||
|
.expect(200, 'ok()');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts requests with the internal product query param to internal routes', async () => {
|
||||||
|
await supertest(innerServer.listener)
|
||||||
|
.get(testInternalRoute)
|
||||||
|
.query({ [internalProductQueryParam]: 'anything', myValue: 'test' })
|
||||||
|
.expect(200, 'ok()');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts requests with the internal product query param to public routes', async () => {
|
||||||
|
await supertest(innerServer.listener)
|
||||||
|
.get(testInternalRoute)
|
||||||
|
.query({ [internalProductQueryParam]: 'anything', myValue: 'test' })
|
||||||
.expect(200, 'ok()');
|
.expect(200, 'ok()');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,11 +4,8 @@
|
||||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
import { mockRouter } from '@kbn/core-http-router-server-mocks';
|
||||||
import { Request } from '@hapi/hapi';
|
|
||||||
import { ruleTypeRegistryMock } from './rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from './rule_type_registry.mock';
|
||||||
import { CoreKibanaRequest } from '@kbn/core/server';
|
|
||||||
import { savedObjectsClientMock } from '@kbn/core/server/mocks';
|
|
||||||
import { securityMock } from '@kbn/security-plugin/server/mocks';
|
import { securityMock } from '@kbn/security-plugin/server/mocks';
|
||||||
import {
|
import {
|
||||||
AlertingAuthorizationClientFactory,
|
AlertingAuthorizationClientFactory,
|
||||||
|
@ -18,7 +15,6 @@ import { featuresPluginMock } from '@kbn/features-plugin/server/mocks';
|
||||||
|
|
||||||
jest.mock('./authorization/alerting_authorization');
|
jest.mock('./authorization/alerting_authorization');
|
||||||
|
|
||||||
const savedObjectsClient = savedObjectsClientMock.create();
|
|
||||||
const features = featuresPluginMock.createStart();
|
const features = featuresPluginMock.createStart();
|
||||||
|
|
||||||
const securityPluginSetup = securityMock.createSetup();
|
const securityPluginSetup = securityMock.createSetup();
|
||||||
|
@ -32,23 +28,6 @@ const alertingAuthorizationClientFactoryParams: jest.Mocked<AlertingAuthorizatio
|
||||||
features,
|
features,
|
||||||
};
|
};
|
||||||
|
|
||||||
const fakeRequest = {
|
|
||||||
app: {},
|
|
||||||
headers: {},
|
|
||||||
getBasePath: () => '',
|
|
||||||
path: '/',
|
|
||||||
route: { settings: {} },
|
|
||||||
url: {
|
|
||||||
href: '/',
|
|
||||||
},
|
|
||||||
raw: {
|
|
||||||
req: {
|
|
||||||
url: '/',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
getSavedObjectsClient: () => savedObjectsClient,
|
|
||||||
} as unknown as Request;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.resetAllMocks();
|
jest.resetAllMocks();
|
||||||
});
|
});
|
||||||
|
@ -60,7 +39,7 @@ test('creates an alerting authorization client with proper constructor arguments
|
||||||
securityPluginStart,
|
securityPluginStart,
|
||||||
...alertingAuthorizationClientFactoryParams,
|
...alertingAuthorizationClientFactoryParams,
|
||||||
});
|
});
|
||||||
const request = CoreKibanaRequest.from(fakeRequest);
|
const request = mockRouter.createKibanaRequest();
|
||||||
|
|
||||||
factory.create(request);
|
factory.create(request);
|
||||||
|
|
||||||
|
@ -78,7 +57,7 @@ test('creates an alerting authorization client with proper constructor arguments
|
||||||
test('creates an alerting authorization client with proper constructor arguments', async () => {
|
test('creates an alerting authorization client with proper constructor arguments', async () => {
|
||||||
const factory = new AlertingAuthorizationClientFactory();
|
const factory = new AlertingAuthorizationClientFactory();
|
||||||
factory.initialize(alertingAuthorizationClientFactoryParams);
|
factory.initialize(alertingAuthorizationClientFactoryParams);
|
||||||
const request = CoreKibanaRequest.from(fakeRequest);
|
const request = mockRouter.createKibanaRequest();
|
||||||
|
|
||||||
factory.create(request);
|
factory.create(request);
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,7 @@
|
||||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
import { mockRouter } from '@kbn/core-http-router-server-mocks';
|
||||||
import { Request } from '@hapi/hapi';
|
|
||||||
import { CoreKibanaRequest } from '@kbn/core/server';
|
|
||||||
import {
|
import {
|
||||||
MaintenanceWindowClientFactory,
|
MaintenanceWindowClientFactory,
|
||||||
MaintenanceWindowClientFactoryOpts,
|
MaintenanceWindowClientFactoryOpts,
|
||||||
|
@ -33,23 +31,6 @@ const maintenanceWindowClientFactoryParams: jest.Mocked<MaintenanceWindowClientF
|
||||||
savedObjectsService,
|
savedObjectsService,
|
||||||
};
|
};
|
||||||
|
|
||||||
const fakeRequest = {
|
|
||||||
app: {},
|
|
||||||
headers: {},
|
|
||||||
getBasePath: () => '',
|
|
||||||
path: '/',
|
|
||||||
route: { settings: {} },
|
|
||||||
url: {
|
|
||||||
href: '/',
|
|
||||||
},
|
|
||||||
raw: {
|
|
||||||
req: {
|
|
||||||
url: '/',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
getSavedObjectsClient: () => savedObjectsClient,
|
|
||||||
} as unknown as Request;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.resetAllMocks();
|
jest.resetAllMocks();
|
||||||
});
|
});
|
||||||
|
@ -60,7 +41,7 @@ test('creates a maintenance window client with proper constructor arguments when
|
||||||
securityPluginStart,
|
securityPluginStart,
|
||||||
...maintenanceWindowClientFactoryParams,
|
...maintenanceWindowClientFactoryParams,
|
||||||
});
|
});
|
||||||
const request = CoreKibanaRequest.from(fakeRequest);
|
const request = mockRouter.createKibanaRequest();
|
||||||
|
|
||||||
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
|
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
|
||||||
|
|
||||||
|
@ -82,7 +63,7 @@ test('creates a maintenance window client with proper constructor arguments when
|
||||||
test('creates a maintenance window client with proper constructor arguments', async () => {
|
test('creates a maintenance window client with proper constructor arguments', async () => {
|
||||||
const factory = new MaintenanceWindowClientFactory();
|
const factory = new MaintenanceWindowClientFactory();
|
||||||
factory.initialize(maintenanceWindowClientFactoryParams);
|
factory.initialize(maintenanceWindowClientFactoryParams);
|
||||||
const request = CoreKibanaRequest.from(fakeRequest);
|
const request = mockRouter.createKibanaRequest();
|
||||||
|
|
||||||
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
|
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
|
||||||
|
|
||||||
|
@ -107,7 +88,7 @@ test('creates an unauthorized maintenance window client', async () => {
|
||||||
securityPluginStart,
|
securityPluginStart,
|
||||||
...maintenanceWindowClientFactoryParams,
|
...maintenanceWindowClientFactoryParams,
|
||||||
});
|
});
|
||||||
const request = CoreKibanaRequest.from(fakeRequest);
|
const request = mockRouter.createKibanaRequest();
|
||||||
|
|
||||||
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
|
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
|
||||||
|
|
||||||
|
@ -130,7 +111,7 @@ test('creates an unauthorized maintenance window client', async () => {
|
||||||
test('getUserName() returns null when security is disabled', async () => {
|
test('getUserName() returns null when security is disabled', async () => {
|
||||||
const factory = new MaintenanceWindowClientFactory();
|
const factory = new MaintenanceWindowClientFactory();
|
||||||
factory.initialize(maintenanceWindowClientFactoryParams);
|
factory.initialize(maintenanceWindowClientFactoryParams);
|
||||||
const request = CoreKibanaRequest.from(fakeRequest);
|
const request = mockRouter.createKibanaRequest();
|
||||||
|
|
||||||
factory.createWithAuthorization(request);
|
factory.createWithAuthorization(request);
|
||||||
const constructorCall = jest.requireMock('./maintenance_window_client').MaintenanceWindowClient
|
const constructorCall = jest.requireMock('./maintenance_window_client').MaintenanceWindowClient
|
||||||
|
@ -146,7 +127,7 @@ test('getUserName() returns a name when security is enabled', async () => {
|
||||||
securityPluginStart,
|
securityPluginStart,
|
||||||
...maintenanceWindowClientFactoryParams,
|
...maintenanceWindowClientFactoryParams,
|
||||||
});
|
});
|
||||||
const request = CoreKibanaRequest.from(fakeRequest);
|
const request = mockRouter.createKibanaRequest();
|
||||||
|
|
||||||
factory.createWithAuthorization(request);
|
factory.createWithAuthorization(request);
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,9 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Request } from '@hapi/hapi';
|
|
||||||
import { RulesClientFactory, RulesClientFactoryOpts } from './rules_client_factory';
|
import { RulesClientFactory, RulesClientFactoryOpts } from './rules_client_factory';
|
||||||
import { ruleTypeRegistryMock } from './rule_type_registry.mock';
|
import { ruleTypeRegistryMock } from './rule_type_registry.mock';
|
||||||
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks';
|
||||||
import { CoreKibanaRequest } from '@kbn/core/server';
|
|
||||||
import {
|
import {
|
||||||
savedObjectsClientMock,
|
savedObjectsClientMock,
|
||||||
savedObjectsServiceMock,
|
savedObjectsServiceMock,
|
||||||
|
@ -26,6 +24,7 @@ import { alertingAuthorizationClientFactoryMock } from './alerting_authorization
|
||||||
import { AlertingAuthorization } from './authorization';
|
import { AlertingAuthorization } from './authorization';
|
||||||
import { AlertingAuthorizationClientFactory } from './alerting_authorization_client_factory';
|
import { AlertingAuthorizationClientFactory } from './alerting_authorization_client_factory';
|
||||||
import { SECURITY_EXTENSION_ID } from '@kbn/core-saved-objects-server';
|
import { SECURITY_EXTENSION_ID } from '@kbn/core-saved-objects-server';
|
||||||
|
import { mockRouter } from '@kbn/core-http-router-server-mocks';
|
||||||
|
|
||||||
jest.mock('./rules_client');
|
jest.mock('./rules_client');
|
||||||
jest.mock('./authorization/alerting_authorization');
|
jest.mock('./authorization/alerting_authorization');
|
||||||
|
@ -54,23 +53,6 @@ const rulesClientFactoryParams: jest.Mocked<RulesClientFactoryOpts> = {
|
||||||
alertingAuthorizationClientFactory as unknown as AlertingAuthorizationClientFactory,
|
alertingAuthorizationClientFactory as unknown as AlertingAuthorizationClientFactory,
|
||||||
};
|
};
|
||||||
|
|
||||||
const fakeRequest = {
|
|
||||||
app: {},
|
|
||||||
headers: {},
|
|
||||||
getBasePath: () => '',
|
|
||||||
path: '/',
|
|
||||||
route: { settings: {} },
|
|
||||||
url: {
|
|
||||||
href: '/',
|
|
||||||
},
|
|
||||||
raw: {
|
|
||||||
req: {
|
|
||||||
url: '/',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
getSavedObjectsClient: () => savedObjectsClient,
|
|
||||||
} as unknown as Request;
|
|
||||||
|
|
||||||
const actionsAuthorization = actionsAuthorizationMock.create();
|
const actionsAuthorization = actionsAuthorizationMock.create();
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -86,7 +68,7 @@ beforeEach(() => {
|
||||||
test('creates a rules client with proper constructor arguments when security is enabled', async () => {
|
test('creates a rules client with proper constructor arguments when security is enabled', async () => {
|
||||||
const factory = new RulesClientFactory();
|
const factory = new RulesClientFactory();
|
||||||
factory.initialize({ securityPluginSetup, securityPluginStart, ...rulesClientFactoryParams });
|
factory.initialize({ securityPluginSetup, securityPluginStart, ...rulesClientFactoryParams });
|
||||||
const request = CoreKibanaRequest.from(fakeRequest);
|
const request = mockRouter.createKibanaRequest();
|
||||||
|
|
||||||
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
|
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
|
||||||
alertingAuthorizationClientFactory.create.mockReturnValue(
|
alertingAuthorizationClientFactory.create.mockReturnValue(
|
||||||
|
@ -130,7 +112,7 @@ test('creates a rules client with proper constructor arguments when security is
|
||||||
test('creates a rules client with proper constructor arguments', async () => {
|
test('creates a rules client with proper constructor arguments', async () => {
|
||||||
const factory = new RulesClientFactory();
|
const factory = new RulesClientFactory();
|
||||||
factory.initialize(rulesClientFactoryParams);
|
factory.initialize(rulesClientFactoryParams);
|
||||||
const request = CoreKibanaRequest.from(fakeRequest);
|
const request = mockRouter.createKibanaRequest();
|
||||||
|
|
||||||
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
|
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
|
||||||
alertingAuthorizationClientFactory.create.mockReturnValue(
|
alertingAuthorizationClientFactory.create.mockReturnValue(
|
||||||
|
@ -170,7 +152,7 @@ test('creates a rules client with proper constructor arguments', async () => {
|
||||||
test('getUserName() returns null when security is disabled', async () => {
|
test('getUserName() returns null when security is disabled', async () => {
|
||||||
const factory = new RulesClientFactory();
|
const factory = new RulesClientFactory();
|
||||||
factory.initialize(rulesClientFactoryParams);
|
factory.initialize(rulesClientFactoryParams);
|
||||||
factory.create(CoreKibanaRequest.from(fakeRequest), savedObjectsService);
|
factory.create(mockRouter.createKibanaRequest(), savedObjectsService);
|
||||||
const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0];
|
const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0];
|
||||||
|
|
||||||
const userNameResult = await constructorCall.getUserName();
|
const userNameResult = await constructorCall.getUserName();
|
||||||
|
@ -184,7 +166,7 @@ test('getUserName() returns a name when security is enabled', async () => {
|
||||||
securityPluginSetup,
|
securityPluginSetup,
|
||||||
securityPluginStart,
|
securityPluginStart,
|
||||||
});
|
});
|
||||||
factory.create(CoreKibanaRequest.from(fakeRequest), savedObjectsService);
|
factory.create(mockRouter.createKibanaRequest(), savedObjectsService);
|
||||||
const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0];
|
const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0];
|
||||||
|
|
||||||
securityPluginStart.authc.getCurrentUser.mockReturnValueOnce({
|
securityPluginStart.authc.getCurrentUser.mockReturnValueOnce({
|
||||||
|
@ -197,7 +179,7 @@ test('getUserName() returns a name when security is enabled', async () => {
|
||||||
test('getActionsClient() returns ActionsClient', async () => {
|
test('getActionsClient() returns ActionsClient', async () => {
|
||||||
const factory = new RulesClientFactory();
|
const factory = new RulesClientFactory();
|
||||||
factory.initialize(rulesClientFactoryParams);
|
factory.initialize(rulesClientFactoryParams);
|
||||||
factory.create(CoreKibanaRequest.from(fakeRequest), savedObjectsService);
|
factory.create(mockRouter.createKibanaRequest(), savedObjectsService);
|
||||||
const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0];
|
const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0];
|
||||||
|
|
||||||
const actionsClient = await constructorCall.getActionsClient();
|
const actionsClient = await constructorCall.getActionsClient();
|
||||||
|
@ -207,7 +189,7 @@ test('getActionsClient() returns ActionsClient', async () => {
|
||||||
test('createAPIKey() returns { apiKeysEnabled: false } when security is disabled', async () => {
|
test('createAPIKey() returns { apiKeysEnabled: false } when security is disabled', async () => {
|
||||||
const factory = new RulesClientFactory();
|
const factory = new RulesClientFactory();
|
||||||
factory.initialize(rulesClientFactoryParams);
|
factory.initialize(rulesClientFactoryParams);
|
||||||
factory.create(CoreKibanaRequest.from(fakeRequest), savedObjectsService);
|
factory.create(mockRouter.createKibanaRequest(), savedObjectsService);
|
||||||
const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0];
|
const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0];
|
||||||
|
|
||||||
const createAPIKeyResult = await constructorCall.createAPIKey();
|
const createAPIKeyResult = await constructorCall.createAPIKey();
|
||||||
|
@ -217,7 +199,7 @@ test('createAPIKey() returns { apiKeysEnabled: false } when security is disabled
|
||||||
test('createAPIKey() returns { apiKeysEnabled: false } when security is enabled but ES security is disabled', async () => {
|
test('createAPIKey() returns { apiKeysEnabled: false } when security is enabled but ES security is disabled', async () => {
|
||||||
const factory = new RulesClientFactory();
|
const factory = new RulesClientFactory();
|
||||||
factory.initialize(rulesClientFactoryParams);
|
factory.initialize(rulesClientFactoryParams);
|
||||||
factory.create(CoreKibanaRequest.from(fakeRequest), savedObjectsService);
|
factory.create(mockRouter.createKibanaRequest(), savedObjectsService);
|
||||||
const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0];
|
const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0];
|
||||||
|
|
||||||
securityPluginStart.authc.apiKeys.grantAsInternalUser.mockResolvedValueOnce(null);
|
securityPluginStart.authc.apiKeys.grantAsInternalUser.mockResolvedValueOnce(null);
|
||||||
|
@ -232,7 +214,7 @@ test('createAPIKey() returns an API key when security is enabled', async () => {
|
||||||
securityPluginSetup,
|
securityPluginSetup,
|
||||||
securityPluginStart,
|
securityPluginStart,
|
||||||
});
|
});
|
||||||
factory.create(CoreKibanaRequest.from(fakeRequest), savedObjectsService);
|
factory.create(mockRouter.createKibanaRequest(), savedObjectsService);
|
||||||
const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0];
|
const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0];
|
||||||
|
|
||||||
securityPluginStart.authc.apiKeys.grantAsInternalUser.mockResolvedValueOnce({
|
securityPluginStart.authc.apiKeys.grantAsInternalUser.mockResolvedValueOnce({
|
||||||
|
@ -254,7 +236,7 @@ test('createAPIKey() throws when security plugin createAPIKey throws an error',
|
||||||
securityPluginSetup,
|
securityPluginSetup,
|
||||||
securityPluginStart,
|
securityPluginStart,
|
||||||
});
|
});
|
||||||
factory.create(CoreKibanaRequest.from(fakeRequest), savedObjectsService);
|
factory.create(mockRouter.createKibanaRequest(), savedObjectsService);
|
||||||
const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0];
|
const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0];
|
||||||
|
|
||||||
securityPluginStart.authc.apiKeys.grantAsInternalUser.mockRejectedValueOnce(
|
securityPluginStart.authc.apiKeys.grantAsInternalUser.mockRejectedValueOnce(
|
||||||
|
|
|
@ -5,8 +5,7 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Request } from '@hapi/hapi';
|
import { mockRouter } from '@kbn/core-http-router-server-mocks';
|
||||||
import { CoreKibanaRequest } from '@kbn/core/server';
|
|
||||||
import {
|
import {
|
||||||
RulesSettingsClientFactory,
|
RulesSettingsClientFactory,
|
||||||
RulesSettingsClientFactoryOpts,
|
RulesSettingsClientFactoryOpts,
|
||||||
|
@ -33,23 +32,6 @@ const rulesSettingsClientFactoryParams: jest.Mocked<RulesSettingsClientFactoryOp
|
||||||
savedObjectsService,
|
savedObjectsService,
|
||||||
};
|
};
|
||||||
|
|
||||||
const fakeRequest = {
|
|
||||||
app: {},
|
|
||||||
headers: {},
|
|
||||||
getBasePath: () => '',
|
|
||||||
path: '/',
|
|
||||||
route: { settings: {} },
|
|
||||||
url: {
|
|
||||||
href: '/',
|
|
||||||
},
|
|
||||||
raw: {
|
|
||||||
req: {
|
|
||||||
url: '/',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
getSavedObjectsClient: () => savedObjectsClient,
|
|
||||||
} as unknown as Request;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.resetAllMocks();
|
jest.resetAllMocks();
|
||||||
});
|
});
|
||||||
|
@ -60,7 +42,7 @@ test('creates a rules settings client with proper constructor arguments when sec
|
||||||
securityPluginStart,
|
securityPluginStart,
|
||||||
...rulesSettingsClientFactoryParams,
|
...rulesSettingsClientFactoryParams,
|
||||||
});
|
});
|
||||||
const request = CoreKibanaRequest.from(fakeRequest);
|
const request = mockRouter.createKibanaRequest();
|
||||||
|
|
||||||
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
|
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
|
||||||
|
|
||||||
|
@ -82,7 +64,7 @@ test('creates a rules settings client with proper constructor arguments when sec
|
||||||
test('creates a rules settings client with proper constructor arguments', async () => {
|
test('creates a rules settings client with proper constructor arguments', async () => {
|
||||||
const factory = new RulesSettingsClientFactory();
|
const factory = new RulesSettingsClientFactory();
|
||||||
factory.initialize(rulesSettingsClientFactoryParams);
|
factory.initialize(rulesSettingsClientFactoryParams);
|
||||||
const request = CoreKibanaRequest.from(fakeRequest);
|
const request = mockRouter.createKibanaRequest();
|
||||||
|
|
||||||
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
|
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
|
||||||
|
|
||||||
|
@ -107,7 +89,7 @@ test('creates an unauthorized rules settings client', async () => {
|
||||||
securityPluginStart,
|
securityPluginStart,
|
||||||
...rulesSettingsClientFactoryParams,
|
...rulesSettingsClientFactoryParams,
|
||||||
});
|
});
|
||||||
const request = CoreKibanaRequest.from(fakeRequest);
|
const request = mockRouter.createKibanaRequest();
|
||||||
|
|
||||||
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
|
savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient);
|
||||||
|
|
||||||
|
@ -130,7 +112,7 @@ test('creates an unauthorized rules settings client', async () => {
|
||||||
test('getUserName() returns null when security is disabled', async () => {
|
test('getUserName() returns null when security is disabled', async () => {
|
||||||
const factory = new RulesSettingsClientFactory();
|
const factory = new RulesSettingsClientFactory();
|
||||||
factory.initialize(rulesSettingsClientFactoryParams);
|
factory.initialize(rulesSettingsClientFactoryParams);
|
||||||
const request = CoreKibanaRequest.from(fakeRequest);
|
const request = mockRouter.createKibanaRequest();
|
||||||
|
|
||||||
factory.createWithAuthorization(request);
|
factory.createWithAuthorization(request);
|
||||||
const constructorCall =
|
const constructorCall =
|
||||||
|
@ -146,7 +128,7 @@ test('getUserName() returns a name when security is enabled', async () => {
|
||||||
securityPluginStart,
|
securityPluginStart,
|
||||||
...rulesSettingsClientFactoryParams,
|
...rulesSettingsClientFactoryParams,
|
||||||
});
|
});
|
||||||
const request = CoreKibanaRequest.from(fakeRequest);
|
const request = mockRouter.createKibanaRequest();
|
||||||
|
|
||||||
factory.createWithAuthorization(request);
|
factory.createWithAuthorization(request);
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@
|
||||||
"@kbn/core-capabilities-common",
|
"@kbn/core-capabilities-common",
|
||||||
"@kbn/unified-search-plugin",
|
"@kbn/unified-search-plugin",
|
||||||
"@kbn/core-http-server-mocks",
|
"@kbn/core-http-server-mocks",
|
||||||
|
"@kbn/core-http-router-server-mocks",
|
||||||
],
|
],
|
||||||
"exclude": ["target/**/*"]
|
"exclude": ["target/**/*"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,9 @@
|
||||||
* 2.0.
|
* 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Request } from '@hapi/hapi';
|
import { mockRouter } from '@kbn/core-http-router-server-mocks';
|
||||||
|
|
||||||
import { AlertsClientFactory, AlertsClientFactoryProps } from './alerts_client_factory';
|
import { AlertsClientFactory, AlertsClientFactoryProps } from './alerts_client_factory';
|
||||||
import { ElasticsearchClient, KibanaRequest, CoreKibanaRequest } from '@kbn/core/server';
|
import { ElasticsearchClient, KibanaRequest } from '@kbn/core/server';
|
||||||
import { loggingSystemMock } from '@kbn/core/server/mocks';
|
import { loggingSystemMock } from '@kbn/core/server/mocks';
|
||||||
import { securityMock } from '@kbn/security-plugin/server/mocks';
|
import { securityMock } from '@kbn/security-plugin/server/mocks';
|
||||||
import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks';
|
import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks';
|
||||||
|
@ -29,22 +28,6 @@ const alertsClientFactoryParams: AlertsClientFactoryProps = {
|
||||||
getRuleType: jest.fn(),
|
getRuleType: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const fakeRequest = {
|
|
||||||
app: {},
|
|
||||||
headers: {},
|
|
||||||
getBasePath: () => '',
|
|
||||||
path: '/',
|
|
||||||
route: { settings: {} },
|
|
||||||
url: {
|
|
||||||
href: '/',
|
|
||||||
},
|
|
||||||
raw: {
|
|
||||||
req: {
|
|
||||||
url: '/',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as unknown as Request;
|
|
||||||
|
|
||||||
const auditLogger = auditLoggerMock.create();
|
const auditLogger = auditLoggerMock.create();
|
||||||
|
|
||||||
describe('AlertsClientFactory', () => {
|
describe('AlertsClientFactory', () => {
|
||||||
|
@ -57,7 +40,10 @@ describe('AlertsClientFactory', () => {
|
||||||
test('creates an alerts client with proper constructor arguments', async () => {
|
test('creates an alerts client with proper constructor arguments', async () => {
|
||||||
const factory = new AlertsClientFactory();
|
const factory = new AlertsClientFactory();
|
||||||
factory.initialize({ ...alertsClientFactoryParams });
|
factory.initialize({ ...alertsClientFactoryParams });
|
||||||
const request = CoreKibanaRequest.from(fakeRequest);
|
const request = mockRouter.createKibanaRequest({
|
||||||
|
headers: {},
|
||||||
|
path: '/',
|
||||||
|
});
|
||||||
await factory.create(request);
|
await factory.create(request);
|
||||||
|
|
||||||
expect(jest.requireMock('./alerts_client').AlertsClient).toHaveBeenCalledWith({
|
expect(jest.requireMock('./alerts_client').AlertsClient).toHaveBeenCalledWith({
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
"@kbn/share-plugin",
|
"@kbn/share-plugin",
|
||||||
"@kbn/alerting-state-types",
|
"@kbn/alerting-state-types",
|
||||||
"@kbn/alerts-as-data-utils",
|
"@kbn/alerts-as-data-utils",
|
||||||
|
"@kbn/core-http-router-server-mocks",
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"target/**/*",
|
"target/**/*",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue