Skip to content

Commit

Permalink
[SIEM] Fix bug on url + inspect functionality on hosts/hostDetails pa…
Browse files Browse the repository at this point in the history
…ge (#44671)

* refactor code to use react-router params instead of regex inside of use-url-state
Fix inspect in hosts/host details page
Fix some url state issue too

* add search in breadcrumb + fix existing unit testing

* refactor code to use react-router params instead of regex inside of use-url-state
Fix inspect in hosts/host details page
Fix some url state issue too

* add search in breadcrumb + fix existing unit testing

* fix bug by doing cypress test

* clean up + unit testing

* review I

* [SIEM] Fixes the Anomalies table paging to work again

* Updated to look more like the PR in flight to have a smaller diff

* fix cyclic deps

* remove redundant comment

* review II

* review II + fix circular dependency

* fix host url
  • Loading branch information
XavierM authored Sep 5, 2019
1 parent 7d22b74 commit a712751
Show file tree
Hide file tree
Showing 63 changed files with 2,601 additions and 1,745 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ export const ALL_HOSTS_WIDGET_DRAGGABLE_HOSTS = `${ALL_HOSTS_WIDGET} ${ALL_HOSTS

/** Clicking this button displays the `Events` tab */
export const EVENTS_TAB_BUTTON = '[data-test-subj="navigation-events"]';

export const NAVIGATION_HOSTS_ALL_HOSTS = '[data-test-subj="navigation-link-allHosts"]';

export const NAVIGATION_HOSTS_ANOMALIES = '[data-test-subj="navigation-link-anomalies"]';
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@ export const ABSOLUTE_DATE_RANGE = {
'/app/siem#/network/?kqlQuery=(filterQuery:!n,queryLocation:network.page)&timerange=(global:(linkTo:!(),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(),timerange:(from:1564776209186,kind:absolute,to:1564779809186)))',
urlKqlNetworkNetwork: `/app/siem#/network/?_g=()&kqlQuery=(filterQuery:(expression:'source.ip:%20"10.142.0.9"',kind:kuery),queryLocation:network.page)&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))`,
urlKqlNetworkHosts: `/app/siem#/network/?_g=()&kqlQuery=(filterQuery:(expression:'source.ip:%20"10.142.0.9"',kind:kuery),queryLocation:hosts.page)&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))`,
urlKqlHostsNetwork: `/app/siem#/hosts/?_g=()&kqlQuery=(filterQuery:(expression:'source.ip:%20"10.142.0.9"',kind:kuery),queryLocation:network.page)&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))`,
urlKqlHostsHosts: `/app/siem#/hosts/?_g=()&kqlQuery=(filterQuery:(expression:'source.ip:%20"10.142.0.9"',kind:kuery),queryLocation:hosts.page)&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))`,
urlKqlHostsNetwork: `/app/siem#/hosts/allHosts?_g=()&kqlQuery=(filterQuery:(expression:'source.ip:%20"10.142.0.9"',kind:kuery),queryLocation:network.page)&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))`,
urlKqlHostsHosts: `/app/siem#/hosts/allHosts?_g=()&kqlQuery=(filterQuery:(expression:'source.ip:%20"10.142.0.9"',kind:kuery),queryLocation:hosts.page)&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))`,
urlHost:
'/app/siem#/hosts/authentications?timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))',
};
export const DATE_PICKER_START_DATE_POPOVER_BUTTON =
'[data-test-subj="globalDatePicker"] [data-test-subj="superDatePickerstartDatePopoverButton"]';
'div[data-test-subj="globalDatePicker"] button[data-test-subj="superDatePickerstartDatePopoverButton"]';
export const DATE_PICKER_END_DATE_POPOVER_BUTTON =
'[data-test-subj="globalDatePicker"] [data-test-subj="superDatePickerendDatePopoverButton"]';
export const DATE_PICKER_START_DATE_POPOVER_BUTTON_TIMELINE =
Expand All @@ -56,3 +58,6 @@ export const DATE_PICKER_APPLY_BUTTON_TIMELINE =
export const DATE_PICKER_ABSOLUTE_INPUT = '[data-test-subj="superDatePickerAbsoluteDateInput"]';
export const KQL_INPUT = '[data-test-subj="kqlInput"]';
export const TIMELINE_TITLE = '[data-test-subj="timeline-title"]';

