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] Fix bug on url + inspect functionality on hosts/hostDetails page #44671

Merged
merged 16 commits into from
Sep 5, 2019
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 @@ -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', () => {
XavierM marked this conversation as resolved.
Show resolved Hide resolved
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;
XavierM marked this conversation as resolved.
Show resolved Hide resolved
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