Added product header check (#112180)
* Added product header check * Added suggestions from code review
This commit is contained in:
parent
e15f74ea1d
commit
117e076200
|
@ -57,6 +57,13 @@ describe('ElasticsearchService', () => {
|
||||||
return mockConnectionStatusClient;
|
return mockConnectionStatusClient;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
mockPingClient.asInternalUser.transport.request.mockResolvedValue(
|
||||||
|
interactiveSetupMock.createApiResponse({
|
||||||
|
statusCode: 200,
|
||||||
|
body: {},
|
||||||
|
headers: { 'x-elastic-product': 'Elasticsearch' },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
setupContract = service.setup({
|
setupContract = service.setup({
|
||||||
elasticsearch: mockElasticsearchPreboot,
|
elasticsearch: mockElasticsearchPreboot,
|
||||||
|
@ -537,6 +544,19 @@ some weird+ca/with
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('fails if host is not Elasticsearch', async () => {
|
||||||
|
mockPingClient.asInternalUser.ping.mockResolvedValue(
|
||||||
|
interactiveSetupMock.createApiResponse({ statusCode: 200, body: true })
|
||||||
|
);
|
||||||
|
mockPingClient.asInternalUser.transport.request.mockResolvedValue(
|
||||||
|
interactiveSetupMock.createApiResponse({ statusCode: 200, body: {}, headers: {} })
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(setupContract.ping('http://localhost:9200')).rejects.toMatchInlineSnapshot(
|
||||||
|
`[Error: Host did not respond with valid Elastic product header.]`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('succeeds if host does not require authentication', async () => {
|
it('succeeds if host does not require authentication', async () => {
|
||||||
mockPingClient.asInternalUser.ping.mockResolvedValue(
|
mockPingClient.asInternalUser.ping.mockResolvedValue(
|
||||||
interactiveSetupMock.createApiResponse({ statusCode: 200, body: true })
|
interactiveSetupMock.createApiResponse({ statusCode: 200, body: true })
|
||||||
|
|
|
@ -290,6 +290,7 @@ export class ElasticsearchService {
|
||||||
ssl: { verificationMode: 'none' },
|
ssl: { verificationMode: 'none' },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.logger.debug(`Connecting to host "${host}"`);
|
||||||
let authRequired = false;
|
let authRequired = false;
|
||||||
try {
|
try {
|
||||||
await client.asInternalUser.ping();
|
await client.asInternalUser.ping();
|
||||||
|
@ -304,10 +305,9 @@ export class ElasticsearchService {
|
||||||
}
|
}
|
||||||
|
|
||||||
authRequired = getErrorStatusCode(error) === 401;
|
authRequired = getErrorStatusCode(error) === 401;
|
||||||
} finally {
|
|
||||||
await client.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.logger.debug(`Fetching certificate chain from host "${host}"`);
|
||||||
let certificateChain: Certificate[] | undefined;
|
let certificateChain: Certificate[] | undefined;
|
||||||
const { protocol, hostname, port } = new URL(host);
|
const { protocol, hostname, port } = new URL(host);
|
||||||
if (protocol === 'https:') {
|
if (protocol === 'https:') {
|
||||||
|
@ -320,10 +320,32 @@ export class ElasticsearchService {
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
`Failed to fetch peer certificate from host "${host}": ${getDetailedErrorMessage(error)}`
|
`Failed to fetch peer certificate from host "${host}": ${getDetailedErrorMessage(error)}`
|
||||||
);
|
);
|
||||||
|
await client.close();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This check is a security requirement - Do not remove it!
|
||||||
|
this.logger.debug(`Verifying that host "${host}" responds with Elastic product header`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await client.asInternalUser.transport.request({
|
||||||
|
method: 'OPTIONS',
|
||||||
|
path: '/',
|
||||||
|
});
|
||||||
|
if (response.headers?.['x-elastic-product'] !== 'Elasticsearch') {
|
||||||
|
throw new Error('Host did not respond with valid Elastic product header.');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(
|
||||||
|
`Host "${host}" is not a valid Elasticsearch cluster: ${getDetailedErrorMessage(error)}`
|
||||||
|
);
|
||||||
|
await client.close();
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
await client.close();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
authRequired,
|
authRequired,
|
||||||
certificateChain,
|
certificateChain,
|
||||||
|
|
Loading…
Reference in a new issue