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];
+ }
+ }
+}