Skip to content

Commit

Permalink
Fix for Bug#114687 (Bug#36529541), Tests fail after mysql_native_pass…
Browse files Browse the repository at this point in the history
…word has been made optional in server.

Change-Id: Icb3ef2af3d457d07aa693813bb8a912eb552e80b
  • Loading branch information
fjssilva committed Apr 18, 2024
1 parent 9901917 commit 22b061b
Show file tree
Hide file tree
Showing 11 changed files with 182 additions and 166 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

Version 9.0.0

- Fix for Bug#114687 (Bug#36529541), Tests fail after mysql_native_password has been made optional in server.

- WL#16319, Remove deprecated insensitive terminology based methods.

- WL#16324, Update static MySQL keywords list.
Expand Down
10 changes: 10 additions & 0 deletions src/test/java/testsuite/BaseTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,16 @@ protected boolean supportsTLSv1_2(ServerVersion version) throws Exception {
|| version.meetsMinimum(new ServerVersion(5, 6, 0)) && Util.isEnterpriseEdition(version.toString());
}

protected boolean supportsMysqlNativePassword(Statement st) throws Exception {
return isPluginActive(st, "mysql_native_password");
}

protected boolean isPluginActive(Statement st, String plugin) throws SQLException {
ResultSet rsCheck = st.executeQuery(
"SELECT EXISTS(SELECT * FROM information_schema.plugins WHERE plugin_name = '" + plugin + "' AND plugin_status = 'ACTIVE') AS is_active");
return rsCheck.next() && rsCheck.getBoolean(1);
}

