[8.x] [core] get headers from fakeRequest in secondary user client (#192394) (#193815)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[core] get headers from fakeRequest in secondary user client
(#192394)](https://github.com/elastic/kibana/pull/192394)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Kevin
Lacabane","email":"kevin.lacabane@elastic.co"},"sourceCommit":{"committedDate":"2024-09-13T02:32:13Z","message":"[core]
get headers from fakeRequest in secondary user client (#192394)\n\n##
Summary\r\n\r\nCloses
https://github.com/elastic/kibana/issues/192004\r\n\r\nCalling
`client.asSecondaryAuthUser` from a client scoped to a fake\r\nrequest
instantiated with `getKibanaFakeRequest` returns the
following\r\nerror:\r\n`Error: asSecondaryAuthUser called from a client
scoped to a request\r\nwithout 'authorization' header.`.\r\n\r\nThis is
because we use the same branch when dealing with a real or
fake\r\nrequest and expect the headers to be cached. There are existing
tests to\r\nverify a fake request works but these requests are raw
objects not\r\ncreated through `getKibanaFakeRequest`\r\n\r\n###
Testing\r\nThis snippet does not throw\r\n```\r\nconst fakeRequest =
getFakeKibanaRequest({ id: apiKey.id, api_key: apiKey.apiKey
});\r\nconst esClient =
server.core.elasticsearch.client.asScoped(fakeRequest).asSecondaryAuthUser;\r\n```\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"0987f70112aeeef0ffa9b670d86a5b5f82d60454","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","backport:prev-minor"],"title":"[core]
get headers from fakeRequest in secondary user
client","number":192394,"url":"https://github.com/elastic/kibana/pull/192394","mergeCommit":{"message":"[core]
get headers from fakeRequest in secondary user client (#192394)\n\n##
Summary\r\n\r\nCloses
https://github.com/elastic/kibana/issues/192004\r\n\r\nCalling
`client.asSecondaryAuthUser` from a client scoped to a fake\r\nrequest
instantiated with `getKibanaFakeRequest` returns the
following\r\nerror:\r\n`Error: asSecondaryAuthUser called from a client
scoped to a request\r\nwithout 'authorization' header.`.\r\n\r\nThis is
because we use the same branch when dealing with a real or
fake\r\nrequest and expect the headers to be cached. There are existing
tests to\r\nverify a fake request works but these requests are raw
objects not\r\ncreated through `getKibanaFakeRequest`\r\n\r\n###
Testing\r\nThis snippet does not throw\r\n```\r\nconst fakeRequest =
getFakeKibanaRequest({ id: apiKey.id, api_key: apiKey.apiKey
});\r\nconst esClient =
server.core.elasticsearch.client.asScoped(fakeRequest).asSecondaryAuthUser;\r\n```\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"0987f70112aeeef0ffa9b670d86a5b5f82d60454"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/192394","number":192394,"mergeCommit":{"message":"[core]
get headers from fakeRequest in secondary user client (#192394)\n\n##
Summary\r\n\r\nCloses
https://github.com/elastic/kibana/issues/192004\r\n\r\nCalling
`client.asSecondaryAuthUser` from a client scoped to a fake\r\nrequest
instantiated with `getKibanaFakeRequest` returns the
following\r\nerror:\r\n`Error: asSecondaryAuthUser called from a client
scoped to a request\r\nwithout 'authorization' header.`.\r\n\r\nThis is
because we use the same branch when dealing with a real or
fake\r\nrequest and expect the headers to be cached. There are existing
tests to\r\nverify a fake request works but these requests are raw
objects not\r\ncreated through `getKibanaFakeRequest`\r\n\r\n###
Testing\r\nThis snippet does not throw\r\n```\r\nconst fakeRequest =
getFakeKibanaRequest({ id: apiKey.id, api_key: apiKey.apiKey
});\r\nconst esClient =
server.core.elasticsearch.client.asScoped(fakeRequest).asSecondaryAuthUser;\r\n```\r\n\r\n---------\r\n\r\nCo-authored-by:
kibanamachine
<42973632+kibanamachine@users.noreply.github.com>","sha":"0987f70112aeeef0ffa9b670d86a5b5f82d60454"}}]}]
BACKPORT-->

Co-authored-by: Kevin Lacabane <kevin.lacabane@elastic.co>
This commit is contained in:
Kibana Machine 2024-09-24 16:57:44 +10:00 committed by GitHub
parent 64e46465d1
commit 022813ba21
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 56 additions and 3 deletions

View file

@ -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'],

View file

@ -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;
});

View file

@ -118,6 +118,19 @@ function createKibanaRequestMock<P = any, Q = any, B = any>({
);
}
function createFakeKibanaRequestMock({
headers = { accept: 'something/html' },
}: {
headers?: Record<string, string>;
}): KibanaRequest {
const fakeRequest = {
headers,
path: '/',
};
return CoreKibanaRequest.from(fakeRequest);
}
const createResponseFactoryMock = (): jest.Mocked<KibanaResponseFactory> => ({
ok: jest.fn(),
created: jest.fn(),
@ -140,5 +153,6 @@ const createResponseFactoryMock = (): jest.Mocked<KibanaResponseFactory> => ({
export const mockRouter = {
create: createRouterMock,
createKibanaRequest: createKibanaRequestMock,
createFakeKibanaRequest: createFakeKibanaRequestMock,
createResponseFactory: createResponseFactoryMock,
};

View file

@ -39,6 +39,7 @@ const createToolkitMock = (): ToolkitMock => {
export const httpServerMock = {
createKibanaRequest: mockRouter.createKibanaRequest,
createFakeKibanaRequest: mockRouter.createFakeKibanaRequest,
createRawRequest: hapiMocks.createRequest,
createResponseFactory: mockRouter.createResponseFactory,
createLifecycleResponseFactory: createLifecycleResponseFactoryMock,