Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Reporting] Use a shim for server config #62086

Merged
merged 20 commits into from
Apr 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,27 @@
*/

import { cryptoFactory } from '../../../server/lib/crypto';
import { createMockServer } from '../../../test_helpers';
import { Logger } from '../../../types';
import { decryptJobHeaders } from './decrypt_job_headers';

let mockServer: any;
beforeEach(() => {
mockServer = createMockServer('');
});

const encryptHeaders = async (headers: Record<string, string>) => {
const crypto = cryptoFactory(mockServer);
const encryptHeaders = async (encryptionKey: string, headers: Record<string, string>) => {
const crypto = cryptoFactory(encryptionKey);
return await crypto.encrypt(headers);
};

describe('headers', () => {
test(`fails if it can't decrypt headers`, async () => {
await expect(
const getDecryptedHeaders = () =>
decryptJobHeaders({
encryptionKey: 'abcsecretsauce',
job: {
headers: 'Q53+9A+zf+Xe+ceR/uB/aR/Sw/8e+M+qR+WiG+8z+EY+mo+HiU/zQL+Xn',
},
logger: ({
error: jest.fn(),
} as unknown) as Logger,
server: mockServer,
})
).rejects.toMatchInlineSnapshot(
});
await expect(getDecryptedHeaders()).rejects.toMatchInlineSnapshot(
`[Error: Failed to decrypt report job data. Please ensure that xpack.reporting.encryptionKey is set and re-generate this report. Error: Invalid IV length]`
);
});
Expand All @@ -42,15 +36,15 @@ describe('headers', () => {
baz: 'quix',
};

const encryptedHeaders = await encryptHeaders(headers);
const encryptedHeaders = await encryptHeaders('abcsecretsauce', headers);
const decryptedHeaders = await decryptJobHeaders({
encryptionKey: 'abcsecretsauce',
job: {
title: 'cool-job-bro',
type: 'csv',
headers: encryptedHeaders,
},
logger: {} as Logger,
server: mockServer,
});
expect(decryptedHeaders).toEqual(headers);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import { i18n } from '@kbn/i18n';
import { cryptoFactory } from '../../../server/lib/crypto';
import { CryptoFactory, ServerFacade, Logger } from '../../../types';
import { CryptoFactory, Logger } from '../../../types';

interface HasEncryptedHeaders {
headers?: string;
Expand All @@ -17,15 +17,15 @@ export const decryptJobHeaders = async <
JobParamsType,
JobDocPayloadType extends HasEncryptedHeaders
>({
server,
encryptionKey,
job,
logger,
}: {
server: ServerFacade;
encryptionKey?: string;
job: JobDocPayloadType;
logger: Logger;
}): Promise<Record<string, string>> => {
const crypto: CryptoFactory = cryptoFactory(server);
const crypto: CryptoFactory = cryptoFactory(encryptionKey);
try {
const decryptedHeaders: Record<string, string> = await crypto.decrypt(job.headers);
return decryptedHeaders;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,32 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { createMockReportingCore, createMockServer } from '../../../test_helpers';
import { ReportingCore } from '../../../server';
import sinon from 'sinon';
import { createMockReportingCore } from '../../../test_helpers';
import { ReportingConfig, ReportingCore } from '../../../server/types';
import { JobDocPayload } from '../../../types';
import { JobDocPayloadPDF } from '../../printable_pdf/types';
import { getConditionalHeaders, getCustomLogo } from './index';

let mockConfig: ReportingConfig;
let mockReportingPlugin: ReportingCore;
let mockServer: any;

const getMockConfig = (mockConfigGet: sinon.SinonStub) => ({
get: mockConfigGet,
kbnConfig: { get: mockConfigGet },
});

beforeEach(async () => {
mockReportingPlugin = await createMockReportingCore();
mockServer = createMockServer('');
const mockConfigGet = sinon
.stub()
.withArgs('kibanaServer', 'hostname')
.returns('custom-hostname');
mockConfig = getMockConfig(mockConfigGet);
mockReportingPlugin = await createMockReportingCore(mockConfig);
});

describe('conditions', () => {
test(`uses hostname from reporting config if set`, async () => {
const settings: any = {
'xpack.reporting.kibanaServer.hostname': 'custom-hostname',
};

mockServer = createMockServer({ settings });

const permittedHeaders = {
foo: 'bar',
baz: 'quix',
Expand All @@ -33,121 +38,20 @@ describe('conditions', () => {
const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
config: mockConfig,
});

expect(conditionalHeaders.conditions.hostname).toEqual(
mockServer.config().get('xpack.reporting.kibanaServer.hostname')
mockConfig.get('kibanaServer', 'hostname')
);
});

test(`uses hostname from server.config if reporting config not set`, async () => {
const permittedHeaders = {
foo: 'bar',
baz: 'quix',
};

const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
});

expect(conditionalHeaders.conditions.hostname).toEqual(mockServer.config().get('server.host'));
});

test(`uses port from reporting config if set`, async () => {
const settings = {
'xpack.reporting.kibanaServer.port': 443,
};

mockServer = createMockServer({ settings });

const permittedHeaders = {
foo: 'bar',
baz: 'quix',
};

const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
});

expect(conditionalHeaders.conditions.port).toEqual(
mockServer.config().get('xpack.reporting.kibanaServer.port')
expect(conditionalHeaders.conditions.port).toEqual(mockConfig.get('kibanaServer', 'port'));
expect(conditionalHeaders.conditions.protocol).toEqual(
mockConfig.get('kibanaServer', 'protocol')
);
});

test(`uses port from server if reporting config not set`, async () => {
const permittedHeaders = {
foo: 'bar',
baz: 'quix',
};

const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
});

expect(conditionalHeaders.conditions.port).toEqual(mockServer.config().get('server.port'));
});

test(`uses basePath from server config`, async () => {
const permittedHeaders = {
foo: 'bar',
baz: 'quix',
};

const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
});

expect(conditionalHeaders.conditions.basePath).toEqual(
mockServer.config().get('server.basePath')
mockConfig.kbnConfig.get('server', 'basePath')
);
});

test(`uses protocol from reporting config if set`, async () => {
const settings = {
'xpack.reporting.kibanaServer.protocol': 'https',
};

mockServer = createMockServer({ settings });

const permittedHeaders = {
foo: 'bar',
baz: 'quix',
};

const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
});

expect(conditionalHeaders.conditions.protocol).toEqual(
mockServer.config().get('xpack.reporting.kibanaServer.protocol')
);
});