protected String getHighestCommonTlsVersion() throws Exception {
// Find out which TLS protocol versions are supported by this JVM.
SSLContext sslContext = SSLContext.getInstance("TLS");
Expand Down
157 changes: 64 additions & 93 deletions src/test/java/testsuite/regression/ConnectionRegressionTest.java

Large diffs are not rendered by default.

7 changes: 1 addition & 6 deletions src/test/java/testsuite/regression/SyntaxRegressionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1978,12 +1978,7 @@ public void testUserAccountPwdExpiration() throws Exception {
public void testInnodbTablespaceEncryption() throws Exception {
assumeTrue(versionMeetsMinimum(5, 7, 11), "MySQL 5.7.11+ is required to run this test.");

boolean keyringPluginIsActive = false;
this.rs = this.stmt.executeQuery("SELECT (PLUGIN_STATUS='ACTIVE') AS `TRUE` FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE 'keyring_file'");
if (this.rs.next()) {
keyringPluginIsActive = this.rs.getBoolean(1);
}

boolean keyringPluginIsActive = isPluginActive(this.stmt, "keyring_file");
if (keyringPluginIsActive) {
createTable("testInnodbTablespaceEncryption", "(id INT, txt VARCHAR(100)) ENCRYPTION='y'");

Expand Down
4 changes: 1 addition & 3 deletions src/test/java/testsuite/simple/AuthenticationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -549,9 +549,7 @@ public void testWl14650() throws Exception {
boolean installPluginInRuntime = false;
try {
// Install plugin if required.
this.rs = this.stmt.executeQuery("SELECT (PLUGIN_LIBRARY LIKE 'auth_test_plugin%') AS installed FROM INFORMATION_SCHEMA.PLUGINS "
+ "WHERE PLUGIN_NAME='cleartext_plugin_server'");
installPluginInRuntime = !this.rs.next() || !this.rs.getBoolean(1);
installPluginInRuntime = !isPluginActive(this.stmt, "cleartext_plugin_server");

if (installPluginInRuntime) {
try {
Expand Down
6 changes: 6 additions & 0 deletions src/test/java/testsuite/x/devapi/DevApiBaseTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,12 @@ int getPreparedStatementExecutionsCount(Session sess, int prepStmtId) {
return -1;
}

protected boolean isPluginActive(Session sess, String plugin) {
SqlResult res = sess.sql("SELECT EXISTS(SELECT * FROM information_schema.plugins WHERE plugin_name = ? AND plugin_status = 'ACTIVE') AS is_active")
.bind(plugin).execute();
return res.fetchOne().getBoolean(0);
}

protected boolean supportsTestCertificates(Session sess) {
SqlResult res = sess.sql("SELECT @@mysqlx_ssl_ca, @@ssl_ca").execute();
if (res.hasNext()) {
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/testsuite/x/devapi/Ipv6SupportTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public void setupIpv6SupportTest() {
}

this.session.sql("DROP USER IF EXISTS '" + this.testUser + "'@'%'").execute();
this.session.sql("CREATE USER '" + this.testUser + "'@'%' IDENTIFIED WITH mysql_native_password BY '" + this.testUser + "'").execute();
this.session.sql("CREATE USER '" + this.testUser + "'@'%' IDENTIFIED BY '" + this.testUser + "'").execute();
this.session.sql("GRANT ALL ON *.* TO '" + this.testUser + "'@'%'").execute();
}
}
Expand Down
143 changes: 81 additions & 62 deletions src/test/java/testsuite/x/devapi/SecureSessionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ public void teardownSecureSessionTest() {
public void testNonSecureSession() {
try {
Session testSession = this.fact.getSession(this.baseUrl);
testSession.sql("CREATE USER IF NOT EXISTS 'testPlainAuth'@'%' IDENTIFIED WITH mysql_native_password BY 'pwd'").execute();
testSession.sql("CREATE USER IF NOT EXISTS 'testPlainAuth'@'%' IDENTIFIED BY 'pwd'").execute();
testSession.sql("GRANT SELECT ON *.* TO 'testPlainAuth'@'%'").execute();
testSession.close();

Expand All @@ -187,6 +187,11 @@ public void testNonSecureSession() {
userAndSslFreeBaseUrl = userAndSslFreeBaseUrl.replaceAll(PropertyKey.USER.getKeyName() + "=", PropertyKey.USER.getKeyName() + "VOID=");
userAndSslFreeBaseUrl = userAndSslFreeBaseUrl.replaceAll(PropertyKey.PASSWORD.getKeyName() + "=", PropertyKey.PASSWORD.getKeyName() + "VOID=");

// Connect securely once so that the user credentials get cached in case of using caching_sha2_password by default.
testSession = this.fact.getSession(userAndSslFreeBaseUrl + makeParam(PropertyKey.xdevapiSslMode, XdevapiSslMode.REQUIRED)
+ makeParam(PropertyKey.USER, "testPlainAuth") + makeParam(PropertyKey.PASSWORD, "pwd"));

// Connect via non-secure session.
testSession = this.fact.getSession(userAndSslFreeBaseUrl + makeParam(PropertyKey.xdevapiSslMode, XdevapiSslMode.DISABLED)
+ makeParam(PropertyKey.USER, "testPlainAuth") + makeParam(PropertyKey.PASSWORD, "pwd"));
assertNonSecureSession(testSession);
Expand Down Expand Up @@ -379,9 +384,13 @@ public void testSecureSessionVerifyServerCertificateIdentityFailure() {
*/
@Test
public void testAuthMechanisms() throws Throwable {
boolean supportsMysqlNative = isPluginActive(this.session, "mysql_native_password");

try {
this.session.sql("CREATE USER IF NOT EXISTS 'testAuthMechNative'@'%' IDENTIFIED WITH mysql_native_password BY 'mysqlnative'").execute();
this.session.sql("GRANT SELECT ON *.* TO 'testAuthMechNative'@'%'").execute();
if (supportsMysqlNative) {
this.session.sql("CREATE USER IF NOT EXISTS 'testAuthMechNative'@'%' IDENTIFIED WITH mysql_native_password BY 'mysqlnative'").execute();
this.session.sql("GRANT SELECT ON *.* TO 'testAuthMechNative'@'%'").execute();
}
this.session.sql("CREATE USER IF NOT EXISTS 'testAuthMechSha256'@'%' IDENTIFIED WITH sha256_password BY 'sha256'").execute();
this.session.sql("GRANT SELECT ON *.* TO 'testAuthMechSha256'@'%'").execute();
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.3"))) {
Expand Down Expand Up @@ -419,15 +428,17 @@ public void testAuthMechanisms() throws Throwable {

// With default auth mechanism for secure connections (PLAIN).

// *** User: mysqlnative; Auth: default.
props.setProperty(PropertyKey.USER.getKeyName(), "testAuthMechNative");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "mysqlnative");
if (supportsMysqlNative) {
// *** User: mysqlnative; Auth: default.
props.setProperty(PropertyKey.USER.getKeyName(), "testAuthMechNative");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "mysqlnative");

testSession = this.fact.getSession(props);
assertSecureSession(testSession);
assertEquals(AuthMech.PLAIN, getAuthMech.apply(testSession)); // Connection is secure, passwords are safe & account gets cached.
assertUser("testAuthMechNative", testSession);
testSession.close();
testSession = this.fact.getSession(props);
assertSecureSession(testSession);
assertEquals(AuthMech.PLAIN, getAuthMech.apply(testSession)); // Connection is secure, passwords are safe & account gets cached.
assertUser("testAuthMechNative", testSession);
testSession.close();
}

if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.3"))) {
// *** User: testAuthMechSha256; Auth: default.
Expand Down Expand Up @@ -455,35 +466,37 @@ public void testAuthMechanisms() throws Throwable {

// Forcing an auth mechanism.

// *** User: testAuthMechNative; Auth: PLAIN.
props.setProperty(PropertyKey.USER.getKeyName(), "testAuthMechNative");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "mysqlnative");
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "PLAIN");

testSession = this.fact.getSession(props);
assertSecureSession(testSession);
assertEquals(AuthMech.PLAIN, getAuthMech.apply(testSession)); // Connection is secure, passwords are safe.
assertUser("testAuthMechNative", testSession);
testSession.close();

// *** User: testAuthMechNative; Auth: MYSQL41.
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "MYSQL41");
if (supportsMysqlNative) {
// *** User: testAuthMechNative; Auth: PLAIN.
props.setProperty(PropertyKey.USER.getKeyName(), "testAuthMechNative");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "mysqlnative");
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "PLAIN");

testSession = this.fact.getSession(props);
assertSecureSession(testSession);
assertEquals(AuthMech.MYSQL41, getAuthMech.apply(testSession)); // Matching auth mechanism.
assertUser("testAuthMechNative", testSession);
testSession.close();
testSession = this.fact.getSession(props);
assertSecureSession(testSession);
assertEquals(AuthMech.PLAIN, getAuthMech.apply(testSession)); // Connection is secure, passwords are safe.
assertUser("testAuthMechNative", testSession);
testSession.close();

if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.4"))) { // SHA256_MEMORY support added in MySQL 8.0.4.
// *** User: testAuthMechNative; Auth: SHA256_MEMORY.
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "SHA256_MEMORY");
// *** User: testAuthMechNative; Auth: MYSQL41.
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "MYSQL41");

testSession = this.fact.getSession(props);
assertSecureSession(testSession);
assertEquals(AuthMech.SHA256_MEMORY, getAuthMech.apply(testSession)); // Account is cached by now.
assertEquals(AuthMech.MYSQL41, getAuthMech.apply(testSession)); // Matching auth mechanism.
assertUser("testAuthMechNative", testSession);
testSession.close();

if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.4"))) { // SHA256_MEMORY support added in MySQL 8.0.4.
// *** User: testAuthMechNative; Auth: SHA256_MEMORY.
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "SHA256_MEMORY");

testSession = this.fact.getSession(props);
assertSecureSession(testSession);
assertEquals(AuthMech.SHA256_MEMORY, getAuthMech.apply(testSession)); // Account is cached by now.
assertUser("testAuthMechNative", testSession);
testSession.close();
}
}

if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.3"))) {
Expand Down Expand Up @@ -566,15 +579,17 @@ public void testAuthMechanisms() throws Throwable {

// With default auth mechanism for non-secure connections (MYSQL41|SHA2_MEMORY).

// *** User: testAuthMechNative; Auth: default.
props.setProperty(PropertyKey.USER.getKeyName(), "testAuthMechNative");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "mysqlnative");
if (supportsMysqlNative) {
// *** User: testAuthMechNative; Auth: default.
props.setProperty(PropertyKey.USER.getKeyName(), "testAuthMechNative");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "mysqlnative");

testSession = this.fact.getSession(props);
assertNonSecureSession(testSession);
assertEquals(AuthMech.MYSQL41, getAuthMech.apply(testSession)); // Matching auth mechanism.
assertUser("testAuthMechNative", testSession);
testSession.close();
testSession = this.fact.getSession(props);
assertNonSecureSession(testSession);
assertEquals(AuthMech.MYSQL41, getAuthMech.apply(testSession)); // Matching auth mechanism.
assertUser("testAuthMechNative", testSession);
testSession.close();
}

if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.4"))) { // SHA256_PASSWORD requires secure connections in MySQL 8.0.3 and below.
// *** User: testAuthMechSha256; Auth: default.
Expand Down Expand Up @@ -602,31 +617,33 @@ public void testAuthMechanisms() throws Throwable {

// Forcing an auth mechanism.

// *** User: testAuthMechNative; Auth: PLAIN.
props.setProperty(PropertyKey.USER.getKeyName(), "testAuthMechNative");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "mysqlnative");
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "PLAIN");

assertThrows(XProtocolError.class, "PLAIN authentication is not allowed via unencrypted connection\\.", () -> this.fact.getSession(props));

// *** User: testAuthMechNative; Auth: MYSQL41.
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "MYSQL41");
if (supportsMysqlNative) {
// *** User: testAuthMechNative; Auth: PLAIN.
props.setProperty(PropertyKey.USER.getKeyName(), "testAuthMechNative");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "mysqlnative");
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "PLAIN");

testSession = this.fact.getSession(props);
assertNonSecureSession(testSession);
assertEquals(AuthMech.MYSQL41, getAuthMech.apply(testSession)); // Matching auth mechanism.
assertUser("testAuthMechNative", testSession);
testSession.close();
assertThrows(XProtocolError.class, "PLAIN authentication is not allowed via unencrypted connection\\.", () -> this.fact.getSession(props));

if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.4"))) { // SHA256_MEMORY support added in MySQL 8.0.4.
// *** User: testAuthMechNative; Auth: SHA256_MEMORY.
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "SHA256_MEMORY");
// *** User: testAuthMechNative; Auth: MYSQL41.
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "MYSQL41");

