Added product header check (#112180)

* Added product header check

* Added suggestions from code review
This commit is contained in:
Thom Heymann 2021-09-16 16:14:26 +01:00 committed by GitHub
parent e15f74ea1d
commit 117e076200
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 44 additions and 2 deletions

View file

@ -57,6 +57,13 @@ describe('ElasticsearchService', () => {
return mockConnectionStatusClient;
}
});
mockPingClient.asInternalUser.transport.request.mockResolvedValue(
interactiveSetupMock.createApiResponse({
statusCode: 200,
body: {},
headers: { 'x-elastic-product': 'Elasticsearch' },
})
);
setupContract = service.setup({
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 () => {
mockPingClient.asInternalUser.ping.mockResolvedValue(
interactiveSetupMock.createApiResponse({ statusCode: 200, body: true })

View file

@ -290,6 +290,7 @@ export class ElasticsearchService {
ssl: { verificationMode: 'none' },
});
this.logger.debug(`Connecting to host "${host}"`);
let authRequired = false;
try {
await client.asInternalUser.ping();
@ -304,10 +305,9 @@ export class ElasticsearchService {
}
authRequired = getErrorStatusCode(error) === 401;
} finally {
await client.close();
}
this.logger.debug(`Fetching certificate chain from host "${host}"`);
let certificateChain: Certificate[] | undefined;
const { protocol, hostname, port } = new URL(host);
if (protocol === 'https:') {
@ -320,10 +320,32 @@ export class ElasticsearchService {
this.logger.error(
`Failed to fetch peer certificate from host "${host}": ${getDetailedErrorMessage(error)}`
);
await client.close();
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 {
authRequired,
certificateChain,