Kibana request headers (#79218)
* Adding X-Kibana header for the legacy client requests * Specifying `X-Kibana: true` header for all requests coming from Kibana * Dev Tools now override the X-Kibana header to false * DevTools doesn't need to do anything, it's not using the ES client * Switching from `X-Kibana: true` to `User-Agent: Kibana` * Switching from `X-Kibana: true` to `User-Agent: Kibana` * Adding a constant * Starting to add unit tests... We currently allow end-users to set whatever headers they'd like to be forwarded to Elasticsearch with `elasticsearch.customHeaders` and `elasticsearch.requestHeadersWhitelist`. This is potentially problematic with us always specifying `User-Agent: kibana` as it could interfere with what our end-users have done... * Switching from user-agent to X-elastic-product-origin * Adding some tests * Adding and updating the legacy client unit tests T# * /s/KIBANA_HEADERS/DEFAULT_HEADERS and a deepFreeze * Adding comment for why `x-elastic-product-origin` exists
This commit is contained in:
parent
9794188cbf
commit
1ad68fdef7
|
@ -19,6 +19,7 @@
|
|||
|
||||
import { duration } from 'moment';
|
||||
import { ElasticsearchClientConfig, parseClientOptions } from './client_config';
|
||||
import { DEFAULT_HEADERS } from '../default_headers';
|
||||
|
||||
const createConfig = (
|
||||
parts: Partial<ElasticsearchClientConfig> = {}
|
||||
|
@ -36,6 +37,18 @@ const createConfig = (
|
|||
};
|
||||
|
||||
describe('parseClientOptions', () => {
|
||||
it('includes headers designing the HTTP request as originating from Kibana by default', () => {
|
||||
const config = createConfig({});
|
||||
|
||||
expect(parseClientOptions(config, false)).toEqual(
|
||||
expect.objectContaining({
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
describe('basic options', () => {
|
||||
it('`customHeaders` option', () => {
|
||||
const config = createConfig({
|
||||
|
@ -48,6 +61,7 @@ describe('parseClientOptions', () => {
|
|||
expect(parseClientOptions(config, false)).toEqual(
|
||||
expect.objectContaining({
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
foo: 'bar',
|
||||
hello: 'dolly',
|
||||
},
|
||||
|
@ -55,6 +69,25 @@ describe('parseClientOptions', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('`customHeaders` take precedence to default kibana headers', () => {
|
||||
const customHeader = {
|
||||
[Object.keys(DEFAULT_HEADERS)[0]]: 'foo',
|
||||
};
|
||||
const config = createConfig({
|
||||
customHeaders: {
|
||||
...customHeader,
|
||||
},
|
||||
});
|
||||
|
||||
expect(parseClientOptions(config, false)).toEqual(
|
||||
expect.objectContaining({
|
||||
headers: {
|
||||
...customHeader,
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('`keepAlive` option', () => {
|
||||
expect(parseClientOptions(createConfig({ keepAlive: true }), false)).toEqual(
|
||||
expect.objectContaining({ agent: { keepAlive: true } })
|
||||
|
|
|
@ -22,6 +22,7 @@ import { URL } from 'url';
|
|||
import { Duration } from 'moment';
|
||||
import { ClientOptions, NodeOptions } from '@elastic/elasticsearch';
|
||||
import { ElasticsearchConfig } from '../elasticsearch_config';
|
||||
import { DEFAULT_HEADERS } from '../default_headers';
|
||||
|
||||
/**
|
||||
* Configuration options to be used to create a {@link IClusterClient | cluster client} using the
|
||||
|
@ -61,7 +62,10 @@ export function parseClientOptions(
|
|||
const clientOptions: ClientOptions = {
|
||||
sniffOnStart: config.sniffOnStart,
|
||||
sniffOnConnectionFault: config.sniffOnConnectionFault,
|
||||
headers: config.customHeaders,
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
...config.customHeaders,
|
||||
},
|
||||
};
|
||||
|
||||
if (config.pingTimeout != null) {
|
||||
|
|
|
@ -24,6 +24,7 @@ import { GetAuthHeaders } from '../../http';
|
|||
import { elasticsearchClientMock } from './mocks';
|
||||
import { ClusterClient } from './cluster_client';
|
||||
import { ElasticsearchClientConfig } from './client_config';
|
||||
import { DEFAULT_HEADERS } from '../default_headers';
|
||||
|
||||
const createConfig = (
|
||||
parts: Partial<ElasticsearchClientConfig> = {}
|
||||
|
@ -127,7 +128,7 @@ describe('ClusterClient', () => {
|
|||
|
||||
expect(scopedClient.child).toHaveBeenCalledTimes(1);
|
||||
expect(scopedClient.child).toHaveBeenCalledWith({
|
||||
headers: { foo: 'bar', 'x-opaque-id': expect.any(String) },
|
||||
headers: { ...DEFAULT_HEADERS, foo: 'bar', 'x-opaque-id': expect.any(String) },
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -147,7 +148,7 @@ describe('ClusterClient', () => {
|
|||
|
||||
expect(scopedClient.child).toHaveBeenCalledTimes(1);
|
||||
expect(scopedClient.child).toHaveBeenCalledWith({
|
||||
headers: { authorization: 'auth', 'x-opaque-id': expect.any(String) },
|
||||
headers: { ...DEFAULT_HEADERS, authorization: 'auth', 'x-opaque-id': expect.any(String) },
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -171,7 +172,7 @@ describe('ClusterClient', () => {
|
|||
|
||||
expect(scopedClient.child).toHaveBeenCalledTimes(1);
|
||||
expect(scopedClient.child).toHaveBeenCalledWith({
|
||||
headers: { authorization: 'auth', 'x-opaque-id': expect.any(String) },
|
||||
headers: { ...DEFAULT_HEADERS, authorization: 'auth', 'x-opaque-id': expect.any(String) },
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -193,6 +194,7 @@ describe('ClusterClient', () => {
|
|||
expect(scopedClient.child).toHaveBeenCalledTimes(1);
|
||||
expect(scopedClient.child).toHaveBeenCalledWith({
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
foo: 'bar',
|
||||
hello: 'dolly',
|
||||
'x-opaque-id': expect.any(String),
|
||||
|
@ -214,6 +216,7 @@ describe('ClusterClient', () => {
|
|||
expect(scopedClient.child).toHaveBeenCalledTimes(1);
|
||||
expect(scopedClient.child).toHaveBeenCalledWith({
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
'x-opaque-id': 'my-fake-id',
|
||||
},
|
||||
});
|
||||
|
@ -239,6 +242,7 @@ describe('ClusterClient', () => {
|
|||
expect(scopedClient.child).toHaveBeenCalledTimes(1);
|
||||
expect(scopedClient.child).toHaveBeenCalledWith({
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
foo: 'auth',
|
||||
hello: 'dolly',
|
||||
'x-opaque-id': expect.any(String),
|
||||
|
@ -266,6 +270,7 @@ describe('ClusterClient', () => {
|
|||
expect(scopedClient.child).toHaveBeenCalledTimes(1);
|
||||
expect(scopedClient.child).toHaveBeenCalledWith({
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
foo: 'request',
|
||||
hello: 'dolly',
|
||||
'x-opaque-id': expect.any(String),
|
||||
|
@ -273,6 +278,52 @@ describe('ClusterClient', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('respect the precedence of config headers over default headers', () => {
|
||||
const headerKey = Object.keys(DEFAULT_HEADERS)[0];
|
||||
const config = createConfig({
|
||||
customHeaders: {
|
||||
[headerKey]: 'foo',
|
||||
},
|
||||
});
|
||||
getAuthHeaders.mockReturnValue({});
|
||||
|
||||
const clusterClient = new ClusterClient(config, logger, getAuthHeaders);
|
||||
const request = httpServerMock.createKibanaRequest();
|
||||
|
||||
clusterClient.asScoped(request);
|
||||
|
||||
expect(scopedClient.child).toHaveBeenCalledTimes(1);
|
||||
expect(scopedClient.child).toHaveBeenCalledWith({
|
||||
headers: {
|
||||
[headerKey]: 'foo',
|
||||
'x-opaque-id': expect.any(String),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('respect the precedence of request headers over default headers', () => {
|
||||
const headerKey = Object.keys(DEFAULT_HEADERS)[0];
|
||||
const config = createConfig({
|
||||
requestHeadersWhitelist: [headerKey],
|
||||
});
|
||||
getAuthHeaders.mockReturnValue({});
|
||||
|
||||
const clusterClient = new ClusterClient(config, logger, getAuthHeaders);
|
||||
const request = httpServerMock.createKibanaRequest({
|
||||
headers: { [headerKey]: 'foo' },
|
||||
});
|
||||
|
||||
clusterClient.asScoped(request);
|
||||
|
||||
expect(scopedClient.child).toHaveBeenCalledTimes(1);
|
||||
expect(scopedClient.child).toHaveBeenCalledWith({
|
||||
headers: {
|
||||
[headerKey]: 'foo',
|
||||
'x-opaque-id': expect.any(String),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('respect the precedence of x-opaque-id header over config headers', () => {
|
||||
const config = createConfig({
|
||||
customHeaders: {
|
||||
|
@ -292,6 +343,7 @@ describe('ClusterClient', () => {
|
|||
expect(scopedClient.child).toHaveBeenCalledTimes(1);
|
||||
expect(scopedClient.child).toHaveBeenCalledWith({
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
'x-opaque-id': 'from request',
|
||||
},
|
||||
});
|
||||
|
@ -315,7 +367,7 @@ describe('ClusterClient', () => {
|
|||
|
||||
expect(scopedClient.child).toHaveBeenCalledTimes(1);
|
||||
expect(scopedClient.child).toHaveBeenCalledWith({
|
||||
headers: { authorization: 'auth' },
|
||||
headers: { ...DEFAULT_HEADERS, authorization: 'auth' },
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -339,7 +391,7 @@ describe('ClusterClient', () => {
|
|||
|
||||
expect(scopedClient.child).toHaveBeenCalledTimes(1);
|
||||
expect(scopedClient.child).toHaveBeenCalledWith({
|
||||
headers: { foo: 'bar' },
|
||||
headers: { ...DEFAULT_HEADERS, foo: 'bar' },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -26,6 +26,7 @@ import { ElasticsearchClient } from './types';
|
|||
import { configureClient } from './configure_client';
|
||||
import { ElasticsearchClientConfig } from './client_config';
|
||||
import { ScopedClusterClient, IScopedClusterClient } from './scoped_cluster_client';
|
||||
import { DEFAULT_HEADERS } from '../default_headers';
|
||||
|
||||
const noop = () => undefined;
|
||||
|
||||
|
@ -108,6 +109,7 @@ export class ClusterClient implements ICustomClusterClient {
|
|||
}
|
||||
|
||||
return {
|
||||
...DEFAULT_HEADERS,
|
||||
...this.config.customHeaders,
|
||||
...scopedHeaders,
|
||||
};
|
||||
|
|
27
src/core/server/elasticsearch/default_headers.ts
Normal file
27
src/core/server/elasticsearch/default_headers.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { deepFreeze } from '@kbn/std';
|
||||
|
||||
export const DEFAULT_HEADERS = deepFreeze({
|
||||
// Elasticsearch uses this to identify when a request is coming from Kibana, to allow Kibana to
|
||||
// access system indices using the standard ES APIs without logging a warning. After migrating to
|
||||
// use the new system index APIs, this header can be removed.
|
||||
'x-elastic-product-origin': 'kibana',
|
||||
});
|
|
@ -23,6 +23,7 @@ import {
|
|||
LegacyElasticsearchClientConfig,
|
||||
parseElasticsearchClientConfig,
|
||||
} from './elasticsearch_client_config';
|
||||
import { DEFAULT_HEADERS } from '../default_headers';
|
||||
const logger = loggingSystemMock.create();
|
||||
afterEach(() => jest.clearAllMocks());
|
||||
|
||||
|
@ -41,26 +42,27 @@ test('parses minimally specified config', () => {
|
|||
logger.get()
|
||||
)
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"apiVersion": "master",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {
|
||||
"xsrf": "something",
|
||||
},
|
||||
"host": "localhost",
|
||||
"path": "/elasticsearch",
|
||||
"port": "80",
|
||||
"protocol": "http:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"sniffOnConnectionFault": false,
|
||||
"sniffOnStart": false,
|
||||
}
|
||||
`);
|
||||
"apiVersion": "master",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {
|
||||
"x-elastic-product-origin": "kibana",
|
||||
"xsrf": "something",
|
||||
},
|
||||
"host": "localhost",
|
||||
"path": "/elasticsearch",
|
||||
"port": "80",
|
||||
"protocol": "http:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"sniffOnConnectionFault": false,
|
||||
"sniffOnStart": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('parses fully specified config', () => {
|
||||
|
@ -104,63 +106,66 @@ test('parses fully specified config', () => {
|
|||
expect(elasticsearchConfig.ssl).not.toBe(elasticsearchClientConfig.ssl);
|
||||
|
||||
expect(elasticsearchClientConfig).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"apiVersion": "v7.0.0",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"auth": "elastic:changeme",
|
||||
"headers": Object {
|
||||
"xsrf": "something",
|
||||
"apiVersion": "v7.0.0",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"auth": "elastic:changeme",
|
||||
"headers": Object {
|
||||
"x-elastic-product-origin": "kibana",
|
||||
"xsrf": "something",
|
||||
},
|
||||
"host": "localhost",
|
||||
"path": "/elasticsearch",
|
||||
"port": "80",
|
||||
"protocol": "http:",
|
||||
"query": null,
|
||||
},
|
||||
Object {
|
||||
"auth": "elastic:changeme",
|
||||
"headers": Object {
|
||||
"x-elastic-product-origin": "kibana",
|
||||
"xsrf": "something",
|
||||
},
|
||||
"host": "domain.com",
|
||||
"path": "/elasticsearch",
|
||||
"port": "1234",
|
||||
"protocol": "http:",
|
||||
"query": null,
|
||||
},
|
||||
Object {
|
||||
"auth": "elastic:changeme",
|
||||
"headers": Object {
|
||||
"x-elastic-product-origin": "kibana",
|
||||
"xsrf": "something",
|
||||
},
|
||||
"host": "es.local",
|
||||
"path": "/",
|
||||
"port": "443",
|
||||
"protocol": "https:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"pingTimeout": 12345,
|
||||
"requestTimeout": 54321,
|
||||
"sniffInterval": 11223344,
|
||||
"sniffOnConnectionFault": true,
|
||||
"sniffOnStart": true,
|
||||
"ssl": Object {
|
||||
"ca": Array [
|
||||
"content-of-ca-path-1",
|
||||
"content-of-ca-path-2",
|
||||
],
|
||||
"cert": "content-of-certificate-path",
|
||||
"checkServerIdentity": [Function],
|
||||
"key": "content-of-key-path",
|
||||
"passphrase": "key-pass",
|
||||
"rejectUnauthorized": true,
|
||||
},
|
||||
"host": "localhost",
|
||||
"path": "/elasticsearch",
|
||||
"port": "80",
|
||||
"protocol": "http:",
|
||||
"query": null,
|
||||
},
|
||||
Object {
|
||||
"auth": "elastic:changeme",
|
||||
"headers": Object {
|
||||
"xsrf": "something",
|
||||
},
|
||||
"host": "domain.com",
|
||||
"path": "/elasticsearch",
|
||||
"port": "1234",
|
||||
"protocol": "http:",
|
||||
"query": null,
|
||||
},
|
||||
Object {
|
||||
"auth": "elastic:changeme",
|
||||
"headers": Object {
|
||||
"xsrf": "something",
|
||||
},
|
||||
"host": "es.local",
|
||||
"path": "/",
|
||||
"port": "443",
|
||||
"protocol": "https:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"pingTimeout": 12345,
|
||||
"requestTimeout": 54321,
|
||||
"sniffInterval": 11223344,
|
||||
"sniffOnConnectionFault": true,
|
||||
"sniffOnStart": true,
|
||||
"ssl": Object {
|
||||
"ca": Array [
|
||||
"content-of-ca-path-1",
|
||||
"content-of-ca-path-2",
|
||||
],
|
||||
"cert": "content-of-certificate-path",
|
||||
"checkServerIdentity": [Function],
|
||||
"key": "content-of-key-path",
|
||||
"passphrase": "key-pass",
|
||||
"rejectUnauthorized": true,
|
||||
},
|
||||
}
|
||||
`);
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('parses config timeouts of moment.Duration type', () => {
|
||||
|
@ -181,29 +186,30 @@ test('parses config timeouts of moment.Duration type', () => {
|
|||
logger.get()
|
||||
)
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"apiVersion": "master",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {
|
||||
"xsrf": "something",
|
||||
},
|
||||
"host": "localhost",
|
||||
"path": "/elasticsearch",
|
||||
"port": "9200",
|
||||
"protocol": "http:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"pingTimeout": 100,
|
||||
"requestTimeout": 30000,
|
||||
"sniffInterval": 60000,
|
||||
"sniffOnConnectionFault": false,
|
||||
"sniffOnStart": false,
|
||||
}
|
||||
`);
|
||||
"apiVersion": "master",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {
|
||||
"x-elastic-product-origin": "kibana",
|
||||
"xsrf": "something",
|
||||
},
|
||||
"host": "localhost",
|
||||
"path": "/elasticsearch",
|
||||
"port": "9200",
|
||||
"protocol": "http:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"pingTimeout": 100,
|
||||
"requestTimeout": 30000,
|
||||
"sniffInterval": 60000,
|
||||
"sniffOnConnectionFault": false,
|
||||
"sniffOnStart": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
describe('#auth', () => {
|
||||
|
@ -225,36 +231,38 @@ describe('#auth', () => {
|
|||
{ auth: false }
|
||||
)
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"apiVersion": "v7.0.0",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {
|
||||
"xsrf": "something",
|
||||
},
|
||||
"host": "localhost",
|
||||
"path": "/elasticsearch",
|
||||
"port": "80",
|
||||
"protocol": "http:",
|
||||
"query": null,
|
||||
},
|
||||
Object {
|
||||
"headers": Object {
|
||||
"xsrf": "something",
|
||||
},
|
||||
"host": "es.local",
|
||||
"path": "/",
|
||||
"port": "443",
|
||||
"protocol": "https:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"sniffOnConnectionFault": true,
|
||||
"sniffOnStart": true,
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"apiVersion": "v7.0.0",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {
|
||||
"x-elastic-product-origin": "kibana",
|
||||
"xsrf": "something",
|
||||
},
|
||||
"host": "localhost",
|
||||
"path": "/elasticsearch",
|
||||
"port": "80",
|
||||
"protocol": "http:",
|
||||
"query": null,
|
||||
},
|
||||
Object {
|
||||
"headers": Object {
|
||||
"x-elastic-product-origin": "kibana",
|
||||
"xsrf": "something",
|
||||
},
|
||||
"host": "es.local",
|
||||
"path": "/",
|
||||
"port": "443",
|
||||
"protocol": "https:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"sniffOnConnectionFault": true,
|
||||
"sniffOnStart": true,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('is not set if username is not specified', () => {
|
||||
|
@ -274,26 +282,27 @@ Object {
|
|||
{ auth: true }
|
||||
)
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"apiVersion": "v7.0.0",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {
|
||||
"xsrf": "something",
|
||||
},
|
||||
"host": "es.local",
|
||||
"path": "/",
|
||||
"port": "443",
|
||||
"protocol": "https:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"sniffOnConnectionFault": true,
|
||||
"sniffOnStart": true,
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"apiVersion": "v7.0.0",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {
|
||||
"x-elastic-product-origin": "kibana",
|
||||
"xsrf": "something",
|
||||
},
|
||||
"host": "es.local",
|
||||
"path": "/",
|
||||
"port": "443",
|
||||
"protocol": "https:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"sniffOnConnectionFault": true,
|
||||
"sniffOnStart": true,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('is not set if password is not specified', () => {
|
||||
|
@ -313,26 +322,48 @@ Object {
|
|||
{ auth: true }
|
||||
)
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"apiVersion": "v7.0.0",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {
|
||||
"xsrf": "something",
|
||||
Object {
|
||||
"apiVersion": "v7.0.0",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {
|
||||
"x-elastic-product-origin": "kibana",
|
||||
"xsrf": "something",
|
||||
},
|
||||
"host": "es.local",
|
||||
"path": "/",
|
||||
"port": "443",
|
||||
"protocol": "https:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"sniffOnConnectionFault": true,
|
||||
"sniffOnStart": true,
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#customHeaders', () => {
|
||||
test('override the default headers', () => {
|
||||
const headerKey = Object.keys(DEFAULT_HEADERS)[0];
|
||||
const parsedConfig = parseElasticsearchClientConfig(
|
||||
{
|
||||
apiVersion: 'master',
|
||||
customHeaders: { [headerKey]: 'foo' },
|
||||
logQueries: false,
|
||||
sniffOnStart: false,
|
||||
sniffOnConnectionFault: false,
|
||||
hosts: ['http://localhost/elasticsearch'],
|
||||
requestHeadersWhitelist: [],
|
||||
},
|
||||
"host": "es.local",
|
||||
"path": "/",
|
||||
"port": "443",
|
||||
"protocol": "https:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"sniffOnConnectionFault": true,
|
||||
"sniffOnStart": true,
|
||||
}
|
||||
`);
|
||||
logger.get()
|
||||
);
|
||||
expect(parsedConfig.hosts[0].headers).toEqual({
|
||||
[headerKey]: 'foo',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -361,24 +392,24 @@ describe('#log', () => {
|
|||
expect(typeof esLogger.close).toBe('function');
|
||||
|
||||
expect(loggingSystemMock.collect(logger)).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"debug": Array [],
|
||||
"error": Array [
|
||||
Array [
|
||||
"some-error",
|
||||
],
|
||||
],
|
||||
"fatal": Array [],
|
||||
"info": Array [],
|
||||
"log": Array [],
|
||||
"trace": Array [],
|
||||
"warn": Array [
|
||||
Array [
|
||||
"some-warning",
|
||||
],
|
||||
],
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"debug": Array [],
|
||||
"error": Array [
|
||||
Array [
|
||||
"some-error",
|
||||
],
|
||||
],
|
||||
"fatal": Array [],
|
||||
"info": Array [],
|
||||
"log": Array [],
|
||||
"trace": Array [],
|
||||
"warn": Array [
|
||||
Array [
|
||||
"some-warning",
|
||||
],
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('default logger with #logQueries = true', () => {
|
||||
|
@ -407,35 +438,35 @@ Object {
|
|||
expect(typeof esLogger.close).toBe('function');
|
||||
|
||||
expect(loggingSystemMock.collect(logger)).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"debug": Array [
|
||||
Array [
|
||||
"304
|
||||
METHOD /some-path
|
||||
?query=2",
|
||||
Object {
|
||||
"tags": Array [
|
||||
"query",
|
||||
"debug": Array [
|
||||
Array [
|
||||
"304
|
||||
METHOD /some-path
|
||||
?query=2",
|
||||
Object {
|
||||
"tags": Array [
|
||||
"query",
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
"error": Array [
|
||||
Array [
|
||||
"some-error",
|
||||
],
|
||||
],
|
||||
"fatal": Array [],
|
||||
"info": Array [],
|
||||
"log": Array [],
|
||||
"trace": Array [],
|
||||
"warn": Array [
|
||||
Array [
|
||||
"some-warning",
|
||||
],
|
||||
],
|
||||
}
|
||||
`);
|
||||
"error": Array [
|
||||
Array [
|
||||
"some-error",
|
||||
],
|
||||
],
|
||||
"fatal": Array [],
|
||||
"info": Array [],
|
||||
"log": Array [],
|
||||
"trace": Array [],
|
||||
"warn": Array [
|
||||
Array [
|
||||
"some-warning",
|
||||
],
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('custom logger', () => {
|
||||
|
@ -476,28 +507,30 @@ describe('#ssl', () => {
|
|||
logger.get()
|
||||
)
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"apiVersion": "v7.0.0",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {},
|
||||
"host": "es.local",
|
||||
"path": "/",
|
||||
"port": "443",
|
||||
"protocol": "https:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"sniffOnConnectionFault": true,
|
||||
"sniffOnStart": true,
|
||||
"ssl": Object {
|
||||
"ca": undefined,
|
||||
"rejectUnauthorized": false,
|
||||
},
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"apiVersion": "v7.0.0",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {
|
||||
"x-elastic-product-origin": "kibana",
|
||||
},
|
||||
"host": "es.local",
|
||||
"path": "/",
|
||||
"port": "443",
|
||||
"protocol": "https:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"sniffOnConnectionFault": true,
|
||||
"sniffOnStart": true,
|
||||
"ssl": Object {
|
||||
"ca": undefined,
|
||||
"rejectUnauthorized": false,
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('#verificationMode = certificate', () => {
|
||||
|
@ -521,29 +554,31 @@ Object {
|
|||
).toBeUndefined();
|
||||
|
||||
expect(clientConfig).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"apiVersion": "v7.0.0",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {},
|
||||
"host": "es.local",
|
||||
"path": "/",
|
||||
"port": "443",
|
||||
"protocol": "https:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"sniffOnConnectionFault": true,
|
||||
"sniffOnStart": true,
|
||||
"ssl": Object {
|
||||
"ca": undefined,
|
||||
"checkServerIdentity": [Function],
|
||||
"rejectUnauthorized": true,
|
||||
},
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"apiVersion": "v7.0.0",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {
|
||||
"x-elastic-product-origin": "kibana",
|
||||
},
|
||||
"host": "es.local",
|
||||
"path": "/",
|
||||
"port": "443",
|
||||
"protocol": "https:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"sniffOnConnectionFault": true,
|
||||
"sniffOnStart": true,
|
||||
"ssl": Object {
|
||||
"ca": undefined,
|
||||
"checkServerIdentity": [Function],
|
||||
"rejectUnauthorized": true,
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('#verificationMode = full', () => {
|
||||
|
@ -562,28 +597,30 @@ Object {
|
|||
logger.get()
|
||||
)
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"apiVersion": "v7.0.0",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {},
|
||||
"host": "es.local",
|
||||
"path": "/",
|
||||
"port": "443",
|
||||
"protocol": "https:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"sniffOnConnectionFault": true,
|
||||
"sniffOnStart": true,
|
||||
"ssl": Object {
|
||||
"ca": undefined,
|
||||
"rejectUnauthorized": true,
|
||||
},
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"apiVersion": "v7.0.0",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {
|
||||
"x-elastic-product-origin": "kibana",
|
||||
},
|
||||
"host": "es.local",
|
||||
"path": "/",
|
||||
"port": "443",
|
||||
"protocol": "https:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"sniffOnConnectionFault": true,
|
||||
"sniffOnStart": true,
|
||||
"ssl": Object {
|
||||
"ca": undefined,
|
||||
"rejectUnauthorized": true,
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('#verificationMode is unknown', () => {
|
||||
|
@ -628,30 +665,32 @@ Object {
|
|||
{ ignoreCertAndKey: true }
|
||||
)
|
||||
).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"apiVersion": "v7.0.0",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {},
|
||||
"host": "es.local",
|
||||
"path": "/",
|
||||
"port": "443",
|
||||
"protocol": "https:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"sniffOnConnectionFault": true,
|
||||
"sniffOnStart": true,
|
||||
"ssl": Object {
|
||||
"ca": Array [
|
||||
"content-of-ca-path",
|
||||
],
|
||||
"checkServerIdentity": [Function],
|
||||
"rejectUnauthorized": true,
|
||||
},
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"apiVersion": "v7.0.0",
|
||||
"hosts": Array [
|
||||
Object {
|
||||
"headers": Object {
|
||||
"x-elastic-product-origin": "kibana",
|
||||
},
|
||||
"host": "es.local",
|
||||
"path": "/",
|
||||
"port": "443",
|
||||
"protocol": "https:",
|
||||
"query": null,
|
||||
},
|
||||
],
|
||||
"keepAlive": true,
|
||||
"log": [Function],
|
||||
"sniffOnConnectionFault": true,
|
||||
"sniffOnStart": true,
|
||||
"ssl": Object {
|
||||
"ca": Array [
|
||||
"content-of-ca-path",
|
||||
],
|
||||
"checkServerIdentity": [Function],
|
||||
"rejectUnauthorized": true,
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -25,6 +25,7 @@ import url from 'url';
|
|||
import { pick } from '@kbn/std';
|
||||
import { Logger } from '../../logging';
|
||||
import { ElasticsearchConfig } from '../elasticsearch_config';
|
||||
import { DEFAULT_HEADERS } from '../default_headers';
|
||||
|
||||
/**
|
||||
* @privateRemarks Config that consumers can pass to the Elasticsearch JS client is complex and includes
|
||||
|
@ -130,7 +131,10 @@ export function parseElasticsearchClientConfig(
|
|||
protocol: uri.protocol,
|
||||
path: uri.pathname,
|
||||
query: uri.query,
|
||||
headers: config.customHeaders,
|
||||
headers: {
|
||||
...DEFAULT_HEADERS,
|
||||
...config.customHeaders,
|
||||
},
|
||||
};
|
||||
|
||||
if (needsAuth) {
|
||||
|
|
Loading…
Reference in a new issue