test(`uses protocol from server.info`, async () => {
const permittedHeaders = {
foo: 'bar',
baz: 'quix',
};

const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
});

expect(conditionalHeaders.conditions.protocol).toEqual(mockServer.info.protocol);
});
});

test('uses basePath from job when creating saved object service', async () => {
Expand All @@ -161,14 +65,14 @@ test('uses basePath from job when creating saved object service', async () => {
const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
config: mockConfig,
});
const jobBasePath = '/sbp/s/marketing';
await getCustomLogo({
reporting: mockReportingPlugin,
job: { basePath: jobBasePath } as JobDocPayloadPDF,
conditionalHeaders,
server: mockServer,
config: mockConfig,
});

const getBasePath = mockGetSavedObjectsClient.mock.calls[0][0].getBasePath;
Expand All @@ -179,21 +83,26 @@ test(`uses basePath from server if job doesn't have a basePath when creating sav
const mockGetSavedObjectsClient = jest.fn();
mockReportingPlugin.getSavedObjectsClient = mockGetSavedObjectsClient;

const mockConfigGet = sinon.stub();
mockConfigGet.withArgs('kibanaServer', 'hostname').returns('localhost');
mockConfigGet.withArgs('server', 'basePath').returns('/sbp');
mockConfig = getMockConfig(mockConfigGet);

const permittedHeaders = {
foo: 'bar',
baz: 'quix',
};
const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: permittedHeaders,
server: mockServer,
config: mockConfig,
});

await getCustomLogo({
reporting: mockReportingPlugin,
job: {} as JobDocPayloadPDF,
conditionalHeaders,
server: mockServer,
config: mockConfig,
});

const getBasePath = mockGetSavedObjectsClient.mock.calls[0][0].getBasePath;
Expand Down Expand Up @@ -225,19 +134,26 @@ test(`uses basePath from server if job doesn't have a basePath when creating sav

describe('config formatting', () => {
test(`lowercases server.host`, async () => {
mockServer = createMockServer({ settings: { 'server.host': 'COOL-HOSTNAME' } });
const mockConfigGet = sinon
.stub()
.withArgs('server', 'host')
.returns('COOL-HOSTNAME');
mockConfig = getMockConfig(mockConfigGet);

const conditionalHeaders = await getConditionalHeaders({
job: {} as JobDocPayload<any>,
filteredHeaders: {},
server: mockServer,
config: mockConfig,
});
expect(conditionalHeaders.conditions.hostname).toEqual('cool-hostname');
});

test(`lowercases xpack.reporting.kibanaServer.hostname`, async () => {
mockServer = createMockServer({
settings: { 'xpack.reporting.kibanaServer.hostname': 'GREAT-HOSTNAME' },
});
test(`lowercases kibanaServer.hostname`, async () => {
const mockConfigGet = sinon
.stub()
.withArgs('kibanaServer', 'hostname')
.returns('GREAT-HOSTNAME');
mockConfig = getMockConfig(mockConfigGet);
const conditionalHeaders = await getConditionalHeaders({
job: {
title: 'cool-job-bro',
Expand All @@ -249,7 +165,7 @@ describe('config formatting', () => {
},
},
filteredHeaders: {},
server: mockServer,
config: mockConfig,
});
expect(conditionalHeaders.conditions.hostname).toEqual('great-hostname');
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,31 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { ConditionalHeaders, ServerFacade } from '../../../types';

import { ReportingConfig } from '../../../server/types';
import { ConditionalHeaders } from '../../../types';

export const getConditionalHeaders = <JobDocPayloadType>({
server,
config,
job,
filteredHeaders,
}: {
server: ServerFacade;
config: ReportingConfig;
job: JobDocPayloadType;
filteredHeaders: Record<string, string>;
}) => {
const config = server.config();
const { kbnConfig } = config;
const [hostname, port, basePath, protocol] = [
config.get('xpack.reporting.kibanaServer.hostname') || config.get('server.host'),
config.get('xpack.reporting.kibanaServer.port') || config.get('server.port'),
config.get('server.basePath'),
config.get('xpack.reporting.kibanaServer.protocol') || server.info.protocol,
config.get('kibanaServer', 'hostname'),
config.get('kibanaServer', 'port'),
kbnConfig.get('server', 'basePath'),
config.get('kibanaServer', 'protocol'),
] as [string, number, string, string];

const conditionalHeaders: ConditionalHeaders = {
headers: filteredHeaders,
conditions: {
hostname: hostname.toLowerCase(),
hostname: hostname ? hostname.toLowerCase() : hostname,
port,
basePath,
protocol,
Expand Down
Loading