From cdb43627525db86cd38f2aff95dad407cc792cbd Mon Sep 17 00:00:00 2001 From: ArvinHuang <1095369685@qq.com> Date: Wed, 1 Mar 2023 18:15:21 +0800 Subject: [PATCH 01/10] =?UTF-8?q?getInstanceFromFlow=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ArvinHuang <1095369685@qq.com> --- resources-front-end/src/views/job-dashboard/log/Logs.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources-front-end/src/views/job-dashboard/log/Logs.vue b/resources-front-end/src/views/job-dashboard/log/Logs.vue index eae027c6..e80fb9eb 100644 --- a/resources-front-end/src/views/job-dashboard/log/Logs.vue +++ b/resources-front-end/src/views/job-dashboard/log/Logs.vue @@ -254,7 +254,7 @@ export default { getInstanceIdFromFlow() { return getInstanceId().then((res) => { const result = [] - for (const [instance] of Object.entries(res.data)) { + for (const instance of Object.values(res.data)) { if (instance.host === window.location.host) { this.currentInstanceId = instance.instance_id } From 6e7cc1a5148d023c6dee59563aef4bffbf9196e2 Mon Sep 17 00:00:00 2001 From: ArvinHuang <1095369685@qq.com> Date: Mon, 20 Mar 2023 10:33:50 +0800 Subject: [PATCH 02/10] version check Signed-off-by: ArvinHuang <1095369685@qq.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d56a8a38..0924cb1a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 fateboard fateboard - 1.10.0 + 1.10.1 org.springframework.boot From 756419ec36a52b29e9efe64a79889953291144ea Mon Sep 17 00:00:00 2001 From: ArvinHuang <1095369685@qq.com> Date: Mon, 20 Mar 2023 10:34:57 +0800 Subject: [PATCH 03/10] version 1.11.0 Signed-off-by: ArvinHuang <1095369685@qq.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0924cb1a..167e776d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 fateboard fateboard - 1.10.1 + 1.11.0 org.springframework.boot From 98b91a5a3a28b18c4ffee2dadc8fd4fc728e8df0 Mon Sep 17 00:00:00 2001 From: ArvinHuang <1095369685@qq.com> Date: Mon, 20 Mar 2023 15:27:37 +0800 Subject: [PATCH 04/10] =?UTF-8?q?binning=5Fcount=E5=B1=95=E7=A4=BA?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=8C=E4=BD=BF=E7=94=A8binNums=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E8=AE=A1=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ArvinHuang <1095369685@qq.com> --- resources-front-end/src/transform/fn/binningDataHandler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources-front-end/src/transform/fn/binningDataHandler.js b/resources-front-end/src/transform/fn/binningDataHandler.js index 6fc82f4c..cc086a5b 100644 --- a/resources-front-end/src/transform/fn/binningDataHandler.js +++ b/resources-front-end/src/transform/fn/binningDataHandler.js @@ -215,7 +215,7 @@ export default function(data, header, type, partyId, role, Currentrole, skipStat monotonicity: skipStatic ? '-' : (Currentrole === 'host' ? '-' : (data[key].isWoeMonotonic ? data[key].isWoeMonotonic.toString() : 'false')), partyid: partyId, role, - binning_count: data[key].splitPoints.length || data[key].ivArray.length + binning_count: data[key].binNums }) options.push({ value: key, From 6baf8669a7dad13fe524dc3d97255322c9f030be Mon Sep 17 00:00:00 2001 From: ArvinHuang <1095369685@qq.com> Date: Mon, 20 Mar 2023 15:28:23 +0800 Subject: [PATCH 05/10] =?UTF-8?q?binNums=E6=95=B0=E6=8D=AE=E5=B1=95?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ArvinHuang <1095369685@qq.com> --- resources-front-end/src/transform/fn/binningDataHandler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources-front-end/src/transform/fn/binningDataHandler.js b/resources-front-end/src/transform/fn/binningDataHandler.js index cc086a5b..672751d4 100644 --- a/resources-front-end/src/transform/fn/binningDataHandler.js +++ b/resources-front-end/src/transform/fn/binningDataHandler.js @@ -215,7 +215,7 @@ export default function(data, header, type, partyId, role, Currentrole, skipStat monotonicity: skipStatic ? '-' : (Currentrole === 'host' ? '-' : (data[key].isWoeMonotonic ? data[key].isWoeMonotonic.toString() : 'false')), partyid: partyId, role, - binning_count: data[key].binNums + binning_count: parseFloat(data[key].binNums) }) options.push({ value: key, From 36836a74847bee9e5cdb83db50f843354c1ca528 Mon Sep 17 00:00:00 2001 From: ArvinHuang <1095369685@qq.com> Date: Thu, 23 Mar 2023 16:15:56 +0800 Subject: [PATCH 06/10] version 1.11.1 Signed-off-by: ArvinHuang <1095369685@qq.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 167e776d..caaa51dd 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 fateboard fateboard - 1.11.0 + 1.11.1 org.springframework.boot From 67a9c05a3da14890938828803f21685c5ba8f963 Mon Sep 17 00:00:00 2001 From: kakawu Date: Wed, 29 Mar 2023 16:41:38 +0800 Subject: [PATCH 07/10] Comment repetition attribute --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index caaa51dd..a783dd52 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ 1.1.10 - 1.1.10 + 1.18.24 2.0.0 From 0f64d1faea38df2f5f11ff009be9b7b832b165be Mon Sep 17 00:00:00 2001 From: kakawu Date: Mon, 3 Apr 2023 13:01:28 +0800 Subject: [PATCH 08/10] version num change --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a783dd52..019baccb 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 fateboard fateboard - 1.11.1 + 1.11.0 org.springframework.boot From 4a454213ea995778fddfce6b77da0bc9fb897ef2 Mon Sep 17 00:00:00 2001 From: kakawu <945844419@qq.com> Date: Wed, 5 Apr 2023 23:15:46 +0800 Subject: [PATCH 09/10] sensitive info encrypt Signed-off-by: kakawu <945844419@qq.com> --- .../ai/fate/board/services/UserService.java | 12 + .../ai/fate/board/utils/StandardRSAUtils.java | 328 +++++++++++++++--- src/main/resources/application.properties | 2 + 3 files changed, 292 insertions(+), 50 deletions(-) diff --git a/src/main/java/com/webank/ai/fate/board/services/UserService.java b/src/main/java/com/webank/ai/fate/board/services/UserService.java index dc8eb73a..60e60233 100644 --- a/src/main/java/com/webank/ai/fate/board/services/UserService.java +++ b/src/main/java/com/webank/ai/fate/board/services/UserService.java @@ -16,6 +16,8 @@ package com.webank.ai.fate.board.services; import com.webank.ai.fate.board.pojo.UserDTO; +import com.webank.ai.fate.board.utils.StandardRSAUtils; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -63,6 +65,16 @@ public boolean checkUser(String username, String password) { updateConfig(); String usernameValue = getValue("server.board.login.username"); String passwordValue = getValue("server.board.login.password"); + String privateKey = getValue("server.board.encrypt.private_key"); + String encrypted = getValue("server.board.encrypt.enable"); + if (StringUtils.isNotBlank(privateKey) && "true".equalsIgnoreCase(encrypted)) { + try { + passwordValue = StandardRSAUtils.decryptByPrivateKey(passwordValue, privateKey); + } catch (Exception e) { + logger.error("decrypt password error"); + return false; + } + } if (!username.equals(usernameValue)) { return false; diff --git a/src/main/java/com/webank/ai/fate/board/utils/StandardRSAUtils.java b/src/main/java/com/webank/ai/fate/board/utils/StandardRSAUtils.java index e590e0c9..96bff4e1 100644 --- a/src/main/java/com/webank/ai/fate/board/utils/StandardRSAUtils.java +++ b/src/main/java/com/webank/ai/fate/board/utils/StandardRSAUtils.java @@ -1,12 +1,13 @@ package com.webank.ai.fate.board.utils; -import org.apache.commons.codec.binary.Base64; - import javax.crypto.Cipher; +import java.io.ByteArrayOutputStream; import java.security.*; +import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; import java.util.HashMap; import java.util.Map; @@ -15,69 +16,296 @@ */ public class StandardRSAUtils { - private static Map keyMap = new HashMap<>(); + /** + * 加密算法RSA + */ + public static final String KEY_ALGORITHM = "RSA"; + + /** + * 签名算法 + */ + public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; + + /** + * 获取公钥的key + */ + private static final String PUBLIC_KEY = "RSAPublicKey"; + + /** + * 获取私钥的key + */ + private static final String PRIVATE_KEY = "RSAPrivateKey"; + + /** + * RSA最大加密明文大小 + */ + private static final int MAX_ENCRYPT_BLOCK = 245; /** - * 随机生成密钥对 + * RSA最大解密密文大小 + */ + private static final int MAX_DECRYPT_BLOCK = 256; + + /** + *

+ * 生成密钥对(公钥和私钥) + *

* - * @throws NoSuchAlgorithmException + * @return + * @throws Exception */ - public static void getKeyPair() throws Exception { - //KeyPairGenerator类用于生成公钥和密钥对,基于RSA算法生成对象 - KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); - keyPairGen.initialize(2048, new SecureRandom()); - //生成一个密钥对,保存在keyPair中 + public static Map genKeyPair() throws Exception { + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM); + keyPairGen.initialize(2048); KeyPair keyPair = keyPairGen.generateKeyPair(); - PrivateKey privateKey = keyPair.getPrivate();//得到私钥 - PublicKey publicKey = keyPair.getPublic();//得到公钥 - //得到公钥字符串 - String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded())); - //得到私钥字符串 - String privateKeyString = new String(Base64.encodeBase64(privateKey.getEncoded())); - //将公钥和私钥保存到Map - keyMap.put(0, publicKeyString);//0表示公钥 - keyMap.put(1, privateKeyString);//1表示私钥 + RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); + RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); + Map keyMap = new HashMap(2); + keyMap.put(PUBLIC_KEY, publicKey); + keyMap.put(PRIVATE_KEY, privateKey); + return keyMap; } /** - * RSA公钥加密 + *

+ * 用私钥对信息生成数字签名 + *

* - * @param str 加密字符串 - * @param publicKey 公钥 - * @return 密文 - * @throws Exception 加密过程中的异常信息 + * @param msg 已加密数据 + * @param privateKey 私钥(BASE64编码) + * @return + * @throws Exception */ - public static String encrypt(String str, String publicKey) throws Exception { - //base64编码的公钥 - byte[] decoded = Base64.decodeBase64(publicKey); - RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA") - .generatePublic(new X509EncodedKeySpec(decoded)); - //RAS加密 - Cipher cipher = Cipher.getInstance("RSA"); - cipher.init(Cipher.ENCRYPT_MODE, pubKey); - String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8"))); - return outStr; + public static String sign(String msg, String privateKey) throws Exception { + byte[] data = msg.getBytes(); + byte[] keyBytes = Base64.getDecoder().decode(privateKey); + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec); + Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); + signature.initSign(privateK); + signature.update(data); + return Base64.getEncoder().encodeToString(signature.sign()); } /** - * RSA私钥解密 + *

+ * 校验数字签名 + *

* - * @param str 加密字符串 - * @param privateKey 私钥 - * @return 铭文 - * @throws Exception 解密过程中的异常信息 + * @param msg 已加密数据 + * @param publicKey 公钥(BASE64编码) + * @param sign 数字签名 + * @return + * @throws Exception */ - public static String decrypt(String str, String privateKey) throws Exception { - //Base64解码加密后的字符串 - byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8")); - //Base64编码的私钥 - byte[] decoded = Base64.decodeBase64(privateKey); - PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded)); - //RSA解密 - Cipher cipher = Cipher.getInstance("RSA"); - cipher.init(Cipher.DECRYPT_MODE, priKey); - String outStr = new String(cipher.doFinal(inputByte)); - return outStr; + public static boolean verify(String msg, String publicKey, String sign) + throws Exception { + byte[] data = msg.getBytes(); + byte[] keyBytes = Base64.getDecoder().decode(publicKey); + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + PublicKey publicK = keyFactory.generatePublic(keySpec); + Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); + signature.initVerify(publicK); + signature.update(data); + return signature.verify(Base64.getDecoder().decode(sign)); + } + /** + *

+ * 私钥解密 + *

+ * + * @param encryptedDataStr 已加密数据 + * @param privateKey 私钥(BASE64编码) + * @return + * @throws Exception + */ + public static String decryptByPrivateKey(String encryptedDataStr, String privateKey) + throws Exception { + byte[] encryptedData = Base64.getDecoder().decode(encryptedDataStr); + byte[] keyBytes = Base64.getDecoder().decode(privateKey); + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(Cipher.DECRYPT_MODE, privateK); + int inputLen = encryptedData.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] cache; + int i = 0; + // 对数据分段解密 + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_DECRYPT_BLOCK) { + cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); + } else { + cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_DECRYPT_BLOCK; + } + byte[] decryptedData = out.toByteArray(); + out.close(); + return new String(decryptedData); } + + /** + *

+ * 公钥解密 + *

+ * + * @param encryptedDataStr 已加密数据 + * @param publicKey 公钥(BASE64编码) + * @return + * @throws Exception + */ + public static String decryptByPublicKey(String encryptedDataStr, String publicKey) + throws Exception { + byte[] encryptedData = Base64.getDecoder().decode(encryptedDataStr); + byte[] keyBytes = Base64.getDecoder().decode(publicKey); + X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + Key publicK = keyFactory.generatePublic(x509KeySpec); + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(Cipher.DECRYPT_MODE, publicK); + int inputLen = encryptedData.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] cache; + int i = 0; + // 对数据分段解密 + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_DECRYPT_BLOCK) { + cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); + } else { + cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_DECRYPT_BLOCK; + } + byte[] decryptedData = out.toByteArray(); + out.close(); + return new String(decryptedData); + } + + /** + *

+ * 公钥加密 + *

+ * + * @param msg 源数据 + * @param publicKey 公钥(BASE64编码) + * @return + * @throws Exception + */ + public static String encryptByPublicKey(String msg, String publicKey) + throws Exception { + byte[] data = msg.getBytes(); + byte[] keyBytes = Base64.getDecoder().decode(publicKey); + X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + Key publicK = keyFactory.generatePublic(x509KeySpec); + // 对数据加密 + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(Cipher.ENCRYPT_MODE, publicK); + int inputLen = data.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] cache; + int i = 0; + // 对数据分段加密 + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { + cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); + } else { + cache = cipher.doFinal(data, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_ENCRYPT_BLOCK; + } + byte[] encryptedData = out.toByteArray(); + out.close(); + + String encryptedDataStr = Base64.getEncoder().encodeToString(encryptedData); + return encryptedDataStr; + } + + /** + *

+ * 私钥加密 + *

+ * + * @param msg 源数据 + * @param privateKey 私钥(BASE64编码) + * @return + * @throws Exception + */ + public static String encryptByPrivateKey(String msg, String privateKey) + throws Exception { + byte[] data = msg.getBytes(); + byte[] keyBytes = Base64.getDecoder().decode(privateKey); + PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); + Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); + cipher.init(Cipher.ENCRYPT_MODE, privateK); + int inputLen = data.length; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + int offSet = 0; + byte[] cache; + int i = 0; + // 对数据分段加密 + while (inputLen - offSet > 0) { + if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { + cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); + } else { + cache = cipher.doFinal(data, offSet, inputLen - offSet); + } + out.write(cache, 0, cache.length); + i++; + offSet = i * MAX_ENCRYPT_BLOCK; + } + byte[] encryptedData = out.toByteArray(); + out.close(); + + String encryptedDataStr = Base64.getEncoder().encodeToString(encryptedData); + return encryptedDataStr; + } + + /** + *

+ * 获取私钥 + *

+ * + * @param keyMap 密钥对 + * @return + * @throws Exception + */ + public static String getPrivateKey(Map keyMap) + throws Exception { + Key key = (Key) keyMap.get(PRIVATE_KEY); + return Base64.getEncoder().encodeToString(key.getEncoded()); + } + + /** + *

+ * 获取公钥 + *

+ * + * @param keyMap 密钥对 + * @return + * @throws Exception + */ + public static String getPublicKey(Map keyMap) + throws Exception { + Key key = (Key) keyMap.get(PUBLIC_KEY); + return Base64.getEncoder().encodeToString(key.getEncoded()); + } + + } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index fe7e208a..0b0e8a6c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -18,6 +18,8 @@ server.compression.enabled=true server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain server.board.login.username=admin server.board.login.password=admin +server.board.encrypt.private_key= +server.board.encrypt.enable=false #only [h,m,s] is available server.servlet.session.timeout=4h server.servlet.session.cookie.max-age=4h From 113e24d52d5ef10307dd0d92fef1c24e7fb067dd Mon Sep 17 00:00:00 2001 From: ArvinHuang <1095369685@qq.com> Date: Tue, 11 Apr 2023 10:37:21 +0800 Subject: [PATCH 10/10] update:Release.md Signed-off-by: ArvinHuang <1095369685@qq.com> --- RELEASE.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/RELEASE.md b/RELEASE.md index 27682b6e..34e973d7 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,3 +1,11 @@ +# Release 1.11.0 + +#### Major Features and Improvements +**Major Features** + +* Binning component display optimization +* Password configuration item allows encryption + # Release 1.10.0 #### Major Features and Improvements