Browse Source

[Feature-7804][Task] DingTalk alert plugin adds signature. (#7805)

* DingTalk alarm component adds signature.

* fix code style.

* fix code style.

* add dingtalk document link

* fix DingTalkAlertChannelFactoryTest

* update NAME_DING_TALK_SECRET
3.0.0/version-upgrade
Kerwin 3 years ago committed by GitHub
parent
commit
cb8c875fa8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 46
      dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkAlertChannelFactory.java
  2. 3
      dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkParamsConstants.java
  3. 43
      dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkSender.java
  4. 2
      dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/test/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkAlertChannelFactoryTest.java
  5. 1
      dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
  6. 3
      dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js

46
dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkAlertChannelFactory.java

@ -45,46 +45,60 @@ public final class DingTalkAlertChannelFactory implements AlertChannelFactory {
@Override @Override
public List<PluginParams> params() { public List<PluginParams> params() {
InputParam webHookParam = InputParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_WEB_HOOK, DingTalkParamsConstants.DING_TALK_WEB_HOOK) InputParam webHookParam = InputParam
.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_WEB_HOOK, DingTalkParamsConstants.DING_TALK_WEB_HOOK)
.addValidate(Validate.newBuilder() .addValidate(Validate.newBuilder()
.setRequired(true) .setRequired(true)
.build()) .build())
.build(); .build();
InputParam keywordParam = InputParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_KEYWORD, DingTalkParamsConstants.DING_TALK_KEYWORD) InputParam keywordParam = InputParam
.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_KEYWORD, DingTalkParamsConstants.DING_TALK_KEYWORD)
.addValidate(Validate.newBuilder() .addValidate(Validate.newBuilder()
.setRequired(true) .setRequired(false)
.build())
.build();
InputParam secretParam = InputParam
.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_SECRET, DingTalkParamsConstants.DING_TALK_SECRET)
.addValidate(Validate.newBuilder()
.setRequired(false)
.build()) .build())
.build(); .build();
RadioParam isEnableProxy = RadioParam isEnableProxy = RadioParam
RadioParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PROXY_ENABLE, DingTalkParamsConstants.DING_TALK_PROXY_ENABLE) .newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PROXY_ENABLE, DingTalkParamsConstants.DING_TALK_PROXY_ENABLE)
.addParamsOptions(new ParamsOptions(STRING_YES, STRING_TRUE, false)) .addParamsOptions(new ParamsOptions(STRING_YES, STRING_TRUE, false))
.addParamsOptions(new ParamsOptions(STRING_NO, STRING_FALSE, false)) .addParamsOptions(new ParamsOptions(STRING_NO, STRING_FALSE, false))
.setValue(STRING_TRUE) .setValue(STRING_FALSE)
.addValidate(Validate.newBuilder() .addValidate(Validate.newBuilder()
.setRequired(false) .setRequired(false)
.build()) .build())
.build(); .build();
InputParam proxyParam = InputParam proxyParam = InputParam
InputParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PROXY, DingTalkParamsConstants.DING_TALK_PROXY) .newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PROXY, DingTalkParamsConstants.DING_TALK_PROXY)
.addValidate(Validate.newBuilder() .addValidate(Validate.newBuilder()
.setRequired(false).build()) .setRequired(false)
.build())
.build(); .build();
InputParam portParam = InputParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PORT, DingTalkParamsConstants.DING_TALK_PORT) InputParam portParam = InputParam
.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PORT, DingTalkParamsConstants.DING_TALK_PORT)
.addValidate(Validate.newBuilder() .addValidate(Validate.newBuilder()
.setRequired(false).build()) .setRequired(false)
.build())
.build(); .build();
InputParam userParam = InputParam userParam = InputParam
InputParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_USER, DingTalkParamsConstants.DING_TALK_USER) .newBuilder(DingTalkParamsConstants.NAME_DING_TALK_USER, DingTalkParamsConstants.DING_TALK_USER)
.addValidate(Validate.newBuilder() .addValidate(Validate.newBuilder()
.setRequired(false).build()) .setRequired(false)
.build())
.build(); .build();
PasswordParam passwordParam = PasswordParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PASSWORD, DingTalkParamsConstants.DING_TALK_PASSWORD) PasswordParam passwordParam = PasswordParam
.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PASSWORD, DingTalkParamsConstants.DING_TALK_PASSWORD)
.setPlaceholder("if enable use authentication, you need input password") .setPlaceholder("if enable use authentication, you need input password")
.build(); .build();
return Arrays.asList(webHookParam, keywordParam, isEnableProxy, proxyParam, portParam, userParam, passwordParam); return Arrays.asList(webHookParam, keywordParam, secretParam, isEnableProxy, proxyParam, portParam, userParam, passwordParam);
} }
@Override @Override

3
dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkParamsConstants.java

