From 0987f70112aeeef0ffa9b670d86a5b5f82d60454 Mon Sep 17 00:00:00 2001 From: Kevin Lacabane Date: Fri, 13 Sep 2024 04:32:13 +0200 Subject: [PATCH] [core] get headers from fakeRequest in secondary user client (#192394) ## Summary Closes https://github.com/elastic/kibana/issues/192004 Calling `client.asSecondaryAuthUser` from a client scoped to a fake request instantiated with `getKibanaFakeRequest` returns the following error: `Error: asSecondaryAuthUser called from a client scoped to a request without 'authorization' header.`. This is because we use the same branch when dealing with a real or fake request and expect the headers to be cached. There are existing tests to verify a fake request works but these requests are raw objects not created through `getKibanaFakeRequest` ### Testing This snippet does not throw ``` const fakeRequest = getFakeKibanaRequest({ id: apiKey.id, api_key: apiKey.apiKey }); const esClient = server.core.elasticsearch.client.asScoped(fakeRequest).asSecondaryAuthUser; ``` --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../src/cluster_client.test.ts | 37 +++++++++++++++++++ .../src/cluster_client.ts | 7 ++-- .../src/router.mock.ts | 14 +++++++ .../src/http_server.mocks.ts | 1 + 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/cluster_client.test.ts b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/cluster_client.test.ts index 8ba9f8aae6549..ae938603bd1da 100644 --- a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/cluster_client.test.ts +++ b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/cluster_client.test.ts @@ -936,6 +936,43 @@ describe('ClusterClient', () => { ); }); + it('uses the authorization header from the request when using a `KibanaFakeRequest`', () => { + const config = createConfig({ + requestHeadersWhitelist: ['authorization', 'foo'], + }); + authHeaders.get.mockReturnValue({ + [AUTHORIZATION_HEADER]: 'will_not_be_used', + }); + + const clusterClient = new ClusterClient({ + config, + logger, + type: 'custom-type', + authHeaders, + agentFactoryProvider, + kibanaVersion, + }); + + const request = httpServerMock.createFakeKibanaRequest({ + headers: { + authorization: 'fake_request_auth', + }, + }); + + const scopedClusterClient = clusterClient.asScoped(request); + // trigger client instantiation via getter + client = scopedClusterClient.asSecondaryAuthUser; + + expect(internalClient.child).toHaveBeenCalledTimes(1); + expect(internalClient.child).toHaveBeenCalledWith( + expect.objectContaining({ + headers: expect.objectContaining({ + [ES_SECONDARY_AUTH_HEADER]: request.headers.authorization, + }), + }) + ); + }); + it('throws when used with a `FakeRequest` without authorization header', () => { const config = createConfig({ requestHeadersWhitelist: ['authorization', 'foo'], diff --git a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/cluster_client.ts b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/cluster_client.ts index 54db27b618635..141c564ee5538 100644 --- a/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/cluster_client.ts +++ b/packages/core/elasticsearch/core-elasticsearch-client-server-internal/src/cluster_client.ts @@ -164,9 +164,10 @@ export class ClusterClient implements ICustomClusterClient { } private getSecondaryAuthHeaders(request: ScopeableRequest): Headers { - const headerSource = isRealRequest(request) - ? this.authHeaders?.get(request) ?? {} - : request.headers; + const headerSource = + isRealRequest(request) && !request.isFakeRequest + ? this.authHeaders?.get(request) ?? {} + : request.headers; const authorizationHeader = Object.entries(headerSource).find(([key, value]) => { return key.toLowerCase() === AUTHORIZATION_HEADER && value !== undefined; }); 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 f208bc1765008..858c0753eeb2d 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 @@ -118,6 +118,19 @@ function createKibanaRequestMock

({ ); } +function createFakeKibanaRequestMock({ + headers = { accept: 'something/html' }, +}: { + headers?: Record; +}): KibanaRequest { + const fakeRequest = { + headers, + path: '/', + }; + + return CoreKibanaRequest.from(fakeRequest); +} + const createResponseFactoryMock = (): jest.Mocked => ({ ok: jest.fn(), created: jest.fn(), @@ -140,5 +153,6 @@ const createResponseFactoryMock = (): jest.Mocked => ({ export const mockRouter = { create: createRouterMock, createKibanaRequest: createKibanaRequestMock, + createFakeKibanaRequest: createFakeKibanaRequestMock, createResponseFactory: createResponseFactoryMock, }; diff --git a/packages/core/http/core-http-server-mocks/src/http_server.mocks.ts b/packages/core/http/core-http-server-mocks/src/http_server.mocks.ts index 7910006323ca1..760090b39714a 100644 --- a/packages/core/http/core-http-server-mocks/src/http_server.mocks.ts +++ b/packages/core/http/core-http-server-mocks/src/http_server.mocks.ts @@ -39,6 +39,7 @@ const createToolkitMock = (): ToolkitMock => { export const httpServerMock = { createKibanaRequest: mockRouter.createKibanaRequest, + createFakeKibanaRequest: mockRouter.createFakeKibanaRequest, createRawRequest: hapiMocks.createRequest, createResponseFactory: mockRouter.createResponseFactory, createLifecycleResponseFactory: createLifecycleResponseFactoryMock,