Added was-authorized auditd renderer (#33470)

* Added was-authorized auditd renderer
* https://github.com/elastic/ingest-dev/issues/301
This commit is contained in:
Frank Hassanabad 2019-03-20 19:36:06 -06:00 committed by GitHub
parent 664a74b6af
commit e390ed5ddc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 1099 additions and 2 deletions

View file

@ -1637,6 +1637,70 @@ Can be one or multiple IPv4 or IPv6 addresses.",
},
"zeek": null,
},
Object {
"_id": "26",
"auditd": Object {
"data": Object {
"acct": null,
"op": null,
"terminal": "/dev/pts/0",
},
"result": "success",
"session": "338",
"summary": Object {
"actor": Object {
"primary": "root",
"secondary": "alice",
},
"how": "/sbin/pam_tally2",
"message_type": null,
"object": Object {
"primary": "/dev/pts/0",
"secondary": null,
"type": "user-session",
},
"sequence": null,
},
},
"destination": null,
"event": Object {
"action": "was-authorized",
"category": "user-login",
"dataset": null,
"id": null,
"module": "auditd",
"severity": null,
},
"geo": null,
"host": Object {
"id": "0a63559c1acf4c419d979c4b4d8b83ff",
"ip": Array [
"139.59.11.147",
"10.47.0.5",
"fe80::ec0b:1bff:fe29:80bd",
],
"name": "suricata-bangalore",
},
"http": null,
"network": null,
"process": Object {
"args": null,
"executable": "/sbin/pam_tally2",
"name": null,
"pid": 21170,
"ppid": null,
"title": null,
"working_directory": null,
},
"source": null,
"suricata": null,
"timestamp": "2019-03-13T03:34:08.890Z",
"url": null,
"user": Object {
"name": "alice",
},
"zeek": null,
},
]
}
eventIdToNoteIds={Object {}}
@ -1691,6 +1755,10 @@ Can be one or multiple IPv4 or IPv6 addresses.",
"isInstance": [Function],
"renderRow": [Function],
},
Object {
"isInstance": [Function],
"renderRow": [Function],
},
]
}
sort={

View file

@ -0,0 +1,178 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`AuditAcquiredCredsDetails rendering it renders the default AuditAcquiredCredsDetails 1`] = `
<Component
intl={
Object {
"defaultFormats": Object {},
"defaultLocale": "en",
"formatDate": [Function],
"formatHTMLMessage": [Function],
"formatMessage": [Function],
"formatNumber": [Function],
"formatPlural": [Function],
"formatRelative": [Function],
"formatTime": [Function],
"formats": Object {
"date": Object {
"full": Object {
"day": "numeric",
"month": "long",
"weekday": "long",
"year": "numeric",
},
"long": Object {
"day": "numeric",
"month": "long",
"year": "numeric",
},
"medium": Object {
"day": "numeric",
"month": "short",
"year": "numeric",
},
"short": Object {
"day": "numeric",
"month": "numeric",
"year": "2-digit",
},
},
"number": Object {
"currency": Object {
"style": "currency",
},
"percent": Object {
"style": "percent",
},
},
"relative": Object {
"days": Object {
"units": "day",
},
"hours": Object {
"units": "hour",
},
"minutes": Object {
"units": "minute",
},
"months": Object {
"units": "month",
},
"seconds": Object {
"units": "second",
},
"years": Object {
"units": "year",
},
},
"time": Object {
"full": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
"timeZoneName": "short",
},
"long": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
"timeZoneName": "short",
},
"medium": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
},
"short": Object {
"hour": "numeric",
"minute": "numeric",
},
},
},
"formatters": Object {
"getDateTimeFormat": [Function],
"getMessageFormat": [Function],
"getNumberFormat": [Function],
"getPluralFormat": [Function],
"getRelativeFormat": [Function],
},
"locale": "en",
"messages": Object {},
"now": [Function],
"onError": [Function],
"textComponent": Symbol(react.fragment),
"timeZone": null,
}
}
>
<pure(Component)
browserFields={Object {}}
data={
Object {
"_id": "22",
"auditd": Object {
"data": Object {
"acct": "alice",
"op": "PAM:setcred",
"terminal": "ssh",
},
"result": "success",
"session": "340",
"summary": Object {
"actor": Object {
"primary": "alice",
"secondary": "alice",
},
"how": "/usr/sbin/sshd",
"message_type": null,
"object": Object {
"primary": "ssh",
"secondary": "8.42.77.171",
"type": "user-session",
},
"sequence": null,
},
},
"destination": null,
"event": Object {
"action": "disposed-credentials",
"category": "user-login",
"dataset": null,
"id": null,
"module": "auditd",
"severity": null,
},
"geo": null,
"host": Object {
"id": "0a63559c1acf4c419d979c4b4d8b83ff",
"ip": Array [
"139.59.11.147",
"10.47.0.5",
"fe80::ec0b:1bff:fe29:80bd",
],
"name": "suricata-bangalore",
},
"http": null,
"network": null,
"process": Object {
"args": null,
"executable": "/usr/sbin/sshd",
"name": null,
"pid": 21202,
"ppid": null,
"title": null,
"working_directory": null,
},
"source": null,
"suricata": null,
"timestamp": "2019-03-13T03:35:21.614Z",
"url": null,
"user": Object {
"name": "root",
},
"zeek": null,
}
}
/>
</Component>
`;

