This is an automated email from the ASF dual-hosted git repository.

panjuan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new 044cb78  Refactor openGauss frontend SCRAM SHA-256 authentication 
(#14073)
044cb78 is described below

commit 044cb78c3fd7e1c6ef586ee27d914d879b408b30
Author: 吴伟杰 <[email protected]>
AuthorDate: Mon Dec 13 19:00:42 2021 +0800

    Refactor openGauss frontend SCRAM SHA-256 authentication (#14073)
    
    * Refactor openGauss SCRAM SHA-256 authentication
    
    * Complete test cases
    
    * Fix checkstyle
    
    * Update javadoc
---
 ... OpenGaussAuthenticationSCRAMSha256Packet.java} |   4 +-
 ...nGaussAuthenticationSCRAMSha256PacketTest.java} |   4 +-
 .../OpenGaussAuthenticationEngine.java             |  29 ++++--
 .../OpenGaussAuthenticationHandler.java            |  93 ++++++++----------
 .../OpenGaussAuthenticationEngineTest.java         |  25 +++--
 .../OpenGaussAuthenticationHandlerTest.java        |  15 ++-
 .../fixture/OpenGaussAuthenticationAlgorithm.java  | 105 +++++++++++++++++++++
 7 files changed, 185 insertions(+), 90 deletions(-)

diff --git 
a/shardingsphere-db-protocol/shardingsphere-db-protocol-opengauss/src/main/java/org/apache/shardingsphere/db/protocol/opengauss/packet/authentication/OpenGaussAuthenticationSha256Packet.java
 
b/shardingsphere-db-protocol/shardingsphere-db-protocol-opengauss/src/main/java/org/apache/shardingsphere/db/protocol/opengauss/packet/authentication/OpenGaussAuthenticationSCRAMSha256Packet.java
similarity index 92%
rename from 
shardingsphere-db-protocol/shardingsphere-db-protocol-opengauss/src/main/java/org/apache/shardingsphere/db/protocol/opengauss/packet/authentication/OpenGaussAuthenticationSha256Packet.java
rename to 
shardingsphere-db-protocol/shardingsphere-db-protocol-opengauss/src/main/java/org/apache/shardingsphere/db/protocol/opengauss/packet/authentication/OpenGaussAuthenticationSCRAMSha256Packet.java
index 60c2aef..19c1b16 100644
--- 
a/shardingsphere-db-protocol/shardingsphere-db-protocol-opengauss/src/main/java/org/apache/shardingsphere/db/protocol/opengauss/packet/authentication/OpenGaussAuthenticationSha256Packet.java
+++ 
b/shardingsphere-db-protocol/shardingsphere-db-protocol-opengauss/src/main/java/org/apache/shardingsphere/db/protocol/opengauss/packet/authentication/OpenGaussAuthenticationSCRAMSha256Packet.java
@@ -24,10 +24,10 @@ import 
org.apache.shardingsphere.db.protocol.postgresql.packet.identifier.Postgr
 import 
org.apache.shardingsphere.db.protocol.postgresql.payload.PostgreSQLPacketPayload;
 
 /**
- * Authentication request sha256 for openGauss.
+ * Authentication request SCRAM SHA-256 for openGauss.
  */
 @RequiredArgsConstructor
