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

[SIEM] [Case] Case workflow api schema #51535

Merged
merged 44 commits into from
Jan 8, 2020
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
99626ed
init case commit, mostly boilerplate
stephmilovic Nov 15, 2019
97cac86
all right! cooking up the APIs finally
stephmilovic Nov 18, 2019
5f566ac
trying to post
stephmilovic Nov 18, 2019
5808a24
fixes post case
stephmilovic Nov 19, 2019
e47965e
update case api added
stephmilovic Nov 20, 2019
f6e8784
response type cleanup
stephmilovic Nov 20, 2019
514d395
temp mapping
stephmilovic Nov 20, 2019
655ecce
change to saved object
stephmilovic Nov 20, 2019
bc55d64
code cleanup
stephmilovic Nov 20, 2019
1f4bd1f
posting comments
stephmilovic Nov 21, 2019
2a1bd4e
about to refactor a bit
stephmilovic Nov 22, 2019
ced5899
initial APIs complete
stephmilovic Nov 22, 2019
b67409b
cleanup and added link to API documentation
stephmilovic Nov 22, 2019
5eab03b
fix comment response format
stephmilovic Nov 25, 2019
c27f242
update return types
stephmilovic Nov 25, 2019
482de76
Merge branch 'master' into case-workflow-api-schema
stephmilovic Nov 25, 2019
71bc1bb
references updated and comments on case are optional
stephmilovic Nov 25, 2019
8ea5c14
add a test
stephmilovic Nov 26, 2019
864d048
Merge branch 'master' into case-workflow-api-schema
stephmilovic Dec 2, 2019
2c8e731
tests
stephmilovic Dec 2, 2019
d1837f4
delete case tests added
stephmilovic Dec 2, 2019
22a6263
finished testing
stephmilovic Dec 2, 2019
13c7302
Merge branch 'master' into case-workflow-api-schema
stephmilovic Dec 3, 2019
d97ec09
update a few fields and get rid of updated date tracking
stephmilovic Dec 4, 2019
384aa4b
fix var names
stephmilovic Dec 4, 2019
6de8d09
clean up tests
stephmilovic Dec 4, 2019
1386bfc
fix tests again
stephmilovic Dec 5, 2019
5114a74
Merge branch 'master' into case-workflow-api-schema
elasticmachine Dec 9, 2019
1cb8adf
Merge branch 'master' into case-workflow-api-schema
elasticmachine Dec 15, 2019
730e5b6
lint fixes
stephmilovic Dec 15, 2019
8e1e94b
Merge branch 'master' into case-workflow-api-schema
elasticmachine Dec 17, 2019
1172e1b
Merge branch 'master' into case-workflow-api-schema
elasticmachine Dec 20, 2019
d48bb5f
security plugin changes
stephmilovic Dec 20, 2019
0cd4391
Merge branch 'master' into case-workflow-api-schema
elasticmachine Dec 23, 2019
5536fa1
Merge branch 'master' into case-workflow-api-schema
elasticmachine Jan 2, 2020
4a24bd2
resolve merge conflicts
stephmilovic Jan 6, 2020
b55bd97
Merge branch 'case-workflow-api-schema' of ssh://ssh.github.com:443/s…
stephmilovic Jan 6, 2020
468b0c1
Merge branch 'master' into case-workflow-api-schema
stephmilovic Jan 7, 2020
d0c0a10
Merge branch 'master' into case-workflow-api-schema
elasticmachine Jan 7, 2020
7af64f0
Merge branch 'master' into case-workflow-api-schema
elasticmachine Jan 8, 2020
81928a3
rm lint changes
stephmilovic Jan 8, 2020
b58b904
Merge branch 'case-workflow-api-schema' of ssh://ssh.github.com:443/s…
stephmilovic Jan 8, 2020
c11df85
remove temporary mappings from legacy siem
stephmilovic Jan 8, 2020
60a727b
rm case saved object mappings from siem
stephmilovic Jan 8, 2020
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
11 changes: 11 additions & 0 deletions x-pack/legacy/plugins/siem/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,17 @@ export const siem = (kibana: any) => {
},
},
mappings: savedObjectMappings,
// TODO: Remove once while Saved Object Mappings API is programmed for the NP See: https://github.com/elastic/kibana/issues/50309
savedObjectSchemas: {
stephmilovic marked this conversation as resolved.
Show resolved Hide resolved
'case-workflow': {
indexPattern: '.case-testing-ground', // TODO: Change this name and use kibana.yml settings to override it.
stephmilovic marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reason for having this stored in a separate index? If we can avoid it, we should as a failed migration requires each of these indices to to removed currently and won't be resolved until 8.0.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i will need it in a separate index, but apparently there is a way to get access to the kibana.yml from this part of the code which I had not believed to be possible. I need to track down an example, brb!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed these lines for now since they will need to be done from the NP side ultimately. could have to do with these failures, we'll see

isNamespaceAgnostic: false,
},
'case-workflow-comment': {
indexPattern: '.case-testing-ground', // TODO: Change this name and use kibana.yml settings to override it.
isNamespaceAgnostic: false,
},
},
},
init(server: Server) {
const { config, newPlatform, plugins, route } = server;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
/* eslint-disable @typescript-eslint/no-empty-interface */
/* eslint-disable @typescript-eslint/camelcase */
import {
NewCaseFormatted,
NewCommentFormatted,
} from '../../../../../../../x-pack/plugins/case/server';
import { ElasticsearchMappingOf } from '../../utils/typed_elasticsearch_mappings';

// Temporary file to write mappings for case
// while Saved Object Mappings API is programmed for the NP
// See: https://github.com/elastic/kibana/issues/50309

export const caseSavedObjectType = 'case-workflow';
export const caseCommentSavedObjectType = 'case-workflow-comment';

export const caseSavedObjectMappings: {
[caseSavedObjectType]: ElasticsearchMappingOf<NewCaseFormatted>;
} = {
[caseSavedObjectType]: {
properties: {
assignees: {
properties: {
username: {
type: 'keyword',
},
full_name: {
type: 'keyword',
},
},
},
created_at: {
type: 'date',
},
description: {
type: 'text',
},
title: {
type: 'keyword',
},
created_by: {
properties: {
username: {
type: 'keyword',
},
full_name: {
type: 'keyword',
},
},
},
state: {
type: 'keyword',
},
tags: {
type: 'keyword',
},
case_type: {
type: 'keyword',
},
},
},
};

export const caseCommentSavedObjectMappings: {
[caseCommentSavedObjectType]: ElasticsearchMappingOf<NewCommentFormatted>;
} = {
[caseCommentSavedObjectType]: {
properties: {
comment: {
type: 'text',
},
created_at: {
type: 'date',
},
created_by: {
properties: {
full_name: {
type: 'keyword',
},
username: {
type: 'keyword',
},
},
},
},
},
};
6 changes: 6 additions & 0 deletions x-pack/legacy/plugins/siem/server/saved_objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,16 @@ import {
timelineSavedObjectType,
timelineSavedObjectMappings,
} from './lib/timeline/saved_object_mappings';
import {
caseSavedObjectMappings,
caseCommentSavedObjectMappings,
} from './lib/case/saved_object_mappings_temp';

export { noteSavedObjectType, pinnedEventSavedObjectType, timelineSavedObjectType };
export const savedObjectMappings = {
...timelineSavedObjectMappings,
...noteSavedObjectMappings,
...pinnedEventSavedObjectMappings,
...caseSavedObjectMappings,
...caseCommentSavedObjectMappings,
};
9 changes: 9 additions & 0 deletions x-pack/plugins/case/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Case Workflow

*Experimental Feature*

Elastic is developing a Case Management Workflow. Follow our progress:

- [Case API Documentation](https://documenter.getpostman.com/view/172706/SW7c2SuF?version=latest)
- [Github Meta](https://github.com/elastic/kibana/issues/50103)

9 changes: 9 additions & 0 deletions x-pack/plugins/case/kibana.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"configPath": ["xpack", "case"],
"id": "case",
"kibanaVersion": "kibana",
"requiredPlugins": ["security"],
"server": true,
"ui": false,
"version": "8.0.0"
}
15 changes: 15 additions & 0 deletions x-pack/plugins/case/server/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { schema, TypeOf } from '@kbn/config-schema';

export const ConfigSchema = schema.object({
enabled: schema.boolean({ defaultValue: false }),
indexPattern: schema.string({ defaultValue: '.case-test-2' }),
secret: schema.string({ defaultValue: 'Cool secret huh?' }),
});

export type ConfigType = TypeOf<typeof ConfigSchema>;
8 changes: 8 additions & 0 deletions x-pack/plugins/case/server/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export const CASE_SAVED_OBJECT = 'case-workflow';
export const CASE_COMMENT_SAVED_OBJECT = 'case-workflow-comment';
14 changes: 14 additions & 0 deletions x-pack/plugins/case/server/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { PluginInitializerContext } from '../../../../src/core/server';
import { ConfigSchema } from './config';
import { CasePlugin } from './plugin';
export { NewCaseFormatted, NewCommentFormatted } from './routes/api/types';

export const config = { schema: ConfigSchema };
export const plugin = (initializerContext: PluginInitializerContext) =>
new CasePlugin(initializerContext);
63 changes: 63 additions & 0 deletions x-pack/plugins/case/server/plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { first, map } from 'rxjs/operators';
import { CoreSetup, Logger, PluginInitializerContext } from 'kibana/server';
import { ConfigType } from './config';
import { initCaseApi } from './routes/api';
import { CaseService } from './services';
import { PluginSetupContract as SecurityPluginSetup } from '../../security/server';

function createConfig$(context: PluginInitializerContext) {
return context.config.create<ConfigType>().pipe(map(config => config));
}

export interface PluginsSetup {
security: SecurityPluginSetup;
}

export class CasePlugin {
private readonly log: Logger;

constructor(private readonly initializerContext: PluginInitializerContext) {
this.log = this.initializerContext.logger.get();
}

public async setup(core: CoreSetup, plugins: PluginsSetup) {
const config = await createConfig$(this.initializerContext)
.pipe(first())
.toPromise();

if (!config.enabled) {
return;
}
const service = new CaseService(this.log);

this.log.debug(
`Setting up Case Workflow with core contract [${Object.keys(
core
)}] and plugins [${Object.keys(plugins)}]`
);

const caseService = await service.setup({
authentication: plugins.security.authc,
});

const router = core.http.createRouter();
initCaseApi({
caseService,
router,
});
}

public start() {
this.log.debug(`Starting Case Workflow`);
}

public stop() {
this.log.debug(`Stopping Case Workflow`);
}
}
35 changes: 35 additions & 0 deletions x-pack/plugins/case/server/routes/api/__fixtures__/authc_mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { Authentication } from '../../../../../security/server';

const getCurrentUser = jest.fn().mockReturnValue({
username: 'awesome',
full_name: 'Awesome D00d',
});
const getCurrentUserThrow = jest.fn().mockImplementation(() => {
throw new Error('Bad User - the user is not authenticated');
});

export const authenticationMock = {
create: (): jest.Mocked<Authentication> => ({
login: jest.fn(),
createAPIKey: jest.fn(),
getCurrentUser,
invalidateAPIKey: jest.fn(),
isAuthenticated: jest.fn(),
logout: jest.fn(),
getSessionInfo: jest.fn(),
}),
createInvalid: (): jest.Mocked<Authentication> => ({
login: jest.fn(),
createAPIKey: jest.fn(),
getCurrentUser: getCurrentUserThrow,
invalidateAPIKey: jest.fn(),
isAuthenticated: jest.fn(),
logout: jest.fn(),
getSessionInfo: jest.fn(),
}),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { SavedObjectsClientContract, SavedObjectsErrorHelpers } from 'src/core/server';
import { CASE_COMMENT_SAVED_OBJECT } from '../../../constants';

export const createMockSavedObjectsRepository = (savedObject: any[] = []) => {
const mockSavedObjectsClientContract = ({
get: jest.fn((type, id) => {
const result = savedObject.filter(s => s.id === id);
if (!result.length) {
throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
}
return result[0];
}),
find: jest.fn(findArgs => {
if (findArgs.hasReference && findArgs.hasReference.id === 'bad-guy') {
throw SavedObjectsErrorHelpers.createBadRequestError('Error thrown for testing');
}
return {
total: savedObject.length,
saved_objects: savedObject,
};
}),
create: jest.fn((type, attributes, references) => {
if (attributes.description === 'Throw an error' || attributes.comment === 'Throw an error') {
throw SavedObjectsErrorHelpers.createBadRequestError('Error thrown for testing');
}
if (type === CASE_COMMENT_SAVED_OBJECT) {
return {
type,
id: 'mock-comment',
attributes,
...references,
updated_at: '2019-12-02T22:48:08.327Z',
version: 'WzksMV0=',
};
}
return {
type,
id: 'mock-it',
attributes,
references: [],
updated_at: '2019-12-02T22:48:08.327Z',
version: 'WzksMV0=',
};
}),
update: jest.fn((type, id, attributes) => {
if (!savedObject.find(s => s.id === id)) {
throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
}
return {
id,
type,
updated_at: '2019-11-22T22:50:55.191Z',
version: 'WzE3LDFd',
attributes,
};
}),
delete: jest.fn((type: string, id: string) => {
const result = savedObject.filter(s => s.id === id);
if (!result.length) {
throw SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
}
if (type === 'case-workflow-comment' && id === 'bad-guy') {
throw SavedObjectsErrorHelpers.createBadRequestError('Error thrown for testing');
}
return {};
}),
deleteByNamespace: jest.fn(),
} as unknown) as jest.Mocked<SavedObjectsClientContract>;

return mockSavedObjectsClientContract;
};
11 changes: 11 additions & 0 deletions x-pack/plugins/case/server/routes/api/__fixtures__/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export { mockCases, mockCasesErrorTriggerData, mockCaseComments } from './mock_saved_objects';
export { createMockSavedObjectsRepository } from './create_mock_so_repository';
export { createRouteContext } from './route_contexts';
export { authenticationMock } from './authc_mock';
export { createRoute } from './mock_router';
Loading