View file

@ -0,0 +1,84 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`auditWasAuthorizedRowRenderer renders correctly against snapshot 1`] = `
<span>
<styled.div>
<span>
some children
</span>
<styled.div
width={100}
>
<pure(Component)
browserFields={Object {}}
data={
Object {
"_id": "26",
"auditd": Object {
"data": Object {
"acct": null,
"op": null,
"terminal": "/dev/pts/0",
},
"result": "success",
"session": "338",
"summary": Object {
"actor": Object {
"primary": "root",
"secondary": "alice",
},
"how": "/sbin/pam_tally2",
"message_type": null,
"object": Object {
"primary": "/dev/pts/0",
"secondary": null,
"type": "user-session",
},
"sequence": null,
},
},
"destination": null,
"event": Object {
"action": "was-authorized",
"category": "user-login",
"dataset": null,
"id": null,
"module": "auditd",
"severity": null,
},
"geo": null,
"host": Object {
"id": "0a63559c1acf4c419d979c4b4d8b83ff",
"ip": Array [
"139.59.11.147",
"10.47.0.5",
"fe80::ec0b:1bff:fe29:80bd",
],
"name": "suricata-bangalore",
},
"http": null,
"network": null,
"process": Object {
"args": null,
"executable": "/sbin/pam_tally2",
"name": null,
"pid": 21170,
"ppid": null,
"title": null,
"working_directory": null,
},
"source": null,
"suricata": null,
"timestamp": "2019-03-13T03:34:08.890Z",
"url": null,
"user": Object {
"name": "alice",
},
"zeek": null,
}
}
/>
</styled.div>
</styled.div>
</span>
`;

View file

@ -379,7 +379,7 @@ describe('AuditdStartedSessionDetails', () => {
<TestProviders>
<AuditdStartedSessionLine
id="hello-i-am-an-id"
args="arg1 arg 2 arg 3"
args="arg1 arg2 arg 3"
userName={undefined}
secondary={undefined}
session={undefined}
@ -391,7 +391,7 @@ describe('AuditdStartedSessionDetails', () => {
/>
</TestProviders>
);
expect(wrapper.text()).toEqual('Sessionarg1 arg 2 arg 3');
expect(wrapper.text()).toEqual('Sessionarg1 arg2 arg 3');
});
});
});

View file