-public final class OpenGaussAuthenticationSha256Packet implements 
PostgreSQLIdentifierPacket {
+public final class OpenGaussAuthenticationSCRAMSha256Packet implements 
PostgreSQLIdentifierPacket {
     
     private static final int AUTH_REQ_SHA256 = 10;
     
diff --git 
a/shardingsphere-db-protocol/shardingsphere-db-protocol-opengauss/src/test/java/org/apache/shardingsphere/db/protocol/opengauss/packet/authentication/OpenGaussAuthenticationSha256PacketTest.java
 
b/shardingsphere-db-protocol/shardingsphere-db-protocol-opengauss/src/test/java/org/apache/shardingsphere/db/protocol/opengauss/packet/authentication/OpenGaussAuthenticationSCRAMSha256PacketTest.java
similarity index 90%
rename from 
shardingsphere-db-protocol/shardingsphere-db-protocol-opengauss/src/test/java/org/apache/shardingsphere/db/protocol/opengauss/packet/authentication/OpenGaussAuthenticationSha256PacketTest.java
rename to 
shardingsphere-db-protocol/shardingsphere-db-protocol-opengauss/src/test/java/org/apache/shardingsphere/db/protocol/opengauss/packet/authentication/OpenGaussAuthenticationSCRAMSha256PacketTest.java
index 42f0c46..8edb95b 100644
--- 
a/shardingsphere-db-protocol/shardingsphere-db-protocol-opengauss/src/test/java/org/apache/shardingsphere/db/protocol/opengauss/packet/authentication/OpenGaussAuthenticationSha256PacketTest.java
+++ 
b/shardingsphere-db-protocol/shardingsphere-db-protocol-opengauss/src/test/java/org/apache/shardingsphere/db/protocol/opengauss/packet/authentication/OpenGaussAuthenticationSCRAMSha256PacketTest.java
@@ -26,7 +26,7 @@ import static org.junit.Assert.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
-public final class OpenGaussAuthenticationSha256PacketTest {
+public final class OpenGaussAuthenticationSCRAMSha256PacketTest {
     
     private static final byte[] RANDOM_64_CODE = new byte[64];
     
@@ -34,7 +34,7 @@ public final class OpenGaussAuthenticationSha256PacketTest {
     
     private static final int SERVER_ITERATION = 2048;
     
-    private final OpenGaussAuthenticationSha256Packet packet = new 
OpenGaussAuthenticationSha256Packet(RANDOM_64_CODE, TOKEN, SERVER_ITERATION);
+    private final OpenGaussAuthenticationSCRAMSha256Packet packet = new 
OpenGaussAuthenticationSCRAMSha256Packet(RANDOM_64_CODE, TOKEN, 
SERVER_ITERATION);
     
     @Test
     public void assertWrite() {
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/main/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/OpenGaussAuthenticationEngine.java
 
b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/main/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/OpenGaussAuthenticationEngine.java
index 25a61c0..a71d4f0 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/main/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/OpenGaussAuthenticationEngine.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/main/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/OpenGaussAuthenticationEngine.java
@@ -19,9 +19,8 @@ package 
org.apache.shardingsphere.proxy.frontend.opengauss.authentication;
 
 import com.google.common.base.Strings;
 import io.netty.channel.ChannelHandlerContext;
-import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.shardingsphere.db.protocol.CommonConstants;
-import 
org.apache.shardingsphere.db.protocol.opengauss.packet.authentication.OpenGaussAuthenticationSha256Packet;
+import 
org.apache.shardingsphere.db.protocol.opengauss.packet.authentication.OpenGaussAuthenticationSCRAMSha256Packet;
 import org.apache.shardingsphere.db.protocol.payload.PacketPayload;
 import 
org.apache.shardingsphere.db.protocol.postgresql.constant.PostgreSQLErrorCode;
 import 
org.apache.shardingsphere.db.protocol.postgresql.constant.PostgreSQLServerInfo;
@@ -44,6 +43,7 @@ import 
org.apache.shardingsphere.proxy.frontend.postgresql.authentication.except
 import 
org.apache.shardingsphere.proxy.frontend.postgresql.authentication.exception.PostgreSQLProtocolViolationException;
 
 import java.nio.charset.Charset;
+import java.util.concurrent.ThreadLocalRandom;
 
 /**
  * Authentication engine for openGauss.
@@ -58,18 +58,27 @@ public final class OpenGaussAuthenticationEngine implements 
AuthenticationEngine
     
     private String clientEncoding;
     
-    private final String random64Code;
+    private final String saltHexString;
     
-    private final String token;
+    private final String nonceHexString;
     
     private final int serverIteration;
     
     private AuthenticationResult currentAuthResult;
     
     public OpenGaussAuthenticationEngine() {
-        random64Code = RandomStringUtils.randomAlphanumeric(64);
-        token = RandomStringUtils.randomAlphanumeric(8);
-        serverIteration = 2048;
+        saltHexString = generateRandomHexString(64);
+        nonceHexString = generateRandomHexString(8);
+        serverIteration = 10000;
+    }
+    
+    private String generateRandomHexString(final int length) {
+        ThreadLocalRandom random = ThreadLocalRandom.current();
+        StringBuilder result = new StringBuilder(length);
+        for (int i = 0; i < result.capacity(); i++) {
+            result.append(Integer.toString(random.nextInt(0x10), 0x10));
+        }
+        return result.toString();
     }
     
     @Override
@@ -98,7 +107,7 @@ public final class OpenGaussAuthenticationEngine implements 
AuthenticationEngine
         if (Strings.isNullOrEmpty(user)) {
             throw new InvalidAuthorizationSpecificationException("no 
PostgreSQL user name specified in startup packet");
         }
-        context.writeAndFlush(new 
OpenGaussAuthenticationSha256Packet(random64Code.getBytes(), token.getBytes(), 
serverIteration));
+        context.writeAndFlush(new 
OpenGaussAuthenticationSCRAMSha256Packet(saltHexString.getBytes(), 
nonceHexString.getBytes(), serverIteration));
         currentAuthResult = AuthenticationResultBuilder.continued(user, "", 
comStartupPacket.getDatabase());
         return currentAuthResult;
     }
@@ -109,8 +118,8 @@ public final class OpenGaussAuthenticationEngine implements 
AuthenticationEngine
             throw new PostgreSQLProtocolViolationException("password", 
Character.toString(messageType));
         }
         PostgreSQLPasswordMessagePacket passwordMessagePacket = new 
PostgreSQLPasswordMessagePacket(payload);
-        PostgreSQLLoginResult loginResult =
-                
OpenGaussAuthenticationHandler.loginWithSha256Password(currentAuthResult.getUsername(),
 currentAuthResult.getDatabase(), random64Code, token, serverIteration, 
passwordMessagePacket);
+        PostgreSQLLoginResult loginResult = 
OpenGaussAuthenticationHandler.loginWithSCRAMSha256Password(currentAuthResult.getUsername(),
 currentAuthResult.getDatabase(),
+                saltHexString, nonceHexString, serverIteration, 
passwordMessagePacket);
         if (PostgreSQLErrorCode.SUCCESSFUL_COMPLETION != 
loginResult.getErrorCode()) {
             throw new 
PostgreSQLAuthenticationException(loginResult.getErrorCode(), 
loginResult.getErrorMessage());
         }
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/main/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/OpenGaussAuthenticationHandler.java
 
b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/main/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/OpenGaussAuthenticationHandler.java
index e4ba856..78aedbe 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/main/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/OpenGaussAuthenticationHandler.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/main/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/OpenGaussAuthenticationHandler.java
@@ -34,17 +34,19 @@ import javax.crypto.Mac;
 import javax.crypto.SecretKeyFactory;
 import javax.crypto.spec.PBEKeySpec;
 import javax.crypto.spec.SecretKeySpec;
-import java.nio.charset.StandardCharsets;
 import java.security.InvalidKeyException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.spec.InvalidKeySpecException;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.LinkedList;
 import java.util.Locale;
 
 /**
  * Authentication handler for openGauss.
+ * 
+ * @see <a 
href="https://opengauss.org/zh/blogs/blogs.html?post/douxin/sm3_for_opengauss/";>SM3
 for openGauss</a>
  */
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 public final class OpenGaussAuthenticationHandler {
@@ -55,19 +57,21 @@ public final class OpenGaussAuthenticationHandler {
     
     private static final String SHA256_ALGORITHM = "SHA-256";
     
+    private static final String CLIENT_KEY = "Client Key";
+    
     /**
-     * Login with sha256 password.
+     * Login with SCRAM SHA-256 password.
      *
      * @param username username
      * @param databaseName database name
-     * @param random64Code random 64 code
-     * @param token token
+     * @param salt salt in hex string
+     * @param nonce nonce in hex string
      * @param serverIteration server iteration
      * @param passwordMessagePacket password message packet
      * @return openGauss(PostgreSQL) login result
      */
-    public static PostgreSQLLoginResult loginWithSha256Password(final String 
username, final String databaseName, final String random64Code, final String 
token, final int serverIteration,
-                                                                final 
PostgreSQLPasswordMessagePacket passwordMessagePacket) {
+    public static PostgreSQLLoginResult loginWithSCRAMSha256Password(final 
String username, final String databaseName, final String salt, final String 
nonce, final int serverIteration,
+                                                                     final 
PostgreSQLPasswordMessagePacket passwordMessagePacket) {
         String clientDigest = passwordMessagePacket.getDigest();
         Grantee grantee = new Grantee(username, "%");
         if (!Strings.isNullOrEmpty(databaseName) && 
!ProxyContext.getInstance().schemaExists(databaseName)) {
@@ -76,7 +80,7 @@ public final class OpenGaussAuthenticationHandler {
         if (!SQLCheckEngine.check(grantee, getRules(databaseName))) {
             return new 
PostgreSQLLoginResult(PostgreSQLErrorCode.INVALID_AUTHORIZATION_SPECIFICATION, 
String.format("unknown username: %s", username));
         }
-        if (!SQLCheckEngine.check(grantee, (a, b) -> 
isPasswordRight((ShardingSphereUser) a, (Object[]) b), new 
Object[]{clientDigest, random64Code, token, serverIteration}, 
getRules(databaseName))) {
+        if (!SQLCheckEngine.check(grantee, (a, b) -> 
isPasswordRight((ShardingSphereUser) a, (Object[]) b), new 
Object[]{clientDigest, salt, nonce, serverIteration}, getRules(databaseName))) {
             return new 
PostgreSQLLoginResult(PostgreSQLErrorCode.INVALID_PASSWORD, 
String.format("password authentication failed for user \"%s\"", username));
         }
         return null == databaseName || SQLCheckEngine.check(databaseName, 
getRules(databaseName), grantee)
@@ -84,15 +88,6 @@ public final class OpenGaussAuthenticationHandler {
                 : new 
PostgreSQLLoginResult(PostgreSQLErrorCode.PRIVILEGE_NOT_GRANTED, 
String.format("Access denied for user '%s' to database '%s'", username, 
databaseName));
     }
     
-    private static boolean isPasswordRight(final ShardingSphereUser user, 
final Object[] args) {
-        String clientDigest = (String) args[0];
-        String random64Code = (String) args[1];
-        String token = (String) args[2];
-        int serverIteration = (int) args[3];
-        String expectedDigest = new 
String(doRFC5802Algorithm(user.getPassword(), random64Code, token, 
serverIteration));
-        return expectedDigest.equals(clientDigest);
-    }
-    
     private static Collection<ShardingSphereRule> getRules(final String 
databaseName) {
         Collection<ShardingSphereRule> result = new LinkedList<>();
         if (!Strings.isNullOrEmpty(databaseName) && 
ProxyContext.getInstance().schemaExists(databaseName)) {
@@ -102,23 +97,36 @@ public final class OpenGaussAuthenticationHandler {
         return result;
     }
     
-    private static byte[] doRFC5802Algorithm(final String password, final 
String random64code, final String token, final int serverIteration) {
-        byte[] k = generateKFromPBKDF2(password, random64code, 
serverIteration);
-        byte[] clientKey = getKeyFromHmac(k, "Client 
Key".getBytes(StandardCharsets.UTF_8));
+    private static boolean isPasswordRight(final ShardingSphereUser user, 
final Object[] args) {
+        String h3HexString = (String) args[0];
+        String salt = (String) args[1];
+        String nonce = (String) args[2];
+        int serverIteration = (int) args[3];
+        byte[] serverStoredKey = calculatedStoredKey(user.getPassword(), salt, 
serverIteration);
+        byte[] h3 = hexStringToBytes(h3HexString);
+        byte[] h2 = calculateH2(user.getPassword(), salt, nonce, 
serverIteration);
+        byte[] clientCalculatedStoredKey = sha256(xor(h3, h2));
+        return Arrays.equals(clientCalculatedStoredKey, serverStoredKey);
+    }
+    
+    private static byte[] calculatedStoredKey(final String password, final 
String salt, final int serverIteration) {
+        byte[] k = generateKFromPBKDF2(password, salt, serverIteration);
+        byte[] clientKey = getKeyFromHmac(k, CLIENT_KEY.getBytes());
+        return sha256(clientKey);
+    }
+    
+    private static byte[] calculateH2(final String password, final String 
salt, final String nonce, final int serverIteration) {
+        byte[] k = generateKFromPBKDF2(password, salt, serverIteration);
+        byte[] clientKey = getKeyFromHmac(k, CLIENT_KEY.getBytes());
         byte[] storedKey = sha256(clientKey);
-        byte[] tokenBytes = hexStringToBytes(token);
-        byte[] hmacResult = getKeyFromHmac(storedKey, tokenBytes);
-        byte[] h = xorBetweenPassword(hmacResult, clientKey, clientKey.length);
-        byte[] result = new byte[h.length * 2];
-        bytesToHex(h, result, 0, h.length);
-        return result;
+        return getKeyFromHmac(storedKey, hexStringToBytes(nonce));
     }
     
     @SneakyThrows({NoSuchAlgorithmException.class, 
InvalidKeySpecException.class})
-    private static byte[] generateKFromPBKDF2(final String password, final 
String random64code, final int serverIteration) {
+    private static byte[] generateKFromPBKDF2(final String password, final 
String saltString, final int serverIteration) {
         char[] chars = password.toCharArray();
-        byte[] random32code = hexStringToBytes(random64code);
-        PBEKeySpec spec = new PBEKeySpec(chars, random32code, serverIteration, 
32 * 8);
+        byte[] salt = hexStringToBytes(saltString);
+        PBEKeySpec spec = new PBEKeySpec(chars, salt, serverIteration, 32 * 8);
         SecretKeyFactory skf = 
SecretKeyFactory.getInstance(PBKDF2_WITH_HMAC_SHA1_ALGORITHM);
         return skf.generateSecret(spec).getEncoded();
     }
@@ -157,36 +165,15 @@ public final class OpenGaussAuthenticationHandler {
         return mac.doFinal(data);
     }
     
-    private static String bytesToHexString(final byte[] src) {
-        StringBuilder result = new StringBuilder();
-        for (byte each : src) {
-            int v = each & 0xFF;
-            String hv = Integer.toHexString(v);
-            if (hv.length() < 2) {
-                result.append(0);
-            }
-            result.append(hv);
+    private static byte[] xor(final byte[] password1, final byte[] password2) {
+        if (password1.length != password2.length) {
+            throw new IllegalArgumentException("Xor values with different 
length");
         }
-        return result.toString();
-    }
-    
-    private static byte[] xorBetweenPassword(final byte[] password1, final 
byte[] password2, final int length) {
+        int length = password1.length;
         byte[] result = new byte[length];
         for (int i = 0; i < length; i++) {
             result[i] = (byte) (password1[i] ^ password2[i]);
         }
         return result;
     }
-    
-    private static void bytesToHex(final byte[] bytes, final byte[] hex, final 
int offset, final int length) {
-        final char[] lookup = {'0', '1', '2', '3', '4', '5', '6', '7', '8', 
'9', 'a', 'b', 'c', 'd', 'e', 'f'};
-        int pos = offset;
-        for (int i = 0; i < length; i++) {
-            int c = bytes[i] & 0xFF;
-            int j = c >> 4;
-            hex[pos++] = (byte) lookup[j];
-            j = c & 0xF;
-            hex[pos++] = (byte) lookup[j];
-        }
-    }
 }
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/test/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/OpenGaussAuthenticationEngineTest.java
 
b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/test/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/OpenGaussAuthenticationEngineTest.java
index bd64e03..6ab951d 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/test/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/OpenGaussAuthenticationEngineTest.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/test/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/OpenGaussAuthenticationEngineTest.java
@@ -27,7 +27,7 @@ import 
org.apache.shardingsphere.authority.config.AuthorityRuleConfiguration;
 import org.apache.shardingsphere.authority.rule.AuthorityRule;
 import org.apache.shardingsphere.authority.rule.builder.AuthorityRuleBuilder;
 import org.apache.shardingsphere.db.protocol.CommonConstants;
-import 
org.apache.shardingsphere.db.protocol.opengauss.packet.authentication.OpenGaussAuthenticationSha256Packet;
+import 
org.apache.shardingsphere.db.protocol.opengauss.packet.authentication.OpenGaussAuthenticationSCRAMSha256Packet;
 import org.apache.shardingsphere.db.protocol.payload.PacketPayload;
 import 
org.apache.shardingsphere.db.protocol.postgresql.payload.PostgreSQLPacketPayload;
 import 
org.apache.shardingsphere.infra.config.algorithm.ShardingSphereAlgorithmConfiguration;
@@ -41,6 +41,7 @@ import 
org.apache.shardingsphere.mode.metadata.MetaDataContexts;
 import org.apache.shardingsphere.mode.metadata.persist.MetaDataPersistService;
 import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
 import 
org.apache.shardingsphere.proxy.frontend.authentication.AuthenticationResult;
+import 
org.apache.shardingsphere.proxy.frontend.opengauss.authentication.fixture.OpenGaussAuthenticationAlgorithm;
 import 
org.apache.shardingsphere.proxy.frontend.postgresql.authentication.exception.InvalidAuthorizationSpecificationException;
 import 
org.apache.shardingsphere.proxy.frontend.postgresql.authentication.exception.PostgreSQLAuthenticationException;
 import 
org.apache.shardingsphere.proxy.frontend.postgresql.authentication.exception.PostgreSQLProtocolViolationException;
@@ -53,7 +54,6 @@ import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
 import java.lang.reflect.Field;
-import java.lang.reflect.Method;
 import java.nio.charset.StandardCharsets;
 import java.util.Collections;
 import java.util.LinkedHashMap;
@@ -142,9 +142,9 @@ public final class OpenGaussAuthenticationEngineTest {
         AuthenticationResult actual = 
engine.authenticate(channelHandlerContext, payload);
         assertFalse(actual.isFinished());
         assertThat(actual.getUsername(), is(username));
-        ArgumentCaptor<OpenGaussAuthenticationSha256Packet> argumentCaptor = 
ArgumentCaptor.forClass(OpenGaussAuthenticationSha256Packet.class);
+        ArgumentCaptor<OpenGaussAuthenticationSCRAMSha256Packet> 
argumentCaptor = 
ArgumentCaptor.forClass(OpenGaussAuthenticationSCRAMSha256Packet.class);
         verify(channelHandlerContext).writeAndFlush(argumentCaptor.capture());
-        OpenGaussAuthenticationSha256Packet sha256Packet = 
argumentCaptor.getValue();
+        OpenGaussAuthenticationSCRAMSha256Packet sha256Packet = 
argumentCaptor.getValue();
         String random64Code = new String(getRandom64Code(sha256Packet));
         String token = new String(getToken(sha256Packet));
         int serverIteration = getServerIteration(sha256Packet);
@@ -177,30 +177,27 @@ public final class OpenGaussAuthenticationEngineTest {
     }
     
     @SneakyThrows(ReflectiveOperationException.class)
-    private byte[] getRandom64Code(final OpenGaussAuthenticationSha256Packet 
packet) {
-        Field field = 
OpenGaussAuthenticationSha256Packet.class.getDeclaredField("random64Code");
+    private byte[] getRandom64Code(final 
OpenGaussAuthenticationSCRAMSha256Packet packet) {
+        Field field = 
OpenGaussAuthenticationSCRAMSha256Packet.class.getDeclaredField("random64Code");
         field.setAccessible(true);
         return (byte[]) field.get(packet);
     }
     
     @SneakyThrows(ReflectiveOperationException.class)
-    private byte[] getToken(final OpenGaussAuthenticationSha256Packet packet) {
-        Field field = 
OpenGaussAuthenticationSha256Packet.class.getDeclaredField("token");
+    private byte[] getToken(final OpenGaussAuthenticationSCRAMSha256Packet 
packet) {
+        Field field = 
OpenGaussAuthenticationSCRAMSha256Packet.class.getDeclaredField("token");
         field.setAccessible(true);
         return (byte[]) field.get(packet);
     }
     
     @SneakyThrows(ReflectiveOperationException.class)
-    private int getServerIteration(final OpenGaussAuthenticationSha256Packet 
packet) {
-        Field field = 
OpenGaussAuthenticationSha256Packet.class.getDeclaredField("serverIteration");
+    private int getServerIteration(final 
OpenGaussAuthenticationSCRAMSha256Packet packet) {
+        Field field = 
OpenGaussAuthenticationSCRAMSha256Packet.class.getDeclaredField("serverIteration");
         field.setAccessible(true);
         return (int) field.get(packet);
     }
     
-    @SneakyThrows(ReflectiveOperationException.class)
     private String encodeDigest(final String password, final String 
random64code, final String token, final int serverIteration) {
-        Method method = 
OpenGaussAuthenticationHandler.class.getDeclaredMethod("doRFC5802Algorithm", 
String.class, String.class, String.class, int.class);
-        method.setAccessible(true);
-        return new String((byte[]) 
method.invoke(OpenGaussAuthenticationHandler.class, password, random64code, 
token, serverIteration));
+        return new 
String(OpenGaussAuthenticationAlgorithm.doRFC5802Algorithm(password, 
random64code, token, serverIteration));
     }
 }
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/test/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/OpenGaussAuthenticationHandlerTest.java
 
b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/test/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/OpenGaussAuthenticationHandlerTest.java
index 0cb1717..b454e93 100644
--- 
a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/test/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/OpenGaussAuthenticationHandlerTest.java
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/test/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/OpenGaussAuthenticationHandlerTest.java
@@ -42,12 +42,12 @@ import 
org.apache.shardingsphere.mode.manager.ContextManager;
 import org.apache.shardingsphere.mode.metadata.MetaDataContexts;
 import org.apache.shardingsphere.mode.metadata.persist.MetaDataPersistService;
 import org.apache.shardingsphere.proxy.backend.context.ProxyContext;
+import 
org.apache.shardingsphere.proxy.frontend.opengauss.authentication.fixture.OpenGaussAuthenticationAlgorithm;
 import 
org.apache.shardingsphere.proxy.frontend.postgresql.authentication.PostgreSQLLoginResult;
 import org.junit.Before;
 import org.junit.Test;
 
 import java.lang.reflect.Field;
-import java.lang.reflect.Method;
 import java.nio.charset.StandardCharsets;
 import java.util.Collections;
 import java.util.HashMap;
@@ -92,21 +92,21 @@ public final class OpenGaussAuthenticationHandlerTest {
     @Test
     public void assertLoginWithPassword() {
         initProxyContext(new ShardingSphereUser(username, password, "%"));
-        PostgreSQLLoginResult postgreSQLLoginResult = 
OpenGaussAuthenticationHandler.loginWithSha256Password(username, database, 
random64Code, token, serverIteration, passwordMessagePacket);
+        PostgreSQLLoginResult postgreSQLLoginResult = 
OpenGaussAuthenticationHandler.loginWithSCRAMSha256Password(username, database, 
random64Code, token, serverIteration, passwordMessagePacket);
         assertThat(postgreSQLLoginResult.getErrorCode(), 
is(PostgreSQLErrorCode.SUCCESSFUL_COMPLETION));
     }
     
     @Test
     public void assertLoginWithAbsentUser() {
         initProxyContext(new ShardingSphereUser("username", password, "%"));
-        PostgreSQLLoginResult postgreSQLLoginResult = 
OpenGaussAuthenticationHandler.loginWithSha256Password(username, database, 
random64Code, token, serverIteration, passwordMessagePacket);
+        PostgreSQLLoginResult postgreSQLLoginResult = 
OpenGaussAuthenticationHandler.loginWithSCRAMSha256Password(username, database, 
random64Code, token, serverIteration, passwordMessagePacket);
         assertThat(postgreSQLLoginResult.getErrorCode(), 
is(PostgreSQLErrorCode.INVALID_AUTHORIZATION_SPECIFICATION));
     }
     
     @Test
     public void assertLoginWithIncorrectPassword() {
         initProxyContext(new ShardingSphereUser(username, "password", "%"));
-        PostgreSQLLoginResult postgreSQLLoginResult = 
OpenGaussAuthenticationHandler.loginWithSha256Password(username, database, 
random64Code, token, serverIteration, passwordMessagePacket);
+        PostgreSQLLoginResult postgreSQLLoginResult = 
OpenGaussAuthenticationHandler.loginWithSCRAMSha256Password(username, database, 
random64Code, token, serverIteration, passwordMessagePacket);
         assertThat(postgreSQLLoginResult.getErrorCode(), 
is(PostgreSQLErrorCode.INVALID_PASSWORD));
     }
     
@@ -114,7 +114,7 @@ public final class OpenGaussAuthenticationHandlerTest {
     public void assertLoginWithNonExistDatabase() {
         initProxyContext(new ShardingSphereUser(username, password, "%"));
         String database = "non_exist_database";
-        PostgreSQLLoginResult postgreSQLLoginResult = 
OpenGaussAuthenticationHandler.loginWithSha256Password(username, database, 
random64Code, token, serverIteration, passwordMessagePacket);
+        PostgreSQLLoginResult postgreSQLLoginResult = 
OpenGaussAuthenticationHandler.loginWithSCRAMSha256Password(username, database, 
random64Code, token, serverIteration, passwordMessagePacket);
         assertThat(postgreSQLLoginResult.getErrorCode(), 
is(PostgreSQLErrorCode.INVALID_CATALOG_NAME));
     }
     
@@ -157,10 +157,7 @@ public final class OpenGaussAuthenticationHandlerTest {
         return new 
ShardingSphereRuleMetaData(Collections.singletonList(authorityRuleConfiguration),
 Collections.singleton(rule));
     }
     
-    @SneakyThrows(ReflectiveOperationException.class)
     private String encodeDigest(final String password, final String 
random64code, final String token, final int serverIteration) {
-        Method method = 
OpenGaussAuthenticationHandler.class.getDeclaredMethod("doRFC5802Algorithm", 
String.class, String.class, String.class, int.class);
-        method.setAccessible(true);
-        return new String((byte[]) 
method.invoke(OpenGaussAuthenticationHandler.class, password, random64code, 
token, serverIteration));
+        return new 
String(OpenGaussAuthenticationAlgorithm.doRFC5802Algorithm(password, 
random64code, token, serverIteration));
     }
 }
diff --git 
a/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/test/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/fixture/OpenGaussAuthenticationAlgorithm.java
 
b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/test/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/fixture/OpenGaussAuthenticationAlgorithm.java
new file mode 100644
index 0000000..52df555
--- /dev/null
+++ 
b/shardingsphere-proxy/shardingsphere-proxy-frontend/shardingsphere-proxy-frontend-opengauss/src/test/java/org/apache/shardingsphere/proxy/frontend/opengauss/authentication/fixture/OpenGaussAuthenticationAlgorithm.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package 
org.apache.shardingsphere.proxy.frontend.opengauss.authentication.fixture;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import lombok.SneakyThrows;
+import 
org.apache.shardingsphere.proxy.frontend.opengauss.authentication.OpenGaussAuthenticationHandler;
+
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class OpenGaussAuthenticationAlgorithm {
+    
+    /**
+     * Generate client digest.
+     * 
+     * @param password password
+     * @param random64code random 64 code (salt)
+     * @param token token (nonce)
+     * @param serverIteration server iteration
+     * @return client digest
+     */
+    public static byte[] doRFC5802Algorithm(final String password, final 
String random64code, final String token, final int serverIteration) {
+        byte[] k = generateKFromPBKDF2(password, random64code, 
serverIteration);
+        byte[] clientKey = getKeyFromHmac(k, "Client 
Key".getBytes(StandardCharsets.UTF_8));
+        byte[] storedKey = sha256(clientKey);
+        byte[] tokenBytes = hexStringToBytes(token);
+        byte[] hmacResult = getKeyFromHmac(storedKey, tokenBytes);
+        byte[] h = xor(hmacResult, clientKey);
+        byte[] result = new byte[h.length * 2];
+        bytesToHex(h, result, 0, h.length);
+        return result;
+    }
+    
+    @SneakyThrows(ReflectiveOperationException.class)
+    private static byte[] generateKFromPBKDF2(final String password, final 
String saltString, final int serverIteration) {
+        Method generateKFromPBKDF2Method = 
OpenGaussAuthenticationHandler.class.getDeclaredMethod("generateKFromPBKDF2", 
String.class, String.class, int.class);
+        generateKFromPBKDF2Method.setAccessible(true);
+        return (byte[]) generateKFromPBKDF2Method.invoke(null, password, 
saltString, serverIteration);
+    }
+    
+    @SneakyThrows(ReflectiveOperationException.class)
+    private static byte[] getKeyFromHmac(final byte[] key, final byte[] data) {
+        Method getKeyFromHmacMethod = 
OpenGaussAuthenticationHandler.class.getDeclaredMethod("getKeyFromHmac", 
byte[].class, byte[].class);
+        getKeyFromHmacMethod.setAccessible(true);
+        return (byte[]) getKeyFromHmacMethod.invoke(null, key, data);
+    }
+    
+    @SneakyThrows(ReflectiveOperationException.class)
+    private static byte[] sha256(final byte[] str) {
+        Method sha256Method = 
OpenGaussAuthenticationHandler.class.getDeclaredMethod("sha256", byte[].class);
+        sha256Method.setAccessible(true);
+        return (byte[]) sha256Method.invoke(null, str);
+    }
+    
+    @SneakyThrows(ReflectiveOperationException.class)
+    private static byte[] hexStringToBytes(final String rawHexString) {
+        Method hexStringToBytesMethod = 
OpenGaussAuthenticationHandler.class.getDeclaredMethod("hexStringToBytes", 
String.class);
+        hexStringToBytesMethod.setAccessible(true);
+        return (byte[]) hexStringToBytesMethod.invoke(null, rawHexString);
+    }
+    
+    @SneakyThrows(ReflectiveOperationException.class)
+    private static byte[] calculateH2(final String password, final String 
random64code, final String token, final int serverIteration) {
+        Method calculateH2Method = 
OpenGaussAuthenticationHandler.class.getDeclaredMethod("calculateH2", 
String.class, String.class, String.class, int.class);
+        calculateH2Method.setAccessible(true);
+        return (byte[]) calculateH2Method.invoke(null, password, random64code, 
token, serverIteration);
+    }
+    
+    @SneakyThrows(ReflectiveOperationException.class)
+    private static byte[] xor(final byte[] value1, final byte[] value2) {
+        Method xorMethod = 
OpenGaussAuthenticationHandler.class.getDeclaredMethod("xor", byte[].class, 
byte[].class);
+        xorMethod.setAccessible(true);
+        return (byte[]) xorMethod.invoke(null, value1, value2);
+    }
+    
+    private static void bytesToHex(final byte[] bytes, final byte[] hex, final 
int offset, final int length) {
+        final char[] lookup = {'0', '1', '2', '3', '4', '5', '6', '7', '8', 
'9', 'a', 'b', 'c', 'd', 'e', 'f'};
+        int pos = offset;
+        for (int i = 0; i < length; i++) {
+            int c = bytes[i] & 0xFF;
+            int j = c >> 4;
+            hex[pos++] = (byte) lookup[j];
+            j = c & 0xF;
+            hex[pos++] = (byte) lookup[j];
+        }
+    }
+}

Reply via email to