diff --git a/packages/core/http/core-http-router-server-internal/src/request.ts b/packages/core/http/core-http-router-server-internal/src/request.ts index 7e8e927bd4671..26ac377c00bf3 100644 --- a/packages/core/http/core-http-router-server-internal/src/request.ts +++ b/packages/core/http/core-http-router-server-internal/src/request.ts @@ -201,6 +201,7 @@ export class CoreKibanaRequest< xsrfRequired: ((request.route?.settings as RouteOptions)?.app as KibanaRouteOptions)?.xsrfRequired ?? true, // some places in LP call KibanaRequest.from(request) manually. remove fallback to true before v8 + access: this.getAccess(request), tags: request.route?.settings?.tags || [], timeout: { payload: payloadTimeout, @@ -222,6 +223,13 @@ export class CoreKibanaRequest< options, }; } + /** infer route access from path if not declared */ + private getAccess(request: RawRequest): 'internal' | 'public' { + return ( + ((request.route?.settings as RouteOptions)?.app as KibanaRouteOptions)?.access ?? + (request.path.startsWith('/internal') ? 'internal' : 'public') + ); + } private getAuthRequired(request: RawRequest): boolean | 'optional' { if (isFakeRawRequest(request)) { diff --git a/packages/core/http/core-http-router-server-mocks/src/router.mock.ts b/packages/core/http/core-http-router-server-mocks/src/router.mock.ts index 1a3262fdf1f80..9b2d90e18640b 100644 --- a/packages/core/http/core-http-router-server-mocks/src/router.mock.ts +++ b/packages/core/http/core-http-router-server-mocks/src/router.mock.ts @@ -71,7 +71,7 @@ function createKibanaRequestMock
({
routeTags,
routeAuthRequired,
validation = {},
- kibanaRouteOptions = { xsrfRequired: true },
+ kibanaRouteOptions = { xsrfRequired: true, access: 'public' },
kibanaRequestState = {
requestId: '123',
requestUuid: '123e4567-e89b-12d3-a456-426614174000',
diff --git a/packages/core/http/core-http-server-internal/src/http_server.test.ts b/packages/core/http/core-http-server-internal/src/http_server.test.ts
index 92fa63c502558..b6a120e06ab8d 100644
--- a/packages/core/http/core-http-server-internal/src/http_server.test.ts
+++ b/packages/core/http/core-http-server-internal/src/http_server.test.ts
@@ -817,6 +817,56 @@ test('allows attaching metadata to attach meta-data tag strings to a route', asy
await supertest(innerServer.listener).get('/without-tags').expect(200, { tags: [] });
});
+test('allows declaring route access to flag a route as public or internal', async () => {
+ const access = 'internal';
+ const { registerRouter, server: innerServer } = await server.setup(config);
+
+ const router = new Router('', logger, enhanceWithContext);
+ router.get({ path: '/with-access', validate: false, options: { access } }, (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 } })
+ );
+ registerRouter(router);
+
+ await server.start();
+ await supertest(innerServer.listener).get('/with-access').expect(200, { access });
+
+ await supertest(innerServer.listener).get('/without-access').expect(200, { access: 'public' });
+});
+
+test('infers access flag from path if not defined', async () => {
+ const { registerRouter, server: innerServer } = await server.setup(config);
+
+ const router = new Router('', logger, enhanceWithContext);
+ router.get({ path: '/internal/foo', validate: false }, (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/internal/foo', validate: false }, (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 } })
+ );
+ registerRouter(router);
+
+ await server.start();
+ await supertest(innerServer.listener).get('/internal/foo').expect(200, { access: 'internal' });
+
+ await supertest(innerServer.listener).get('/random/foo').expect(200, { access: 'public' });
+ await supertest(innerServer.listener)
+ .get('/random/internal/foo')
+ .expect(200, { access: 'public' });
+ await supertest(innerServer.listener)
+ .get('/api/foo/internal/my-foo')
+ .expect(200, { access: 'public' });
+});
+
test('exposes route details of incoming request to a route handler', async () => {
const { registerRouter, server: innerServer } = await server.setup(config);
@@ -833,6 +883,7 @@ test('exposes route details of incoming request to a route handler', async () =>
options: {
authRequired: true,
xsrfRequired: false,
+ access: 'public',
tags: [],
timeout: {},
},
@@ -1010,6 +1061,7 @@ test('exposes route details of incoming request to a route handler (POST + paylo
options: {
authRequired: true,
xsrfRequired: true,
+ access: 'public',
tags: [],
timeout: {
payload: 10000,
diff --git a/packages/core/http/core-http-server-internal/src/http_server.ts b/packages/core/http/core-http-server-internal/src/http_server.ts
index fb19795d77dce..1ef5be6c67a54 100644
--- a/packages/core/http/core-http-server-internal/src/http_server.ts
+++ b/packages/core/http/core-http-server-internal/src/http_server.ts
@@ -524,6 +524,7 @@ export class HttpServer {
const kibanaRouteOptions: KibanaRouteOptions = {
xsrfRequired: route.options.xsrfRequired ?? !isSafeMethod(route.method),
+ access: route.options.access ?? (route.path.startsWith('/internal') ? 'internal' : 'public'),
};
this.server!.route({
diff --git a/packages/core/http/core-http-server-internal/src/lifecycle_handlers.test.ts b/packages/core/http/core-http-server-internal/src/lifecycle_handlers.test.ts
index 5e182005fd40c..d13bd001bbbb9 100644
--- a/packages/core/http/core-http-server-internal/src/lifecycle_handlers.test.ts
+++ b/packages/core/http/core-http-server-internal/src/lifecycle_handlers.test.ts
@@ -167,6 +167,7 @@ describe('xsrf post-auth handler', () => {
path: '/some-path',
kibanaRouteOptions: {
xsrfRequired: false,
+ access: 'public',
},
});
diff --git a/packages/core/http/core-http-server-internal/src/lifecycle_handlers.ts b/packages/core/http/core-http-server-internal/src/lifecycle_handlers.ts
index 3fe9c8ac727ff..af148413265e8 100644
--- a/packages/core/http/core-http-server-internal/src/lifecycle_handlers.ts
+++ b/packages/core/http/core-http-server-internal/src/lifecycle_handlers.ts
@@ -60,6 +60,7 @@ export const createVersionCheckPostAuthHandler = (kibanaVersion: string): OnPost
};
};
+// TODO: implement header required for accessing internal routes. See https://github.com/elastic/kibana/issues/151940
export const createCustomHeadersPreResponseHandler = (config: HttpConfig): OnPreResponseHandler => {
const {
name: serverName,
diff --git a/packages/core/http/core-http-server/src/router/request.ts b/packages/core/http/core-http-server/src/router/request.ts
index ef33bec14f841..e0664cb1ea29a 100644
--- a/packages/core/http/core-http-server/src/router/request.ts
+++ b/packages/core/http/core-http-server/src/router/request.ts
@@ -19,6 +19,7 @@ import type { Headers } from './headers';
*/
export interface KibanaRouteOptions extends RouteOptionsApp {
xsrfRequired: boolean;
+ access: 'internal' | 'public';
}
/**
diff --git a/packages/core/http/core-http-server/src/router/route.ts b/packages/core/http/core-http-server/src/router/route.ts
index 78d76bb4ba7b8..e2b11aec08e1a 100644
--- a/packages/core/http/core-http-server/src/router/route.ts
+++ b/packages/core/http/core-http-server/src/router/route.ts
@@ -120,6 +120,18 @@ export interface RouteConfigOptions