Skip to content

Commit

Permalink
Merge pull request #4 from hidapple/open-graylog
Browse files Browse the repository at this point in the history
Open graylog
  • Loading branch information
hidapple authored Apr 14, 2019
2 parents 988763d + 7cf7520 commit 3b539bd
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 45 deletions.
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,15 @@ Create Graylog notification of your stream and choose `Microsoft Teams Alarm Cal
#### 3. Configure Microsoft Teams Alarm Callback
Input your Teams incoming webhook published at #1 and fill out other configurations. Here is a screenshot of configuration example.


![Teams notification configuraiton](img/configuration.png)

#### 4. Receive notification
You will receive notification message.
You will receive notification message like below.

![Teams notification message](img/message.png)

Getting started
---------------
Getting development started
---------------------------

This project is using Maven 3 and requires Java 8 or higher.

Expand Down
Binary file modified img/configuration.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified img/message.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>org.graylog.plugins</groupId>
<artifactId>graylog-plugin-teams</artifactId>
<version>1.0.0</version>
<version>1.1.0</version>
<packaging>jar</packaging>

<name>${project.artifactId}</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,6 @@

import com.floreysoft.jmte.Engine;
import com.google.common.collect.Lists;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.graylog.plugins.teams.client.TeamsClient;
import org.graylog.plugins.teams.client.TeamsClientException;
import org.graylog.plugins.teams.client.TeamsMessageCard;
Expand All @@ -28,6 +21,14 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
* TeamsNotification is Graylog Notification(AlarmCallback) Plugin.
*/
Expand Down Expand Up @@ -55,8 +56,10 @@ public void call(Stream stream, AlertCondition.CheckResult result) throws AlarmC
configuration.getString(TeamsNotificationConfig.COLOR),
"Alert for Graylog stream: " + stream.getTitle(),
result.getResultDescription(),
buildDetailMsg(stream, result, configuration.getString(TeamsNotificationConfig.DETAIL_MESSAGE))
buildDetailMsg(stream, result, configuration.getString(TeamsNotificationConfig.DETAIL_MESSAGE)),
configuration.getString(TeamsNotificationConfig.GRAYLOG_URL)
);
System.out.println(req.toJsonString());
try {
client.postMessageCard(req);
} catch(TeamsClientException ex) {
Expand All @@ -74,6 +77,12 @@ public ConfigurationRequest getRequestedConfiguration() {
"Microsoft Teams Incoming Webhook URL",
Optional.NOT_OPTIONAL));

configRequest.addField(new TextField(
TeamsNotificationConfig.GRAYLOG_URL, "Graylog URL",
"",
"URL to be attached in notification",
Optional.OPTIONAL));

configRequest.addField(new TextField(
TeamsNotificationConfig.COLOR, "Color",
"0076D7",
Expand All @@ -97,7 +106,7 @@ public ConfigurationRequest getRequestedConfiguration() {
"${else}" +
"<No backlog>\n" +
"${end}",
"Detail message. Basic Markdown syntax is acceptable.",
"Detail message supporting basic Markdown syntax",
Optional.OPTIONAL,
Attribute.TEXTAREA));

Expand Down Expand Up @@ -127,6 +136,7 @@ public void checkConfiguration() throws ConfigurationException {
}
validateURI(configuration, TeamsNotificationConfig.WEBHOOK_URL);
validateURI(configuration, TeamsNotificationConfig.PROXY);
validateURI(configuration, TeamsNotificationConfig.GRAYLOG_URL);

// Not error but warning
if (configuration.stringIsSet(TeamsNotificationConfig.COLOR)) {
Expand Down Expand Up @@ -175,10 +185,15 @@ private Map<String, Object> getModel(Stream stream, AlertCondition.CheckResult r

private void validateURI(Configuration config, String field) throws ConfigurationException {
if (!config.stringIsSet(field)) return;

String uri = config.getString(field);
try {
new URI(Objects.requireNonNull(config.getString(field)));
new URI(Objects.requireNonNull(uri));
} catch (URISyntaxException ex) {
throw new ConfigurationException(field + " is invalid as URI");
}
if (!uri.startsWith("http://") && !uri.startsWith("https://")) {
throw new ConfigurationException(field + " supports only http(s)");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ public class TeamsNotificationConfig {

public static final String WEBHOOK_URL = "webhook_url";

public static final String GRAYLOG_URL = "graylog_url";

public static final String COLOR = "color";

public static final String DETAIL_MESSAGE = "detail_message";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.apache.commons.lang.StringUtils;

/**
* MessageCard is representing Outlook Actionable Message Card request.
Expand All @@ -26,8 +27,9 @@ public class TeamsMessageCard {
private String title;
private String text;
private List<Section> sections;
private List<PotentialAction> potentialAction;

public TeamsMessageCard(String color, String title, String text, String detailMsg) {
public TeamsMessageCard(String color, String title, String text, String detailMsg, String url) {
this.type = "MessageCard";
this.context = "https://schema.org/extensions";
this.themeColor = color;
Expand All @@ -36,6 +38,13 @@ public TeamsMessageCard(String color, String title, String text, String detailMs
if (!StringUtils.isEmpty(detailMsg)) {
this.sections = Lists.newArrayList(new Section("Detail Message:", detailMsg));
}
if (!StringUtils.isEmpty(url)) {
Map<String, String> target = new HashMap<>();
target.put("os", "default");
target.put("uri", url);
this.potentialAction = Lists.newArrayList(
new PotentialAction("OpenUri", "Open Graylog", Lists.newArrayList(target)));
}
}

public String toJsonString() {
Expand All @@ -45,9 +54,12 @@ public String toJsonString() {
params.put("themeColor", themeColor);
params.put("title", title);
params.put("text", text);
if (Objects.nonNull(this.sections)) {
if (Objects.nonNull(sections)) {
params.put("sections", sections);
}
if (Objects.nonNull(potentialAction)) {
params.put("potentialAction", potentialAction);
}

try {
return new ObjectMapper().writeValueAsString(params);
Expand All @@ -70,4 +82,23 @@ public Section(String title, String text) {
this.text = text;
}
}

@JsonInclude(Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public static class PotentialAction {
@JsonProperty("@type")
String type;
@JsonProperty("name")
String name;
@JsonProperty("targets")
List<Map<String, String>> targets;

@JsonCreator
PotentialAction(String type, String name, List<Map<String, String>> targets) {
this.type = type;
this.name = name;
this.targets = targets;
}
}

}
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
package org.graylog.plugins.teams.alerts;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

import com.google.common.collect.Lists;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.graylog2.plugin.alarms.callbacks.AlarmCallbackConfigurationException;
import org.graylog2.plugin.configuration.Configuration;
Expand All @@ -17,6 +9,15 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

class TeamsNotificationTest {

private TeamsNotification sut;
Expand All @@ -40,14 +41,15 @@ void getAttribute() throws AlarmCallbackConfigurationException {
void getRequestedConfiguration() {
List<String> expectedConfigFields = Lists.newArrayList(
TeamsNotificationConfig.WEBHOOK_URL,
TeamsNotificationConfig.GRAYLOG_URL,
TeamsNotificationConfig.COLOR,
TeamsNotificationConfig.DETAIL_MESSAGE,
TeamsNotificationConfig.PROXY
);

Map<String, ConfigurationField> actual = sut.getRequestedConfiguration().getFields();

assertEquals(4, actual.size());
assertEquals(expectedConfigFields.size(), actual.size());
expectedConfigFields.forEach(
expected -> assertTrue(actual.containsKey(expected)));
}
Expand Down Expand Up @@ -92,6 +94,16 @@ void checkConfiguration_Fail_WebhookURLIsInvalid() throws AlarmCallbackConfigura
assertEquals(TeamsNotificationConfig.WEBHOOK_URL + " is invalid as URI", ex.getMessage());
}

@Test
void checkConfiguration_Fail_WebhookURLIsUnsupportedProtocol() throws AlarmCallbackConfigurationException {
Map<String, Object> m = createValidConfigMap();
m.replace(TeamsNotificationConfig.WEBHOOK_URL, "ftp://localhost");
sut.initialize(new Configuration(m));

ConfigurationException ex = assertThrows(ConfigurationException.class, () -> sut.checkConfiguration());
assertEquals(TeamsNotificationConfig.WEBHOOK_URL + " supports only http(s)", ex.getMessage());
}

@Test
void checkConfiguration_Fail_ProxyURLIsInvalid() throws AlarmCallbackConfigurationException {
Map<String, Object> m = createValidConfigMap();
Expand All @@ -102,9 +114,40 @@ void checkConfiguration_Fail_ProxyURLIsInvalid() throws AlarmCallbackConfigurati
assertEquals(TeamsNotificationConfig.PROXY + " is invalid as URI", ex.getMessage());
}

@Test
void checkConfiguration_Fail_ProxyURLIsUnsupportedProtocol() throws AlarmCallbackConfigurationException {
Map<String, Object> m = createValidConfigMap();
m.replace(TeamsNotificationConfig.PROXY, "ftp://localhost");
sut.initialize(new Configuration(m));

ConfigurationException ex = assertThrows(ConfigurationException.class, () -> sut.checkConfiguration());
assertEquals(TeamsNotificationConfig.PROXY + " supports only http(s)", ex.getMessage());
}

@Test
void checkConfiguration_Fail_GraylogURLIsInvalid() throws AlarmCallbackConfigurationException {
Map<String, Object> m = createValidConfigMap();
m.replace(TeamsNotificationConfig.GRAYLOG_URL, "invalid URL");
sut.initialize(new Configuration(m));

ConfigurationException ex = assertThrows(ConfigurationException.class, () -> sut.checkConfiguration());
assertEquals(TeamsNotificationConfig.GRAYLOG_URL + " is invalid as URI", ex.getMessage());
}

@Test
void checkConfiguration_Fail_GraylogURLIsUnsupportedProtocol() throws AlarmCallbackConfigurationException {
Map<String, Object> m = createValidConfigMap();
m.replace(TeamsNotificationConfig.GRAYLOG_URL, "ftp://localhost");
sut.initialize(new Configuration(m));

ConfigurationException ex = assertThrows(ConfigurationException.class, () -> sut.checkConfiguration());
assertEquals(TeamsNotificationConfig.GRAYLOG_URL + " supports only http(s)", ex.getMessage());
}

private Map<String, Object> createValidConfigMap() {
Map<String, Object> m = new HashMap<>();
m.put(TeamsNotificationConfig.WEBHOOK_URL, "https://testwebhook.com");
m.put(TeamsNotificationConfig.GRAYLOG_URL, "https://my-graylog.com");
m.put(TeamsNotificationConfig.COLOR, "000000");
m.put(TeamsNotificationConfig.DETAIL_MESSAGE, "Detail");
m.put(TeamsNotificationConfig.PROXY, "http://proxy.com:9999");
Expand Down
23 changes: 12 additions & 11 deletions src/test/java/org/graylog/plugins/teams/client/TeamsClientTest.java
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
package org.graylog.plugins.teams.client;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;

import com.github.tomakehurst.wiremock.WireMockServer;
import java.util.HashMap;
import java.util.Map;
import org.graylog.plugins.teams.alerts.TeamsNotificationConfig;
import org.graylog2.plugin.configuration.Configuration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.Map;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;

class TeamsClientTest {

@Test
Expand Down Expand Up @@ -99,7 +100,7 @@ void postMessageCard() {

// Then
try {
sut.postMessageCard(new TeamsMessageCard("FFFFFF", "Title", "Text", "Detail"));
sut.postMessageCard(new TeamsMessageCard("FFFFFF", "Title", "Text", "Detail", ""));
} catch (Exception ex) {
fail("Exception should not be thrown.", ex);
}
Expand All @@ -119,7 +120,7 @@ void postMessageCard_Fail_UnexpectedRequestCode() {

// Then
TeamsClientException ex = assertThrows(TeamsClientException.class,
() -> sut.postMessageCard(new TeamsMessageCard("FFFFFF", "Title", "Text", "Detail")));
() -> sut.postMessageCard(new TeamsMessageCard("FFFFFF", "Title", "Text", "Detail", "")));
assertEquals("Teams webhook returned unexpected response status. HTTP Status=500", ex.getMessage());
}
}
Expand Down
Loading

0 comments on commit 3b539bd

Please sign in to comment.