mirror of
https://github.com/Graylog2/graylog2-server.git
synced 2026-03-13 09:32:21 +08:00
Update procedure steps to generate links for mutliple events
This commit is contained in:
@@ -21,6 +21,8 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.graylog.events.event.EventDto;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@JsonTypeInfo(
|
||||
use = JsonTypeInfo.Id.NAME,
|
||||
include = JsonTypeInfo.As.EXISTING_PROPERTY,
|
||||
@@ -36,6 +38,8 @@ public interface ActionConfig {
|
||||
|
||||
URIBuilder getLink(EventDto event);
|
||||
|
||||
URIBuilder getLink(Set<EventDto> events);
|
||||
|
||||
String validate();
|
||||
|
||||
class FallbackConfig implements ActionConfig {
|
||||
@@ -53,5 +57,10 @@ public interface ActionConfig {
|
||||
public URIBuilder getLink(EventDto event) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URIBuilder getLink(Set<EventDto> events) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ import jakarta.annotation.Nullable;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.graylog.events.event.EventDto;
|
||||
import org.graylog2.database.entities.DefaultEntityScope;
|
||||
|
||||
import java.util.Set;
|
||||
import org.graylog2.database.entities.ScopedEntity;
|
||||
import org.graylog2.security.html.HTMLSanitizerConverter;
|
||||
import org.mongojack.Id;
|
||||
@@ -59,6 +61,10 @@ public abstract class EventProcedureStep implements ScopedEntity<EventProcedureS
|
||||
return action() != null ? action().config().getLink(event) : null;
|
||||
}
|
||||
|
||||
public URIBuilder getLink(Set<EventDto> events) {
|
||||
return action() != null ? action().config().getLink(events) : null;
|
||||
}
|
||||
|
||||
@AutoValue.Builder
|
||||
public abstract static class Builder implements ScopedEntity.Builder<Builder> {
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@ import jakarta.inject.Inject;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.graylog.events.event.EventDto;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Executes an existing notification with the event.
|
||||
*/
|
||||
@@ -70,6 +73,18 @@ public class ExecuteNotification extends Action {
|
||||
return uriBuilder.build().getLinkPath();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public URIBuilder getLink(Set<EventDto> events) {
|
||||
final String combinedQuery = events.stream()
|
||||
.map(e -> "id:" + e.id())
|
||||
.collect(Collectors.joining(" OR "));
|
||||
final TemplateURI.Builder uriBuilder = new TemplateURI.Builder();
|
||||
uriBuilder.setPath("security/security-events/alerts");
|
||||
uriBuilder.addParameter("query", combinedQuery);
|
||||
return uriBuilder.build().getLinkPath();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public String validate() {
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.graylog.events.event.EventDto;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Redirects the frontend to an existing dashboard.
|
||||
@@ -81,6 +82,12 @@ public class GoToDashboard extends Action {
|
||||
return uriBuilder.build().getLinkPath();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public URIBuilder getLink(Set<EventDto> events) {
|
||||
throw new UnsupportedOperationException("Bulk execution is not supported for Go To Dashboard steps");
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public String validate() {
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.apache.http.client.utils.URIBuilder;
|
||||
import org.graylog.events.event.EventDto;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Redirects the frontend to a link.
|
||||
@@ -75,6 +76,12 @@ public class Link extends Action {
|
||||
}
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public URIBuilder getLink(Set<EventDto> events) {
|
||||
return getLink((EventDto) null);
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public String validate() {
|
||||
|
||||
@@ -29,6 +29,8 @@ import jakarta.annotation.Nullable;
|
||||
import jakarta.inject.Inject;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.graylog.events.event.EventDto;
|
||||
import org.graylog.events.event.EventReplayInfo;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
@@ -119,6 +121,42 @@ public class PerformSearch extends Action {
|
||||
return uriBuilder.build().getLinkPath();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public URIBuilder getLink(Set<EventDto> events) {
|
||||
final TemplateURI.Builder uriBuilder = new TemplateURI.Builder();
|
||||
if (Boolean.TRUE.equals(useSavedSearch())) {
|
||||
uriBuilder.setPath("views/" + savedSearch());
|
||||
uriBuilder.setParameters(parameters());
|
||||
} else {
|
||||
uriBuilder.setPath("search");
|
||||
uriBuilder.addParameter("q", query());
|
||||
}
|
||||
|
||||
DateTime earliestStart = null;
|
||||
DateTime latestEnd = null;
|
||||
for (EventDto event : events) {
|
||||
if (event.replayInfo().isPresent()) {
|
||||
final EventReplayInfo replayInfo = event.replayInfo().get();
|
||||
if (replayInfo.timerangeStart() != null) {
|
||||
earliestStart = earliestStart == null || replayInfo.timerangeStart().isBefore(earliestStart)
|
||||
? replayInfo.timerangeStart() : earliestStart;
|
||||
}
|
||||
if (replayInfo.timerangeEnd() != null) {
|
||||
latestEnd = latestEnd == null || replayInfo.timerangeEnd().isAfter(latestEnd)
|
||||
? replayInfo.timerangeEnd() : latestEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (earliestStart != null && latestEnd != null) {
|
||||
uriBuilder.addParameter("rangetype", "absolute");
|
||||
uriBuilder.addParameter("from", earliestStart.toString());
|
||||
uriBuilder.addParameter("to", latestEnd.toString());
|
||||
}
|
||||
|
||||
return uriBuilder.build().getLinkPath();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@Override
|
||||
public String validate() {
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@MockitoSettings(strictness = Strictness.WARN)
|
||||
@@ -90,6 +91,88 @@ public class ActionTest {
|
||||
assertThat(actionText).contains("/security/security-events/alerts?query=id%3A" + ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPerformSearchGetLink_bulkCombinesTimeranges() {
|
||||
EventDto event1 = mockEventWithReplayInfo("e1",
|
||||
DateTime.parse("2024-01-01T00:00:00.000Z"),
|
||||
DateTime.parse("2024-01-01T12:00:00.000Z"));
|
||||
EventDto event2 = mockEventWithReplayInfo("e2",
|
||||
DateTime.parse("2024-01-02T00:00:00.000Z"),
|
||||
DateTime.parse("2024-01-02T12:00:00.000Z"));
|
||||
|
||||
String link = performSearchQueryConfig().getLink(Set.of(event1, event2)).toString();
|
||||
|
||||
assertThat(link).contains("search?q=");
|
||||
assertThat(link).contains("rangetype=absolute");
|
||||
assertThat(link).contains("from=2024-01-01T00%3A00%3A00.000Z");
|
||||
assertThat(link).contains("to=2024-01-02T12%3A00%3A00.000Z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPerformSearchGetLink_bulkSavedSearch() {
|
||||
EventDto event1 = mockEventWithReplayInfo("e1",
|
||||
DateTime.parse("2024-03-01T00:00:00.000Z"),
|
||||
DateTime.parse("2024-03-01T06:00:00.000Z"));
|
||||
EventDto event2 = mockEventWithReplayInfo("e2",
|
||||
DateTime.parse("2024-02-15T00:00:00.000Z"),
|
||||
DateTime.parse("2024-03-02T00:00:00.000Z"));
|
||||
|
||||
String link = performSavedSearchConfig().getLink(Set.of(event1, event2)).toString();
|
||||
|
||||
assertThat(link).contains("views/" + ID);
|
||||
assertThat(link).contains("rangetype=absolute");
|
||||
assertThat(link).contains("from=2024-02-15T00%3A00%3A00.000Z");
|
||||
assertThat(link).contains("to=2024-03-02T00%3A00%3A00.000Z");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteNotificationGetLink_bulk() {
|
||||
EventDto event1 = mockEvent("event-abc");
|
||||
EventDto event2 = mockEvent("event-def");
|
||||
|
||||
String link = executeNotificationConfig().getLink(Set.of(event1, event2)).toString();
|
||||
|
||||
assertThat(link).contains("security/security-events/alerts");
|
||||
assertThat(link).contains("id%3Aevent-abc");
|
||||
assertThat(link).contains("id%3Aevent-def");
|
||||
assertThat(link).contains("OR");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGoToDashboardGetLink_bulkThrowsUnsupported() {
|
||||
assertThatThrownBy(() -> goToDashboardConfig().getLink(Set.of(event)))
|
||||
.isInstanceOf(UnsupportedOperationException.class)
|
||||
.hasMessageContaining("Go To Dashboard");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLinkGetLink_bulkReturnsSameLink() {
|
||||
Link.Config linkConfig = Link.Config.builder()
|
||||
.link("https://example.com/wiki")
|
||||
.build();
|
||||
|
||||
String link = linkConfig.getLink(Set.of(event)).toString();
|
||||
|
||||
assertThat(link).isEqualTo("https://example.com/wiki");
|
||||
}
|
||||
|
||||
private EventDto mockEvent(String id) {
|
||||
EventDto mock = org.mockito.Mockito.mock(EventDto.class);
|
||||
when(mock.id()).thenReturn(id);
|
||||
return mock;
|
||||
}
|
||||
|
||||
private EventDto mockEventWithReplayInfo(String id, DateTime start, DateTime end) {
|
||||
EventDto mock = mockEvent(id);
|
||||
when(mock.replayInfo()).thenReturn(Optional.of(EventReplayInfo.builder()
|
||||
.timerangeStart(start)
|
||||
.timerangeEnd(end)
|
||||
.query("")
|
||||
.streams(Set.of())
|
||||
.build()));
|
||||
return mock;
|
||||
}
|
||||
|
||||
private ExecuteNotification.Config executeNotificationConfig() {
|
||||
return ExecuteNotification.Config.builder()
|
||||
.type(ExecuteNotification.NAME)
|
||||
|
||||
Reference in New Issue
Block a user