@ -27,6 +27,9 @@ public final class DingTalkParamsConstants {
static final String DING_TALK_KEYWORD = "$t('keyword')"; static final String DING_TALK_KEYWORD = "$t('keyword')";
static final String NAME_DING_TALK_KEYWORD = "Keyword"; static final String NAME_DING_TALK_KEYWORD = "Keyword";
static final String DING_TALK_SECRET = "$t('secret')";
static final String NAME_DING_TALK_SECRET = "Secret";
static final String DING_TALK_PROXY = "$t('proxy')"; static final String DING_TALK_PROXY = "$t('proxy')";
static final String NAME_DING_TALK_PROXY = "Proxy"; static final String NAME_DING_TALK_PROXY = "Proxy";

43
dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkSender.java

@ -20,6 +20,7 @@ package org.apache.dolphinscheduler.plugin.alert.dingtalk;
import org.apache.dolphinscheduler.alert.api.AlertResult; import org.apache.dolphinscheduler.alert.api.AlertResult;
import org.apache.dolphinscheduler.spi.utils.JSONUtils; import org.apache.dolphinscheduler.spi.utils.JSONUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils; import org.apache.commons.codec.binary.StringUtils;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.HttpHost; import org.apache.http.HttpHost;
@ -36,17 +37,29 @@ import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import java.io.IOException; import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/**
* <p>
* https://open.dingtalk.com/document/robots/custom-robot-access
* https://open.dingtalk.com/document/robots/customize-robot-security-settings
* </p>
*/
public final class DingTalkSender { public final class DingTalkSender {
private static final Logger logger = LoggerFactory.getLogger(DingTalkSender.class); private static final Logger logger = LoggerFactory.getLogger(DingTalkSender.class);
private final String url; private final String url;
private final String keyword; private final String keyword;
private final String secret;
private final Boolean enableProxy; private final Boolean enableProxy;
private String proxy; private String proxy;
@ -60,6 +73,7 @@ public final class DingTalkSender {
DingTalkSender(Map<String, String> config) { DingTalkSender(Map<String, String> config) {
url = config.get(DingTalkParamsConstants.NAME_DING_TALK_WEB_HOOK); url = config.get(DingTalkParamsConstants.NAME_DING_TALK_WEB_HOOK);
keyword = config.get(DingTalkParamsConstants.NAME_DING_TALK_KEYWORD); keyword = config.get(DingTalkParamsConstants.NAME_DING_TALK_KEYWORD);
secret = config.get(DingTalkParamsConstants.NAME_DING_TALK_SECRET);
enableProxy = Boolean.valueOf(config.get(DingTalkParamsConstants.NAME_DING_TALK_PROXY_ENABLE)); enableProxy = Boolean.valueOf(config.get(DingTalkParamsConstants.NAME_DING_TALK_PROXY_ENABLE));
if (Boolean.TRUE.equals(enableProxy)) { if (Boolean.TRUE.equals(enableProxy)) {
port = Integer.parseInt(config.get(DingTalkParamsConstants.NAME_DING_TALK_PORT)); port = Integer.parseInt(config.get(DingTalkParamsConstants.NAME_DING_TALK_PORT));
@ -145,8 +159,18 @@ public final class DingTalkSender {
private String sendMsg(String title, String content) throws IOException { private String sendMsg(String title, String content) throws IOException {
String msgToJson = textToJsonString(title + content + "#" + keyword); StringBuilder text = new StringBuilder();
HttpPost httpPost = constructHttpPost(url, msgToJson); if (org.apache.dolphinscheduler.spi.utils.StringUtils.isNotBlank(keyword)) {
text.append(keyword);
text.append(":");
}
text.append(title);
text.append("\n");
text.append(content);
String msgToJson = textToJsonString(text.toString());
HttpPost httpPost = constructHttpPost(org.apache.dolphinscheduler.spi.utils.StringUtils.isBlank(secret) ? url : generateSignedUrl(), msgToJson);
CloseableHttpClient httpClient; CloseableHttpClient httpClient;
if (Boolean.TRUE.equals(enableProxy)) { if (Boolean.TRUE.equals(enableProxy)) {
@ -174,6 +198,21 @@ public final class DingTalkSender {
} }
} }
private String generateSignedUrl() {
Long timestamp = System.currentTimeMillis();
String stringToSign = timestamp + "\n" + secret;
String sign = org.apache.dolphinscheduler.spi.utils.StringUtils.EMPTY;
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)),"UTF-8");
} catch (Exception e) {
logger.error("generate sign error, message:{}", e);
}
return url + "&timestamp=" + timestamp + "&sign=" + sign;
}
static final class DingTalkSendMsgResponse { static final class DingTalkSendMsgResponse {
private Integer errcode; private Integer errcode;
private String errmsg; private String errmsg;

2
dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/test/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkAlertChannelFactoryTest.java

@ -32,7 +32,7 @@ public class DingTalkAlertChannelFactoryTest {
DingTalkAlertChannelFactory dingTalkAlertChannelFactory = new DingTalkAlertChannelFactory(); DingTalkAlertChannelFactory dingTalkAlertChannelFactory = new DingTalkAlertChannelFactory();
List<PluginParams> params = dingTalkAlertChannelFactory.params(); List<PluginParams> params = dingTalkAlertChannelFactory.params();
JSONUtils.toJsonString(params); JSONUtils.toJsonString(params);
Assert.assertEquals(7, params.size()); Assert.assertEquals(8, params.size());
} }
@Test @Test

1
dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js

@ -726,6 +726,7 @@ export default {
WebHook: 'WebHook', WebHook: 'WebHook',
webHook: 'WebHook', webHook: 'WebHook',
Keyword: 'Keyword', Keyword: 'Keyword',
Secret: 'Secret',
Proxy: 'Proxy', Proxy: 'Proxy',
receivers: 'Receivers', receivers: 'Receivers',
receiverCcs: 'ReceiverCcs', receiverCcs: 'ReceiverCcs',

3
dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js

@ -725,7 +725,8 @@ export default {
IsEnableProxy: '启用代理', IsEnableProxy: '启用代理',
WebHook: 'Web钩子', WebHook: 'Web钩子',
webHook: 'Web钩子', webHook: 'Web钩子',
Keyword: '密钥', Keyword: '关键词',
Secret: '密钥',
Proxy: '代理', Proxy: '代理',
receivers: '收件人', receivers: '收件人',
receiverCcs: '抄送人', receiverCcs: '抄送人',

Loading…
Cancel
Save