testSession = this.fact.getSession(props);
assertNonSecureSession(testSession);
assertEquals(AuthMech.SHA256_MEMORY, getAuthMech.apply(testSession)); // Account is cached by now.
assertEquals(AuthMech.MYSQL41, getAuthMech.apply(testSession)); // Matching auth mechanism.
assertUser("testAuthMechNative", testSession);
testSession.close();

if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.4"))) { // SHA256_MEMORY support added in MySQL 8.0.4.
// *** User: testAuthMechNative; Auth: SHA256_MEMORY.
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "SHA256_MEMORY");

testSession = this.fact.getSession(props);
assertNonSecureSession(testSession);
assertEquals(AuthMech.SHA256_MEMORY, getAuthMech.apply(testSession)); // Account is cached by now.
assertUser("testAuthMechNative", testSession);
testSession.close();
}
}

if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.3"))) {
Expand Down Expand Up @@ -694,7 +711,9 @@ public void testAuthMechanisms() throws Throwable {

props.remove(PropertyKey.xdevapiAuth.getKeyName());
} finally {
this.session.sql("DROP USER IF EXISTS testAuthMechNative").execute();
if (supportsMysqlNative) {
this.session.sql("DROP USER IF EXISTS testAuthMechNative").execute();
}
this.session.sql("DROP USER IF EXISTS testAuthMechSha256").execute();
this.session.sql("DROP USER IF EXISTS testAuthMechCachingSha2").execute();
}
Expand Down Expand Up @@ -822,8 +841,7 @@ public void testBug25494338() throws Exception {
Properties props = new Properties(this.sslFreeTestProperties);
testSession = this.fact.getSession(props);

testSession.sql("CREATE USER 'bug25494338user'@'%' IDENTIFIED WITH mysql_native_password BY 'pwd' REQUIRE CIPHER '" + expectedCipher2 + "'")
.execute();
testSession.sql("CREATE USER 'bug25494338user'@'%' IDENTIFIED BY 'pwd' REQUIRE CIPHER '" + expectedCipher2 + "'").execute();
testSession.sql("GRANT SELECT ON *.* TO 'bug25494338user'@'%'").execute();

props.setProperty(PropertyKey.xdevapiSslMode.getKeyName(), PropertyDefinitions.XdevapiSslMode.VERIFY_CA.toString());
Expand Down Expand Up @@ -920,6 +938,7 @@ public void testBug26227653() {
public void testBug27629553() {
assumeTrue(supportsTestCertificates(this.session),
"This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
assumeTrue(isPluginActive(this.session, "mysql_native_password"), "This test requires support for 'mysql_native_password'");

Session testSession = this.fact.getSession(this.baseUrl);
testSession.sql("CREATE USER IF NOT EXISTS 'testBug27629553'@'%' IDENTIFIED WITH mysql_native_password").execute();
Expand Down
8 changes: 7 additions & 1 deletion src/test/java/testsuite/x/devapi/SessionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ private String getRandomTestSchemaName() {

@Test
public void urlWithDefaultSchema() {
assumeTrue(isPluginActive(this.session, "mysql_native_password"), "This test requires support for 'mysql_native_password'");

try {
// Create user with mysql_native_password authentication plugin as it can be used with any of the authentication mechanisms.
this.session.sql("CREATE USER IF NOT EXISTS 'testUserN'@'%' IDENTIFIED WITH mysql_native_password BY 'testUserN'").execute();
Expand Down Expand Up @@ -190,6 +192,8 @@ public void urlWithDefaultSchema() {

@Test
public void urlWithoutDefaultSchema() {
assumeTrue(isPluginActive(this.session, "mysql_native_password"), "This test requires support for 'mysql_native_password'");

try {
// Create user with mysql_native_password authentication plugin as it can be used with any of the authentication mechanisms.
this.session.sql("CREATE USER IF NOT EXISTS 'testUserN'@'%' IDENTIFIED WITH mysql_native_password BY 'testUserN'").execute();
Expand Down Expand Up @@ -240,6 +244,8 @@ public void urlWithoutDefaultSchema() {

@Test
public void invalidDefaultSchema() {
assumeTrue(isPluginActive(this.session, "mysql_native_password"), "This test requires support for 'mysql_native_password'");

try {
// Create user with mysql_native_password authentication plugin as it can be used with any of the authentication mechanisms.
this.session.sql("CREATE USER IF NOT EXISTS 'testUserN'@'%' IDENTIFIED WITH mysql_native_password BY 'testUserN'").execute();
Expand Down Expand Up @@ -353,7 +359,7 @@ public void errorOnPacketTooBig() {
@Test
public void testBug21690043() {
try {
this.session.sql("CREATE USER 'bug21690043user1'@'%' IDENTIFIED WITH mysql_native_password").execute();
this.session.sql("CREATE USER 'bug21690043user1'@'%'").execute();
this.session.sql("GRANT SELECT ON *.* TO 'bug21690043user1'@'%'").execute();

Properties props = new Properties();
Expand Down
Loading

0 comments on commit 22b061b

Please sign in to comment.