export const HOST_DETAIL_SIEM_KIBANA = '[data-test-subj="all-hosts"] a.euiLink';
export const BREADCRUMBS = '[data-test-subj="breadcrumbs"] a';
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

/** The SIEM app's Hosts page */
export const HOSTS_PAGE = '/app/siem#/hosts';
export const HOSTS_PAGE = '/app/siem#/hosts/allHosts';

/** Kibana's login page */
export const LOGIN_PAGE = '/login';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {
DATE_PICKER_START_DATE_POPOVER_BUTTON_TIMELINE,
KQL_INPUT,
TIMELINE_TITLE,
HOST_DETAIL_SIEM_KIBANA,
BREADCRUMBS,
} from '../../lib/url_state';
import { DEFAULT_TIMEOUT, loginAndWaitForPage } from '../../lib/util/helpers';
import {
Expand All @@ -25,8 +27,10 @@ import {
hostExistsQuery,
toggleTimelineVisibility,
} from '../../lib/timeline/helpers';
import { NAVIGATION_NETWORK } from '../../lib/navigation/selectors';
import { NAVIGATION_NETWORK, NAVIGATION_HOSTS } from '../../lib/navigation/selectors';
import { HOSTS_PAGE } from '../../lib/urls';
import { waitForAllHostsWidget } from '../../lib/hosts/helpers';
import { NAVIGATION_HOSTS_ALL_HOSTS, NAVIGATION_HOSTS_ANOMALIES } from '../../lib/hosts/selectors';

describe('url state', () => {
afterEach(() => {
Expand Down Expand Up @@ -190,6 +194,65 @@ describe('url state', () => {
);
});

it('sets the url state when kql is set and check if href reflect this change', () => {
loginAndWaitForPage(ABSOLUTE_DATE_RANGE.url);
cy.get(KQL_INPUT, { timeout: 5000 }).type('source.ip: "10.142.0.9" {enter}');
cy.get(NAVIGATION_HOSTS)
.first()
.click({ force: true });
cy.get(NAVIGATION_NETWORK).should(
'have.attr',
'href',
"#/link-to/network?kqlQuery=(filterQuery:(expression:'source.ip:%20%2210.142.0.9%22%20',kind:kuery),queryLocation:network.page)&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))"
);
});

it('sets KQL in host page and detail page and check if href match on breadcrumb, tabs and subTabs', () => {
loginAndWaitForPage(ABSOLUTE_DATE_RANGE.urlHost);
cy.get(KQL_INPUT, { timeout: 5000 }).type('host.name: "siem-kibana" {enter}');
cy.get(NAVIGATION_HOSTS_ALL_HOSTS)
.first()
.click({ force: true });
waitForAllHostsWidget();
cy.get(HOST_DETAIL_SIEM_KIBANA, { timeout: 5000 })
.first()
.invoke('text')
.should('eq', 'siem-kibana');
cy.get(HOST_DETAIL_SIEM_KIBANA)
.first()
.click({ force: true });
cy.get(KQL_INPUT, { timeout: 5000 }).type('agent.type: "auditbeat" {enter}');
cy.get(NAVIGATION_HOSTS).should(
'have.attr',
'href',
"#/link-to/hosts?kqlQuery=(filterQuery:(expression:'host.name:%20%22siem-kibana%22%20',kind:kuery),queryLocation:hosts.page)&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))"
);
cy.get(NAVIGATION_NETWORK).should(
'have.attr',
'href',
'#/link-to/network?timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))'
);
cy.get(NAVIGATION_HOSTS_ANOMALIES).should(
'have.attr',
'href',
"#/hosts/siem-kibana/anomalies?kqlQuery=(filterQuery:(expression:'agent.type:%20%22auditbeat%22%20',kind:kuery),queryLocation:hosts.details)&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))"
);
cy.get(BREADCRUMBS)
.eq(1)
.should(
'have.attr',
'href',
"#/link-to/hosts?kqlQuery=(filterQuery:(expression:'host.name:%20%22siem-kibana%22%20',kind:kuery),queryLocation:hosts.page)&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))"
);
cy.get(BREADCRUMBS)
.eq(2)
.should(
'have.attr',
'href',
"#/link-to/hosts/siem-kibana?kqlQuery=(filterQuery:(expression:'agent.type:%20%22auditbeat%22%20',kind:kuery),queryLocation:hosts.details)&timerange=(global:(linkTo:!(timeline),timerange:(from:1564689809186,kind:absolute,to:1564691609186)),timeline:(linkTo:!(global),timerange:(from:1564689809186,kind:absolute,to:1564691609186)))"
);
});

it('clears kql when navigating to a new page', () => {
loginAndWaitForPage(ABSOLUTE_DATE_RANGE.urlKqlHostsHosts);
cy.get(NAVIGATION_NETWORK).click({ force: true });
Expand All @@ -202,17 +265,10 @@ describe('url state', () => {
executeKQL(hostExistsQuery);
assertAtLeastOneEventMatchesSearch();
const bestTimelineName = 'The Best Timeline';
cy.get(TIMELINE_TITLE).type(bestTimelineName);
cy.hash().then(hash => {
const matched = hash.match(/(?<=timelineId=\').+?(?=\')/g);
const newTimelineId = matched && matched.length > 0 ? matched[0] : 'null';
expect(matched).to.have.lengthOf(1);
cy.log('hash', hash);
cy.log('matched', matched);
cy.log('newTimelineId', newTimelineId);
cy.visit(
`/app/siem#/timelines?timelineId='${newTimelineId}'&timerange=(global:(linkTo:!(),timerange:(from:1565274377369,kind:absolute,to:1565360777369)),timeline:(linkTo:!(),timerange:(from:1565274377369,kind:absolute,to:1565360777369)))`
).then(() => cy.get(TIMELINE_TITLE).should('have.attr', 'value', bestTimelineName));
});
cy.get(TIMELINE_TITLE, { timeout: 5000 }).type(bestTimelineName);
cy.url().should('include', 'timelineId=');
cy.visit(
`/app/siem#/timelines?timerange=(global:(linkTo:!(),timerange:(from:1565274377369,kind:absolute,to:1565360777369)),timeline:(linkTo:!(),timerange:(from:1565274377369,kind:absolute,to:1565360777369)))`
).then(() => cy.get(TIMELINE_TITLE).should('have.attr', 'value', bestTimelineName));
});
});
22 changes: 14 additions & 8 deletions x-pack/legacy/plugins/siem/public/components/link_to/link_to.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,27 @@ interface LinkToPageProps {

export const LinkToPage = pure<LinkToPageProps>(({ match }) => (
<Switch>
<Route path={`${match.url}/overview`} component={RedirectToOverviewPage} />
<Route exact path={`${match.url}/hosts`} component={RedirectToHostsPage} />
<Route path={`${match.url}/:pageName(overview)`} component={RedirectToOverviewPage} />
<Route exact path={`${match.url}/:pageName(hosts)`} component={RedirectToHostsPage} />
<Route
path={`${match.url}/hosts/:tabName(${HostsTableType.hosts}|${HostsTableType.authentications}|${HostsTableType.uncommonProcesses}|${HostsTableType.anomalies}|${HostsTableType.events})`}
path={`${match.url}/:pageName(hosts)/:tabName(${HostsTableType.hosts}|${HostsTableType.authentications}|${HostsTableType.uncommonProcesses}|${HostsTableType.anomalies}|${HostsTableType.events})`}
component={RedirectToHostsPage}
/>
<Route
path={`${match.url}/hosts/:hostName/:tabName(${HostsTableType.authentications}|${HostsTableType.uncommonProcesses}|${HostsTableType.anomalies}|${HostsTableType.events})`}
path={`${match.url}/:pageName(hosts)/:detailName/:tabName(${HostsTableType.authentications}|${HostsTableType.uncommonProcesses}|${HostsTableType.anomalies}|${HostsTableType.events})`}
component={RedirectToHostDetailsPage}
/>
<Route
path={`${match.url}/:pageName(hosts)/:detailName`}
component={RedirectToHostDetailsPage}
/>
<Route path={`${match.url}/hosts/:hostName`} component={RedirectToHostDetailsPage} />

<Route exact path={`${match.url}/network`} component={RedirectToNetworkPage} />
<Route path={`${match.url}/network/ip/:ip`} component={RedirectToNetworkPage} />
<Route path={`${match.url}/timelines`} component={RedirectToTimelinesPage} />
<Route exact path={`${match.url}/:pageName(network)`} component={RedirectToNetworkPage} />
<Route
path={`${match.url}/:pageName(network)/ip/:detailName`}
component={RedirectToNetworkPage}
/>
<Route path={`${match.url}/:pageName(timelines)`} component={RedirectToTimelinesPage} />
<Redirect to="/" />
</Switch>
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { RedirectWrapper } from './redirect_wrapper';
import { HostsTableType } from '../../store/hosts/model';

export type HostComponentProps = RouteComponentProps<{
hostName: string;
detailName: string;
tabName: HostsTableType;
search: string;
}>;
Expand All @@ -31,22 +31,22 @@ export const RedirectToHostsPage = ({

export const RedirectToHostDetailsPage = ({
match: {
params: { hostName, tabName },
params: { detailName, tabName },
},
location: { search },
}: HostComponentProps) => {
const defaultSelectedTab = HostsTableType.authentications;
const selectedTab = tabName ? tabName : defaultSelectedTab;
const to = `/hosts/${hostName}/${selectedTab}${search}`;
const to = `/hosts/${detailName}/${selectedTab}${search}`;
return <RedirectWrapper to={to} />;
};

export const getHostsUrl = () => '#/link-to/hosts';

export const getTabsOnHostsUrl = (tabName: HostsTableType) => `#/link-to/hosts/${tabName}`;

export const getHostDetailsUrl = (hostName: string) => `#/link-to/hosts/${hostName}`;
export const getHostDetailsUrl = (detailName: string) => `#/link-to/hosts/${detailName}`;

export const getTabsOnHostDetailsUrl = (hostName: string, tabName: HostsTableType) => {
return `#/link-to/hosts/${hostName}/${tabName}`;
export const getTabsOnHostDetailsUrl = (detailName: string, tabName: HostsTableType) => {
return `#/link-to/hosts/${detailName}/${tabName}`;
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ import { RouteComponentProps } from 'react-router-dom';
import { RedirectWrapper } from './redirect_wrapper';

export type NetworkComponentProps = RouteComponentProps<{
ip: string;
detailName: string;
search: string;
}>;

export const RedirectToNetworkPage = ({
match: {
params: { ip },
params: { detailName },
},
location: { search },
}: NetworkComponentProps) => (
<RedirectWrapper to={ip ? `/network/ip/${ip}${search}` : `/network/${search}`} />
<RedirectWrapper to={detailName ? `/network/ip/${detailName}${search}` : `/network${search}`} />
);

export const getNetworkUrl = () => '#/link-to/network';
Loading

0 comments on commit a712751

Please sign in to comment.