[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_SECRETUpdate_README
parent
64efc65edf
commit
cb8c875fa8
|
|
@ -45,46 +45,60 @@ public final class DingTalkAlertChannelFactory implements AlertChannelFactory {
|
|||
|
||||
@Override
|
||||
public List<PluginParams> params() {
|
||||
InputParam webHookParam = InputParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_WEB_HOOK, DingTalkParamsConstants.DING_TALK_WEB_HOOK)
|
||||
.addValidate(Validate.newBuilder()
|
||||
.setRequired(true)
|
||||
.build())
|
||||
.build();
|
||||
InputParam keywordParam = InputParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_KEYWORD, DingTalkParamsConstants.DING_TALK_KEYWORD)
|
||||
.addValidate(Validate.newBuilder()
|
||||
.setRequired(true)
|
||||
.build())
|
||||
.build();
|
||||
RadioParam isEnableProxy =
|
||||
RadioParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PROXY_ENABLE, DingTalkParamsConstants.DING_TALK_PROXY_ENABLE)
|
||||
.addParamsOptions(new ParamsOptions(STRING_YES, STRING_TRUE, false))
|
||||
.addParamsOptions(new ParamsOptions(STRING_NO, STRING_FALSE, false))
|
||||
.setValue(STRING_TRUE)
|
||||
.addValidate(Validate.newBuilder()
|
||||
.setRequired(false)
|
||||
.build())
|
||||
.build();
|
||||
InputParam proxyParam =
|
||||
InputParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PROXY, DingTalkParamsConstants.DING_TALK_PROXY)
|
||||
.addValidate(Validate.newBuilder()
|
||||
.setRequired(false).build())
|
||||
.build();
|
||||
InputParam webHookParam = InputParam
|
||||
.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_WEB_HOOK, DingTalkParamsConstants.DING_TALK_WEB_HOOK)
|
||||
.addValidate(Validate.newBuilder()
|
||||
.setRequired(true)
|
||||
.build())
|
||||
.build();
|
||||
InputParam keywordParam = InputParam
|
||||
.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_KEYWORD, DingTalkParamsConstants.DING_TALK_KEYWORD)
|
||||
.addValidate(Validate.newBuilder()
|
||||
.setRequired(false)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
InputParam portParam = InputParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PORT, DingTalkParamsConstants.DING_TALK_PORT)
|
||||
.addValidate(Validate.newBuilder()
|
||||
.setRequired(false).build())
|
||||
.build();
|
||||
InputParam secretParam = InputParam
|
||||
.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_SECRET, DingTalkParamsConstants.DING_TALK_SECRET)
|
||||
.addValidate(Validate.newBuilder()
|
||||
.setRequired(false)
|
||||
.build())
|
||||
.build();
|
||||
RadioParam isEnableProxy = RadioParam
|
||||
.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PROXY_ENABLE, DingTalkParamsConstants.DING_TALK_PROXY_ENABLE)
|
||||
.addParamsOptions(new ParamsOptions(STRING_YES, STRING_TRUE, false))
|
||||
.addParamsOptions(new ParamsOptions(STRING_NO, STRING_FALSE, false))
|
||||
.setValue(STRING_FALSE)
|
||||
.addValidate(Validate.newBuilder()
|
||||
.setRequired(false)
|
||||
.build())
|
||||
.build();
|
||||
InputParam proxyParam = InputParam
|
||||
.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PROXY, DingTalkParamsConstants.DING_TALK_PROXY)
|
||||
.addValidate(Validate.newBuilder()
|
||||
.setRequired(false)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
InputParam userParam =
|
||||
InputParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_USER, DingTalkParamsConstants.DING_TALK_USER)
|
||||
.addValidate(Validate.newBuilder()
|
||||
.setRequired(false).build())
|
||||
.build();
|
||||
PasswordParam passwordParam = PasswordParam.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PASSWORD, DingTalkParamsConstants.DING_TALK_PASSWORD)
|
||||
.setPlaceholder("if enable use authentication, you need input password")
|
||||
.build();
|
||||
InputParam portParam = InputParam
|
||||
.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PORT, DingTalkParamsConstants.DING_TALK_PORT)
|
||||
.addValidate(Validate.newBuilder()
|
||||
.setRequired(false)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
return Arrays.asList(webHookParam, keywordParam, isEnableProxy, proxyParam, portParam, userParam, passwordParam);
|
||||
InputParam userParam = InputParam
|
||||
.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_USER, DingTalkParamsConstants.DING_TALK_USER)
|
||||
.addValidate(Validate.newBuilder()
|
||||
.setRequired(false)
|
||||
.build())
|
||||
.build();
|
||||
PasswordParam passwordParam = PasswordParam
|
||||
.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PASSWORD, DingTalkParamsConstants.DING_TALK_PASSWORD)
|
||||
.setPlaceholder("if enable use authentication, you need input password")
|
||||
.build();
|
||||
|
||||
return Arrays.asList(webHookParam, keywordParam, secretParam, isEnableProxy, proxyParam, portParam, userParam, passwordParam);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ public final class DingTalkParamsConstants {
|
|||
static final String DING_TALK_KEYWORD = "$t('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 NAME_DING_TALK_PROXY = "Proxy";
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ package org.apache.dolphinscheduler.plugin.alert.dingtalk;
|
|||
import org.apache.dolphinscheduler.alert.api.AlertResult;
|
||||
import org.apache.dolphinscheduler.spi.utils.JSONUtils;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.codec.binary.StringUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpHost;
|
||||
|
|
@ -36,17 +37,29 @@ import org.apache.http.impl.client.HttpClients;
|
|||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
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 {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DingTalkSender.class);
|
||||
private final String url;
|
||||
private final String keyword;
|
||||
private final String secret;
|
||||
private final Boolean enableProxy;
|
||||
|
||||
private String proxy;
|
||||
|
|
@ -60,6 +73,7 @@ public final class DingTalkSender {
|
|||
DingTalkSender(Map<String, String> config) {
|
||||
url = config.get(DingTalkParamsConstants.NAME_DING_TALK_WEB_HOOK);
|
||||
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));
|
||||
if (Boolean.TRUE.equals(enableProxy)) {
|
||||
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 {
|
||||
|
||||
String msgToJson = textToJsonString(title + content + "#" + keyword);
|
||||
HttpPost httpPost = constructHttpPost(url, msgToJson);
|
||||
StringBuilder text = new StringBuilder();
|
||||
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;
|
||||
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 + "×tamp=" + timestamp + "&sign=" + sign;
|
||||
}
|
||||
|
||||
static final class DingTalkSendMsgResponse {
|
||||
private Integer errcode;
|
||||
private String errmsg;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public class DingTalkAlertChannelFactoryTest {
|
|||
DingTalkAlertChannelFactory dingTalkAlertChannelFactory = new DingTalkAlertChannelFactory();
|
||||
List<PluginParams> params = dingTalkAlertChannelFactory.params();
|
||||
JSONUtils.toJsonString(params);
|
||||
Assert.assertEquals(7, params.size());
|
||||
Assert.assertEquals(8, params.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -726,6 +726,7 @@ export default {
|
|||
WebHook: 'WebHook',
|
||||
webHook: 'WebHook',
|
||||
Keyword: 'Keyword',
|
||||
Secret: 'Secret',
|
||||
Proxy: 'Proxy',
|
||||
receivers: 'Receivers',
|
||||
receiverCcs: 'ReceiverCcs',
|
||||
|
|
|
|||
|
|
@ -725,7 +725,8 @@ export default {
|
|||
IsEnableProxy: '启用代理',
|
||||
WebHook: 'Web钩子',
|
||||
webHook: 'Web钩子',
|
||||
Keyword: '密钥',
|
||||
Keyword: '关键词',
|
||||
Secret: '密钥',
|
||||
Proxy: '代理',
|
||||
receivers: '收件人',
|
||||
receiverCcs: '抄送人',
|
||||
|
|
|
|||
Loading…
Reference in New Issue