[CONJ-807] Get Access Denied error after 2.5.2 with commit 4e0705bb306a5f7efef222c6886e3a561b13ab60 Created: 2020-07-09  Updated: 2020-11-17  Resolved: 2020-08-24

Status: Closed
Project: MariaDB Connector/J
Component/s: authentication
Affects Version/s: 2.5.2
Fix Version/s: 2.7.0

Type: Bug Priority: Major
Reporter: xixibu Assignee: Diego Dupin
Resolution: Fixed Votes: 0
Labels: regression
Environment:

Ubuntu 18.04.4 LTS, Java version: 11.0.7, Apache Maven 3.6.0, MariaDB Connector J 2.5.2+. And it seems I can only reproduce with cloud MySQL server


Issue Links:
Relates
relates to CONJ-832 Intermittent Connection Failures to A... Closed
relates to R2DBC-7 authentication error when using multi... Closed

 Description   

After apply commit 4e0705bb306a5f7efef222c6886e3a561b13ab60, and run multi-thread program to connect to MySQL server with MariaDB Connector J , it has a high chance to meet with error "Access denied for xx".
Test code as follows:

 
import java.sql.*;
import java.time.Instant;
import java.util.Properties;
 
public class TestCache extends Thread {
	// Default no of threads to 10
	private static int NUM_OF_THREADS = 40;
	private static int LOOP = 5;
	private static int pass_conn = 0;
	static int c_nextId = 1;
	private static String url = "jdbc:mysql://server:3306/testj?user=user&password=password";
 
	int m_myId;
	int pass_conn_i = 0;
 
	synchronized static int getNextId() {
		return c_nextId++;
	}
 
	public static void main(String args[]) {
		try {
			// Load the JDBC driver
			Class.forName("org.mariadb.jdbc.Driver");
			System.out.println("Driver loaded");
 
			// Create the threads
			Thread[] threadList = new Thread[NUM_OF_THREADS];
 
			double startTime = System.nanoTime();
			// spawn threads
			for (int i = 0; i < NUM_OF_THREADS; i++) {
				threadList[i] = new TestCache();
				threadList[i].start();
			}
 
			// wait for all threads to end
			for (int i = 0; i < NUM_OF_THREADS; i++) {
				threadList[i].join();
				pass_conn += ((TestCache) threadList[i]).getPassCount();
			}
 
			double endTime = System.nanoTime();
			double runtime = (endTime - startTime) / 1000000000;
			System.out.printf("Total runtime is %fs \n", runtime);
			System.out.printf("Throughput is : %f \n", pass_conn / runtime);
			System.out.printf("Pass rate is : %f \n", (double) pass_conn / (NUM_OF_THREADS * LOOP));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
 
	public TestCache() {
		super();
		// Assign an Id to the thread
		m_myId = getNextId();
	}
 
	public void run() {
		int i = 0;
		int failureCount = 0;
		for (i = 0; i < LOOP; i++) {
			try {
				Connection conn = null;
				ResultSet rs = null;
				Statement stmt = null;
 
				Properties info = new Properties();
				info.setProperty("pool", "0");
 
				// Get the connection
				conn = DriverManager.getConnection(url, info);
				stmt = conn.createStatement(); // Create a Statement
 
				// Execute the Query
				rs = stmt.executeQuery("select user() as user");
 
				if (rs.next()) {
					pass_conn_i += 1;
				}
 
				// Close all the resources
				rs.close();
				rs = null;
 
				stmt.close();
				stmt = null;
 
				conn.close();
				conn = null;
				yield(); // Yield To other threads
			} catch (Exception e) {
				System.out.println("Thread " + m_myId + " got Exception: " + e);
				e.printStackTrace();
				failureCount++;
				yield(); // Yield To other threads
			}
		}
		System.out.println("Thread " + m_myId + " is finished. ");
		System.out.println("Failure Count: " + failureCount);
		yield(); // Yield To other threads
	}
 
	public int getPassCount() {
		return pass_conn_i;
	}
 
}



 Comments   
Comment by Diego Dupin [ 2020-07-09 ]

could you indicate what you mean by "Access denied for xx" ? is it server error like "Access denied for user 'root'@'localhost' (using password: YES)" or some AccessControlException for classloader for example ?

Comment by xixibu [ 2020-07-10 ]

Hi @Diego,

I mean server error "Access denied for user 'root'@'localhost' (using password: YES)"

The reason I can only reproduce it with cloud server maybe because that the auth switch process is different.

I tried to capture some packet of the problematic one, if I did not do wrong, it seems the login packet is same with that connection succeeded, the problem may occur during the auth switch process.

Comment by xixibu [ 2020-07-10 ]

When using Jmeter to test, I also observed some empty login packet without user/password, seems also relevant to this.

Comment by xixibu [ 2020-07-20 ]

Hi @Diego,

May I ask is there any update for this?

Comment by xixibu [ 2020-08-10 ]

Hi @Diego,

May I ask is there any update for this? I have done several round of test, and has identified that this is the commit that causes the problem.

Comment by xixibu [ 2020-08-11 ]

Hi @Diego,

I've proposed a PR request for this in https://github.com/mariadb-corporation/mariadb-connector-j/pull/159, can you help check?

For conj-742, squirrel reports " Client does not support authentication protocol requested by server. plugin type was = 'xxx' "
This problem was fixed in commit 4e0705b.
But after this commit changed the loader into static, it reports Access denied problem (stack as at bottom). And this problem as been reported on conj-807.
I've tested that for conj-742, there is only need to specify the class loader Driver.class.getClassLoader() to solve the squirrel client problem. So I proposed this fix to solve both conj-742 and conj-807.

Thread 35 got Exception: java.sql.SQLInvalidAuthorizationSpecException: Could not connect to address=(host=xx)(port=3306)(type=master) : Access denied for user 'xx'@'xx' (using password: YES)
java.sql.SQLInvalidAuthorizationSpecException: Could not connect to address=(host=xx)(port=3306)(type=master) : Access denied for user 'xx'@'xx' (using password: YES)
at org.mariadb.jdbc.internal.util.exceptions.ExceptionMapper.get(ExceptionMapper.java:239)
at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.connectWithoutProxy(AbstractConnectProtocol.java:1241)
at org.mariadb.jdbc.internal.util.Utils.retrieveProxy(Utils.java:610)
at org.mariadb.jdbc.MariaDbConnection.newConnection(MariaDbConnection.java:142)
at org.mariadb.jdbc.Driver.connect(Driver.java:86)
at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:677)
at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:189)
at TestCache.run(TestCache.java:100)
Caused by: java.sql.SQLException: Access denied for user 'xx'@'xx' (using password: YES)
at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.authenticationHandler(AbstractConnectProtocol.java:729)
at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.createConnection(AbstractConnectProtocol.java:507)
at org.mariadb.jdbc.internal.protocol.AbstractConnectProtocol.connectWithoutProxy(AbstractConnectProtocol.java:1236)
... 6 more

Thanks & Best Regards,
Qianqian

Comment by Diego Dupin [ 2020-08-19 ]

allright, using multiple classloader, use of static might create issue like you describe.
PR will be added to next version

Generated at Thu Feb 08 03:18:27 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.