@ -0,0 +1,397 @@
/*
* 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 toJson from 'enzyme-to-json';
import * as React from 'react';
import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers';
import { BrowserFields } from 'x-pack/plugins/secops/public/containers/source';
import { mockBrowserFields } from '../../../../containers/source/mock';
import { mockEcsData, TestProviders } from '../../../../mock';
import {
AuditdWasAuthorizedDetails,
AuditdWasAuthorizedLine,
} from './auditd_was_authorized_details';
describe('AuditAcquiredCredsDetails', () => {
describe('rendering', () => {
test('it renders the default AuditAcquiredCredsDetails', () => {
// I cannot and do not want to use the BrowserFields mocks for the snapshot tests as they are too heavy
const browserFields: BrowserFields = {};
const wrapper = shallowWithIntl(
<TestProviders>
<AuditdWasAuthorizedDetails browserFields={browserFields} data={mockEcsData[21]} />
</TestProviders>
);
expect(toJson(wrapper)).toMatchSnapshot();
});
test('it returns auditd if the data does contain auditd data', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedDetails browserFields={mockBrowserFields} data={mockEcsData[19]} />
</TestProviders>
);
expect(wrapper.text()).toEqual(
'Sessionjohnson@zeek-sanfranin/was authorized to use/usr/bin/gpgconf--list-dirs agent-socket'
);
});
test('it returns null for text if the data contains no auditd data', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedDetails browserFields={mockBrowserFields} data={mockEcsData[0]} />
</TestProviders>
);
expect(wrapper.text()).toBeNull();
});
});
// NOTE: It's best if all the arguments are sent into this function and they typically should be otherwise
// you have something wrong with your beats. These tests are to ensure the function does not
// crash. If you need to format things prettier because not all the data is there, then update
// these tests with those changes
describe('#AuditdWasAuthorizedLine', () => {
test('it returns pretty output if you send in all your happy path data', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedLine
id="hello-i-am-an-id"
hostName="host-1"
userName="username-1"
session="session-1"
primary="username-1"
secondary="username-1"
processExecutable="process-1"
processTitle="process-title-1"
workingDirectory="working-directory-1"
args="arg1 arg2 arg3"
/>
</TestProviders>
);
expect(wrapper.text()).toEqual(
'Sessionsession-1username-1@host-1inworking-directory-1was authorized to useprocess-1arg1 arg2 arg3'
);
});
test('it returns a session with username if username, primary, and secondary all equal each other ', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedLine
id="hello-i-am-an-id"
hostName="host-1"
session="session-1"
userName="username-1"
primary="username-1"
secondary="username-1"
processExecutable="process-1"
processTitle="process-title-1"
workingDirectory="working-directory-1"
args="arg1 arg2 arg3"
/>
</TestProviders>
);
expect(wrapper.text()).toEqual(
'Sessionsession-1username-1@host-1inworking-directory-1was authorized to useprocess-1arg1 arg2 arg3'
);
});
test('it returns a session with username if primary and secondary equal unset', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedLine
id="hello-i-am-an-id"
hostName="host-1"
session="session-1"
userName="username-1"
primary="unset"
secondary="unset"
processExecutable="process-1"
processTitle="process-title-1"
workingDirectory="working-directory-1"
args="arg1 arg2 arg3"
/>
</TestProviders>
);
expect(wrapper.text()).toEqual(
'Sessionsession-1username-1@host-1inworking-directory-1was authorized to useprocess-1arg1 arg2 arg3'
);
});
test('it returns a session with username if primary and secondary equal unset with different casing', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedLine
id="hello-i-am-an-id"
hostName="host-1"
userName="username-1"
session="session-1"
primary="Unset"
secondary="uNseT"
processExecutable="process-1"
processTitle="process-title-1"
workingDirectory="working-directory-1"
args="arg1 arg2 arg3"
/>
</TestProviders>
);
expect(wrapper.text()).toEqual(
'Sessionsession-1username-1@host-1inworking-directory-1was authorized to useprocess-1arg1 arg2 arg3'
);
});
test('it returns a session with username if primary and secondary are undefined', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedLine
id="hello-i-am-an-id"
hostName="host-1"
session="session-1"
primary={undefined}
secondary={undefined}
userName="username-1"
processExecutable="process-1"
processTitle="process-title-1"
workingDirectory="working-directory-1"
args="arg1 arg2 arg3"
/>
</TestProviders>
);
expect(wrapper.text()).toEqual(
'Sessionsession-1username-1@host-1inworking-directory-1was authorized to useprocess-1arg1 arg2 arg3'
);
});
test('it returns a session with "as" wording if username, primary, and secondary are all different', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedLine
id="hello-i-am-an-id"
hostName="host-1"
session="session-1"
userName="[username-1]"
primary="[username-2]"
secondary="[username-3]"
processExecutable="process-1"
processTitle="process-title-1"
workingDirectory="working-directory-1"
args="arg1 arg2 arg3"
/>
</TestProviders>
);
expect(wrapper.text()).toEqual(
'Sessionsession-1[username-2]as[username-3]@host-1inworking-directory-1was authorized to useprocess-1arg1 arg2 arg3'
);
});
test('it returns a session with "as" wording if username and primary are the same but secondary is different', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedLine
id="hello-i-am-an-id"
hostName="host-1"
session="session-1"
userName="[username-1]"
primary="[username-1]"
secondary="[username-2]"
processExecutable="process-1"
processTitle="process-title-1"
workingDirectory="working-directory-1"
args="arg1 arg2 arg3"
/>
</TestProviders>
);
expect(wrapper.text()).toEqual(
'Sessionsession-1[username-1]as[username-2]@host-1inworking-directory-1was authorized to useprocess-1arg1 arg2 arg3'
);
});
test('it returns a session with primary if username and secondary are unset with different casing', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedLine
id="hello-i-am-an-id"
hostName="host-1"
userName="unseT"
session="session-1"
primary="[username-primary]"
secondary="unset"
processExecutable="process-1"
processTitle="process-title-1"
workingDirectory="working-directory-1"
args="arg1 arg2 arg3"
/>
</TestProviders>
);
expect(wrapper.text()).toEqual(
'Sessionsession-1[username-primary]@host-1inworking-directory-1was authorized to useprocess-1arg1 arg2 arg3'
);
});
test('it returns a session with primary if username and secondary are undefined', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedLine
id="hello-i-am-an-id"
hostName="host-1"
session="session-1"
primary="[username-primary]"
userName={undefined}
secondary={undefined}
processExecutable="process-1"
processTitle="process-title-1"
workingDirectory="working-directory-1"
args="arg1 arg2 arg3"
/>
</TestProviders>
);
expect(wrapper.text()).toEqual(
'Sessionsession-1[username-primary]@host-1inworking-directory-1was authorized to useprocess-1arg1 arg2 arg3'
);
});
test('it returns just a session if only given an id', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedLine
id="hello-i-am-an-id"
userName={undefined}
secondary={undefined}
session={undefined}
hostName={undefined}
primary={undefined}
processExecutable={undefined}
processTitle={undefined}
workingDirectory={undefined}
args={undefined}
/>
</TestProviders>
);
expect(wrapper.text()).toEqual('Session');
});
test('it returns only session and hostName if only hostname and an id is given', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedLine
id="hello-i-am-an-id"
hostName="some-host-name"
userName={undefined}
secondary={undefined}
session={undefined}
primary={undefined}
processExecutable={undefined}
processTitle={undefined}
workingDirectory={undefined}
args={undefined}
/>
</TestProviders>
);
expect(wrapper.text()).toEqual('Session@some-host-name');
});
test('it returns only a session and user name if only a user name and id is given', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedLine
id="hello-i-am-an-id"
userName="some-user-name"
secondary={undefined}
session={undefined}
hostName={undefined}
primary={undefined}
processExecutable={undefined}
processTitle={undefined}
workingDirectory={undefined}
args={undefined}
/>
</TestProviders>
);
expect(wrapper.text()).toEqual('Sessionsome-user-name');
});
test('it returns only a process name if only given a process name and id', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedLine
id="hello-i-am-an-id"
userName={undefined}
processExecutable="some-process-name"
secondary={undefined}
session={undefined}
hostName={undefined}
primary={undefined}
processTitle={undefined}
workingDirectory={undefined}
args={undefined}
/>
</TestProviders>
);
expect(wrapper.text()).toEqual('Sessionwas authorized to usesome-process-name');
});
test('it returns only session if process title with id is given', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedLine
id="hello-i-am-an-id"
processTitle="some-process-title"
userName="some-user-name"
secondary={undefined}
session={undefined}
hostName={undefined}
primary={undefined}
processExecutable={undefined}
workingDirectory={undefined}
args={undefined}
/>
</TestProviders>
);
expect(wrapper.text()).toEqual('Sessionsome-user-name');
});
test('it returns only a working directory if that is all that is given with a id', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedLine
id={'hello-i-am-an-id'}
workingDirectory="some-working-directory"
userName={undefined}
secondary={undefined}
session={undefined}
hostName={undefined}
primary={undefined}
processExecutable={undefined}
processTitle={undefined}
args={undefined}
/>
</TestProviders>
);
expect(wrapper.text()).toEqual('Sessioninsome-working-directory');
});
test('it returns only the session args with id if that is all that is given (very unlikely situation)', () => {
const wrapper = mountWithIntl(
<TestProviders>
<AuditdWasAuthorizedLine
id="hello-i-am-an-id"
args="arg1 arg2 arg 3"
userName={undefined}
secondary={undefined}
session={undefined}
hostName={undefined}
primary={undefined}
processExecutable={undefined}
processTitle={undefined}
workingDirectory={undefined}
/>
</TestProviders>
);
expect(wrapper.text()).toEqual('Sessionarg1 arg2 arg 3');
});
});
});

View file

@ -0,0 +1,171 @@
/*
* 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 { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { EuiSpacer } from '@elastic/eui';
import { get } from 'lodash/fp';
import * as React from 'react';
import { pure } from 'recompose';
import styled from 'styled-components';
import { BrowserFields } from '../../../../containers/source';
import { Ecs } from '../../../../graphql/types';
import { DraggableBadge } from '../../../draggables';
import { PrimarySecondaryUserInfo } from './primary_secondary_user_info';
import { SourceDest } from './source_dest_ip';
import * as i18n from './translations';
const Details = styled.div`
margin: 10px 0px 10px 10px;
`;
const TokensFlexItem = styled(EuiFlexItem)`
margin-left: 3px;
`;
interface Props {
id: string;
hostName: string | null | undefined;
userName: string | null | undefined;
primary: string | null | undefined;
secondary: string | null | undefined;
processExecutable: string | null | undefined;
processTitle: string | null | undefined;
workingDirectory: string | null | undefined;
args: string | null | undefined;
session: string | null | undefined;
}
export const AuditdWasAuthorizedLine = pure<Props>(
({
id,
hostName,
userName,
primary,
secondary,
processExecutable,
processTitle,
workingDirectory,
args,
session,
}) => (
<EuiFlexGroup justifyContent="center" gutterSize="none" wrap={true}>
<TokensFlexItem grow={false} component="span">
{i18n.SESSION}
</TokensFlexItem>
<TokensFlexItem grow={false} component="span">
<DraggableBadge
contextId="auditd-acquired-creds"
eventId={id}
field="auditd.session"
value={session}
iconType="number"
/>
</TokensFlexItem>
<TokensFlexItem grow={false} component="span">
<PrimarySecondaryUserInfo
contextId="auditd-acquired-creds"
eventId={id}
userName={userName}
primary={primary}
secondary={secondary}
/>
</TokensFlexItem>
{hostName != null && (
<TokensFlexItem grow={false} component="span">
@
</TokensFlexItem>
)}
<TokensFlexItem grow={false} component="span">
<DraggableBadge
contextId="auditd-acquired-creds"
eventId={id}
field="host.name"
value={hostName}
/>
</TokensFlexItem>
{workingDirectory != null && (
<TokensFlexItem grow={false} component="span">
{i18n.IN}
</TokensFlexItem>
)}
<TokensFlexItem grow={false} component="span">
<DraggableBadge
contextId="auditd-acquired-creds"
eventId={id}
field="process.working_directory"
value={workingDirectory}
iconType="folderOpen"
/>
</TokensFlexItem>
{processExecutable != null && (
<TokensFlexItem grow={false} component="span">
{i18n.WAS_AUTHORIZED_TO_USE}
</TokensFlexItem>
)}
<TokensFlexItem grow={false} component="span">
<DraggableBadge
contextId="auditd-acquired-creds"
eventId={id}
field="process.executable"
value={processExecutable}
iconType="console"
/>
</TokensFlexItem>
<TokensFlexItem grow={false} component="span">
{args !== '' && (
<DraggableBadge
contextId="auditd-acquired-creds"
eventId={id}
field="process.title"
queryValue={processTitle != null ? processTitle : ''}
value={args}
/>
)}
</TokensFlexItem>
</EuiFlexGroup>
)
);
export const AuditdWasAuthorizedDetails = pure<{ browserFields: BrowserFields; data: Ecs }>(
({ browserFields, data }) => {
const id = data._id;
const session: string | null | undefined = get('auditd.session', data);
const hostName: string | null | undefined = get('host.name', data);
const userName: string | null | undefined = get('user.name', data);
const processExecutable: string | null | undefined = get('process.executable', data);
const processTitle: string | null | undefined = get('process.title', data);
const workingDirectory: string | null | undefined = get('process.working_directory', data);
const primary: string | null | undefined = get('auditd.summary.actor.primary', data);
const secondary: string | null | undefined = get('auditd.summary.actor.secondary', data);
const rawArgs: string[] | null | undefined = get('process.args', data);
const args: string = rawArgs != null ? rawArgs.slice(1).join(' ') : '';
if (data.process != null) {
return (
<Details>
<AuditdWasAuthorizedLine
id={id}
hostName={hostName}
userName={userName}
processExecutable={processExecutable}
processTitle={processTitle}
workingDirectory={workingDirectory}
args={args}
session={session}
primary={primary}
secondary={secondary}
/>
<EuiSpacer size="s" />
<SourceDest data={data} browserFields={browserFields} />
</Details>
);
} else {
return null;
}
}
);

View file

@ -0,0 +1,88 @@
/*
* 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 { mount, shallow } from 'enzyme';
import toJson from 'enzyme-to-json';
import { cloneDeep } from 'lodash/fp';
import * as React from 'react';
import { BrowserFields } from 'x-pack/plugins/secops/public/containers/source';
import { mockBrowserFields } from '../../../../containers/source/mock';
import { Ecs } from '../../../../graphql/types';
import { mockEcsData, TestProviders } from '../../../../mock';
import { auditdWasAuthorizedRowRenderer } from '.';
describe('auditWasAuthorizedRowRenderer', () => {
let nonAuditd: Ecs;
let auditd: Ecs;
beforeEach(() => {
nonAuditd = cloneDeep(mockEcsData[0]);
auditd = cloneDeep(mockEcsData[25]);
});
test('renders correctly against snapshot', () => {
// I cannot and do not want to use the BrowserFields mocks for the snapshot tests as they are too heavy
const browserFields: BrowserFields = {};
const children = auditdWasAuthorizedRowRenderer.renderRow({
browserFields,
data: auditd,
width: 100,
children: <span>some children</span>,
});
const wrapper = shallow(<span>{children}</span>);
expect(toJson(wrapper)).toMatchSnapshot();
});
test('should return false if not a auditd datum', () => {
expect(auditdWasAuthorizedRowRenderer.isInstance(nonAuditd)).toBe(false);
});
test('should return true if it is a auditd datum', () => {
expect(auditdWasAuthorizedRowRenderer.isInstance(auditd)).toBe(true);
});
test('should return false when action is set to some other value', () => {
auditd.event != null
? (auditd.event.action = 'some other value')
: expect(auditd.event).toBeDefined();
expect(auditdWasAuthorizedRowRenderer.isInstance(auditd)).toBe(false);
});
test('should render children normally if it does not have a auditd object', () => {
const children = auditdWasAuthorizedRowRenderer.renderRow({
browserFields: mockBrowserFields,
data: nonAuditd,
width: 100,
children: <span>some children</span>,
});
const wrapper = mount(
<TestProviders>
<span>{children}</span>
</TestProviders>
);
expect(wrapper.text()).toEqual('some children');
});
test('should render a auditd row', () => {
const children = auditdWasAuthorizedRowRenderer.renderRow({
browserFields: mockBrowserFields,
data: auditd,
width: 100,
children: <span>some children </span>,
});
const wrapper = mount(
<TestProviders>
<span>{children}</span>
</TestProviders>
);
expect(wrapper.text()).toContain(
'some children Session338rootasalice@suricata-bangalorewas authorized to use/sbin/pam_tally2'
);
});
});

View file

@ -0,0 +1,41 @@
/*
* 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 { get } from 'lodash/fp';
import React from 'react';
import styled from 'styled-components';
import { RowRenderer, RowRendererContainer } from '.';
import { AuditdWasAuthorizedDetails } from './auditd_was_authorized_details';
const AuditdWasAuthorizedRow = styled.div`
width: 100%;
overflow: hidden;
&:hover {
background-color: ${props => props.theme.eui.euiTableHoverColor};
}
`;
export const auditdWasAuthorizedRowRenderer: RowRenderer = {
isInstance: ecs => {
const module: string | null | undefined = get('event.module', ecs);
const action: string | null | undefined = get('event.action', ecs);
return (
module != null &&
module.toLowerCase() === 'auditd' &&
action != null &&
action.toLowerCase() === 'was-authorized'
);
},
renderRow: ({ browserFields, data, width, children }) => (
<AuditdWasAuthorizedRow>
{children}
<RowRendererContainer width={width}>
<AuditdWasAuthorizedDetails browserFields={browserFields} data={data} />
</RowRendererContainer>
</AuditdWasAuthorizedRow>
),
};

View file

@ -10,6 +10,7 @@ import { auditdEndedSessionRowRenderer } from './auditd_ended_session_row_render
import { auditdExecutedRowRenderer } from './auditd_executed_row_renderer';
import { auditdLoggedinRowRenderer } from './auditd_loggedin_row_renderer';
import { auditdStartedSessionRowRenderer } from './auditd_started_session_row_renderer';
import { auditdWasAuthorizedRowRenderer } from './auditd_was_authorized_row_renderer';
import { ColumnRenderer } from './column_renderer';
import { emptyColumnRenderer } from './empty_column_renderer';
import { plainColumnRenderer } from './plain_column_renderer';
@ -25,6 +26,7 @@ export * from './auditd_disposed_creds_row_renderer';
export * from './auditd_executed_row_renderer';
export * from './auditd_started_session_row_renderer';
export * from './auditd_loggedin_row_renderer';
export * from './auditd_was_authorized_row_renderer';
export * from './column_renderer';
export * from './row_renderer';
export * from './empty_column_renderer';
@ -41,6 +43,7 @@ export const rowRenderers: RowRenderer[] = [
suricataRowRenderer,
auditdExecutedRowRenderer,
auditdLoggedinRowRenderer,
auditdWasAuthorizedRowRenderer,
auditAcquiredCredsRowRenderer,
auditdEndedSessionRowRenderer,
auditDisposedCredsRowRenderer,

View file

@ -87,6 +87,13 @@ export const IN = i18n.translate('xpack.secops.auditd.disposed.inDescription', {
defaultMessage: 'in',
});
export const WAS_AUTHORIZED_TO_USE = i18n.translate(
'xpack.secops.auditd.wasauthorized.wasAuthorizedToUseDescription',
{
defaultMessage: 'was authorized to use',
}
);
export const ACQUIRED_CREDENTIALS_TO = i18n.translate(
'xpack.secops.auditd.acquired.credentialsDescription',
{

View file

@ -1086,4 +1086,64 @@ export const mockEcsData: Ecs[] = [
},
zeek: null,
},
{
_id: '26',
timestamp: '2019-03-13T03:34:08.890Z',
event: {
action: 'was-authorized',
severity: null,
module: 'auditd',
category: 'user-login',
id: null,
dataset: null,
},
auditd: {
result: 'success',
session: '338',
data: {
acct: null,
terminal: '/dev/pts/0',
op: null,
},
summary: {
actor: {
primary: 'root',
secondary: 'alice',
},
object: {
primary: '/dev/pts/0',
secondary: null,
type: 'user-session',
},
how: '/sbin/pam_tally2',
message_type: null,
sequence: null,
},
},
host: {
id: '0a63559c1acf4c419d979c4b4d8b83ff',
name: 'suricata-bangalore',
ip: ['139.59.11.147', '10.47.0.5', 'fe80::ec0b:1bff:fe29:80bd'],
},
source: null,
destination: null,
geo: null,
suricata: null,
network: null,
http: null,
url: null,
user: {
name: 'alice',
},
process: {
pid: 21170,
name: null,
ppid: null,
args: null,
executable: '/sbin/pam_tally2',
title: null,
working_directory: null,
},
zeek: null,
},
];