[Authz] Mandatory Security Config (#215180)

## Summary

This PR makes `security` a required field for route registration. To
incorporate the new required filed, changes has been made:

1. **Test file updates**. A lot of the updates made in this PR were made
in tests.
2. **Versioned route security configuration**. For the versioned route
`security` config has been lifted up to the top-level definition:

    Before
    ```ts
    router.versioned
      .get({
        path: '/api/path',
        options: { ... },
        ...
      }, handler)
      .addVersion({
         version: 1,
         validate: false,
         security: {
          authz: {
            requiredPrivileges: ['privilege'],
          },
         },
      });
    ```
    
    After
    ```ts
    router.versioned
      .get({
        path: '/api/path',
        options: { ... },
         security: {
          authz: {
            requiredPrivileges: ['privilege'],
          },
         },
        ...
      }, handler)
      .addVersion({
         version: 1,
         validate: false,
      });
    ```

3. **Type adjustments for route wrappers**. Type changes has been made
in:
-
`x-pack/solutions/observability/plugins/infra/server/lib/adapters/framework/adapter_types.ts`
-
`x-pack/solutions/observability/plugins/metrics_data_access/server/lib/adapters/framework/adapter_types.ts`
-
`x-pack/solutions/observability/plugins/synthetics/server/routes/types.ts`
-
`x-pack/solutions/observability/plugins/uptime/server/legacy_uptime/routes/types.ts`

Security was made an optional field for the wrappers defined in those
files, since the default security is provided in the wrapper itself and
then passed down to the core router.

### 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
- [x] The PR description includes the appropriate Release Notes section,
and the correct `release_note:*` label is applied per the
[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)


__Closes: https://github.com/elastic/kibana/issues/215331__

---------

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Elena Shostak 2025-03-27 20:04:53 +01:00 committed by GitHub
parent 2aa857643d
commit 7a41906d88
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
253 changed files with 6835 additions and 3201 deletions

View file

@ -307,6 +307,12 @@ export class EsoModelVersionExample
{
path: '/internal/eso_mv_example/generate',
validate: false,
security: {
authz: {
enabled: false,
reason: 'This routes delegates authorization to SO client.',
},
},
},
async (context, request, response) => {
const { elasticsearch } = await context.core;
@ -358,6 +364,12 @@ export class EsoModelVersionExample
{
path: '/internal/eso_mv_example/read_raw',
validate: false,
security: {
authz: {
enabled: false,
reason: 'This routes delegates authorization to SO client.',
},
},
},
async (context, request, response) => {
// Read the raw documents so we can display the model versions prior to migration transformations
@ -394,6 +406,9 @@ export class EsoModelVersionExample
{
path: '/internal/eso_mv_example/get_objects',
validate: false,
security: {
authz: { enabled: false, reason: 'This routes delegates authorization to SO client.' },
},
},
async (context, request, response) => {
// Get the objects via the SO client so we can display how the objects are migrated via the MV definitions
@ -431,6 +446,9 @@ export class EsoModelVersionExample
{
path: '/internal/eso_mv_example/get_decrypted',
validate: false,
security: {
authz: { enabled: false, reason: 'This route delegates authorization to SO client.' },
},
},
async (context, request, response) => {
// Decrypt the objects as the internal user so we can display the secrets

View file

@ -56,6 +56,7 @@ export class FeatureControlsPluginExample
{
path: '/internal/my_plugin/read',
validate: false,
security: { authz: { requiredPrivileges: ['my_closed_example_api'] } },
},
async (context, request, response) => {
return response.ok({

View file

@ -16,6 +16,9 @@ export function defineRoutes(router: IRouter) {
.get({
path: '/api/feature_flags_example/example',
access: 'public',
security: {
authz: { enabled: false, reason: 'Public route that does not require authorization' },
},
})
.addVersion(
{

View file

@ -40,6 +40,12 @@ export class PrebootExamplePlugin implements PrebootPlugin {
prebootRouter.get(
{
path: '/api/preboot/state',
security: {
authz: {
enabled: false,
reason: 'This route is opted out of authorization as it is a core preboot route',
},
},
validate: false,
options: { authRequired: false },
},
@ -55,6 +61,12 @@ export class PrebootExamplePlugin implements PrebootPlugin {
prebootRouter.post(
{
path: '/api/preboot/complete_setup',
security: {
authz: {
enabled: false,
reason: 'This route is opted out of authorization as it is a core preboot route',
},
},
validate: {
body: schema.object({ shouldReloadConfig: schema.boolean() }),
},
@ -69,6 +81,12 @@ export class PrebootExamplePlugin implements PrebootPlugin {
prebootRouter.post(
{
path: '/api/preboot/write_config',
security: {
authz: {
enabled: false,
reason: 'This route is opted out of authorization as it is a core preboot route',
},
},
validate: {
body: schema.object({ key: schema.string(), value: schema.string() }),
},
@ -91,6 +109,9 @@ export class PrebootExamplePlugin implements PrebootPlugin {
prebootRouter.post(
{
path: '/api/preboot/connect_to_es',
security: {
authz: { enabled: false, reason: 'This route delegates authorization to es client' },
},
validate: {
body: schema.object({
host: schema.string(),

View file

@ -27,6 +27,12 @@ export const defineReducerStreamRoute = (router: IRouter, logger: Logger) => {
.post({
path: RESPONSE_STREAM_API_ENDPOINT.REDUCER_STREAM,
access: 'internal',
security: {
authz: {
enabled: false,
reason: 'This route is opted out of authorization as it is a developer example endpoint.',
},
},
})
.addVersion(
{

View file

@ -27,6 +27,12 @@ export const defineReduxStreamRoute = (router: IRouter, logger: Logger) => {
.post({
path: RESPONSE_STREAM_API_ENDPOINT.REDUX_STREAM,
access: 'internal',
security: {
authz: {
enabled: false,
reason: 'This route is opted out of authorization as it is a developer example endpoint.',
},
},
})
.addVersion(
{

View file

@ -22,6 +22,12 @@ export const defineSimpleStringStreamRoute = (router: IRouter, logger: Logger) =
.post({
path: RESPONSE_STREAM_API_ENDPOINT.SIMPLE_STRING_STREAM,
access: 'internal',
security: {
authz: {
enabled: false,
reason: 'This route is opted out of authorization as it is a developer example endpoint.',
},
},
})
.addVersion(
{

View file

@ -14,6 +14,13 @@ export const registerInternalDeprecatedRoute = (router: IRouter) => {
router.get(
{
path: DEPRECATED_ROUTES.INTERNAL_DEPRECATED_ROUTE,
security: {
authz: {
enabled: false,
reason:
'This route is opted out of authorization because it is only intended for test use',
},
},
validate: false,
options: {
// Explicitly set access is to internal
@ -40,6 +47,13 @@ export const registerInternalDeprecatedRoute = (router: IRouter) => {
{
path: DEPRECATED_ROUTES.INTERNAL_ONLY_ROUTE,
validate: false,
security: {
authz: {
enabled: false,
reason:
'This route is opted out of authorization because it is only intended for test use',
},
},
// If no access is specified then it defaults to internal
},
async (ctx, req, res) => {

View file

@ -16,6 +16,13 @@ export const registerDeprecatedRoute = (router: IRouter) => {
{
path: DEPRECATED_ROUTES.DEPRECATED_ROUTE,
validate: false,
security: {
authz: {
enabled: false,
reason:
'This route is opted out of authorization because it is only intended for test use',
},
},
options: {
access: 'public',
deprecated: {
@ -38,6 +45,13 @@ export const registerDeprecatedRoute = (router: IRouter) => {
{
path: DEPRECATED_ROUTES.REMOVED_ROUTE,
validate: false,
security: {
authz: {
enabled: false,
reason:
'This route is opted out of authorization because it is only intended for test use',
},
},
options: {
access: 'public',
deprecated: {
@ -57,6 +71,13 @@ export const registerDeprecatedRoute = (router: IRouter) => {
router.post(
{
path: DEPRECATED_ROUTES.MIGRATED_ROUTE,
security: {
authz: {
enabled: false,
reason:
'This route is opted out of authorization because it is only intended for test use',
},
},
validate: {
body: schema.object({
test: schema.maybe(schema.boolean()),

View file

@ -14,6 +14,13 @@ export const registerVersionedDeprecatedRoute = (router: IRouter) => {
router.versioned
.get({
path: DEPRECATED_ROUTES.VERSIONED_ROUTE,
security: {
authz: {
enabled: false,
reason:
'This route is opted out of authorization because it is only intended for test use',
},
},
description: 'Routing example plugin deprecated versioned route.',
access: 'public',
options: {
@ -43,6 +50,13 @@ export const registerVersionedDeprecatedRoute = (router: IRouter) => {
router.versioned
.get({
path: DEPRECATED_ROUTES.VERSIONED_INTERNAL_ROUTE,
security: {
authz: {
enabled: false,
reason:
'This route is opted out of authorization because it is only intended for test use',
},
},
description: 'Routing example plugin deprecated versioned route.',
access: 'internal',
options: {

View file

@ -30,6 +30,13 @@ export function registerPostMessageRoute(router: IRouter) {
router.post(
{
path: `${POST_MESSAGE_ROUTE_PATH}/{id}`,
security: {
authz: {
enabled: false,
reason:
'This route is opted out of authorization because it is only intended for test use',
},
},
validate: {
params: schema.object({
// This parameter name matches the one in POST_MESSAGE_ROUTE_PATH: `api/post_message/{id}`.
@ -63,6 +70,13 @@ export function registerGetMessageByIdRoute(router: IRouter) {
router.get(
{
path: `${INTERNAL_GET_MESSAGE_BY_ID_ROUTE}/{id}`,
security: {
authz: {
enabled: false,
reason:
'This route is opted out of authorization because it is only intended for test use',
},
},
options: {
access: 'internal',
},

View file

@ -19,6 +19,13 @@ export function registerGetRandomNumberBetweenRoute(router: IRouter) {
router.get(
{
path: RANDOM_NUMBER_BETWEEN_ROUTE_PATH,
security: {
authz: {
enabled: false,
reason:
'This route is opted out of authorization because it is only intended for test use',
},
},
validate: {
query: schema.object({
max: schema.number({ defaultValue: 10 }),

View file

@ -19,6 +19,13 @@ export function registerGetRandomNumberRoute(router: IRouter) {
router.get(
{
path: RANDOM_NUMBER_ROUTE_PATH,
security: {
authz: {
enabled: false,
reason:
'This route is opted out of authorization because it is only intended for test use',
},
},
validate: {},
},
async (context, request, response) => {

View file

@ -12,7 +12,13 @@ import { BASE_API_ROUTE } from '../common';
export const registerRoutes = ({ router, log, screenshotMode }: RouteDependencies) => {
router.get(
{ path: `${BASE_API_ROUTE}/check_is_screenshot`, validate: false },
{
path: `${BASE_API_ROUTE}/check_is_screenshot`,
validate: false,
security: {
authz: { enabled: false, reason: 'Screenshot api is public' },
},
},
async (ctx, req, res) => {
log.info(`Reading screenshot mode from a request: ${screenshotMode.isScreenshotMode(req)}`);
log.info(`Reading is screenshot mode from ctx: ${(await ctx.screenshotMode).isScreenshot}`);

View file

@ -24,6 +24,12 @@ export function registerServerSearchRoute(router: IRouter<DataRequestHandlerCont
field: schema.maybe(schema.string()),
}),
},
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization check to es.',
},
},
},
async (context, request, response) => {
const { index, field } = request.query;

View file

@ -17,6 +17,12 @@ export function defineRoutes(router: IRouter, logger: Logger) {
.get({
path: '/internal/sse_examples/clock',
access: 'internal',
security: {
authz: {
enabled: false,
reason: 'This route is opted out of authorization since it is an example sse route',
},
},
})
.addVersion(
{

View file

@ -24,6 +24,7 @@ const routeValidation = {
const routeConfig = {
path: '/_dev/cpu_profile',
validate: routeValidation,
security: { authz: { requiredPrivileges: ['foo'] } },
};
export function registerRoute(logger: Logger, router: IRouter): void {

View file

@ -26,6 +26,7 @@ const routeValidation = {
const routeConfig = {
path: '/_dev/heap_profile',
validate: routeValidation,
security: { authz: { requiredPrivileges: ['foo'] } },
};
export function registerRoute(logger: Logger, router: IRouter): void {

View file

@ -71,6 +71,7 @@ export const plugin: PluginInitializer<
path: MOCK_IDP_LOGIN_PATH,
validate: false,
options: { authRequired: false },
security: { authz: { enabled: false, reason: '' } },
},
async (context, request, response) => {
return response.renderAnonymousCoreApp();
@ -85,6 +86,7 @@ export const plugin: PluginInitializer<
path: '/mock_idp/supported_roles',
validate: false,
options: { authRequired: false },
security: { authz: { enabled: false, reason: '' } },
},
(context, request, response) => {
try {
@ -110,6 +112,7 @@ export const plugin: PluginInitializer<
body: createSAMLResponseSchema,
},
options: { authRequired: false },
security: { authz: { enabled: false, reason: '' } },
},
async (context, request, response) => {
const { protocol, hostname, port } = core.http.getServerInfo();
@ -134,6 +137,7 @@ export const plugin: PluginInitializer<
path: MOCK_IDP_LOGOUT_PATH,
validate: false,
options: { authRequired: false },
security: { authz: { enabled: false, reason: '' } },
},
async (context, request, response) => {
return response.redirected({ headers: { location: '/' } });

View file

@ -48,6 +48,12 @@ describe('registerRouteForBundle', () => {
httpResource: true,
},
validate: expect.any(Object),
security: {
authz: {
enabled: false,
reason: expect.any(String),
},
},
},
handler
);

View file

@ -41,6 +41,12 @@ export function registerRouteForBundle(
path: schema.string(),
}),
},
security: {
authz: {
enabled: false,
reason: 'This route is used for serving assets and does not require authorization.',
},
},
},
createDynamicAssetHandler({
publicPath,

View file

@ -48,7 +48,15 @@ describe('HttpResources service', () => {
getDeps: () => PrebootDeps | SetupDeps
) {
describe(`${name} register`, () => {
const routeConfig: RouteConfig<any, any, any, 'get'> = { path: '/', validate: false };
const routeConfig: RouteConfig<any, any, any, 'get'> = {
path: '/',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
};
let register: HttpResources['register'];
beforeEach(async () => {

View file

@ -53,6 +53,11 @@ describe('Router', () => {
{
path: '/',
validate: { body: validation, query: validation, params: validation },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
options: {
deprecated: {
documentationUrl: 'https://fake-url.com',
@ -103,12 +108,22 @@ describe('Router', () => {
.post({
path: '/versioned',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion({ version: '999', validate: false }, async (ctx, req, res) => res.ok());
router.get(
{
path: '/unversioned',
validate: { body: validation, query: validation, params: validation },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok()
);
@ -131,6 +146,11 @@ describe('Router', () => {
{
path: '/',
validate: staticOrLazy ? fooValidation : () => fooValidation,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok()
);
@ -158,6 +178,11 @@ describe('Router', () => {
router.post(
{
path: '/public',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
options: {
access: 'public',
},
@ -168,6 +193,11 @@ describe('Router', () => {
router.post(
{
path: '/internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
options: {
access: 'internal',
},
@ -194,6 +224,11 @@ describe('Router', () => {
router.post(
{
path: '/public',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
options: {
access: 'public',
},
@ -204,6 +239,11 @@ describe('Router', () => {
router.post(
{
path: '/public-resource',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
options: {
access: 'public',
httpResource: true,
@ -240,6 +280,11 @@ describe('Router', () => {
router.post(
{
path: '/',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
validate: lazyValidation,
},
(context, req, res) => res.ok()
@ -299,6 +344,11 @@ describe('Router', () => {
{
path: '/',
validate: { params: { validate: () => 'error' } } as any,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({})
)
@ -316,6 +366,11 @@ describe('Router', () => {
path: '/',
validate: false,
options: { security: { authz: { requiredPrivileges: [] } } } as any,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({})
)
@ -333,6 +388,11 @@ describe('Router', () => {
path: '/',
options: { body: { output: 'file' } } as any, // We explicitly don't support 'file'
validate: { body: schema.object({}, { unknowns: 'allow' }) },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({})
)
@ -384,7 +444,18 @@ describe('Router', () => {
it('should default `output: "stream" and parse: false` when no body validation is required but not a GET', () => {
const router = new Router('', logger, enhanceWithContext, routerOptions);
router.post({ path: '/', validate: {} }, (context, req, res) => res.ok({}));
router.post(
{
path: '/',
validate: {},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({})
);
const [route] = router.getRoutes();
expect(route.options).toEqual({ body: { output: 'stream', parse: false } });
});
@ -392,7 +463,16 @@ describe('Router', () => {
it('should NOT default `output: "stream" and parse: false` when the user has specified body options (he cares about it)', () => {
const router = new Router('', logger, enhanceWithContext, routerOptions);
router.post(
{ path: '/', options: { body: { maxBytes: 1 } }, validate: {} },
{
path: '/',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
options: { body: { maxBytes: 1 } },
validate: {},
},
(context, req, res) => res.ok({})
);
const [route] = router.getRoutes();
@ -401,7 +481,18 @@ describe('Router', () => {
it('should NOT default `output: "stream" and parse: false` when no body validation is required and GET', () => {
const router = new Router('', logger, enhanceWithContext, routerOptions);
router.get({ path: '/', validate: {} }, (context, req, res) => res.ok({}));
router.get(
{
path: '/',
validate: {},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({})
);
const [route] = router.getRoutes();
expect(route.options).toEqual({});
});

View file

@ -65,6 +65,11 @@ describe('Versioned route', () => {
description: 'test',
summary: 'test',
enableQueryVersion: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion({ version: '2023-10-31', validate: false }, handlerFn);
@ -88,7 +93,15 @@ describe('Versioned route', () => {
it('can register multiple handlers', () => {
versionedRouter
.get({ path: '/test/{id}', access: 'internal' })
.get({
path: '/test/{id}',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion({ version: '1', validate: false }, handlerFn)
.addVersion({ version: '2', validate: false }, handlerFn)
.addVersion({ version: '3', validate: false }, handlerFn);
@ -111,7 +124,15 @@ describe('Versioned route', () => {
it('does not allow specifying a handler for the same version more than once', () => {
expect(() =>
versionedRouter
.get({ path: '/test/{id}', access: 'internal' })
.get({
path: '/test/{id}',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion({ version: '1', validate: false }, handlerFn)
.addVersion({ version: '1', validate: false }, handlerFn)
.addVersion({ version: '3', validate: false }, handlerFn)
@ -123,22 +144,54 @@ describe('Versioned route', () => {
it('only allows versions that are numbers greater than 0 for internal APIs', () => {
expect(() =>
versionedRouter
.get({ path: '/test/{id}', access: 'internal' })
.get({
path: '/test/{id}',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion({ version: 'foo' as ApiVersion, validate: false }, handlerFn)
).toThrowError(`Invalid version number`);
expect(() =>
versionedRouter
.get({ path: '/test/{id}', access: 'internal' })
.get({
path: '/test/{id}',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion({ version: '-1', validate: false }, handlerFn)
).toThrowError(`Invalid version number`);
expect(() =>
versionedRouter
.get({ path: '/test/{id}', access: 'internal' })
.get({
path: '/test/{id}',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion({ version: '1.1', validate: false }, handlerFn)
).toThrowError(`Invalid version number`);
expect(() =>
versionedRouter
.get({ path: '/test/{id}', access: 'internal' })
.get({
path: '/test/{id}',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion({ version: '1', validate: false }, handlerFn)
).not.toThrow();
});
@ -146,22 +199,54 @@ describe('Versioned route', () => {
it('only allows correctly formatted version date strings for public APIs', () => {
expect(() =>
versionedRouter
.get({ path: '/test/{id}', access: 'public' })
.get({
path: '/test/{id}',
access: 'public',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion({ version: '1-1-2020' as ApiVersion, validate: false }, handlerFn)
).toThrowError(/Invalid version/);
expect(() =>
versionedRouter
.get({ path: '/test/{id}', access: 'public' })
.get({
path: '/test/{id}',
access: 'public',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion({ version: '', validate: false }, handlerFn)
).toThrowError(/Invalid version/);
expect(() =>
versionedRouter
.get({ path: '/test/{id}', access: 'public' })
.get({
path: '/test/{id}',
access: 'public',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion({ version: 'abc', validate: false }, handlerFn)
).toThrowError(/Invalid version/);
expect(() =>
versionedRouter
.get({ path: '/test/{id}', access: 'public' })
.get({
path: '/test/{id}',
access: 'public',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion({ version: '2023-10-31', validate: false }, handlerFn)
).not.toThrow();
});
@ -180,6 +265,11 @@ describe('Versioned route', () => {
excludeFromOAS: true,
httpResource: true,
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
};
versionedRouter.post(opts);
@ -206,7 +296,15 @@ describe('Versioned route', () => {
it('allows public versions other than "2023-10-31"', () => {
expect(() =>
CoreVersionedRouter.from({ router, log: loggingSystemMock.createLogger(), env: notDevEnv })
.get({ access: 'public', path: '/foo' })
.get({
access: 'public',
path: '/foo',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion({ version: '2023-01-31', validate: false }, (ctx, req, res) => res.ok())
).not.toThrow();
});
@ -219,7 +317,17 @@ describe('Versioned route', () => {
testValidation;
(router.registerRoute as jest.Mock).mockImplementation((opts) => (handler = opts.handler));
versionedRouter.post({ path: '/test/{id}', access: 'internal' }).addVersion(
versionedRouter
.post({
path: '/test/{id}',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion(
{
version: '1',
validate: staticOrLazy === 'static' ? fooValidation : () => fooValidation,
@ -258,7 +366,17 @@ describe('Versioned route', () => {
(router.registerRoute as jest.Mock).mockImplementation((opts) => (handler = opts.handler));
const lazyValidation = jest.fn(() => fooValidation);
versionedRouter.post({ path: '/test/{id}', access: 'internal' }).addVersion(
versionedRouter
.post({
path: '/test/{id}',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion(
{
version: '1',
validate: lazyValidation,
@ -312,7 +430,15 @@ describe('Versioned route', () => {
it('only allows "2023-10-31" as public route versions', () => {
expect(() =>
versionedRouter
.get({ access: 'public', path: '/foo' })
.get({
access: 'public',
path: '/foo',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion({ version: '2023-01-31', validate: false }, (ctx, req, res) => res.ok())
).toThrow(/Invalid public version/);
});
@ -323,7 +449,17 @@ describe('Versioned route', () => {
testValidation;
(router.registerRoute as jest.Mock).mockImplementation((opts) => (handler = opts.handler));
versionedRouter.post({ path: '/test/{id}', access: 'internal' }).addVersion(
versionedRouter
.post({
path: '/test/{id}',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion(
{
version: '1',
validate: fooValidation,
@ -356,7 +492,17 @@ describe('Versioned route', () => {
env: devEnv,
log: loggingSystemMock.createLogger(),
});
versionedRouter.post({ path: '/test/{id}', access: 'internal' }).addVersion(
versionedRouter
.post({
path: '/test/{id}',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion(
{
version: '1',
validate: { response: { 500: { description: 'jest description', body: undefined } } },
@ -389,7 +535,17 @@ describe('Versioned route', () => {
env: devEnv,
log: loggingSystemMock.createLogger(),
});
versionedRouter.post({ path: '/test/{id}', access: 'internal' }).addVersion(
versionedRouter
.post({
path: '/test/{id}',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion(
{
version: '1',
validate: fooValidation,
@ -427,7 +583,17 @@ describe('Versioned route', () => {
(router.registerRoute as jest.Mock).mockImplementation(
(opts) => (bypassVersionHandler = opts.handler)
);
versionedRouter.post({ path: '/bypass_me/{id?}', access: 'internal' }).addVersion(
versionedRouter
.post({
path: '/bypass_me/{id?}',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion(
{
version: '1',
validate: false,
@ -439,7 +605,17 @@ describe('Versioned route', () => {
(router.registerRoute as jest.Mock).mockImplementation(
(opts) => (doNotBypassHandler1 = opts.handler)
);
versionedRouter.put({ path: '/do_not_bypass_me/{id}', access: 'internal' }).addVersion(
versionedRouter
.put({
path: '/do_not_bypass_me/{id}',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion(
{
version: '1',
validate: false,
@ -451,7 +627,17 @@ describe('Versioned route', () => {
(router.registerRoute as jest.Mock).mockImplementation(
(opts) => (doNotBypassHandler2 = opts.handler)
);
versionedRouter.get({ path: '/do_not_bypass_me_either', access: 'internal' }).addVersion(
versionedRouter
.get({
path: '/do_not_bypass_me_either',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion(
{
version: '1',
validate: false,
@ -497,7 +683,15 @@ describe('Versioned route', () => {
},
};
versionedRouter
.get({ path: '/test/{id}', access: 'internal' })
.get({
path: '/test/{id}',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion(
{
version: '1',
@ -705,7 +899,17 @@ describe('Versioned route', () => {
it('for routes with validation', async () => {
const { fooValidation } = testValidation;
(router.registerRoute as jest.Mock).mockImplementation((opts) => (handler = opts.handler));
versionedRouter.post({ path: '/test/{id}', access: 'internal' }).addVersion(
versionedRouter
.post({
path: '/test/{id}',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion(
{
version: '1',
validate: fooValidation,
@ -762,7 +966,17 @@ describe('Versioned route', () => {
it('for routes without validation', async () => {
(router.registerRoute as jest.Mock).mockImplementation((opts) => (handler = opts.handler));
versionedRouter.post({ path: '/test/{id}', access: 'internal' }).addVersion(
versionedRouter
.post({
path: '/test/{id}',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
})
.addVersion(
{
version: '1',
validate: false,

View file

@ -27,9 +27,33 @@ describe('Versioned router', () => {
});
it('can register multiple routes', () => {
versionedRouter.get({ path: '/test/{id}', access: 'internal' });
versionedRouter.post({ path: '/test', access: 'internal' });
versionedRouter.delete({ path: '/test', access: 'internal' });
versionedRouter.get({
path: '/test/{id}',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
access: 'internal',
});
versionedRouter.post({
path: '/test',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
access: 'internal',
});
versionedRouter.delete({
path: '/test',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
access: 'internal',
});
expect(versionedRouter.getRoutes()).toHaveLength(3);
});
@ -42,14 +66,32 @@ describe('Versioned router', () => {
path: '/test/{id}',
access: 'internal',
discontinued: 'x.y.z',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
});
versionedRouter.post({
path: '/test',
access: 'internal',
summary: 'Post test',
description: 'Post test description',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
});
versionedRouter.delete({
path: '/test',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
});
versionedRouter.delete({ path: '/test', access: 'internal' });
expect(versionedRouter.getRoutes()).toMatchInlineSnapshot(`
Array [
Object {
@ -59,6 +101,13 @@ describe('Versioned router', () => {
"options": Object {
"access": "internal",
"discontinued": "x.y.z",
"security": Object {
"authz": Object {
"requiredPrivileges": Array [
"foo",
],
},
},
},
"path": "/test/{id}",
},
@ -69,6 +118,13 @@ describe('Versioned router', () => {
"options": Object {
"access": "internal",
"description": "Post test description",
"security": Object {
"authz": Object {
"requiredPrivileges": Array [
"foo",
],
},
},
"summary": "Post test",
},
"path": "/test",
@ -79,6 +135,13 @@ describe('Versioned router', () => {
"method": "delete",
"options": Object {
"access": "internal",
"security": Object {
"authz": Object {
"requiredPrivileges": Array [
"foo",
],
},
},
},
"path": "/test",
},

View file

@ -13,13 +13,29 @@ describe('createVersionedRouterMock#getRoute', () => {
it('throws if no routes are registered', () => {
const versionedRouter = createVersionedRouterMock();
expect(() => versionedRouter.getRoute('get', '/foo')).toThrow(/No routes registered/);
versionedRouter.get({ path: '/foo', access: 'internal' });
versionedRouter.get({
path: '/foo',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
});
expect(() => versionedRouter.getRoute('get', '/foo')).not.toThrow();
expect(() => versionedRouter.getRoute('get', '/bar')).toThrow(/No routes registered/);
});
it('allows versioned routes to be introspected', () => {
const versionedRouter = createVersionedRouterMock();
const route = versionedRouter.get({ path: '/foo', access: 'internal' });
const route = versionedRouter.get({
path: '/foo',
access: 'internal',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
});
// Empty case
expect(versionedRouter.getRoute('get', '/foo')).toMatchInlineSnapshot(`
@ -27,6 +43,13 @@ describe('createVersionedRouterMock#getRoute', () => {
"config": Object {
"access": "internal",
"path": "/foo",
"security": Object {
"authz": Object {
"requiredPrivileges": Array [
"foo",
],
},
},
},
"versions": Object {},
}
@ -44,6 +67,13 @@ describe('createVersionedRouterMock#getRoute', () => {
"config": Object {
"access": "internal",
"path": "/foo",
"security": Object {
"authz": Object {
"requiredPrivileges": Array [
"foo",
],
},
},
},
"versions": Object {
"1": Object {

View file

@ -211,6 +211,11 @@ test('valid params', async () => {
test: schema.string(),
}),
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({ body: req.params.test });
@ -241,6 +246,11 @@ test('invalid params', async () => {
test: schema.number(),
}),
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({ body: String(req.params.test) });
@ -276,6 +286,11 @@ test('valid query', async () => {
quux: schema.number(),
}),
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({ body: req.query });
@ -306,6 +321,11 @@ test('invalid query', async () => {
bar: schema.number(),
}),
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({ body: req.query });
@ -341,6 +361,11 @@ test('valid body', async () => {
baz: schema.number(),
}),
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({ body: req.body });
@ -379,6 +404,11 @@ test('valid body with validate function', async () => {
}
},
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({ body: req.body });
@ -422,6 +452,11 @@ test('not inline validation - specifying params', async () => {
validate: {
body: bodyValidation,
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({ body: req.body });
@ -465,6 +500,11 @@ test('not inline validation - specifying validation handler', async () => {
validate: {
body: bodyValidation,
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({ body: req.body });
@ -517,6 +557,11 @@ test('not inline handler - KibanaRequest', async () => {
}
},
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
handler
);
@ -566,6 +611,11 @@ test('not inline handler - RequestHandler', async () => {
}
},
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
handler
);
@ -598,6 +648,11 @@ test('invalid body', async () => {
bar: schema.number(),
}),
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({ body: req.body });
@ -633,6 +688,11 @@ test('handles putting', async () => {
key: schema.string(),
}),
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({ body: req.body });
@ -664,6 +724,11 @@ test('handles deleting', async () => {
id: schema.number(),
}),
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({ body: { key: req.params.id } });
@ -695,9 +760,29 @@ describe('with `basepath: /bar` and `rewriteBasePath: false`', () => {
} as HttpConfig;
const router = new Router('/', logger, enhanceWithContext, routerOptions);
router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'value:/' }));
router.get({ path: '/foo', validate: false }, (context, req, res) =>
res.ok({ body: 'value:/foo' })
router.get(
{
path: '/',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: 'value:/' })
);
router.get(
{
path: '/foo',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: 'value:/foo' })
);
const { registerRouter, server: innerServer } = await server.setup({
@ -752,9 +837,29 @@ describe('with `basepath: /bar` and `rewriteBasePath: true`', () => {
} as HttpConfig;
const router = new Router('/', logger, enhanceWithContext, routerOptions);
router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'value:/' }));
router.get({ path: '/foo', validate: false }, (context, req, res) =>
res.ok({ body: 'value:/foo' })
router.get(
{
path: '/',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: 'value:/' })
);
router.get(
{
path: '/foo',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: 'value:/foo' })
);
const { registerRouter, server: innerServer } = await server.setup({
@ -804,7 +909,18 @@ describe('with `basepath: /bar` and `rewriteBasePath: true`', () => {
test('with defined `redirectHttpFromPort`', async () => {
const router = new Router('/', logger, enhanceWithContext, routerOptions);
router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'value:/' }));
router.get(
{
path: '/',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: 'value:/' })
);
const { registerRouter } = await server.setup({ config$: configWithSSL$ });
registerRouter(router);
@ -834,11 +950,30 @@ test('allows attaching metadata to attach meta-data tag strings to a route', asy
const { registerRouter, server: innerServer } = await server.setup({ config$ });
const router = new Router('', logger, enhanceWithContext, routerOptions);
router.get({ path: '/with-tags', validate: false, options: { tags } }, (context, req, res) =>
res.ok({ body: { tags: req.route.options.tags } })
router.get(
{
path: '/with-tags',
validate: false,
options: { tags },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: { tags: req.route.options.tags } })
);
router.get({ path: '/without-tags', validate: false }, (context, req, res) =>
res.ok({ body: { tags: req.route.options.tags } })
router.get(
{
path: '/without-tags',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: { tags: req.route.options.tags } })
);
registerRouter(router);
@ -853,11 +988,30 @@ test('allows declaring route access to flag a route as public or internal', asyn
const { registerRouter, server: innerServer } = await server.setup({ config$ });
const router = new Router('', logger, enhanceWithContext, routerOptions);
router.get({ path: '/with-access', validate: false, options: { access } }, (context, req, res) =>
res.ok({ body: { access: req.route.options.access } })
router.get(
{
path: '/with-access',
validate: false,
options: { access },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: { access: req.route.options.access } })
);
router.get({ path: '/without-access', validate: false }, (context, req, res) =>
res.ok({ body: { access: req.route.options.access } })
router.get(
{
path: '/without-access',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: { access: req.route.options.access } })
);
registerRouter(router);
@ -871,18 +1025,54 @@ test(`sets access flag to 'internal' if not defined`, async () => {
const { registerRouter, server: innerServer } = await server.setup({ config$ });
const router = new Router('', logger, enhanceWithContext, routerOptions);
router.get({ path: '/internal/foo', validate: false }, (context, req, res) =>
res.ok({ body: { access: req.route.options.access } })
router.get(
{
path: '/internal/foo',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: { access: req.route.options.access } })
);
router.get({ path: '/random/foo', validate: false }, (context, req, res) =>
res.ok({ body: { access: req.route.options.access } })
router.get(
{
path: '/random/foo',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: { access: req.route.options.access } })
);
router.get({ path: '/random/internal/foo', validate: false }, (context, req, res) =>
res.ok({ body: { access: req.route.options.access } })
router.get(
{
path: '/random/internal/foo',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: { access: req.route.options.access } })
);
router.get({ path: '/api/foo/internal/my-foo', validate: false }, (context, req, res) =>
res.ok({ body: { access: req.route.options.access } })
router.get(
{
path: '/api/foo/internal/my-foo',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: { access: req.route.options.access } })
);
registerRouter(router);
@ -902,7 +1092,18 @@ test('exposes route details of incoming request to a route handler', async () =>
const { registerRouter, server: innerServer } = await server.setup({ config$ });
const router = new Router('', logger, enhanceWithContext, routerOptions);
router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: req.route }));
router.get(
{
path: '/',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: req.route })
);
registerRouter(router);
await server.start();
@ -918,6 +1119,11 @@ test('exposes route details of incoming request to a route handler', async () =>
access: 'internal',
tags: [],
timeout: {},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
});
});
@ -933,7 +1139,18 @@ describe('conditional compression', () => {
body: 'hello'.repeat(500),
headers: { 'Content-Type': 'text/html; charset=UTF-8' },
};
router.get({ path: '/', validate: false }, (_context, _req, res) => res.ok(largeRequest));
router.get(
{
path: '/',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(_context, _req, res) => res.ok(largeRequest)
);
registerRouter(router);
await server.start();
return innerServer.listener;
@ -1038,7 +1255,18 @@ describe('response headers', () => {
});
const router = new Router('', logger, enhanceWithContext, routerOptions);
router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: req.route }));
router.get(
{
path: '/',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: req.route })
);
registerRouter(router);
await server.start();
@ -1055,7 +1283,18 @@ describe('response headers', () => {
const { registerRouter, server: innerServer } = await server.setup({ config$ });
const router = new Router('', logger, enhanceWithContext, routerOptions);
router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: req.route }));
router.get(
{
path: '/',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: req.route })
);
registerRouter(router);
await server.start();
@ -1082,6 +1321,11 @@ test('exposes route details of incoming request to a route handler (POST + paylo
path: '/',
validate: { body: schema.object({ test: schema.number() }) },
options: { body: { accepts: 'application/json' } },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: req.route })
);
@ -1103,6 +1347,11 @@ test('exposes route details of incoming request to a route handler (POST + paylo
timeout: {
payload: 10000,
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
body: {
parse: true, // hapi populates the default
maxBytes: 1024, // hapi populates the default
@ -1123,6 +1372,11 @@ describe('body options', () => {
path: '/',
validate: { body: schema.object({ test: schema.number() }) },
options: { body: { accepts: 'multipart/form-data' } }, // supertest sends 'application/json'
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: req.route })
);
@ -1145,6 +1399,11 @@ describe('body options', () => {
path: '/',
validate: { body: schema.object({ test: schema.number() }) },
options: { body: { maxBytes: 1 } },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({ body: req.route })
);
@ -1167,6 +1426,11 @@ describe('body options', () => {
path: '/',
validate: { body: schema.buffer() },
options: { body: { parse: false } },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
expect(req.body).toBeInstanceOf(Buffer);
@ -1200,6 +1464,11 @@ describe('timeout options', () => {
payload: 300000,
},
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({
@ -1234,6 +1503,11 @@ describe('timeout options', () => {
payload: 300000,
},
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({
@ -1267,6 +1541,11 @@ describe('timeout options', () => {
payload: 300000,
},
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({
@ -1300,6 +1579,11 @@ describe('timeout options', () => {
payload: 300000,
},
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({
@ -1335,6 +1619,11 @@ describe('timeout options', () => {
{
path: '/',
validate: { body: schema.maybe(schema.any()) },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({
@ -1371,6 +1660,11 @@ describe('timeout options', () => {
path: '/',
validate: { body: schema.maybe(schema.any()) },
options: { timeout: { idleSocket: 12000 } },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({
@ -1407,6 +1701,11 @@ describe('timeout options', () => {
idleSocket: 10,
},
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
return res.ok({ body: { timeout: req.route.options.timeout } });
@ -1429,6 +1728,11 @@ test('should return a stream in the body', async () => {
path: '/',
validate: { body: schema.stream() },
options: { body: { output: 'stream' } },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => {
expect(req.body).toBeInstanceOf(Readable);
@ -1454,11 +1758,33 @@ test('closes sockets on timeout', async () => {
});
const router = new Router('', logger, enhanceWithContext, routerOptions);
router.get({ path: '/a', validate: false }, async (context, req, res) => {
router.get(
{
path: '/a',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
async (context, req, res) => {
await new Promise((resolve) => setTimeout(resolve, 2000));
return res.ok({});
});
router.get({ path: '/b', validate: false }, (context, req, res) => res.ok({}));
}
);
router.get(
{
path: '/b',
validate: false,
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
(context, req, res) => res.ok({})
);
registerRouter(router);

View file

@ -557,7 +557,7 @@ export interface RouteConfig<P, Q, B, Method extends RouteMethod> {
/**
* Defines the security requirements for a route, including authorization and authentication.
*/
security?: RouteSecurity;
security: RouteSecurity;
/**
* Additional route options {@link RouteConfigOptions}.

View file

@ -36,9 +36,18 @@ export function registerEluHistoryRoute(router: IRouter, elu: () => EluMetrics)
enableQueryVersion: true,
path: '/api/_elu_history',
options: {
authRequired: false,
excludeFromRateLimiter: true,
},
security: {
authz: {
enabled: false,
reason: 'This route is used for internal monitoring and does not require authorization.',
},
authc: {
enabled: false,
reason: 'This route is used for internal monitoring and does not require authentication.',
},
},
})
.addVersion(
{

View file

@ -74,11 +74,18 @@ describe('trace', () => {
const { createRouter } = http;
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asInternalUser.ping({}, { meta: true });
return res.ok({ body: headers || {} });
});
}
);
await root.start();
@ -97,11 +104,18 @@ describe('trace', () => {
const { createRouter } = http;
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asCurrentUser.ping({}, { meta: true });
return res.ok({ body: headers || {} });
});
}
);
await root.start();
@ -120,11 +134,18 @@ describe('trace', () => {
const { createRouter } = http;
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asInternalUser.ping({}, { meta: true });
return res.ok({ body: headers || {} });
});
}
);
await root.start();
@ -139,11 +160,18 @@ describe('trace', () => {
const { createRouter } = http;
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asCurrentUser.ping({}, { meta: true });
return res.ok({ body: headers || {} });
});
}
);
await root.start();
@ -158,7 +186,13 @@ describe('trace', () => {
const { createRouter } = http;
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asInternalUser.ping(
{},
@ -168,7 +202,8 @@ describe('trace', () => {
}
);
return res.ok({ body: headers || {} });
});
}
);
await root.start();
@ -206,11 +241,18 @@ describe('trace', () => {
const { createRouter } = http;
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asCurrentUser.ping({}, { meta: true });
return res.ok({ body: headers || {} });
});
}
);
await rootExecutionContextDisabled.start();
@ -229,7 +271,13 @@ describe('trace', () => {
const { createRouter } = http;
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
executionContext.set(parentContext);
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asCurrentUser.ping({}, { meta: true });
@ -239,7 +287,8 @@ describe('trace', () => {
header: headers?.['x-opaque-id'],
},
});
});
}
);
await rootExecutionContextDisabled.start();
@ -262,10 +311,17 @@ describe('trace', () => {
const { createRouter } = http;
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
executionContext.set(parentContext);
return res.ok({ body: executionContext.get() });
});
}
);
await root.start();
const response = await kbnServerRequest.get(root, '/execution-context').expect(200);
@ -277,11 +333,18 @@ describe('trace', () => {
const { createRouter } = http;
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
executionContext.set(parentContext);
await delay(100);
return res.ok({ body: executionContext.get() });
});
}
);
await root.start();
const response = await kbnServerRequest.get(root, '/execution-context').expect(200);
@ -294,11 +357,18 @@ describe('trace', () => {
const router = createRouter<RequestHandlerContext>('');
let id = 42;
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
executionContext.set({ ...parentContext, id: String(id++) });
await delay(100);
return res.ok({ body: executionContext.get() });
});
}
);
await root.start();
const responseA = await kbnServerRequest.get(root, '/execution-context').expect(200);
@ -314,11 +384,18 @@ describe('trace', () => {
const router = createRouter<RequestHandlerContext>('');
let id = 2;
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
executionContext.set({ ...parentContext, id: String(id) });
await delay(id-- * 100);
return res.ok({ body: executionContext.get() });
});
}
);
await root.start();
const responseA = kbnServerRequest.get(root, '/execution-context');
@ -342,13 +419,20 @@ describe('trace', () => {
const router = createRouter<RequestHandlerContext>('');
let id = 2;
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
executionContext.set(parentContext);
await delay(id-- * 100);
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asCurrentUser.ping({}, { meta: true });
return res.ok({ body: headers || {} });
});
}
);
await root.start();
const responseA = kbnServerRequest
@ -376,8 +460,13 @@ describe('trace', () => {
const { createRouter } = http;
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, (context, req, res) =>
res.ok({ body: executionContext.get() })
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
(context, req, res) => res.ok({ body: executionContext.get() })
);
await root.start();
@ -394,11 +483,18 @@ describe('trace', () => {
const { createRouter } = http;
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asCurrentUser.ping({}, { meta: true });
return res.ok({ body: headers || {} });
});
}
);
await root.start();
const response = await kbnServerRequest
@ -428,9 +524,16 @@ describe('trace', () => {
} = http;
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
return res.ok({ body: executionContext.get()?.toJSON() });
});
}
);
let onPreRoutingContext;
registerOnPreRouting((request, response, t) => {
@ -482,11 +585,18 @@ describe('trace', () => {
const { createRouter } = http;
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asCurrentUser.ping({}, { meta: true });
return res.ok({ body: headers || {} });
});
}
);
await root.start();
@ -504,11 +614,18 @@ describe('trace', () => {
const { createRouter } = http;
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asInternalUser.ping({}, { meta: true });
return res.ok({ body: headers || {} });
});
}
);
await root.start();
@ -526,11 +643,18 @@ describe('trace', () => {
const { createRouter } = http;
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asCurrentUser.ping({}, { meta: true });
return res.ok({ body: headers || {} });
});
}
);
await root.start();
@ -549,12 +673,19 @@ describe('trace', () => {
const { createRouter } = http;
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
executionContext.set(parentContext);
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asCurrentUser.ping({}, { meta: true });
return res.ok({ body: headers || {} });
});
}
);
await root.start();
@ -579,12 +710,19 @@ describe('trace', () => {
id: '42',
description: 'какое-то описание',
};
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
executionContext.set(ctx);
const esClient = (await context.core).elasticsearch.client;
const { headers } = await esClient.asCurrentUser.ping({}, { meta: true });
return res.ok({ body: headers || {} });
});
}
);
await root.start();
@ -600,11 +738,18 @@ describe('trace', () => {
const { createRouter } = http;
const router = createRouter<RequestHandlerContext>('');
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
return executionContext.withContext(parentContext, () =>
res.ok({ body: executionContext.get() })
);
});
}
);
await root.start();
const response = await kbnServerRequest.get(root, '/execution-context').expect(200);
@ -622,7 +767,13 @@ describe('trace', () => {
id: '43',
description: 'nested-description',
};
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
return executionContext.withContext(parentContext, async () => {
await delay(100);
return executionContext.withContext(nestedContext, async () => {
@ -630,7 +781,8 @@ describe('trace', () => {
return res.ok({ body: executionContext.get() });
});
});
});
}
);
await root.start();
const response = await kbnServerRequest.get(root, '/execution-context').expect(200);
@ -648,13 +800,20 @@ describe('trace', () => {
id: '41',
description: 'new-description',
};
router.get({ path: '/execution-context', validate: false }, async (context, req, res) => {
router.get(
{
path: '/execution-context',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
const esClient = (await context.core).elasticsearch.client;
const { headers } = await executionContext.withContext(newContext, () => {
return esClient.asCurrentUser.ping({}, { meta: true });
});
return res.ok({ body: headers || {} });
});
}
);
await root.start();

View file

@ -121,11 +121,14 @@ describe('Cookie based SessionStorage', () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('');
router.get({ path, validate: false }, (context, req, res) => {
router.get(
{ path, validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => {
const sessionStorage = factory.asScoped(req);
sessionStorage.set(sessVal());
return res.ok({});
});
}
);
const factory = await createCookieSessionStorageFactory(
logger.get(),
@ -156,7 +159,9 @@ describe('Cookie based SessionStorage', () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('');
router.get({ path: '/', validate: false }, async (context, req, res) => {
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
async (context, req, res) => {
const sessionStorage = factory.asScoped(req);
const sessionValue = await sessionStorage.get();
if (!sessionValue) {
@ -164,7 +169,8 @@ describe('Cookie based SessionStorage', () => {
return res.ok();
}
return res.ok({ body: { value: sessionValue.value } });
});
}
);
const factory = await createCookieSessionStorageFactory(
logger.get(),
@ -193,11 +199,14 @@ describe('Cookie based SessionStorage', () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('');
router.get({ path: '/', validate: false }, async (context, req, res) => {
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
async (context, req, res) => {
const sessionStorage = factory.asScoped(req);
const sessionValue = await sessionStorage.get();
return res.ok({ body: { value: sessionValue } });
});
}
);
const factory = await createCookieSessionStorageFactory(
logger.get(),
@ -220,7 +229,9 @@ describe('Cookie based SessionStorage', () => {
const router = createRouter('');
let setOnce = false;
router.get({ path: '/', validate: false }, async (context, req, res) => {
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
async (context, req, res) => {
const sessionStorage = factory.asScoped(req);
if (!setOnce) {
setOnce = true;
@ -229,7 +240,8 @@ describe('Cookie based SessionStorage', () => {
}
const sessionValue = await sessionStorage.get();
return res.ok({ body: { value: sessionValue } });
});
}
);
const factory = await createCookieSessionStorageFactory(
logger.get(),
@ -267,7 +279,9 @@ describe('Cookie based SessionStorage', () => {
const router = createRouter('');
let setOnce = false;
router.get({ path: '/', validate: false }, async (context, req, res) => {
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
async (context, req, res) => {
const sessionStorage = factory.asScoped(req);
if (!setOnce) {
setOnce = true;
@ -276,7 +290,8 @@ describe('Cookie based SessionStorage', () => {
}
const sessionValue = await sessionStorage.get();
return res.ok({ body: { value: sessionValue } });
});
}
);
const factory = await createCookieSessionStorageFactory(
logger.get(),
@ -409,7 +424,9 @@ describe('Cookie based SessionStorage', () => {
const router = createRouter('');
router.get({ path: '/', validate: false }, async (context, req, res) => {
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
async (context, req, res) => {
const sessionStorage = factory.asScoped(req);
if (await sessionStorage.get()) {
sessionStorage.clear();
@ -417,7 +434,8 @@ describe('Cookie based SessionStorage', () => {
}
sessionStorage.set(sessVal());
return res.ok({});
});
}
);
const factory = await createCookieSessionStorageFactory(
logger.get(),
@ -471,7 +489,9 @@ describe('Cookie based SessionStorage', () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('');
router.get({ path: '/', validate: false }, async (context, req, res) => {
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
async (context, req, res) => {
const sessionStorage = factory.asScoped(req);
const sessionValue = await sessionStorage.get();
if (!sessionValue) {
@ -479,7 +499,8 @@ describe('Cookie based SessionStorage', () => {
return res.ok();
}
return res.ok({ body: { value: sessionValue.value } });
});
}
);
const factory = await createCookieSessionStorageFactory(
logger.get(),

View file

@ -54,8 +54,13 @@ describe('http service', () => {
registerAuth((req, res, toolkit) => toolkit.authenticated());
const router = createRouter('');
router.get({ path: '/is-auth', validate: false }, (context, req, res) =>
res.ok({ body: { isAuthenticated: auth.isAuthenticated(req) } })
router.get(
{
path: '/is-auth',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
(context, req, res) => res.ok({ body: { isAuthenticated: auth.isAuthenticated(req) } })
);
await root.start();
@ -70,7 +75,12 @@ describe('http service', () => {
const router = createRouter('');
router.get(
{ path: '/is-auth', validate: false, options: { authRequired: false } },
{
path: '/is-auth',
validate: false,
security: { authz: { enabled: false, reason: '' } },
options: { authRequired: false },
},
(context, req, res) => res.ok({ body: { isAuthenticated: auth.isAuthenticated(req) } })
);
@ -84,7 +94,12 @@ describe('http service', () => {
const router = createRouter('');
router.get(
{ path: '/is-auth', validate: false, options: { authRequired: false } },
{
path: '/is-auth',
validate: false,
security: { authz: { enabled: false, reason: '' } },
options: { authRequired: false },
},
(context, req, res) => res.ok({ body: { isAuthenticated: auth.isAuthenticated(req) } })
);
@ -99,7 +114,12 @@ describe('http service', () => {
registerAuth((req, res, toolkit) => toolkit.authenticated());
const router = createRouter('');
router.get(
{ path: '/is-auth', validate: false, options: { authRequired: 'optional' } },
{
path: '/is-auth',
validate: false,
security: { authz: { enabled: false, reason: '' } },
options: { authRequired: 'optional' },
},
(context, req, res) => res.ok({ body: { isAuthenticated: auth.isAuthenticated(req) } })
);
@ -115,7 +135,12 @@ describe('http service', () => {
const router = createRouter('');
router.get(
{ path: '/is-auth', validate: false, options: { authRequired: 'optional' } },
{
path: '/is-auth',
validate: false,
security: { authz: { enabled: false, reason: '' } },
options: { authRequired: 'optional' },
},
(context, req, res) => res.ok({ body: { isAuthenticated: auth.isAuthenticated(req) } })
);
@ -136,8 +161,13 @@ describe('http service', () => {
});
const router = createRouter('');
router.get({ path: '/get-auth', validate: false }, (context, req, res) =>
res.ok({ body: auth.get<{ id: string }>(req) })
router.get(
{
path: '/get-auth',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
(context, req, res) => res.ok({ body: auth.get<{ id: string }>(req) })
);
await root.start();
@ -150,8 +180,13 @@ describe('http service', () => {
const { createRouter, auth } = http;
const router = createRouter('');
router.get({ path: '/get-auth', validate: false }, (context, req, res) =>
res.ok({ body: auth.get(req) })
router.get(
{
path: '/get-auth',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
(context, req, res) => res.ok({ body: auth.get(req) })
);
await root.start();
@ -166,7 +201,12 @@ describe('http service', () => {
registerAuth(authenticate);
const router = createRouter('');
router.get(
{ path: '/get-auth', validate: false, options: { authRequired: false } },
{
path: '/get-auth',
validate: false,
security: { authz: { enabled: false, reason: '' } },
options: { authRequired: false },
},
(context, req, res) => res.ok({ body: auth.get(req) })
);
@ -221,10 +261,13 @@ describe('http service', () => {
);
const router = createRouter('/new-platform');
router.get({ path: '/', validate: false }, async (context, req, res) => {
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
async (context, req, res) => {
await elasticsearch.client.asScoped(req).asInternalUser.ping();
return res.ok();
});
}
);
const coreStart = await root.start();
elasticsearch = coreStart.elasticsearch;
@ -257,10 +300,13 @@ describe('http service', () => {
);
const router = createRouter('/new-platform');
router.get({ path: '/', validate: false }, async (context, req, res) => {
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
async (context, req, res) => {
await elasticsearch.client.asScoped(req).asInternalUser.ping();
return res.ok();
});
}
);
const coreStart = await root.start();
elasticsearch = coreStart.elasticsearch;
@ -294,7 +340,9 @@ describe('http service', () => {
);
const router = createRouter('/new-platform');
router.get({ path: '/', validate: false }, async (context, req, res) => {
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
async (context, req, res) => {
try {
const result = await elasticsearch.client
.asScoped(req)
@ -307,7 +355,8 @@ describe('http service', () => {
body: e,
});
}
});
}
);
const coreStart = await root.start();
elasticsearch = coreStart.elasticsearch;

View file

@ -85,26 +85,38 @@ describe('Http2 - Smoke tests', () => {
},
});
router.post({ path: '/', validate: false }, async (context, req, res) => {
router.post(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
async (context, req, res) => {
return res.ok({
body: { protocol: req.protocol, httpVersion: req.httpVersion },
});
});
router.get({ path: '/', validate: false }, async (context, req, res) => {
}
);
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
async (context, req, res) => {
return res.ok({
body: { protocol: req.protocol, httpVersion: req.httpVersion },
});
});
router.put({ path: '/', validate: false }, async (context, req, res) => {
}
);
router.put(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
async (context, req, res) => {
return res.ok({
body: { protocol: req.protocol, httpVersion: req.httpVersion },
});
});
router.delete({ path: '/', validate: false }, async (context, req, res) => {
}
);
router.delete(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
async (context, req, res) => {
return res.ok({
body: { protocol: req.protocol, httpVersion: req.httpVersion },
});
});
}
);
registerRouter(router);
@ -188,14 +200,21 @@ describe('Http2 - Smoke tests', () => {
},
});
router.get({ path: '/illegal_headers', validate: false }, async (context, req, res) => {
router.get(
{
path: '/illegal_headers',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (context, req, res) => {
return res.ok({
headers: {
connection: 'close',
},
body: { protocol: req.protocol },
});
});
}
);
registerRouter(router);

View file

@ -34,6 +34,7 @@ describe('http auth', () => {
router.get(
{
path: '/route',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: {
authRequired,

View file

@ -73,6 +73,7 @@ describe('Http server', () => {
router.post(
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { body: { accepts: 'application/json' } },
},

View file

@ -62,7 +62,10 @@ describe('OnPreRouting', () => {
} = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'ok' }));
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok({ body: 'ok' })
);
const callingOrder: string[] = [];
registerOnPreRouting((req, res, t) => {
@ -89,11 +92,17 @@ describe('OnPreRouting', () => {
} = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/initial', validate: false }, (context, req, res) =>
res.ok({ body: 'initial' })
router.get(
{ path: '/initial', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok({ body: 'initial' })
);
router.get({ path: '/redirectUrl', validate: false }, (context, req, res) =>
res.ok({ body: 'redirected' })
router.get(
{
path: '/redirectUrl',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
(context, req, res) => res.ok({ body: 'redirected' })
);
let urlBeforeForwarding;
@ -125,7 +134,9 @@ describe('OnPreRouting', () => {
} = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/login', validate: false }, (context, req, res) => {
router.get(
{ path: '/login', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => {
return res.ok({
body: {
rewrittenUrl: req.rewrittenUrl
@ -133,7 +144,8 @@ describe('OnPreRouting', () => {
: undefined,
},
});
});
}
);
registerOnPreRouting((req, res, t) => t.rewriteUrl('/login'));
@ -152,7 +164,9 @@ describe('OnPreRouting', () => {
} = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/reroute-2', validate: false }, (context, req, res) => {
router.get(
{ path: '/reroute-2', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => {
return res.ok({
body: {
rewrittenUrl: req.rewrittenUrl
@ -160,7 +174,8 @@ describe('OnPreRouting', () => {
: undefined,
},
});
});
}
);
registerOnPreRouting((req, res, t) => t.rewriteUrl('/reroute-1'));
registerOnPreRouting((req, res, t) => t.rewriteUrl('/reroute-2'));
@ -180,7 +195,9 @@ describe('OnPreRouting', () => {
} = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/login', validate: false }, (context, req, res) => {
router.get(
{ path: '/login', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => {
return res.ok({
body: {
rewrittenUrl: req.rewrittenUrl
@ -188,7 +205,8 @@ describe('OnPreRouting', () => {
: undefined,
},
});
});
}
);
registerOnPreRouting((req, res, t) => t.next());
@ -206,7 +224,10 @@ describe('OnPreRouting', () => {
const router = createRouter('/');
const redirectUrl = '/redirectUrl';
router.get({ path: '/initial', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/initial', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
registerOnPreRouting((req, res, t) =>
res.redirected({
@ -230,7 +251,10 @@ describe('OnPreRouting', () => {
} = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
registerOnPreRouting((req, res, t) =>
res.unauthorized({
@ -254,7 +278,10 @@ describe('OnPreRouting', () => {
} = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
registerOnPreRouting((req, res, t) => {
throw new Error('reason');
@ -283,7 +310,10 @@ describe('OnPreRouting', () => {
} = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
registerOnPreRouting((req, res, t) => ({} as any));
await server.start();
@ -322,7 +352,9 @@ describe('OnPreRouting', () => {
}
return t.next();
});
router.get({ path: '/', validate: false }, (context, req, res) =>
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) =>
// don't complain customField is not defined on Request type
res.ok({ body: { customField: String((req as any).customField) } })
);
@ -338,7 +370,10 @@ describe('OnPreAuth', () => {
const { registerOnPreAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'ok' }));
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok({ body: 'ok' })
);
const callingOrder: string[] = [];
registerOnPreAuth((req, res, t) => {
@ -362,7 +397,10 @@ describe('OnPreAuth', () => {
const router = createRouter('/');
const redirectUrl = '/redirectUrl';
router.get({ path: '/initial', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/initial', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
registerOnPreAuth((req, res, t) =>
res.redirected({
@ -382,7 +420,10 @@ describe('OnPreAuth', () => {
const { registerOnPreAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
registerOnPreAuth((req, res, t) =>
res.unauthorized({
@ -402,7 +443,10 @@ describe('OnPreAuth', () => {
const { registerOnPreAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
registerOnPreAuth((req, res, t) => {
throw new Error('reason');
@ -427,7 +471,10 @@ describe('OnPreAuth', () => {
const { registerOnPreAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
registerOnPreAuth((req, res, t) => ({} as any));
await server.start();
@ -462,7 +509,9 @@ describe('OnPreAuth', () => {
}
return t.next();
});
router.get({ path: '/', validate: false }, (context, req, res) =>
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) =>
// @ts-expect-error customField property is not defined on request object
res.ok({ body: { customField: String(req.customField) } })
);
@ -484,6 +533,7 @@ describe('OnPreAuth', () => {
router.post(
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: {
body: schema.object({
term: schema.string(),
@ -511,7 +561,10 @@ describe('OnPostAuth', () => {
const { registerOnPostAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'ok' }));
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok({ body: 'ok' })
);
const callingOrder: string[] = [];
registerOnPostAuth((req, res, t) => {
@ -535,7 +588,10 @@ describe('OnPostAuth', () => {
const router = createRouter('/');
const redirectUrl = '/redirectUrl';
router.get({ path: '/initial', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/initial', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
registerOnPostAuth((req, res, t) =>
res.redirected({
@ -555,7 +611,10 @@ describe('OnPostAuth', () => {
const { registerOnPostAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok(undefined));
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok(undefined)
);
registerOnPostAuth((req, res, t) =>
res.unauthorized({
headers: {
@ -574,7 +633,10 @@ describe('OnPostAuth', () => {
const { registerOnPostAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok(undefined));
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok(undefined)
);
registerOnPostAuth((req, res, t) => {
throw new Error('reason');
});
@ -598,7 +660,10 @@ describe('OnPostAuth', () => {
const { registerOnPostAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
registerOnPostAuth((req, res, t) => ({} as any));
await server.start();
@ -633,7 +698,9 @@ describe('OnPostAuth', () => {
return t.next();
});
router.get({ path: '/', validate: false }, (context, req, res) =>
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) =>
// don't complain customField is not defined on Request type
res.ok({ body: { customField: String((req as any).customField) } })
);
@ -655,6 +722,7 @@ describe('OnPostAuth', () => {
router.post(
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: {
body: schema.object({
term: schema.string(),
@ -697,8 +765,9 @@ describe('Auth', () => {
const { registerAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) =>
res.ok({ body: { content: 'ok' } })
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok({ body: { content: 'ok' } })
);
registerAuth((req, res, t) => t.authenticated());
await server.start();
@ -710,8 +779,9 @@ describe('Auth', () => {
const { registerAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) =>
res.ok({ body: { content: 'ok' } })
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok({ body: { content: 'ok' } })
);
registerAuth((req, res, t) => t.notHandled());
await server.start();
@ -725,8 +795,9 @@ describe('Auth', () => {
const { registerAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) =>
res.ok({ body: { authRequired: req.route.options.authRequired } })
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok({ body: { authRequired: req.route.options.authRequired } })
);
const authenticate = jest.fn().mockImplementation((req, res, t) => t.authenticated());
registerAuth(authenticate);
@ -742,7 +813,12 @@ describe('Auth', () => {
const router = createRouter('/');
router.get(
{ path: '/', validate: false, options: { authRequired: false } },
{
path: '/',
validate: false,
security: { authz: { enabled: false, reason: '' } },
options: { authRequired: false },
},
(context, req, res) => res.ok({ body: { authRequired: req.route.options.authRequired } })
);
@ -760,7 +836,12 @@ describe('Auth', () => {
const router = createRouter('/');
router.get(
{ path: '/', validate: false, options: { authRequired: true } },
{
path: '/',
validate: false,
security: { authz: { enabled: false, reason: '' } },
options: { authRequired: true },
},
(context, req, res) => res.ok({ body: { authRequired: req.route.options.authRequired } })
);
@ -777,7 +858,10 @@ describe('Auth', () => {
const { registerAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
registerAuth((req, res) => res.unauthorized());
await server.start();
@ -788,7 +872,10 @@ describe('Auth', () => {
const { registerAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
const redirectTo = '/redirect-url';
registerAuth((req, res, t) =>
t.redirected({
@ -805,7 +892,10 @@ describe('Auth', () => {
const { registerAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
registerAuth((req, res, t) => t.redirected({} as any));
await server.start();
@ -816,7 +906,10 @@ describe('Auth', () => {
const { registerAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
registerAuth((req, t) => {
throw new Error('reason');
});
@ -845,7 +938,10 @@ describe('Auth', () => {
} = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
const sessionStorageFactory = await createCookieSessionStorageFactory<StorageData>(
cookieOptions
@ -895,12 +991,22 @@ describe('Auth', () => {
return toolkit.authenticated();
});
router.get({ path: '/', validate: false }, (context, req, res) => res.ok());
router.get({ path: '/with-cookie', validate: false }, (context, req, res) => {
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
router.get(
{
path: '/with-cookie',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
(context, req, res) => {
const sessionStorage = sessionStorageFactory.asScoped(req);
sessionStorage.clear();
return res.ok();
});
}
);
await server.start();
const responseToSetCookie = await supertest(innerServer.listener).get('/').expect(200);
@ -946,10 +1052,13 @@ describe('Auth', () => {
let fromRouteHandler;
router.get({ path: '/', validate: false }, (context, req, res) => {
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => {
fromRouteHandler = req.headers.authorization;
return res.ok();
});
}
);
await server.start();
const token = 'Basic: user:password';
@ -972,7 +1081,10 @@ describe('Auth', () => {
return toolkit.authenticated({ responseHeaders: authResponseHeader });
});
router.get({ path: '/', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
await server.start();
const response = await supertest(innerServer.listener).get('/').expect(200);
@ -991,7 +1103,10 @@ describe('Auth', () => {
return toolkit.authenticated({ responseHeaders: authResponseHeader });
});
router.get({ path: '/', validate: false }, (context, req, res) => res.badRequest());
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.badRequest()
);
await server.start();
const response = await supertest(innerServer.listener).get('/').expect(400);
@ -1011,7 +1126,9 @@ describe('Auth', () => {
return toolkit.authenticated({ responseHeaders: authResponseHeader });
});
router.get({ path: '/', validate: false }, (context, req, res) =>
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) =>
res.ok({
headers: {
'www-authenticate': 'from handler',
@ -1043,7 +1160,9 @@ describe('Auth', () => {
return toolkit.authenticated({ responseHeaders: authResponseHeader });
});
router.get({ path: '/', validate: false }, (context, req, res) =>
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) =>
res.badRequest({
headers: {
'www-authenticate': 'from handler',
@ -1072,7 +1191,10 @@ describe('Auth', () => {
const router = createRouter('/');
const redirectUrl = '/redirectUrl';
router.get({ path: '/initial', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/initial', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
registerOnPostAuth((req, res, t) =>
res.redirected({
headers: {
@ -1091,7 +1213,10 @@ describe('Auth', () => {
const { registerOnPostAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok(undefined));
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok(undefined)
);
registerOnPostAuth((req, res, t) =>
res.unauthorized({
@ -1111,7 +1236,10 @@ describe('Auth', () => {
const { registerOnPostAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok(undefined));
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok(undefined)
);
registerOnPostAuth((req, res, t) => {
throw new Error('reason');
});
@ -1135,7 +1263,10 @@ describe('Auth', () => {
const { registerOnPostAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
registerOnPostAuth((req, res, t) => ({} as any));
await server.start();
@ -1169,7 +1300,9 @@ describe('Auth', () => {
}
return t.next();
});
router.get({ path: '/', validate: false }, (context, req, res) =>
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) =>
// don't complain customField is not defined on Request type
res.ok({ body: { customField: String((req as any).customField) } })
);
@ -1191,6 +1324,7 @@ describe('Auth', () => {
router.post(
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: {
body: schema.object({
term: schema.string(),
@ -1222,7 +1356,10 @@ describe('OnPreResponse', () => {
} = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'ok' }));
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok({ body: 'ok' })
);
const callingOrder: string[] = [];
registerOnPreResponse((req, res, t) => {
@ -1249,7 +1386,9 @@ describe('OnPreResponse', () => {
} = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) =>
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) =>
res.ok({
headers: {
'x-my-header': 'foo',
@ -1280,7 +1419,9 @@ describe('OnPreResponse', () => {
} = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) =>
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) =>
res.ok({
headers: { 'x-kibana-header': 'value' },
})
@ -1309,7 +1450,10 @@ describe('OnPreResponse', () => {
} = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok(undefined));
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok(undefined)
);
registerOnPreResponse((req, res, t) => {
throw new Error('reason');
});
@ -1337,7 +1481,10 @@ describe('OnPreResponse', () => {
} = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => res.ok());
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok()
);
registerOnPreResponse((req, res, t) => ({} as any));
await server.start();
@ -1368,7 +1515,10 @@ describe('OnPreResponse', () => {
return t.next();
});
router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'ok' }));
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok({ body: 'ok' })
);
await server.start();
@ -1391,6 +1541,7 @@ describe('OnPreResponse', () => {
router.post(
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: {
body: schema.object({
term: schema.string(),
@ -1420,14 +1571,17 @@ describe('OnPreResponse', () => {
} = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => {
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => {
return res.ok({
headers: {
'Original-Header-A': 'A',
},
body: 'original',
});
});
}
);
registerOnPreResponse((req, res, t) => {
return t.render({ body: 'overridden' });
@ -1448,7 +1602,9 @@ describe('OnPreResponse', () => {
} = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => {
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => {
return res.ok({
headers: {
'Original-Header-A': 'A',
@ -1456,7 +1612,8 @@ describe('OnPreResponse', () => {
},
body: 'original',
});
});
}
);
registerOnPreResponse((req, res, t) => {
return t.render({
@ -1483,7 +1640,9 @@ describe('runs with default preResponse handlers', () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) =>
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) =>
res.ok({
headers: {
foo: 'bar',
@ -1520,6 +1679,7 @@ describe('runs with default preResponse deprecation handlers', () => {
{
path: '/deprecated',
validate: false,
security: { authz: { enabled: false, reason: '' } },
options: {
deprecated: {
documentationUrl: 'https://fake-url.com',
@ -1547,6 +1707,7 @@ describe('runs with default preResponse deprecation handlers', () => {
{
path: '/test',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
(context, req, res) => res.ok({})
);
@ -1567,6 +1728,7 @@ describe('runs with default preResponse deprecation handlers', () => {
{
path: '/deprecated',
validate: false,
security: { authz: { enabled: false, reason: '' } },
options: {
deprecated: {
documentationUrl: 'https://fake-url.com',
@ -1593,11 +1755,13 @@ describe('runs with default preResponse deprecation handlers', () => {
.get({
access: 'internal',
path: '/test',
security: { authz: { enabled: false, reason: '' } },
})
.addVersion(
{
version: '1',
validate: false,
security: { authz: { enabled: false, reason: '' } },
options: {
deprecated: {
documentationUrl: 'https://fake-url.com',
@ -1615,6 +1779,7 @@ describe('runs with default preResponse deprecation handlers', () => {
{
version: '2',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (ctx, req, res) => {
return res.ok({ body: { v: '2' } });
@ -1649,11 +1814,13 @@ describe('runs with default preResponse deprecation handlers', () => {
.get({
access: 'internal',
path: '/test',
security: { authz: { enabled: false, reason: '' } },
})
.addVersion(
{
version: '1',
validate: false,
security: { authz: { enabled: false, reason: '' } },
options: {
deprecated: {
documentationUrl: 'https://fake-url.com',
@ -1671,6 +1838,7 @@ describe('runs with default preResponse deprecation handlers', () => {
{
version: '2',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (ctx, req, res) => {
return res.ok({ body: { v: '2' } });
@ -1733,7 +1901,10 @@ describe('run interceptors in the right order', () => {
return t.next();
});
router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'ok' }));
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok({ body: 'ok' })
);
await server.start();
@ -1777,7 +1948,10 @@ describe('run interceptors in the right order', () => {
return t.next();
});
router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'ok' }));
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok({ body: 'ok' })
);
await server.start();
@ -1820,7 +1994,10 @@ describe('run interceptors in the right order', () => {
return t.next();
});
router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'ok' }));
router.get(
{ path: '/', validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => res.ok({ body: 'ok' })
);
await server.start();

View file

@ -78,9 +78,12 @@ describe('core lifecycle handlers', () => {
const testRoute = '/version_check/test/route';
beforeEach(async () => {
router.get({ path: testRoute, validate: false }, (context, req, res) => {
router.get(
{ path: testRoute, validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => {
return res.ok({ body: 'ok' });
});
}
);
await server.start();
});
@ -123,12 +126,22 @@ describe('core lifecycle handlers', () => {
};
beforeEach(async () => {
router.get({ path: testRoute, validate: false }, (context, req, res) => {
router.get(
{ path: testRoute, validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => {
return res.ok({ body: 'ok' });
});
router.get({ path: testErrorRoute, validate: false }, (context, req, res) => {
}
);
router.get(
{
path: testErrorRoute,
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
(context, req, res) => {
return res.badRequest({ body: 'bad request' });
});
}
);
await server.start();
});
@ -155,25 +168,37 @@ describe('core lifecycle handlers', () => {
};
beforeEach(async () => {
router.get({ path: testPath, validate: false }, (context, req, res) => {
router.get(
{ path: testPath, validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => {
return res.ok({ body: 'ok' });
});
}
);
destructiveMethods.forEach((method) => {
((router as any)[method.toLowerCase()] as RouteRegistrar<any, any>)<any, any, any>(
{ path: testPath, validate: false },
{ path: testPath, validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => {
return res.ok({ body: 'ok' });
}
);
((router as any)[method.toLowerCase()] as RouteRegistrar<any, any>)<any, any, any>(
{ path: allowlistedTestPath, validate: false },
{
path: allowlistedTestPath,
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
(context, req, res) => {
return res.ok({ body: 'ok' });
}
);
((router as any)[method.toLowerCase()] as RouteRegistrar<any, any>)<any, any, any>(
{ path: xsrfDisabledTestPath, validate: false, options: { xsrfRequired: false } },
{
path: xsrfDisabledTestPath,
validate: false,
security: { authz: { enabled: false, reason: '' } },
options: { xsrfRequired: false },
},
(context, req, res) => {
return res.ok({ body: 'ok' });
}
@ -253,6 +278,7 @@ describe('core lifecycle handlers', () => {
router.get(
{
path: testInternalRoute,
security: { authz: { enabled: false, reason: '' } },
validate: { query: schema.object({ myValue: schema.string() }) },
options: { access: 'internal' },
},
@ -263,6 +289,7 @@ describe('core lifecycle handlers', () => {
router.get(
{
path: testPublicRoute,
security: { authz: { enabled: false, reason: '' } },
validate: { query: schema.object({ myValue: schema.string() }) },
options: { access: 'public' },
},
@ -338,13 +365,23 @@ describe('core lifecycle handlers with restrict internal routes enforced', () =>
const testPublicRoute = '/restrict_internal_routes/test/route_public';
beforeEach(async () => {
router.get(
{ path: testInternalRoute, validate: false, options: { access: 'internal' } },
{
path: testInternalRoute,
validate: false,
security: { authz: { enabled: false, reason: '' } },
options: { access: 'internal' },
},
(context, req, res) => {
return res.ok({ body: 'ok()' });
}
);
router.get(
{ path: testPublicRoute, validate: false, options: { access: 'public' } },
{
path: testPublicRoute,
validate: false,
security: { authz: { enabled: false, reason: '' } },
options: { access: 'public' },
},
(context, req, res) => {
return res.ok({ body: 'ok()' });
}
@ -394,12 +431,18 @@ describe('core lifecycle handlers with no strict client version check', () => {
await server.preboot({ context: contextServiceMock.createPrebootContract() });
const serverSetup = await server.setup(setupDeps);
router = serverSetup.createRouter('/');
router.get({ path: testRouteGood, validate: false }, (context, req, res) => {
router.get(
{ path: testRouteGood, validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => {
return res.ok({ body: 'ok' });
});
router.get({ path: testRouteBad, validate: false }, (context, req, res) => {
}
);
router.get(
{ path: testRouteBad, validate: false, security: { authz: { enabled: false, reason: '' } } },
(context, req, res) => {
return res.custom({ body: 'nok', statusCode: 500 });
});
}
);
innerServer = serverSetup.server;
await server.start();
});

View file

@ -54,10 +54,13 @@ describe('request logging', () => {
await root.preboot();
const { http } = await root.setup();
http
.createRouter('/')
.get(
{ path: '/ping', validate: false, options: { authRequired: 'optional' } },
http.createRouter('/').get(
{
path: '/ping',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: 'optional' },
},
(context, req, res) => res.ok({ body: 'pong' })
);
await root.start();
@ -95,10 +98,13 @@ describe('request logging', () => {
await root.preboot();
const { http } = await root.setup();
http
.createRouter('/')
.get(
{ path: '/ping', validate: false, options: { authRequired: 'optional' } },
http.createRouter('/').get(
{
path: '/ping',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: 'optional' },
},
(context, req, res) => res.ok({ body: 'pong' })
);
await root.start();
@ -151,10 +157,13 @@ describe('request logging', () => {
await root.preboot();
const { http } = await root.setup();
http
.createRouter('/')
.get(
{ path: '/ping', validate: false, options: { authRequired: 'optional' } },
http.createRouter('/').get(
{
path: '/ping',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: 'optional' },
},
(context, req, res) => res.ok({ body: 'pong' })
);
await root.start();
@ -177,6 +186,7 @@ describe('request logging', () => {
http.createRouter('/').post(
{
path: '/ping',
security: { authz: { enabled: false, reason: '' } },
validate: {
body: schema.object({ message: schema.string() }),
},
@ -206,10 +216,13 @@ describe('request logging', () => {
await root.preboot();
const { http } = await root.setup();
http
.createRouter('/')
.get(
{ path: '/a', validate: false, options: { authRequired: 'optional' } },
http.createRouter('/').get(
{
path: '/a',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: 'optional' },
},
(context, req, res) => res.ok({ body: 'pong' })
);
await root.start();
@ -227,10 +240,13 @@ describe('request logging', () => {
await root.preboot();
const { http } = await root.setup();
http
.createRouter('/')
.get(
{ path: '/ping', validate: false, options: { authRequired: 'optional' } },
http.createRouter('/').get(
{
path: '/ping',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: 'optional' },
},
(context, req, res) => res.ok({ body: 'pong' })
);
await root.start();
@ -246,10 +262,13 @@ describe('request logging', () => {
await root.preboot();
const { http } = await root.setup();
http
.createRouter('/')
.get(
{ path: '/ping', validate: false, options: { authRequired: 'optional' } },
http.createRouter('/').get(
{
path: '/ping',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: 'optional' },
},
(context, req, res) => res.ok({ body: 'pong' })
);
await root.start();
@ -265,10 +284,13 @@ describe('request logging', () => {
await root.preboot();
const { http } = await root.setup();
http
.createRouter('/')
.get(
{ path: '/ping', validate: false, options: { authRequired: 'optional' } },
http.createRouter('/').get(
{
path: '/ping',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: 'optional' },
},
(context, req, res) => res.ok({ headers: { bar: 'world' }, body: 'pong' })
);
await root.start();
@ -287,6 +309,7 @@ describe('request logging', () => {
http.createRouter('/').post(
{
path: '/ping',
security: { authz: { enabled: false, reason: '' } },
validate: {
body: schema.object({ message: schema.string() }),
},
@ -356,6 +379,7 @@ describe('request logging', () => {
http.createRouter('/').post(
{
path: '/ping',
security: { authz: { enabled: false, reason: '' } },
validate: {
body: schema.object({ message: schema.string() }),
},
@ -389,6 +413,7 @@ describe('request logging', () => {
http.createRouter('/').post(
{
path: '/ping',
security: { authz: { enabled: false, reason: '' } },
validate: {
body: schema.object({ message: schema.string() }),
},
@ -456,6 +481,7 @@ describe('request logging', () => {
http.createRouter('/').post(
{
path: '/ping',
security: { authz: { enabled: false, reason: '' } },
validate: {
body: schema.object({ message: schema.string() }),
},
@ -487,10 +513,13 @@ describe('request logging', () => {
await root.preboot();
const { http } = await root.setup();
http
.createRouter('/')
.get(
{ path: '/ping', validate: false, options: { authRequired: 'optional' } },
http.createRouter('/').get(
{
path: '/ping',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: 'optional' },
},
(context, req, res) => res.ok({ body: 'pong' })
);
await root.start();

View file

@ -195,20 +195,36 @@ it.each([
createRoutes: (getRouter) => {
const router1 = getRouter(Symbol('myPlugin'));
router1.get(
{ path: '/api/public-test', validate: false, options: { access: 'public' } },
{
path: '/api/public-test',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { access: 'public' },
},
(_, __, res) => res.ok()
);
router1.post(
{ path: '/api/public-test', validate: false, options: { access: 'public' } },
{
path: '/api/public-test',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { access: 'public' },
},
(_, __, res) => res.ok()
);
router1.get(
{ path: '/api/public-test/{id}', validate: false, options: { access: 'public' } },
{
path: '/api/public-test/{id}',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { access: 'public' },
},
(_, __, res) => res.ok()
);
router1.get(
{
path: '/api/internal-test',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: {
/* empty */
@ -218,11 +234,19 @@ it.each([
);
router1.versioned
.get({ path: '/api/versioned', access: 'public' })
.get({
path: '/api/versioned',
security: { authz: { enabled: false, reason: '' } },
access: 'public',
})
.addVersion({ version: '2023-10-31', validate: false }, (_, __, res) => res.ok());
router1.versioned
.get({ path: '/api/versioned-internal', access: 'internal' })
.get({
path: '/api/versioned-internal',
security: { authz: { enabled: false, reason: '' } },
access: 'internal',
})
.addVersion(
{
version: '1',
@ -239,9 +263,30 @@ it.each([
);
const router2 = getRouter(Symbol('myOtherPlugin'));
router2.get({ path: '/api/my-other-plugin', validate: false }, (_, __, res) => res.ok());
router2.post({ path: '/api/my-other-plugin', validate: false }, (_, __, res) => res.ok());
router2.put({ path: '/api/my-other-plugin', validate: false }, (_, __, res) => res.ok());
router2.get(
{
path: '/api/my-other-plugin',
security: { authz: { enabled: false, reason: '' } },
validate: false,
},
(_, __, res) => res.ok()
);
router2.post(
{
path: '/api/my-other-plugin',
security: { authz: { enabled: false, reason: '' } },
validate: false,
},
(_, __, res) => res.ok()
);
router2.put(
{
path: '/api/my-other-plugin',
security: { authz: { enabled: false, reason: '' } },
validate: false,
},
(_, __, res) => res.ok()
);
},
});
const result = await supertest(server.listener).get('/api/oas').query(queryParam);

View file

@ -36,11 +36,21 @@ describe('Preboot HTTP server', () => {
it('accepts requests before `setup`', async () => {
const { server: innerPrebootServer, registerRoutes } = await server.preboot(prebootDeps);
registerRoutes('', (router) => {
router.get({ path: '/preboot-get', validate: false }, (context, req, res) =>
res.ok({ body: 'hello-get' })
router.get(
{
path: '/preboot-get',
security: { authz: { enabled: false, reason: '' } },
validate: false,
},
(context, req, res) => res.ok({ body: 'hello-get' })
);
router.post({ path: '/preboot-post', validate: false }, (context, req, res) =>
res.ok({ body: 'hello-post' })
router.post(
{
path: '/preboot-post',
security: { authz: { enabled: false, reason: '' } },
validate: false,
},
(context, req, res) => res.ok({ body: 'hello-post' })
);
});
@ -60,21 +70,41 @@ describe('Preboot HTTP server', () => {
it('accepts requests after `setup`, but before `start`', async () => {
const { server: innerPrebootServer, registerRoutes } = await server.preboot(prebootDeps);
registerRoutes('', (router) => {
router.get({ path: '/preboot-get', validate: false }, (context, req, res) =>
res.ok({ body: 'hello-get' })
router.get(
{
path: '/preboot-get',
security: { authz: { enabled: false, reason: '' } },
validate: false,
},
(context, req, res) => res.ok({ body: 'hello-get' })
);
router.post({ path: '/preboot-post', validate: false }, (context, req, res) =>
res.ok({ body: 'hello-post' })
router.post(
{
path: '/preboot-post',
security: { authz: { enabled: false, reason: '' } },
validate: false,
},
(context, req, res) => res.ok({ body: 'hello-post' })
);
});
const { createRouter, server: innerStandardServer } = await server.setup(setupDeps);
const standardRouter = createRouter('');
standardRouter.get({ path: '/standard-get', validate: false }, (context, req, res) =>
res.ok({ body: 'hello-get' })
standardRouter.get(
{
path: '/standard-get',
security: { authz: { enabled: false, reason: '' } },
validate: false,
},
(context, req, res) => res.ok({ body: 'hello-get' })
);
standardRouter.post({ path: '/standard-post', validate: false }, (context, req, res) =>
res.ok({ body: 'hello-post' })
standardRouter.post(
{
path: '/standard-post',
security: { authz: { enabled: false, reason: '' } },
validate: false,
},
(context, req, res) => res.ok({ body: 'hello-post' })
);
// Preboot routes should still work.
@ -101,21 +131,41 @@ describe('Preboot HTTP server', () => {
it('is not available after `start`', async () => {
const { server: innerPrebootServer, registerRoutes } = await server.preboot(prebootDeps);
registerRoutes('', (router) => {
router.get({ path: '/preboot-get', validate: false }, (context, req, res) =>
res.ok({ body: 'hello-get' })
router.get(
{
path: '/preboot-get',
security: { authz: { enabled: false, reason: '' } },
validate: false,
},
(context, req, res) => res.ok({ body: 'hello-get' })
);
router.post({ path: '/preboot-post', validate: false }, (context, req, res) =>
res.ok({ body: 'hello-post' })
router.post(
{
path: '/preboot-post',
security: { authz: { enabled: false, reason: '' } },
validate: false,
},
(context, req, res) => res.ok({ body: 'hello-post' })
);
});
const { createRouter, server: innerStandardServer } = await server.setup(setupDeps);
const standardRouter = createRouter('');
standardRouter.get({ path: '/standard-get', validate: false }, (context, req, res) =>
res.ok({ body: 'hello-get' })
standardRouter.get(
{
path: '/standard-get',
security: { authz: { enabled: false, reason: '' } },
validate: false,
},
(context, req, res) => res.ok({ body: 'hello-get' })
);
standardRouter.post({ path: '/standard-post', validate: false }, (context, req, res) =>
res.ok({ body: 'hello-post' })
standardRouter.post(
{
path: '/standard-post',
security: { authz: { enabled: false, reason: '' } },
validate: false,
},
(context, req, res) => res.ok({ body: 'hello-post' })
);
await server.start();

View file

@ -48,7 +48,12 @@ describe('KibanaRequest', () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get(
{ path: '/', validate: false, options: { authRequired: true } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: true },
},
(context, req, res) => res.ok({ body: { isAuthenticated: req.auth.isAuthenticated } })
);
await server.start();
@ -62,7 +67,12 @@ describe('KibanaRequest', () => {
const router = createRouter('/');
registerAuth((req, res, toolkit) => toolkit.notHandled());
router.get(
{ path: '/', validate: false, options: { authRequired: 'optional' } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: 'optional' },
},
(context, req, res) => res.ok({ body: { isAuthenticated: req.auth.isAuthenticated } })
);
await server.start();
@ -76,7 +86,12 @@ describe('KibanaRequest', () => {
const router = createRouter('/');
registerAuth((req, res, toolkit) => toolkit.redirected({ location: '/any' }));
router.get(
{ path: '/', validate: false, options: { authRequired: 'optional' } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: 'optional' },
},
(context, req, res) => res.ok({ body: { isAuthenticated: req.auth.isAuthenticated } })
);
await server.start();
@ -90,7 +105,12 @@ describe('KibanaRequest', () => {
const router = createRouter('/');
registerAuth((req, res, toolkit) => toolkit.authenticated());
router.get(
{ path: '/', validate: false, options: { authRequired: 'optional' } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: 'optional' },
},
(context, req, res) => res.ok({ body: { isAuthenticated: req.auth.isAuthenticated } })
);
await server.start();
@ -104,7 +124,12 @@ describe('KibanaRequest', () => {
const router = createRouter('/');
registerAuth((req, res, toolkit) => toolkit.authenticated());
router.get(
{ path: '/', validate: false, options: { authRequired: true } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: true },
},
(context, req, res) => res.ok({ body: { isAuthenticated: req.auth.isAuthenticated } })
);
await server.start();
@ -123,7 +148,12 @@ describe('KibanaRequest', () => {
registerAuth((req, res, t) => t.authenticated());
const router = createRouter('/');
router.get(
{ path: '/', validate: false, options: { authRequired: false } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: false },
},
(context, req, res) => res.ok({ body: { authRequired: req.route.options.authRequired } })
);
await server.start();
@ -137,7 +167,12 @@ describe('KibanaRequest', () => {
registerAuth((req, res, t) => t.authenticated());
const router = createRouter('/');
router.get(
{ path: '/', validate: false, options: { authRequired: 'optional' } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: 'optional' },
},
(context, req, res) => res.ok({ body: { authRequired: req.route.options.authRequired } })
);
await server.start();
@ -151,7 +186,12 @@ describe('KibanaRequest', () => {
registerAuth((req, res, t) => t.authenticated());
const router = createRouter('/');
router.get(
{ path: '/', validate: false, options: { authRequired: true } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: true },
},
(context, req, res) => res.ok({ body: { authRequired: req.route.options.authRequired } })
);
await server.start();
@ -173,7 +213,9 @@ describe('KibanaRequest', () => {
const nextSpy = jest.fn();
const done = new Promise<void>((resolve) => {
router.get({ path: '/', validate: false }, async (context, request, res) => {
router.get(
{ path: '/', security: { authz: { enabled: false, reason: '' } }, validate: false },
async (context, request, res) => {
request.events.aborted$.subscribe({
next: nextSpy,
complete: resolve,
@ -182,7 +224,8 @@ describe('KibanaRequest', () => {
// prevents the server to respond
await delay(30000);
return res.ok({ body: 'ok' });
});
}
);
});
await server.start();
@ -206,7 +249,11 @@ describe('KibanaRequest', () => {
const done = new Promise<void>((resolve) => {
router.post(
{ path: '/', validate: { body: schema.any() } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: { body: schema.any() },
},
async (context, request, res) => {
request.events.aborted$.subscribe({
next: nextSpy,
@ -239,14 +286,17 @@ describe('KibanaRequest', () => {
const nextSpy = jest.fn();
const completeSpy = jest.fn();
router.get({ path: '/', validate: false }, async (context, request, res) => {
router.get(
{ path: '/', security: { authz: { enabled: false, reason: '' } }, validate: false },
async (context, request, res) => {
request.events.aborted$.subscribe({
next: nextSpy,
complete: completeSpy,
});
return res.ok({ body: 'ok' });
});
}
);
await server.start();
@ -262,14 +312,17 @@ describe('KibanaRequest', () => {
const nextSpy = jest.fn();
const completeSpy = jest.fn();
router.get({ path: '/', validate: false }, async (context, request, res) => {
router.get(
{ path: '/', security: { authz: { enabled: false, reason: '' } }, validate: false },
async (context, request, res) => {
request.events.aborted$.subscribe({
next: nextSpy,
complete: completeSpy,
});
return res.badRequest();
});
}
);
await server.start();
@ -299,7 +352,11 @@ describe('KibanaRequest', () => {
});
router.post(
{ path: '/', validate: { body: schema.any() } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: { body: schema.any() },
},
async (context, request, res) => {
expect(completeSpy).not.toHaveBeenCalled();
return res.ok({ body: 'ok' });
@ -323,7 +380,9 @@ describe('KibanaRequest', () => {
const nextSpy = jest.fn();
const completeSpy = jest.fn();
router.get({ path: '/', validate: false }, async (context, req, res) => {
router.get(
{ path: '/', security: { authz: { enabled: false, reason: '' } }, validate: false },
async (context, req, res) => {
req.events.completed$.subscribe({
next: nextSpy,
complete: completeSpy,
@ -332,7 +391,8 @@ describe('KibanaRequest', () => {
expect(nextSpy).not.toHaveBeenCalled();
expect(completeSpy).not.toHaveBeenCalled();
return res.ok({ body: 'ok' });
});
}
);
await server.start();
@ -349,7 +409,9 @@ describe('KibanaRequest', () => {
const nextSpy = jest.fn();
const done = new Promise<void>((resolve) => {
router.get({ path: '/', validate: false }, async (context, req, res) => {
router.get(
{ path: '/', security: { authz: { enabled: false, reason: '' } }, validate: false },
async (context, req, res) => {
req.events.completed$.subscribe({
next: nextSpy,
complete: resolve,
@ -358,7 +420,8 @@ describe('KibanaRequest', () => {
expect(nextSpy).not.toHaveBeenCalled();
await delay(30000);
return res.ok({ body: 'ok' });
});
}
);
});
await server.start();
@ -381,7 +444,11 @@ describe('KibanaRequest', () => {
const done = new Promise<void>((resolve) => {
router.post(
{ path: '/', validate: { body: schema.any() } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: { body: schema.any() },
},
async (context, req, res) => {
req.events.completed$.subscribe({
next: nextSpy,
@ -413,9 +480,12 @@ describe('KibanaRequest', () => {
it('accepts x-opaque-id header case-insensitively', async () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, async (context, req, res) => {
router.get(
{ path: '/', security: { authz: { enabled: false, reason: '' } }, validate: false },
async (context, req, res) => {
return res.ok({ body: { requestId: req.id } });
});
}
);
await server.start();
const st = supertest(innerServer.listener);
@ -433,9 +503,12 @@ describe('KibanaRequest', () => {
it('generates a UUID', async () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, async (context, req, res) => {
router.get(
{ path: '/', security: { authz: { enabled: false, reason: '' } }, validate: false },
async (context, req, res) => {
return res.ok({ body: { requestUuid: req.uuid } });
});
}
);
await server.start();
const st = supertest(innerServer.listener);
@ -449,9 +522,12 @@ describe('KibanaRequest', () => {
it('returns the correct values', async () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get({ path: '/', validate: false }, async (context, req, res) => {
router.get(
{ path: '/', security: { authz: { enabled: false, reason: '' } }, validate: false },
async (context, req, res) => {
return res.ok({ body: { httpVersion: req.httpVersion, protocol: req.protocol } });
});
}
);
await server.start();
const st = supertest(innerServer.listener);

View file

@ -49,7 +49,12 @@ describe('request logging', () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get(
{ path: '/', validate: false, options: { authRequired: true } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: true },
},
(context, req, res) => {
return res.ok({ body: { req: String(req) } });
}
@ -66,7 +71,12 @@ describe('request logging', () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get(
{ path: '/', validate: false, options: { authRequired: true } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: true },
},
(context, req, res) => {
return res.ok({ body: { req: JSON.stringify(req) } });
}
@ -98,7 +108,12 @@ describe('request logging', () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get(
{ path: '/', validate: false, options: { authRequired: true } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: true },
},
(context, req, res) => {
return res.ok({ body: { req: inspect(req) } });
}
@ -125,7 +140,7 @@ describe('request logging', () => {
deprecated: undefined,
access: 'internal',
tags: [],
security: undefined,
security: [Object],
timeout: [Object],
body: undefined
}
@ -142,7 +157,12 @@ describe('request logging', () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get(
{ path: '/', validate: false, options: { authRequired: true } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: true },
},
(context, req, res) => {
const rawRequest = ensureRawRequest(req);
return res.ok({ body: { req: String(rawRequest) } });
@ -160,7 +180,12 @@ describe('request logging', () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get(
{ path: '/', validate: false, options: { authRequired: true } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: true },
},
(context, req, res) => {
const rawRequest = ensureRawRequest(req);
return res.ok({ body: { req: JSON.stringify(rawRequest) } });
@ -179,7 +204,12 @@ describe('request logging', () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get(
{ path: '/', validate: false, options: { authRequired: true } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: true },
},
(context, req, res) => {
const rawRequest = ensureRawRequest(req);
return res.ok({ body: { req: inspect(rawRequest) } });
@ -199,7 +229,12 @@ describe('request logging', () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get(
{ path: '/', validate: false, options: { authRequired: true } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: true },
},
(context, req, res) => {
const rawRawRequest = ensureRawRequest(req).raw.req;
return res.ok({ body: { req: String(rawRawRequest) } });
@ -217,7 +252,12 @@ describe('request logging', () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get(
{ path: '/', validate: false, options: { authRequired: true } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: true },
},
(context, req, res) => {
const rawRawRequest = ensureRawRequest(req).raw.req;
return res.ok({ body: { req: JSON.stringify(rawRawRequest) } });
@ -238,7 +278,12 @@ describe('request logging', () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');
router.get(
{ path: '/', validate: false, options: { authRequired: true } },
{
path: '/',
security: { authz: { enabled: false, reason: '' } },
validate: false,
options: { authRequired: true },
},
(context, req, res) => {
const rawRawRequest = ensureRawRequest(req).raw.req;
return res.ok({ body: { req: inspect(rawRawRequest) } });

File diff suppressed because it is too large Load diff

View file

@ -84,6 +84,7 @@ describe('HttpServer - TLS config', () => {
{
path: '/',
validate: false,
security: { authz: { enabled: false, reason: '' } },
},
async (ctx, req, res) => {
return res.ok({

View file

@ -72,7 +72,11 @@ describe('Routing versioned requests', () => {
it('routes requests to the expected handlers', async () => {
router.versioned
.get({ path: '/my-path', access: 'internal' })
.get({
path: '/my-path',
security: { authz: { enabled: false, reason: '' } },
access: 'internal',
})
.addVersion({ validate: false, version: '1' }, async (ctx, req, res) => {
return res.ok({ body: { v: '1' } });
})
@ -102,7 +106,11 @@ describe('Routing versioned requests', () => {
it('handles missing version header (defaults to oldest)', async () => {
await setupServer({ dev: false });
router.versioned
.get({ path: '/my-path', access: 'public' })
.get({
path: '/my-path',
security: { authz: { enabled: false, reason: '' } },
access: 'public',
})
.addVersion({ validate: false, version: '2020-02-02' }, async (ctx, req, res) => {
return res.ok({ body: { v: '1' } });
})
@ -122,7 +130,11 @@ describe('Routing versioned requests', () => {
it('returns the expected output for badly formatted versions', async () => {
router.versioned
.get({ path: '/my-path', access: 'internal' })
.get({
path: '/my-path',
security: { authz: { enabled: false, reason: '' } },
access: 'internal',
})
.addVersion({ validate: false, version: '1' }, async (ctx, req, res) => {
return res.ok({ body: { v: '1' } });
});
@ -142,7 +154,11 @@ describe('Routing versioned requests', () => {
it('returns the expected responses for failed validation', async () => {
router.versioned
.post({ path: '/my-path', access: 'internal' })
.post({
path: '/my-path',
security: { authz: { enabled: false, reason: '' } },
access: 'internal',
})
// Bad request validation
.addVersion(
{
@ -172,7 +188,11 @@ describe('Routing versioned requests', () => {
it('returns the version in response headers', async () => {
router.versioned
.get({ path: '/my-path', access: 'public' })
.get({
path: '/my-path',
security: { authz: { enabled: false, reason: '' } },
access: 'public',
})
.addVersion({ validate: false, version: '2023-10-31' }, async (ctx, req, res) => {
return res.ok({ body: { foo: 'bar' } });
});
@ -190,7 +210,12 @@ describe('Routing versioned requests', () => {
it('returns the version in response headers, even for HTTP resources', async () => {
router.versioned
.get({ path: '/my-path', access: 'public', options: { httpResource: true } })
.get({
path: '/my-path',
security: { authz: { enabled: false, reason: '' } },
access: 'public',
options: { httpResource: true },
})
.addVersion({ validate: false, version: '2023-10-31' }, async (ctx, req, res) => {
return res.ok({ body: { foo: 'bar' } });
});
@ -208,7 +233,11 @@ describe('Routing versioned requests', () => {
it('runs response validation when in dev', async () => {
router.versioned
.get({ path: '/my-path', access: 'internal' })
.get({
path: '/my-path',
security: { authz: { enabled: false, reason: '' } },
access: 'internal',
})
.addVersion(
{ validate: { response: { 200: { body: () => schema.number() } } }, version: '1' },
async (ctx, req, res) => {
@ -278,7 +307,11 @@ describe('Routing versioned requests', () => {
await setupServer({ dev: false });
router.versioned
.get({ path: '/my-path', access: 'internal' })
.get({
path: '/my-path',
security: { authz: { enabled: false, reason: '' } },
access: 'internal',
})
.addVersion(
{ validate: { response: { 200: { body: () => schema.number() } } }, version: '1' },
async (ctx, req, res) => {
@ -301,7 +334,11 @@ describe('Routing versioned requests', () => {
await setupServer({ dev: false });
router.versioned
.get({ path: '/my-internal-path', access: 'internal' })
.get({
path: '/my-internal-path',
security: { authz: { enabled: false, reason: '' } },
access: 'internal',
})
.addVersion(
{ version: '1', validate: { response: { 200: { body: () => schema.number() } } } },
async (ctx, req, res) => res.ok({ body: 'v1' })
@ -326,6 +363,7 @@ describe('Routing versioned requests', () => {
router.versioned
.get({
path: '/my-path',
security: { authz: { enabled: false, reason: '' } },
access: 'public',
})
.addVersion({ version: '2023-10-31', validate: false }, async (ctx, req, res) => res.ok());
@ -333,6 +371,7 @@ describe('Routing versioned requests', () => {
router.versioned
.get({
path: '/my-internal-path',
security: { authz: { enabled: false, reason: '' } },
access: 'internal',
})
.addVersion({ version: '1', validate: false }, async (ctx, req, res) => res.ok());
@ -361,7 +400,11 @@ describe('Routing versioned requests', () => {
});
it('errors when no handler could be found', async () => {
router.versioned.get({ path: '/my-path', access: 'public' });
router.versioned.get({
path: '/my-path',
security: { authz: { enabled: false, reason: '' } },
access: 'public',
});
await server.start();
@ -379,7 +422,11 @@ describe('Routing versioned requests', () => {
await setupServer({ serverless: true, dev: false });
router.versioned
.get({ path: '/my-path', access: 'public' })
.get({
path: '/my-path',
security: { authz: { enabled: false, reason: '' } },
access: 'public',
})
.addVersion({ validate: false, version: '2023-04-04' }, async (ctx, req, res) => {
return res.ok({ body: { v: 'oldest' } });
})
@ -401,7 +448,11 @@ describe('Routing versioned requests', () => {
await setupServer({ serverless: false, dev: false });
router.versioned
.get({ path: '/my-path', access: 'public' })
.get({
path: '/my-path',
security: { authz: { enabled: false, reason: '' } },
access: 'public',
})
.addVersion({ validate: false, version: '2023-04-04' }, async (ctx, req, res) => {
return res.ok({ body: { v: 'oldest' } });
})
@ -423,7 +474,11 @@ describe('Routing versioned requests', () => {
const error = new Error(`some error`);
router.versioned
.get({ path: '/my-path', access: 'internal' })
.get({
path: '/my-path',
security: { authz: { enabled: false, reason: '' } },
access: 'internal',
})
.addVersion({ validate: false, version: '1' }, async (ctx, req, res) => {
throw error;
});
@ -438,7 +493,13 @@ describe('Routing versioned requests', () => {
it('reserves the query parameter "apiVersion" for version negotiation', async () => {
await setupServer({ serverless: false, dev: false });
router.versioned.get({ path: '/my-path', access: 'public' }).addVersion(
router.versioned
.get({
path: '/my-path',
security: { authz: { enabled: false, reason: '' } },
access: 'public',
})
.addVersion(
{
validate: {
request: {
@ -476,7 +537,12 @@ describe('Routing versioned requests', () => {
return res.ok({ body: 'ok' });
});
router.versioned
.get({ path: '/my-public', access: 'public', enableQueryVersion: true })
.get({
path: '/my-public',
security: { authz: { enabled: false, reason: '' } },
access: 'public',
enableQueryVersion: true,
})
.addVersion(
{
validate: { request: { query: schema.object({ a: schema.number() }) } },
@ -486,7 +552,12 @@ describe('Routing versioned requests', () => {
);
router.versioned
.get({ path: '/my-internal', access: 'internal', enableQueryVersion: true })
.get({
path: '/my-internal',
security: { authz: { enabled: false, reason: '' } },
access: 'internal',
enableQueryVersion: true,
})
.addVersion(
{
validate: { request: { query: schema.object({ a: schema.number() }) } },
@ -540,12 +611,20 @@ describe('Routing versioned requests', () => {
);
router.versioned
.get({ path: '/my_path_to_bypass/{id?}', access: 'internal' })
.get({
path: '/my_path_to_bypass/{id?}',
security: { authz: { enabled: false, reason: '' } },
access: 'internal',
})
.addVersion({ validate: false, version: '1' }, async (ctx, req, res) => {
return res.ok({ body: { ok: true } });
});
router.versioned
.get({ path: '/my_other_path', access: 'internal' })
.get({
path: '/my_other_path',
security: { authz: { enabled: false, reason: '' } },
access: 'internal',
})
.addVersion({ validate: false, version: '1' }, async (ctx, req, res) => {
return res.ok({ body: { ok: true } });
});

View file

@ -43,8 +43,13 @@ function applyTestsWithDisableUnsafeEvalSetTo(disableUnsafeEval: boolean) {
const router = http.createRouter('');
const resources = httpResources.createRegistrar(router);
resources.register({ path: '/render-core', validate: false }, (context, req, res) =>
res.renderAnonymousCoreApp()
resources.register(
{
path: '/render-core',
validate: false,
security: { authz: { requiredPrivileges: ['foo'] } },
},
(context, req, res) => res.renderAnonymousCoreApp()
);
await root.start();
@ -58,8 +63,13 @@ function applyTestsWithDisableUnsafeEvalSetTo(disableUnsafeEval: boolean) {
const router = http.createRouter('');
const resources = httpResources.createRegistrar(router);
resources.register({ path: '/render-core', validate: false }, (context, req, res) =>
res.renderAnonymousCoreApp()
resources.register(
{
path: '/render-core',
validate: false,
security: { authz: { requiredPrivileges: ['foo'] } },
},
(context, req, res) => res.renderAnonymousCoreApp()
);
await root.start();
@ -73,7 +83,13 @@ function applyTestsWithDisableUnsafeEvalSetTo(disableUnsafeEval: boolean) {
const router = http.createRouter('');
const resources = httpResources.createRegistrar(router);
resources.register({ path: '/render-core', validate: false }, (context, req, res) =>
resources.register(
{
path: '/render-core',
validate: false,
security: { authz: { requiredPrivileges: ['foo'] } },
},
(context, req, res) =>
res.renderAnonymousCoreApp({
headers: {
'content-security-policy': "script-src 'unsafe-eval'",
@ -104,8 +120,13 @@ function applyTestsWithDisableUnsafeEvalSetTo(disableUnsafeEval: boolean) {
</body>
</html>
`;
resources.register({ path: '/render-html', validate: false }, (context, req, res) =>
res.renderHtml({ body: htmlBody })
resources.register(
{
path: '/render-html',
validate: false,
security: { authz: { requiredPrivileges: ['foo'] } },
},
(context, req, res) => res.renderHtml({ body: htmlBody })
);
await root.start();
@ -121,8 +142,13 @@ function applyTestsWithDisableUnsafeEvalSetTo(disableUnsafeEval: boolean) {
const router = http.createRouter('');
const resources = httpResources.createRegistrar(router);
const jsBody = 'window.alert("from js body");';
resources.register({ path: '/render-js', validate: false }, (context, req, res) =>
res.renderJs({ body: jsBody })
resources.register(
{
path: '/render-js',
validate: false,
security: { authz: { requiredPrivileges: ['foo'] } },
},
(context, req, res) => res.renderJs({ body: jsBody })
);
await root.start();
@ -145,8 +171,13 @@ function applyTestsWithDisableUnsafeEvalSetTo(disableUnsafeEval: boolean) {
</body>
</html>
`;
resources.register({ path: '/render-html', validate: false }, (context, req, res) =>
res.renderHtml({ body: htmlBody })
resources.register(
{
path: '/render-html',
validate: false,
security: { authz: { requiredPrivileges: ['foo'] } },
},
(context, req, res) => res.renderHtml({ body: htmlBody })
);
await root.start();
@ -160,7 +191,13 @@ function applyTestsWithDisableUnsafeEvalSetTo(disableUnsafeEval: boolean) {
const router = http.createRouter('');
const resources = httpResources.createRegistrar(router);
resources.register({ path: '/render-core', validate: false }, (context, req, res) =>
resources.register(
{
path: '/render-core',
validate: false,
security: { authz: { requiredPrivileges: ['foo'] } },
},
(context, req, res) =>
res.renderHtml({
body: '<html><p>Hi</p></html>',
headers: {
@ -189,8 +226,13 @@ function applyTestsWithDisableUnsafeEvalSetTo(disableUnsafeEval: boolean) {
}),
};
resources.register({ path: '/render-js-with-param/{id}', validate }, (context, req, res) =>
res.renderJs({ body: `window.alert(${req.params.id});` })
resources.register(
{
path: '/render-js-with-param/{id}',
validate,
security: { authz: { requiredPrivileges: ['foo'] } },
},
(context, req, res) => res.renderJs({ body: `window.alert(${req.params.id});` })
);
await root.start();
@ -206,8 +248,13 @@ function applyTestsWithDisableUnsafeEvalSetTo(disableUnsafeEval: boolean) {
const router = http.createRouter('');
const resources = httpResources.createRegistrar(router);
const htmlBody = `<p>HtMlr00lz</p>`;
resources.register({ path: '/render-html', validate: false }, (context, req, res) =>
res.renderHtml({ body: htmlBody })
resources.register(
{
path: '/render-html',
validate: false,
security: { authz: { requiredPrivileges: ['foo'] } },
},
(context, req, res) => res.renderHtml({ body: htmlBody })
);
await root.start();

View file

@ -46,9 +46,12 @@ describe('ServerMetricsCollector', () => {
});
it('collect requests infos', async () => {
router.get({ path: '/', validate: false }, async (ctx, req, res) => {
router.get(
{ path: '/', validate: false, security: { authz: { requiredPrivileges: ['foo'] } } },
async (ctx, req, res) => {
return res.ok({ body: '' });
});
}
);
await server.start();
@ -81,17 +84,27 @@ describe('ServerMetricsCollector', () => {
const disconnectRequested$ = new Subject<void>(); // Controls the number of requests in the /disconnect endpoint
const disconnectAborted$ = new Subject<void>(); // Controls the abort event in the /disconnect endpoint
router.get({ path: '/', validate: false }, async (ctx, req, res) => {
router.get(
{ path: '/', validate: false, security: { authz: { requiredPrivileges: ['foo'] } } },
async (ctx, req, res) => {
return res.ok({ body: '' });
});
router.get({ path: '/disconnect', validate: false }, async (ctx, req, res) => {
}
);
router.get(
{
path: '/disconnect',
validate: false,
security: { authz: { requiredPrivileges: ['foo'] } },
},
async (ctx, req, res) => {
disconnectRequested$.next();
req.events.aborted$.subscribe(() => {
disconnectAborted$.next();
});
await never; // Never resolve the request
return res.ok({ body: '' });
});
}
);
await server.start();
await sendGet('/');
@ -148,17 +161,26 @@ describe('ServerMetricsCollector', () => {
});
it('collect response times', async () => {
router.get({ path: '/no-delay', validate: false }, async (ctx, req, res) => {
router.get(
{ path: '/no-delay', validate: false, security: { authz: { requiredPrivileges: ['foo'] } } },
async (ctx, req, res) => {
return res.ok({ body: '' });
});
router.get({ path: '/500-ms', validate: false }, async (ctx, req, res) => {
}
);
router.get(
{ path: '/500-ms', validate: false, security: { authz: { requiredPrivileges: ['foo'] } } },
async (ctx, req, res) => {
await delay(500);
return res.ok({ body: '' });
});
router.get({ path: '/250-ms', validate: false }, async (ctx, req, res) => {
}
);
router.get(
{ path: '/250-ms', validate: false, security: { authz: { requiredPrivileges: ['foo'] } } },
async (ctx, req, res) => {
await delay(250);
return res.ok({ body: '' });
});
}
);
await server.start();
await Promise.all([sendGet('/no-delay'), sendGet('/250-ms')]);
@ -178,11 +200,14 @@ describe('ServerMetricsCollector', () => {
const waitSubject = new Subject();
const hitSubject = new BehaviorSubject(0);
router.get({ path: '/', validate: false }, async (ctx, req, res) => {
router.get(
{ path: '/', validate: false, security: { authz: { requiredPrivileges: ['foo'] } } },
async (ctx, req, res) => {
hitSubject.next(hitSubject.value + 1);
await waitSubject.pipe(take(1)).toPromise();
return res.ok({ body: '' });
});
}
);
await server.start();
const waitForHits = (hits: number) =>
@ -221,9 +246,12 @@ describe('ServerMetricsCollector', () => {
describe('#reset', () => {
it('reset the requests state', async () => {
router.get({ path: '/', validate: false }, async (ctx, req, res) => {
router.get(
{ path: '/', validate: false, security: { authz: { requiredPrivileges: ['foo'] } } },
async (ctx, req, res) => {
return res.ok({ body: '' });
});
}
);
await server.start();
await sendGet('/');
@ -266,13 +294,23 @@ describe('ServerMetricsCollector', () => {
});
it('resets the response times', async () => {
router.get({ path: '/no-delay', validate: false }, async (ctx, req, res) => {
router.get(
{
path: '/no-delay',
validate: false,
security: { authz: { requiredPrivileges: ['foo'] } },
},
async (ctx, req, res) => {
return res.ok({ body: '' });
});
router.get({ path: '/500-ms', validate: false }, async (ctx, req, res) => {
}
);
router.get(
{ path: '/500-ms', validate: false, security: { authz: { requiredPrivileges: ['foo'] } } },
async (ctx, req, res) => {
await delay(500);
return res.ok({ body: '' });
});
}
);
await server.start();

View file

@ -97,7 +97,11 @@ export const registerContentInsights = (
},
},
}
: {}),
: {
security: {
authz: { enabled: false, reason: 'Route delegates authorization to the SO Client' },
},
}),
},
async (context, req, res) => {
const { id, eventType } = req.params;
@ -122,7 +126,11 @@ export const registerContentInsights = (
},
},
}
: {}),
: {
security: {
authz: { enabled: false, reason: 'Route delegates authorization to the SO Client' },
},
}),
},
async (context, req, res) => {
const { id, eventType } = req.params;

View file

@ -126,6 +126,7 @@ Object {
"/bar": Object {
"get": Object {
"deprecated": true,
"description": "[Required authorization] Route required privileges: ALL of [foo].",
"operationId": "get-bar",
"parameters": Array [],
"requestBody": Object {
@ -490,6 +491,7 @@ Object {
"/no-xsrf/{id}/{path}": Object {
"post": Object {
"deprecated": true,
"description": "[Required authorization] Route required privileges: ALL of [foo].",
"operationId": "post-no-xsrf-id-path",
"parameters": Array [],
"requestBody": Object {
@ -702,6 +704,7 @@ Object {
},
"/test": Object {
"get": Object {
"description": "[Required authorization] Route required privileges: ALL of [foo].",
"operationId": "get-test",
"parameters": Array [],
"requestBody": Object {

View file

@ -36,6 +36,7 @@ export const sharedOas = {
deprecated: true,
'x-discontinued': 'route discontinued version or date',
operationId: 'get-bar',
description: '[Required authorization] Route required privileges: ALL of [foo].',
parameters: [],
requestBody: {
content: {

View file

@ -74,7 +74,15 @@ describe('generateOpenApiDocument', () => {
{
method: 'post',
path: '/no-xsrf/{id}/{path*}',
options: { access: 'public', options: { xsrfRequired: false } },
options: {
access: 'public',
options: { xsrfRequired: false },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
},
],
},
@ -247,7 +255,14 @@ describe('generateOpenApiDocument', () => {
method: 'get',
path: '/test',
isVersioned: true,
options: { access: 'public' },
options: {
access: 'public',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
handlers: [
{
fn: jest.fn(),
@ -298,19 +313,46 @@ describe('generateOpenApiDocument', () => {
versionedRouters: {
testVersionedRouter1: {
routes: [
{ path: '/v1-1', options: { access: 'public', options: { tags: ['oas-tag:v1'] } } },
{
path: '/v1-1',
options: {
access: 'public',
options: { tags: ['oas-tag:v1'] },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
},
{
path: '/v1-2',
options: {
access: 'public',
options: { tags: ['foo', 'bar', 'oas-tag:v2', 'oas-tag:v3'] },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
},
],
},
testVersionedRouter2: {
routes: [
{ path: '/v2-1', options: { access: 'public', options: { tags: undefined } } },
{
path: '/v2-1',
options: {
access: 'public',
options: { tags: undefined },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
},
],
},
},
@ -369,6 +411,11 @@ describe('generateOpenApiDocument', () => {
options: {
access: 'public',
options: { availability: { stability: 'experimental' } },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
},
{
@ -376,6 +423,11 @@ describe('generateOpenApiDocument', () => {
options: {
access: 'public',
options: { availability: { stability: 'beta' } },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
},
{
@ -383,12 +435,29 @@ describe('generateOpenApiDocument', () => {
options: {
access: 'public',
options: { availability: { stability: 'stable' } },
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
},
],
},
testVersionedRouter2: {
routes: [{ path: '/v2-1', options: { access: 'public' } }],
routes: [
{
path: '/v2-1',
options: {
access: 'public',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
},
],
},
},
});
@ -471,6 +540,11 @@ describe('generateOpenApiDocument', () => {
{
options: {
access: 'public',
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
},
],

View file

@ -69,6 +69,11 @@ export const getVersionedRouterDefaults = (bodySchema?: RuntimeSchema): Versione
options: {
tags: ['ignore-me', 'oas-tag:versioned'],
},
security: {
authz: {
requiredPrivileges: ['foo'],
},
},
},
isVersioned: true,
handlers: [

View file

@ -192,7 +192,12 @@ export function registerRoutes<TDependencies extends Record<string, any>>({
...options,
access,
},
security,
security: security ?? {
authz: {
enabled: false,
reason: 'Delegates authorization to the es client',
},
},
validate: validationObject,
},
wrappedHandler
@ -204,7 +209,12 @@ export function registerRoutes<TDependencies extends Record<string, any>>({
summary: options.summary,
description: options.description,
options: omit(options, 'access', 'description', 'summary', 'deprecated', 'discontinued'),
security,
security: security ?? {
authz: {
enabled: false,
reason: 'Delegates authorization to the es client',
},
},
}).addVersion(
{
version,

View file

@ -16,10 +16,6 @@ export const setupOptionsListClusterSettingsRoute = ({ http }: CoreSetup) => {
.get({
access: 'internal',
path: '/internal/controls/getExpensiveQueriesSetting',
})
.addVersion(
{
version: '1',
security: {
authz: {
enabled: false,
@ -27,6 +23,10 @@ export const setupOptionsListClusterSettingsRoute = ({ http }: CoreSetup) => {
'This route is opted out from authorization because it does not take a query, params, or a body, so there is no chance of leaking info.',
},
},
})
.addVersion(
{
version: '1',
validate: false,
},
async (context, _, response) => {

View file

@ -29,10 +29,6 @@ export const setupOptionsListSuggestionsRoute = (
.post({
access: 'internal',
path: '/internal/controls/optionsList/{index}',
})
.addVersion(
{
version: '1',
security: {
authz: {
enabled: false,
@ -40,6 +36,10 @@ export const setupOptionsListSuggestionsRoute = (
'This route is opted out from authorization because permissions will be checked by elasticsearch.',
},
},
})
.addVersion(
{
version: '1',
validate: {
request: {
params: schema.object(

View file

@ -20,16 +20,16 @@ export function registerKqlTelemetryRoute(
.post({
path: '/internal/kql_opt_in_stats',
access: 'internal',
})
.addVersion(
{
version: KQL_TELEMETRY_ROUTE_LATEST_VERSION,
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
})
.addVersion(
{
version: KQL_TELEMETRY_ROUTE_LATEST_VERSION,
validate: {
request: {
body: schema.object({

View file

@ -40,14 +40,19 @@ const version = '1';
export function registerSavedQueryRoutes({ http }: CoreSetup): void {
const router = http.createRouter<SavedQueryRouteHandlerContext>();
router.versioned.post({ path: `${SAVED_QUERY_BASE_URL}/_is_duplicate_title`, access }).addVersion(
{
version,
router.versioned
.post({
path: `${SAVED_QUERY_BASE_URL}/_is_duplicate_title`,
access,
security: {
authz: {
requiredPrivileges: ['savedQuery:read'],
},
},
})
.addVersion(
{
version,
validate: {
request: {
body: schema.object({
@ -77,14 +82,19 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void {
}
);
router.versioned.post({ path: `${SAVED_QUERY_BASE_URL}/_create`, access }).addVersion(
{
version,
router.versioned
.post({
path: `${SAVED_QUERY_BASE_URL}/_create`,
access,
security: {
authz: {
requiredPrivileges: ['savedQuery:manage'],
},
},
})
.addVersion(
{
version,
validate: {
request: {
body: SAVED_QUERY_ATTRS_CONFIG,
@ -108,14 +118,19 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void {
}
);
router.versioned.put({ path: `${SAVED_QUERY_BASE_URL}/{id}`, access }).addVersion(
{
version,
router.versioned
.put({
path: `${SAVED_QUERY_BASE_URL}/{id}`,
access,
security: {
authz: {
requiredPrivileges: ['savedQuery:manage'],
},
},
})
.addVersion(
{
version,
validate: {
request: {
params: SAVED_QUERY_ID_CONFIG,
@ -141,14 +156,19 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void {
}
);
router.versioned.get({ path: `${SAVED_QUERY_BASE_URL}/{id}`, access }).addVersion(
{
version,
router.versioned
.get({
path: `${SAVED_QUERY_BASE_URL}/{id}`,
access,
security: {
authz: {
requiredPrivileges: ['savedQuery:read'],
},
},
})
.addVersion(
{
version,
validate: {
request: {
params: SAVED_QUERY_ID_CONFIG,
@ -173,14 +193,19 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void {
}
);
router.versioned.get({ path: `${SAVED_QUERY_BASE_URL}/_count`, access }).addVersion(
{
version,
router.versioned
.get({
path: `${SAVED_QUERY_BASE_URL}/_count`,
access,
security: {
authz: {
requiredPrivileges: ['savedQuery:read'],
},
},
})
.addVersion(
{
version,
validate: {
request: {},
response: {
@ -202,14 +227,19 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void {
}
);
router.versioned.post({ path: `${SAVED_QUERY_BASE_URL}/_find`, access }).addVersion(
{
version,
router.versioned
.post({
path: `${SAVED_QUERY_BASE_URL}/_find`,
access,
security: {
authz: {
requiredPrivileges: ['savedQuery:read'],
},
},
})
.addVersion(
{
version,
validate: {
request: {
body: schema.object({
@ -241,14 +271,19 @@ export function registerSavedQueryRoutes({ http }: CoreSetup): void {
}
);
router.versioned.delete({ path: `${SAVED_QUERY_BASE_URL}/{id}`, access }).addVersion(
{
version,
router.versioned
.delete({
path: `${SAVED_QUERY_BASE_URL}/{id}`,
access,
security: {
authz: {
requiredPrivileges: ['savedQuery:manage'],
},
},
})
.addVersion(
{
version,
validate: {
request: {
params: SAVED_QUERY_ID_CONFIG,

View file

@ -16,16 +16,16 @@ export function registerScriptsRoute(router: IRouter) {
.get({
path: '/internal/scripts/languages',
access: 'internal',
})
.addVersion(
{
version: SCRIPT_LANGUAGES_ROUTE_LATEST_VERSION,
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
})
.addVersion(
{
version: SCRIPT_LANGUAGES_ROUTE_LATEST_VERSION,
validate: {
response: {
'200': {

View file

@ -30,16 +30,16 @@ export function registerSearchRoute(
.post({
path: `${SEARCH_API_BASE_URL}/{strategy}/{id?}`,
access: 'internal',
})
.addVersion(
{
version: '1',
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
})
.addVersion(
{
version: '1',
validate: {
request: {
params: schema.object({
@ -128,16 +128,16 @@ export function registerSearchRoute(
.delete({
path: '/internal/search/{strategy}/{id}',
access: 'internal',
})
.addVersion(
{
version: '1',
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
})
.addVersion(
{
version: '1',
validate: {
request: {
params: schema.object({

View file

@ -34,12 +34,17 @@ const idAndAttrsOnly = (so?: SearchSessionRestResponse) =>
so && { id: so.id, attributes: so.attributes };
export function registerSessionRoutes(router: DataPluginRouter, logger: Logger): void {
router.versioned.post({ path: pathPrefix, access }).addVersion(
{
version,
router.versioned
.post({
path: pathPrefix,
access,
security: {
authz: { requiredPrivileges },
},
})
.addVersion(
{
version,
validate: {
request: {
body: schema.object({
@ -85,12 +90,17 @@ export function registerSessionRoutes(router: DataPluginRouter, logger: Logger):
}
);
router.versioned.get({ path: `${pathPrefix}/{id}`, access }).addVersion(
{
version,
router.versioned
.get({
path: `${pathPrefix}/{id}`,
access,
security: {
authz: { requiredPrivileges },
},
})
.addVersion(
{
version,
validate: {
request: {
params: schema.object({
@ -120,12 +130,17 @@ export function registerSessionRoutes(router: DataPluginRouter, logger: Logger):
}
);
router.versioned.get({ path: `${pathPrefix}/{id}/status`, access }).addVersion(
{
version,
router.versioned
.get({
path: `${pathPrefix}/{id}/status`,
access,
security: {
authz: { requiredPrivileges },
},
})
.addVersion(
{
version,
validate: {
request: {
params: schema.object({
@ -143,7 +158,9 @@ export function registerSessionRoutes(router: DataPluginRouter, logger: Logger):
const { id } = request.params;
try {
const searchContext = await context.search;
const response: SearchSessionStatusRestResponse = await searchContext!.getSessionStatus(id);
const response: SearchSessionStatusRestResponse = await searchContext!.getSessionStatus(
id
);
return res.ok({
body: response,
@ -156,19 +173,26 @@ export function registerSessionRoutes(router: DataPluginRouter, logger: Logger):
}
);
router.versioned.post({ path: `${pathPrefix}/_find`, access }).addVersion(
{
version,
router.versioned
.post({
path: `${pathPrefix}/_find`,
access,
security: {
authz: { requiredPrivileges },
},
})
.addVersion(
{
version,
validate: {
request: {
body: schema.object({
page: schema.maybe(schema.number()),
perPage: schema.maybe(schema.number()),
sortField: schema.maybe(schema.string()),
sortOrder: schema.maybe(schema.oneOf([schema.literal('desc'), schema.literal('asc')])),
sortOrder: schema.maybe(
schema.oneOf([schema.literal('desc'), schema.literal('asc')])
),
filter: schema.maybe(schema.string()),
searchFields: schema.maybe(schema.arrayOf(schema.string())),
search: schema.maybe(schema.string()),
@ -209,12 +233,17 @@ export function registerSessionRoutes(router: DataPluginRouter, logger: Logger):
}
);
router.versioned.delete({ path: `${pathPrefix}/{id}`, access }).addVersion(
{
version,
router.versioned
.delete({
path: `${pathPrefix}/{id}`,
access,
security: {
authz: { requiredPrivileges },
},
})
.addVersion(
{
version,
validate: {
request: {
params: schema.object({
@ -238,12 +267,17 @@ export function registerSessionRoutes(router: DataPluginRouter, logger: Logger):
}
);
router.versioned.post({ path: `${pathPrefix}/{id}/cancel`, access }).addVersion(
{
version,
router.versioned
.post({
path: `${pathPrefix}/{id}/cancel`,
access,
security: {
authz: { requiredPrivileges },
},
})
.addVersion(
{
version,
validate: {
request: {
params: schema.object({
@ -267,12 +301,17 @@ export function registerSessionRoutes(router: DataPluginRouter, logger: Logger):
}
);
router.versioned.put({ path: `${pathPrefix}/{id}`, access }).addVersion(
{
version,
router.versioned
.put({
path: `${pathPrefix}/{id}`,
access,
security: {
authz: { requiredPrivileges },
},
})
.addVersion(
{
version,
validate: {
request: {
params: schema.object({
@ -309,12 +348,17 @@ export function registerSessionRoutes(router: DataPluginRouter, logger: Logger):
}
);
router.versioned.post({ path: `${pathPrefix}/{id}/_extend`, access }).addVersion(
{
version,
router.versioned
.post({
path: `${pathPrefix}/{id}/_extend`,
access,
security: {
authz: { requiredPrivileges },
},
})
.addVersion(
{
version,
validate: {
request: {
params: schema.object({

View file

@ -48,15 +48,20 @@ const responseSchema = () => {
};
export const registerFieldPreviewRoute = ({ router }: RouteDependencies): void => {
router.versioned.post({ path, access: 'internal' }).addVersion(
{
version: '1',
router.versioned
.post({
path,
access: 'internal',
security: {
authz: {
enabled: false,
reason: 'Authorization provided by Elasticsearch',
},
},
})
.addVersion(
{
version: '1',
validate: {
request: {
body: bodySchema,

View file

@ -56,16 +56,16 @@ export const registerExistingIndicesPath = (router: IRouter): void => {
.get({
path: EXISTING_INDICES_PATH,
access: 'internal',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the scoped ES client',
},
},
})
.addVersion(
{
version,
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
validate: {
request: {
query: schema.object({

View file

@ -146,15 +146,21 @@ export const registerFields = (
>,
isRollupsEnabled: () => boolean
) => {
router.versioned.get({ path, access: 'internal', enableQueryVersion: true }).addVersion(
{
version: '1',
router.versioned
.get({
path,
access: 'internal',
enableQueryVersion: true,
security: {
authz: {
enabled: false,
reason: 'Authorization provided by Elasticsearch',
},
},
})
.addVersion(
{
version: '1',
validate: { request: { query: querySchema }, response: validate.response },
},
handler(isRollupsEnabled)

View file

@ -250,26 +250,23 @@ export const registerFieldForWildcard = (
const authz: RouteAuthz = { enabled: false, reason: 'Authorization provided by Elasticsearch' };
// handler
router.versioned.put({ path, access }).addVersion(
router.versioned.put({ path, access, security: { authz } }).addVersion(
{
version,
security: { authz },
validate,
},
configuredHandler
);
router.versioned.post({ path, access }).addVersion(
router.versioned.post({ path, access, security: { authz } }).addVersion(
{
version,
security: { authz },
validate,
},
configuredHandler
);
router.versioned.get({ path, access }).addVersion(
router.versioned.get({ path, access, security: { authz } }).addVersion(
{
version,
security: { authz },
validate: { request: { query: querySchema }, response: validate.response },
},
configuredHandler

View file

@ -41,16 +41,16 @@ export const registerHasDataViewsRoute = (router: IRouter): void => {
.get({
path: '/internal/data_views/has_data_views',
access: 'internal',
})
.addVersion(
{
version: '1',
security: {
authz: {
enabled: false,
reason: 'Authorization provided by saved objects client',
},
},
})
.addVersion(
{
version: '1',
validate: {
response: {
200: {

View file

@ -129,16 +129,16 @@ export const registerHasEsDataRoute = (
.get({
path: '/internal/data_views/has_es_data',
access: 'internal',
})
.addVersion(
{
version: '1',
security: {
authz: {
enabled: false,
reason: 'Authorization provided by Elasticsearch',
},
},
})
.addVersion(
{
version: '1',
validate: {
response: {
200: {

View file

@ -58,14 +58,20 @@ const registerCreateDataViewRouteFactory =
>,
usageCollection?: UsageCounter
) => {
router.versioned.post({ path, access: 'public', description }).addVersion(
{
version: INITIAL_REST_VERSION,
router.versioned
.post({
path,
access: 'public',
description,
security: {
authz: {
requiredPrivileges: ['indexPatterns:manage'],
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
body: schema.object({

View file

@ -70,15 +70,21 @@ const manageDefaultIndexPatternRoutesFactory =
>,
usageCollection?: UsageCounter
) => {
router.versioned.get({ path, access: 'public', description: getDescription }).addVersion(
{
version: INITIAL_REST_VERSION,
router.versioned
.get({
path,
access: 'public',
description: getDescription,
security: {
authz: {
enabled: false,
reason: 'Authorization provided by saved objects client',
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {},
response: {
@ -113,14 +119,20 @@ const manageDefaultIndexPatternRoutesFactory =
})
);
router.versioned.post({ path, access: 'public', description: postDescription }).addVersion(
{
version: INITIAL_REST_VERSION,
router.versioned
.post({
path,
access: 'public',
description: postDescription,
security: {
authz: {
requiredPrivileges: ['indexPatterns:manage'],
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
body: schema.object({

View file

@ -50,14 +50,20 @@ const deleteIndexPatternRouteFactory =
>,
usageCollection?: UsageCounter
) => {
router.versioned.delete({ path, access: 'public', description }).addVersion(
{
version: INITIAL_REST_VERSION,
router.versioned
.delete({
path,
access: 'public',
description,
security: {
authz: {
requiredPrivileges: ['indexPatterns:manage'],
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
params: schema.object(

View file

@ -128,14 +128,20 @@ const updateFieldsActionRouteFactory = (path: string, serviceKey: string, descri
>,
usageCollection?: UsageCounter
) => {
router.versioned.post({ path, access: 'public', description }).addVersion(
{
version: INITIAL_REST_VERSION,
router.versioned
.post({
path,
access: 'public',
description,
security: {
authz: {
requiredPrivileges: ['indexPatterns:manage'],
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
params: schema.object(

View file

@ -54,15 +54,21 @@ const getDataViewRouteFactory =
>,
usageCollection?: UsageCounter
) => {
router.versioned.get({ path, access: 'public', description }).addVersion(
{
version: INITIAL_REST_VERSION,
router.versioned
.get({
path,
access: 'public',
description,
security: {
authz: {
enabled: false,
reason: 'Authorization provided by saved objects client',
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
params: schema.object(

View file

@ -63,15 +63,21 @@ const getDataViewsRouteFactory =
return schema.object({ [serviceKey]: dataViewListSchema });
};
router.versioned.get({ path, access: 'public', description }).addVersion(
{
version: INITIAL_REST_VERSION,
router.versioned
.get({
path,
access: 'public',
description,
security: {
authz: {
enabled: false,
reason: 'Authorization provided by saved objects client',
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {},
response: { 200: { body: responseValidation } },

View file

@ -43,15 +43,20 @@ const hasUserDataViewRouteFactory =
>,
usageCollection?: UsageCounter
) => {
router.versioned.get({ path, access: 'internal' }).addVersion(
{
version: '1',
router.versioned
.get({
path,
access: 'internal',
security: {
authz: {
enabled: false,
reason: 'Authorization provided by saved objects client',
},
},
})
.addVersion(
{
version: '1',
validate: {
request: {},
response: {

View file

@ -79,14 +79,20 @@ const runtimeCreateFieldRouteFactory =
>,
usageCollection?: UsageCounter
) => {
router.versioned.post({ path, access: 'public', description }).addVersion(
{
version: INITIAL_REST_VERSION,
router.versioned
.post({
path,
access: 'public',
description,
security: {
authz: {
requiredPrivileges: ['indexPatterns:manage'],
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
params: schema.object({

View file

@ -62,14 +62,20 @@ const deleteRuntimeFieldRouteFactory =
>,
usageCollection?: UsageCounter
) => {
router.versioned.delete({ path, access: 'public', description }).addVersion(
{
version: INITIAL_REST_VERSION,
router.versioned
.delete({
path,
access: 'public',
description,
security: {
authz: {
requiredPrivileges: ['indexPatterns:manage'],
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
params: schema.object({

View file

@ -70,15 +70,21 @@ const getRuntimeFieldRouteFactory =
>,
usageCollection?: UsageCounter
) => {
router.versioned.get({ path, access: 'public', description }).addVersion(
{
version: INITIAL_REST_VERSION,
router.versioned
.get({
path,
access: 'public',
description,
security: {
authz: {
enabled: false,
reason: 'Authorization provided by saved objects client',
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
params: schema.object({

View file

@ -78,14 +78,20 @@ const putRuntimeFieldRouteFactory =
>,
usageCollection?: UsageCounter
) => {
router.versioned.put({ path, access: 'public', description }).addVersion(
{
version: INITIAL_REST_VERSION,
router.versioned
.put({
path,
access: 'public',
description,
security: {
authz: {
requiredPrivileges: ['indexPatterns:manage'],
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
params: schema.object({

View file

@ -78,14 +78,20 @@ const updateRuntimeFieldRouteFactory =
>,
usageCollection?: UsageCounter
) => {
router.versioned.post({ path, access: 'public', description }).addVersion(
{
version: INITIAL_REST_VERSION,
router.versioned
.post({
path,
access: 'public',
description,
security: {
authz: {
requiredPrivileges: ['indexPatterns:manage'],
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
params: schema.object({

View file

@ -27,15 +27,18 @@ export const registerCreateScriptedFieldRoute = (
>
) => {
router.versioned
.post({ path: '/api/index_patterns/index_pattern/{id}/scripted_field', access: 'public' })
.addVersion(
{
version: INITIAL_REST_VERSION,
.post({
path: '/api/index_patterns/index_pattern/{id}/scripted_field',
access: 'public',
security: {
authz: {
requiredPrivileges: ['indexPatterns:manage'],
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
params: schema.object(

View file

@ -28,15 +28,15 @@ export const registerDeleteScriptedFieldRoute = (
.delete({
path: '/api/index_patterns/index_pattern/{id}/scripted_field/{name}',
access: 'public',
})
.addVersion(
{
version: INITIAL_REST_VERSION,
security: {
authz: {
requiredPrivileges: ['indexPatterns:manage'],
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
params: schema.object(

View file

@ -27,16 +27,19 @@ export const registerGetScriptedFieldRoute = (
>
) => {
router.versioned
.get({ path: '/api/index_patterns/index_pattern/{id}/scripted_field/{name}', access: 'public' })
.addVersion(
{
version: INITIAL_REST_VERSION,
.get({
path: '/api/index_patterns/index_pattern/{id}/scripted_field/{name}',
access: 'public',
security: {
authz: {
enabled: false,
reason: 'Authorization provided by saved objects client',
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
params: schema.object(

View file

@ -27,15 +27,18 @@ export const registerPutScriptedFieldRoute = (
>
) => {
router.versioned
.put({ path: '/api/index_patterns/index_pattern/{id}/scripted_field', access: 'public' })
.addVersion(
{
version: INITIAL_REST_VERSION,
.put({
path: '/api/index_patterns/index_pattern/{id}/scripted_field',
access: 'public',
security: {
authz: {
requiredPrivileges: ['indexPatterns:manage'],
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
params: schema.object(

View file

@ -32,15 +32,15 @@ export const registerUpdateScriptedFieldRoute = (
.post({
path: '/api/index_patterns/index_pattern/{id}/scripted_field/{name}',
access: 'public',
})
.addVersion(
{
version: INITIAL_REST_VERSION,
security: {
authz: {
requiredPrivileges: ['indexPatterns:manage'],
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
params: schema.object(

View file

@ -67,9 +67,11 @@ export const swapReferencesRoute =
const description = previewRoute
? PREVIEW_SWAP_REFERENCES_DESCRIPTION
: SWAP_REFERENCES_DESCRIPTION;
router.versioned.post({ path, access: 'public', description }).addVersion(
{
version: INITIAL_REST_VERSION,
router.versioned
.post({
path,
access: 'public',
description,
security: {
authz: {
enabled: false,
@ -78,6 +80,10 @@ export const swapReferencesRoute =
reason: 'Authorization provided by saved objects client',
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
body: schema.object({

View file

@ -144,14 +144,20 @@ const updateDataViewRouteFactory =
>,
usageCollection?: UsageCounter
) => {
router.versioned.post({ path, access: 'public', description }).addVersion(
{
version: INITIAL_REST_VERSION,
router.versioned
.post({
path,
access: 'public',
description,
security: {
authz: {
requiredPrivileges: ['indexPatterns:manage'],
},
},
})
.addVersion(
{
version: INITIAL_REST_VERSION,
validate: {
request: {
params: schema.object(

View file

@ -44,6 +44,12 @@ function registerRoute(
.versioned.post({
path: '/internal/telemetry/ebt_local_shipper',
access: 'internal',
security: {
authz: {
enabled: false,
reason: 'This route delegates authorization to the Elasticsearch client',
},
},
})
.addVersion(
{

View file

@ -100,17 +100,17 @@ export function registerTelemetryConfigRoutes({
access: 'internal',
path: FetchTelemetryConfigRoute,
options: { authRequired: 'optional' },
})
// Just because it used to be /v2/, we are creating identical v1 and v2.
.addVersion(
{
version: '1',
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
})
// Just because it used to be /v2/, we are creating identical v1 and v2.
.addVersion(
{
version: '1',
validate: v2Validations,
},
v2Handler
@ -131,15 +131,20 @@ export function registerTelemetryConfigRoutes({
// Register the deprecated public and path-based for BWC
// as we know this one is used by other Elastic products to fetch the opt-in status.
router.versioned.get({ access: 'public', path: FetchTelemetryConfigRoutePathBasedV2 }).addVersion(
{
version: '2023-10-31',
router.versioned
.get({
access: 'public',
path: FetchTelemetryConfigRoutePathBasedV2,
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
})
.addVersion(
{
version: '2023-10-31',
validate: v2Validations,
},
v2Handler

View file

@ -38,17 +38,20 @@ export function registerTelemetryLastReported(
};
router.versioned
.get({ access: 'internal', path: LastReportedRoute })
// Just because it used to be /v2/, we are creating identical v1 and v2.
.addVersion(
{
version: '1',
.get({
access: 'internal',
path: LastReportedRoute,
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
})
// Just because it used to be /v2/, we are creating identical v1 and v2.
.addVersion(
{
version: '1',
validate: v2GetValidations,
},
v2GetHandler
@ -56,12 +59,6 @@ export function registerTelemetryLastReported(
.addVersion(
{
version: '2',
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
validate: v2GetValidations,
},
v2GetHandler
@ -77,17 +74,20 @@ export function registerTelemetryLastReported(
};
router.versioned
.put({ access: 'internal', path: LastReportedRoute })
// Just because it used to be /v2/, we are creating identical v1 and v2.
.addVersion(
{
version: '1',
.put({
access: 'internal',
path: LastReportedRoute,
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
})
// Just because it used to be /v2/, we are creating identical v1 and v2.
.addVersion(
{
version: '1',
validate: false,
},
v2PutHandler
@ -95,12 +95,6 @@ export function registerTelemetryLastReported(
.addVersion(
{
version: '2',
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
validate: false,
},
v2PutHandler

View file

@ -126,17 +126,20 @@ export function registerTelemetryOptInRoutes({
};
router.versioned
.post({ access: 'internal', path: OptInRoute })
// Just because it used to be /v2/, we are creating identical v1 and v2.
.addVersion(
{
version: '1',
.post({
access: 'internal',
path: OptInRoute,
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
})
// Just because it used to be /v2/, we are creating identical v1 and v2.
.addVersion(
{
version: '1',
validate: v2Validations,
},
v2Handler

View file

@ -68,16 +68,16 @@ export function registerTelemetryOptInStatsRoutes(
.post({
access: 'public', // It's not used across Kibana, and I didn't want to remove it in this PR just in case.
path: GetOptInStatsRoutePathBasedV2,
})
.addVersion(
{
version: '2023-10-31',
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
})
.addVersion(
{
version: '2023-10-31',
validate: {
request: {
body: schema.object({

View file

@ -93,6 +93,12 @@ export function registerTelemetryUsageStatsRoutes(
router.versioned
.post({
access: 'internal',
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
path: FetchSnapshotTelemetry,
enableQueryVersion: true, // Allow specifying the version through querystring so that we can use it in Dev Console
})
@ -100,12 +106,6 @@ export function registerTelemetryUsageStatsRoutes(
.addVersion(
{
version: '1',
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
validate: v2Validations,
},
v2Handler

View file

@ -54,17 +54,20 @@ export function registerTelemetryUserHasSeenNotice(router: IRouter, currentKiban
};
router.versioned
.put({ access: 'internal', path: UserHasSeenNoticeRoute })
// Just because it used to be /v2/, we are creating identical v1 and v2.
.addVersion(
{
version: '1',
.put({
access: 'internal',
path: UserHasSeenNoticeRoute,
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
})
// Just because it used to be /v2/, we are creating identical v1 and v2.
.addVersion(
{
version: '1',
validate: false,
},
v2Handler

View file

@ -21,10 +21,6 @@ export function registerValueSuggestionsRoute(router: IRouter, config$: Observab
.post({
path: '/internal/kibana/suggestions/values/{index}',
access: 'internal',
})
.addVersion(
{
version: '1',
security: {
authz: {
enabled: false,
@ -32,6 +28,10 @@ export function registerValueSuggestionsRoute(router: IRouter, config$: Observab
'This route is opted out from authorization because uses the current user authorizations.',
},
},
})
.addVersion(
{
version: '1',
validate: {
request: {
params: schema.object(

View file

@ -25,6 +25,12 @@ export class AnalyticsFTRHelpers implements Plugin {
router.post(
{
path: '/internal/analytics_ftr_helpers/opt_in',
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
validate: {
query: schema.object({
consent: schema.boolean(),
@ -43,6 +49,12 @@ export class AnalyticsFTRHelpers implements Plugin {
router.get(
{
path: '/internal/analytics_ftr_helpers/events',
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
validate: {
query: schema.object({
takeNumberOfEvents: schema.number({ min: 1 }),
@ -77,6 +89,12 @@ export class AnalyticsFTRHelpers implements Plugin {
router.get(
{
path: '/internal/analytics_ftr_helpers/count_events',
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
validate: {
query: schema.object({
eventTypes: schema.arrayOf(schema.string()),

View file

@ -59,6 +59,12 @@ export class AnalyticsPluginAPlugin implements Plugin {
router.get(
{
path: '/internal/analytics_plugin_a/stats',
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
validate: {
query: schema.object({
takeNumberOfCounters: schema.number({ min: 1 }),
@ -84,6 +90,12 @@ export class AnalyticsPluginAPlugin implements Plugin {
router.get(
{
path: '/internal/analytics_plugin_a/actions',
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
validate: false,
},
async (context, req, res) => {

View file

@ -19,6 +19,12 @@ export class NewsFeedSimulatorPlugin implements Plugin {
router.get(
{
path: `/api/_newsfeed-FTS-external-service-simulators/kibana/v${version}.json`,
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
validate: false,
options: { authRequired: false },
},
@ -30,6 +36,12 @@ export class NewsFeedSimulatorPlugin implements Plugin {
router.get(
{
path: '/api/_newsfeed-FTS-external-service-simulators/kibana/crash.json',
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
validate: false,
options: { authRequired: false },
},

View file

@ -14,6 +14,12 @@ export const generateOtelMetrics = (router: IRouter, metrics: Metrics) => {
router.post(
{
path: '/api/generate_otel_metrics',
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
validate: {},
},
async function (_context, _req, res): Promise<IKibanaResponse<{}>> {

View file

@ -14,36 +14,64 @@ export class HealthGatewayStatusPlugin implements Plugin<void, void> {
public setup(core: CoreSetup) {
const router = core.http.createRouter();
router.get({ path: '/health/ok/api/status', validate: {} }, async (context, req, res) =>
res.ok()
router.get(
{
path: '/health/ok/api/status',
security: { authz: { enabled: false, reason: '' } },
validate: {},
},
async (context, req, res) => res.ok()
);
router.get({ path: '/health/redirect/api/status', validate: {} }, async (context, req, res) =>
router.get(
{
path: '/health/redirect/api/status',
security: { authz: { enabled: false, reason: '' } },
validate: {},
},
async (context, req, res) =>
res.redirected({ headers: { location: '/health/ok/api/status' } })
);
router.get(
{ path: '/health/unauthorized/api/status', validate: {} },
{
path: '/health/unauthorized/api/status',
security: { authz: { enabled: false, reason: '' } },
validate: {},
},
async (context, req, res) =>
res.unauthorized({
headers: { 'www-authenticate': 'Basic' },
})
);
router.get({ path: '/health/not-found/api/status', validate: {} }, async (context, req, res) =>
res.notFound()
router.get(
{
path: '/health/not-found/api/status',
security: { authz: { enabled: false, reason: '' } },
validate: {},
},
async (context, req, res) => res.notFound()
);
router.get({ path: '/health/slow/api/status', validate: {} }, async (context, req, res) => {
router.get(
{
path: '/health/slow/api/status',
security: { authz: { enabled: false, reason: '' } },
validate: {},
},
async (context, req, res) => {
await new Promise((resolve) => setTimeout(resolve, 5000));
return res.ok();
});
}
);
const sessions = new Set<string>();
router.get(
{
path: '/health/flaky/api/status',
security: { authz: { enabled: false, reason: '' } },
validate: {
query: schema.object({ session: schema.string() }),
},

View file

@ -20,6 +20,12 @@ export const plugin: PluginInitializer<void, never> = async (
router.get(
{
path: '/test_endpoints/verification_code',
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
validate: false,
options: { authRequired: false },
},

View file

@ -25,6 +25,12 @@ export class TestPlugin implements Plugin<TestPluginSetup, TestPluginStart, {},
router.post(
{
path: '/api/interpreter_functional/run_expression',
security: {
authz: {
enabled: false,
reason: 'This route is opted out from authorization',
},
},
validate: {
body: schema.object({
input: schema.maybe(schema.nullable(schema.object({}, { unknowns: 'allow' }))),

Some files were not shown because too many files have changed in this diff Show more