This is an automated email from the ASF dual-hosted git repository. jackietien pushed a commit to branch rc/1.3.5 in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit b1979831936b2ed650843eac56d54e28fb2f101b Author: Hongzhi Gao <761417...@qq.com> AuthorDate: Wed Jun 18 18:12:20 2025 +0800 [To dev/1.3] User password encryption upgraded from MD5 to SHA256 (#15762) * Implement high availability for the C++ client and support tsblock * fix issues on windows * User password encryption upgraded from MD5 to SHA256. Existing users' passwords will be upgraded upon next login. * spotless apply --- .../iotdb/db/auth/ClusterAuthorityFetcher.java | 5 +++++ .../security/encrypt/MessageDigestEncryptTest.java | 12 +++++++++-- .../commons/auth/authorizer/BasicAuthorizer.java | 17 +++++++++++++--- .../security/encrypt/AsymmetricEncrypt.java | 23 ++++++++++++++++++++-- .../security/encrypt/MessageDigestEncrypt.java | 10 +++++----- .../org/apache/iotdb/commons/utils/AuthUtils.java | 22 +++++++++++++++++++-- 6 files changed, 75 insertions(+), 14 deletions(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/ClusterAuthorityFetcher.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/ClusterAuthorityFetcher.java index 107561bdca3..70333039957 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/ClusterAuthorityFetcher.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/ClusterAuthorityFetcher.java @@ -34,6 +34,7 @@ import org.apache.iotdb.commons.exception.IoTDBException; import org.apache.iotdb.commons.exception.MetadataException; import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.path.PathPatternTree; +import org.apache.iotdb.commons.security.encrypt.AsymmetricEncrypt; import org.apache.iotdb.commons.utils.AuthUtils; import org.apache.iotdb.confignode.rpc.thrift.TAuthizedPatternTreeResp; import org.apache.iotdb.confignode.rpc.thrift.TAuthorizerReq; @@ -396,6 +397,10 @@ public class ClusterAuthorityFetcher implements IAuthorityFetcher { return RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS); } else if (password != null && AuthUtils.validatePassword(password, user.getPassword())) { return RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS); + } else if (password != null + && AuthUtils.validatePassword( + password, user.getPassword(), AsymmetricEncrypt.DigestAlgorithm.MD5)) { + return RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS); } else { return RpcUtils.getStatus(TSStatusCode.WRONG_LOGIN_PASSWORD, "Authentication failed."); } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/security/encrypt/MessageDigestEncryptTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/security/encrypt/MessageDigestEncryptTest.java index 2b4dd753f73..56e78f03642 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/security/encrypt/MessageDigestEncryptTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/security/encrypt/MessageDigestEncryptTest.java @@ -25,6 +25,7 @@ import org.apache.iotdb.commons.auth.user.LocalFileUserManager; import org.apache.iotdb.commons.conf.CommonDescriptor; import org.apache.iotdb.commons.exception.IllegalPathException; import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.commons.security.encrypt.AsymmetricEncrypt; import org.apache.iotdb.commons.security.encrypt.MessageDigestEncrypt; import org.apache.iotdb.db.utils.EnvironmentUtils; import org.apache.iotdb.db.utils.constant.TestConstant; @@ -85,13 +86,20 @@ public class MessageDigestEncryptTest { for (User user1 : users) { user = manager.getUser(user1.getName()); assertEquals(user1.getName(), user.getName()); - assertEquals(messageDigestEncrypt.encrypt(user1.getPassword()), user.getPassword()); + assertEquals( + messageDigestEncrypt.encrypt( + user1.getPassword(), AsymmetricEncrypt.DigestAlgorithm.SHA_256), + user.getPassword()); } } @Test public void testMessageDigestValidatePassword() { String password = "root"; - assertTrue(messageDigestEncrypt.validate(password, messageDigestEncrypt.encrypt(password))); + assertTrue( + messageDigestEncrypt.validate( + password, + messageDigestEncrypt.encrypt(password, AsymmetricEncrypt.DigestAlgorithm.SHA_256), + AsymmetricEncrypt.DigestAlgorithm.SHA_256)); } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/BasicAuthorizer.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/BasicAuthorizer.java index e8359bcd070..7a8680a8d9a 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/BasicAuthorizer.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/authorizer/BasicAuthorizer.java @@ -27,6 +27,7 @@ import org.apache.iotdb.commons.auth.user.IUserManager; import org.apache.iotdb.commons.conf.CommonDescriptor; import org.apache.iotdb.commons.exception.StartupException; import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.commons.security.encrypt.AsymmetricEncrypt; import org.apache.iotdb.commons.service.IService; import org.apache.iotdb.commons.service.ServiceType; import org.apache.iotdb.commons.utils.AuthUtils; @@ -118,9 +119,19 @@ public abstract class BasicAuthorizer implements IAuthorizer, IService { @Override public boolean login(String username, String password) throws AuthException { User user = userManager.getUser(username); - return user != null - && password != null - && AuthUtils.validatePassword(password, user.getPassword()); + if (user == null || password == null) { + return false; + } + if (AuthUtils.validatePassword( + password, user.getPassword(), AsymmetricEncrypt.DigestAlgorithm.SHA_256)) { + return true; + } + if (AuthUtils.validatePassword( + password, user.getPassword(), AsymmetricEncrypt.DigestAlgorithm.MD5)) { + userManager.updateUserPassword(username, password); + return true; + } + return false; } @Override diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/security/encrypt/AsymmetricEncrypt.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/security/encrypt/AsymmetricEncrypt.java index 58ba0868763..7ede0bb6cf8 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/security/encrypt/AsymmetricEncrypt.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/security/encrypt/AsymmetricEncrypt.java @@ -21,6 +21,25 @@ package org.apache.iotdb.commons.security.encrypt; public interface AsymmetricEncrypt { + /** + * Defines cryptographic hash algorithms supported by the system. Each enum constant represents a + * specific message digest algorithm compatible with {@link java.security.MessageDigest}. + */ + enum DigestAlgorithm { + MD5("MD5"), + SHA_256("SHA-256"); + + private final String algorithmName; + + DigestAlgorithm(String algorithmName) { + this.algorithmName = algorithmName; + } + + public String getAlgorithmName() { + return this.algorithmName; + } + } + /** * init some providerParameter * @@ -34,7 +53,7 @@ public interface AsymmetricEncrypt { * @param originPassword password to be crypt * @return encrypt password */ - String encrypt(String originPassword); + String encrypt(String originPassword, DigestAlgorithm digestAlgorithm); /** * validate originPassword and encryptPassword @@ -43,5 +62,5 @@ public interface AsymmetricEncrypt { * @param encryptPassword encrypt password * @return true if validate success */ - boolean validate(String originPassword, String encryptPassword); + boolean validate(String originPassword, String encryptPassword, DigestAlgorithm digestAlgorithm); } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/security/encrypt/MessageDigestEncrypt.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/security/encrypt/MessageDigestEncrypt.java index 63ca50413ac..91d84db33c6 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/security/encrypt/MessageDigestEncrypt.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/security/encrypt/MessageDigestEncrypt.java @@ -29,16 +29,15 @@ import java.security.NoSuchAlgorithmException; public class MessageDigestEncrypt implements AsymmetricEncrypt { private static final Logger logger = LoggerFactory.getLogger(MessageDigestEncrypt.class); - private static final String ENCRYPT_ALGORITHM = "MD5"; private static final String STRING_ENCODING = "utf-8"; @Override public void init(String providerParameters) {} @Override - public String encrypt(String originPassword) { + public String encrypt(String originPassword, DigestAlgorithm digestAlgorithm) { try { - MessageDigest messageDigest = MessageDigest.getInstance(ENCRYPT_ALGORITHM); + MessageDigest messageDigest = MessageDigest.getInstance(digestAlgorithm.getAlgorithmName()); messageDigest.update(originPassword.getBytes(STRING_ENCODING)); return new String(messageDigest.digest(), STRING_ENCODING); } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { @@ -48,10 +47,11 @@ public class MessageDigestEncrypt implements AsymmetricEncrypt { } @Override - public boolean validate(String originPassword, String encryptPassword) { + public boolean validate( + String originPassword, String encryptPassword, DigestAlgorithm digestAlgorithm) { if (originPassword == null) { return false; } - return encrypt(originPassword).equals(encryptPassword); + return encrypt(originPassword, digestAlgorithm).equals(encryptPassword); } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/AuthUtils.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/AuthUtils.java index 38f8c689b4f..20c991d470a 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/AuthUtils.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/AuthUtils.java @@ -29,6 +29,7 @@ import org.apache.iotdb.commons.exception.IllegalPathException; import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.path.PathDeserializeUtil; import org.apache.iotdb.commons.path.PathPatternUtil; +import org.apache.iotdb.commons.security.encrypt.AsymmetricEncrypt; import org.apache.iotdb.commons.security.encrypt.AsymmetricEncryptFactory; import org.apache.iotdb.confignode.rpc.thrift.TPermissionInfoResp; import org.apache.iotdb.confignode.rpc.thrift.TRoleResp; @@ -127,7 +128,24 @@ public class AuthUtils { return AsymmetricEncryptFactory.getEncryptProvider( CommonDescriptor.getInstance().getConfig().getEncryptDecryptProvider(), CommonDescriptor.getInstance().getConfig().getEncryptDecryptProviderParameter()) - .validate(originPassword, encryptPassword); + .validate(originPassword, encryptPassword, AsymmetricEncrypt.DigestAlgorithm.SHA_256); + } + + /** + * Checking whether origin password is mapping to encrypt password by encryption + * + * @param originPassword the password before encryption + * @param encryptPassword the password after encryption + * @param digestAlgorithm the algorithm for encryption + */ + public static boolean validatePassword( + String originPassword, + String encryptPassword, + AsymmetricEncrypt.DigestAlgorithm digestAlgorithm) { + return AsymmetricEncryptFactory.getEncryptProvider( + CommonDescriptor.getInstance().getConfig().getEncryptDecryptProvider(), + CommonDescriptor.getInstance().getConfig().getEncryptDecryptProviderParameter()) + .validate(originPassword, encryptPassword, digestAlgorithm); } /** @@ -231,7 +249,7 @@ public class AuthUtils { return AsymmetricEncryptFactory.getEncryptProvider( CommonDescriptor.getInstance().getConfig().getEncryptDecryptProvider(), CommonDescriptor.getInstance().getConfig().getEncryptDecryptProviderParameter()) - .encrypt(password); + .encrypt(password, AsymmetricEncrypt.DigestAlgorithm.SHA_256); } /**