use of com.mysql.cj.protocol.x.XProtocol in project aws-mysql-jdbc by awslabs.
the class SecureSessionTest method testAuthMechanisms.
/**
* Tests that PLAIN, MYSQL41, SHA256_MEMORY, and EXTERNAL authentication mechanisms.
*
* @throws Throwable
*/
@Test
public void testAuthMechanisms() throws Throwable {
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();
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"))) {
this.session.sql("CREATE USER IF NOT EXISTS 'testAuthMechCachingSha2'@'%' IDENTIFIED WITH caching_sha2_password BY 'cachingsha2'").execute();
this.session.sql("GRANT SELECT ON *.* TO 'testAuthMechCachingSha2'@'%'").execute();
}
final Field sf = SessionImpl.class.getDeclaredField("session");
sf.setAccessible(true);
final Field pf = CoreSession.class.getDeclaredField("protocol");
pf.setAccessible(true);
final Field mf = XAuthenticationProvider.class.getDeclaredField("authMech");
mf.setAccessible(true);
Function<Session, AuthMech> getAuthMech = s -> {
try {
return (AuthMech) mf.get(((XProtocol) pf.get(sf.get(s))).getAuthenticationProvider());
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
};
/*
* Access denied (ER_ACCESS_DENIED_ERROR) error message from servers up to version 8.0.11.
* In MySQL 8.0.12 this message changed due to fix for Bug#27675699 - FAILED AUTHENTICATION AT X PLUGIN ALWAYS RETURNS ER_ACCESS_DENIED_ERROR.
* This variable may be redefined as needed along the test.
*/
String accessDeniedErrMsg = "ERROR 1045 \\(HY000\\) Invalid user or password";
/*
* Authenticate using (default) TLS first. As per MySQL 8.0.4 X Plugin this is required so that SHA2[56] logins get cached in SHA2_MEMORY.
*/
Session testSession = null;
Properties props = new Properties(this.sslFreeTestProperties);
// With default auth mechanism for secure connections (PLAIN).
// *** User: mysqlnative; Auth: default.
props.setProperty(PropertyKey.USER.getKeyName(), "testAuthMechNative");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "mysqlnative");
testSession = this.fact.getSession(props);
assertSecureSession(testSession);
// Connection is secure, passwords are safe & account gets cached.
assertEquals(AuthMech.PLAIN, getAuthMech.apply(testSession));
assertUser("testAuthMechNative", testSession);
testSession.close();
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.3"))) {
// *** User: testAuthMechSha256; Auth: default.
props.setProperty(PropertyKey.USER.getKeyName(), "testAuthMechSha256");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "sha256");
testSession = this.fact.getSession(props);
assertSecureSession(testSession);
// Connection is secure, passwords are safe & account gets cached.
assertEquals(AuthMech.PLAIN, getAuthMech.apply(testSession));
assertUser("testAuthMechSha256", testSession);
testSession.close();
}
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.3"))) {
// *** User: testAuthMechCachingSha2; Auth: default.
props.setProperty(PropertyKey.USER.getKeyName(), "testAuthMechCachingSha2");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "cachingsha2");
testSession = this.fact.getSession(props);
assertSecureSession(testSession);
// Connection is secure, passwords are safe & account gets cached.
assertEquals(AuthMech.PLAIN, getAuthMech.apply(testSession));
assertUser("testAuthMechCachingSha2", testSession);
testSession.close();
}
// 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);
// Connection is secure, passwords are safe.
assertEquals(AuthMech.PLAIN, getAuthMech.apply(testSession));
assertUser("testAuthMechNative", testSession);
testSession.close();
// *** User: testAuthMechNative; Auth: MYSQL41.
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "MYSQL41");
testSession = this.fact.getSession(props);
assertSecureSession(testSession);
// Matching auth mechanism.
assertEquals(AuthMech.MYSQL41, getAuthMech.apply(testSession));
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);
// Account is cached by now.
assertEquals(AuthMech.SHA256_MEMORY, getAuthMech.apply(testSession));
assertUser("testAuthMechNative", testSession);
testSession.close();
}
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.3"))) {
// *** User: testAuthMechSha256; Auth: PLAIN.
props.setProperty(PropertyKey.USER.getKeyName(), "testAuthMechSha256");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "sha256");
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "PLAIN");
testSession = this.fact.getSession(props);
assertSecureSession(testSession);
// Connection is secure, passwords are safe.
assertEquals(AuthMech.PLAIN, getAuthMech.apply(testSession));
assertUser("testAuthMechSha256", testSession);
testSession.close();
// *** User: testAuthMechSha256; Auth: MYSQL41.
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "MYSQL41");
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.12"))) {
accessDeniedErrMsg = "ERROR 1045 \\(HY000\\) Access denied for user 'testAuthMechSha256'@.*";
}
// Auth mech mismatch.
assertThrows(XProtocolError.class, accessDeniedErrMsg, () -> this.fact.getSession(props));
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.4"))) {
// SHA256_MEMORY support added in MySQL 8.0.4.
// *** User: testAuthMechSha256; Auth: SHA256_MEMORY.
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "SHA256_MEMORY");
testSession = this.fact.getSession(props);
assertSecureSession(testSession);
// Account is cached by now.
assertEquals(AuthMech.SHA256_MEMORY, getAuthMech.apply(testSession));
assertUser("testAuthMechSha256", testSession);
testSession.close();
}
}
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.3"))) {
// *** User: testAuthMechCachingSha2; Auth: PLAIN.
props.setProperty(PropertyKey.USER.getKeyName(), "testAuthMechCachingSha2");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "cachingsha2");
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "PLAIN");
testSession = this.fact.getSession(props);
assertSecureSession(testSession);
// Connection is secure, passwords are safe.
assertEquals(AuthMech.PLAIN, getAuthMech.apply(testSession));
assertUser("testAuthMechCachingSha2", testSession);
testSession.close();
// *** User: testAuthMechCachingSha2; Auth: MYSQL41.
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "MYSQL41");
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.12"))) {
accessDeniedErrMsg = "ERROR 1045 \\(HY000\\) Access denied for user 'testAuthMechCachingSha2'@.*";
}
// Auth mech mismatch.
assertThrows(XProtocolError.class, accessDeniedErrMsg, () -> this.fact.getSession(props));
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.4"))) {
// SHA256_MEMORY support added in MySQL 8.0.4.
// User: testAuthMechCachingSha2; Auth: SHA256_MEMORY.
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "SHA256_MEMORY");
testSession = this.fact.getSession(props);
assertSecureSession(testSession);
// Account is cached by now.
assertEquals(AuthMech.SHA256_MEMORY, getAuthMech.apply(testSession));
assertUser("testAuthMechCachingSha2", testSession);
testSession.close();
}
}
// *** User: external; Auth: EXTERNAL.
props.setProperty(PropertyKey.USER.getKeyName(), "external");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "external");
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "EXTERNAL");
assertThrows(XProtocolError.class, "ERROR 1251 \\(HY000\\) Invalid authentication method EXTERNAL", () -> this.fact.getSession(props));
props.remove(PropertyKey.xdevapiAuth.getKeyName());
/*
* Authenticate using non-secure connections.
*/
props.setProperty(PropertyKey.xdevapiSslMode.getKeyName(), PropertyDefinitions.XdevapiSslMode.DISABLED.toString());
// 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");
testSession = this.fact.getSession(props);
assertNonSecureSession(testSession);
// Matching auth mechanism.
assertEquals(AuthMech.MYSQL41, getAuthMech.apply(testSession));
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.
props.setProperty(PropertyKey.USER.getKeyName(), "testAuthMechSha256");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "sha256");
testSession = this.fact.getSession(props);
assertNonSecureSession(testSession);
// Account is cached by now.
assertEquals(AuthMech.SHA256_MEMORY, getAuthMech.apply(testSession));
assertUser("testAuthMechSha256", testSession);
testSession.close();
}
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.4"))) {
// CACHING_SHA2_PASSWORD requires secure connections in MySQL 8.0.3 and below.
// *** User: testAuthMechCachingSha2; Auth: default.
props.setProperty(PropertyKey.USER.getKeyName(), "testAuthMechCachingSha2");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "cachingsha2");
testSession = this.fact.getSession(props);
assertNonSecureSession(testSession);
// Account is cached by now.
assertEquals(AuthMech.SHA256_MEMORY, getAuthMech.apply(testSession));
assertUser("testAuthMechCachingSha2", testSession);
testSession.close();
}
// 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");
testSession = this.fact.getSession(props);
assertNonSecureSession(testSession);
// Matching auth mechanism.
assertEquals(AuthMech.MYSQL41, getAuthMech.apply(testSession));
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);
// Account is cached by now.
assertEquals(AuthMech.SHA256_MEMORY, getAuthMech.apply(testSession));
assertUser("testAuthMechNative", testSession);
testSession.close();
}
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.3"))) {
// *** User: testAuthMechSha256; Auth: PLAIN.
props.setProperty(PropertyKey.USER.getKeyName(), "testAuthMechSha256");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "sha256");
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "PLAIN");
assertThrows(XProtocolError.class, "PLAIN authentication is not allowed via unencrypted connection\\.", () -> this.fact.getSession(props));
// *** User: testAuthMechSha256; Auth: MYSQL41.
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "MYSQL41");
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.12"))) {
accessDeniedErrMsg = "ERROR 1045 \\(HY000\\) Access denied for user 'testAuthMechSha256'@.*";
}
// Auth mech mismatch.
assertThrows(XProtocolError.class, accessDeniedErrMsg, () -> this.fact.getSession(props));
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.4"))) {
// SHA256_MEMORY support added in MySQL 8.0.4.
// *** User: testAuthMechSha256; Auth: SHA256_MEMORY.
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "SHA256_MEMORY");
testSession = this.fact.getSession(props);
assertNonSecureSession(testSession);
// Account is cached by now.
assertEquals(AuthMech.SHA256_MEMORY, getAuthMech.apply(testSession));
assertUser("testAuthMechSha256", testSession);
testSession.close();
}
}
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.3"))) {
// *** User: testAuthMechCachingSha2; Auth: PLAIN.
props.setProperty(PropertyKey.USER.getKeyName(), "testAuthMechCachingSha2");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "cachingsha2");
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "PLAIN");
assertThrows(XProtocolError.class, "PLAIN authentication is not allowed via unencrypted connection\\.", () -> this.fact.getSession(props));
// *** User: testAuthMechCachingSha2; Auth: MYSQL41.
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "MYSQL41");
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.12"))) {
accessDeniedErrMsg = "ERROR 1045 \\(HY000\\) Access denied for user 'testAuthMechCachingSha2'@.*";
}
// Auth mech mismatch.
assertThrows(XProtocolError.class, accessDeniedErrMsg, () -> this.fact.getSession(props));
if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.4"))) {
// SHA256_MEMORY support added in MySQL 8.0.4.
// *** User: testAuthMechCachingSha2; Auth: SHA256_MEMORY.
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "SHA256_MEMORY");
testSession = this.fact.getSession(props);
assertNonSecureSession(testSession);
// Account is cached by now.
assertEquals(AuthMech.SHA256_MEMORY, getAuthMech.apply(testSession));
assertUser("testAuthMechCachingSha2", testSession);
testSession.close();
}
}
// *** User: external; Auth: EXTERNAL.
props.setProperty(PropertyKey.USER.getKeyName(), "external");
props.setProperty(PropertyKey.PASSWORD.getKeyName(), "external");
props.setProperty(PropertyKey.xdevapiAuth.getKeyName(), "EXTERNAL");
assertThrows(XProtocolError.class, "ERROR 1251 \\(HY000\\) Invalid authentication method EXTERNAL", () -> this.fact.getSession(props));
props.remove(PropertyKey.xdevapiAuth.getKeyName());
} finally {
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();
}
}
use of com.mysql.cj.protocol.x.XProtocol in project aws-mysql-jdbc by awslabs.
the class TableSelectTest method testBug22038729.
/**
* Tests fix for Bug#22038729, X DEVAPI: ANY API CALL AFTER A FAILED CALL PROC() RESULTS IN HANG
* and for duplicate Bug#25575010, X DEVAPI: ANY API CALL AFTER A FAILED SELECT RESULTS IN HANG
*
* @throws Exception
*/
@Test
public void testBug22038729() throws Exception {
final Field pf = CoreSession.class.getDeclaredField("protocol");
pf.setAccessible(true);
try {
sqlUpdate("drop table if exists testBug22038729");
sqlUpdate("create table testBug22038729 (c1 int, c2 int unsigned, id bigint)");
sqlUpdate("insert into testBug22038729 values(10, 100, -9223372036854775808)");
sqlUpdate("insert into testBug22038729 values(11, 11, 9223372036854775806)");
sqlUpdate("drop procedure if exists testBug22038729p");
sqlUpdate("create procedure testBug22038729p (in p1 int,IN p2 char(20)) begin select -10;select id+1000 from testBug22038729; end;");
// XProtocol.readRowOrNull()
Session sess = new SessionFactory().getSession(this.testProperties);
Table t1 = sess.getDefaultSchema().getTable("testBug22038729");
RowResult rows = t1.select("c1-c2").orderBy("c1 DESC").execute();
assertTrue(rows.hasNext());
Row r = rows.next();
assertEquals(0, r.getInt(0));
assertThrows(XProtocolError.class, "ERROR 1690 \\(22003\\) BIGINT UNSIGNED value is out of range .*", () -> rows.hasNext());
// It was hanging
sess.close();
// XProtocol.readRowOrNull()
sess = new SessionFactory().getSession(this.testProperties);
SqlResult rs1 = sess.sql("select c1-c2 from testBug22038729 order by c1 desc").execute();
assertEquals(0, rs1.fetchOne().getInt(0));
assertThrows(XProtocolError.class, "ERROR 1690 \\(22003\\) BIGINT UNSIGNED value is out of range .*", () -> rs1.fetchOne());
// It was hanging
sess.close();
// XProtocol.drainRows()
sess = new SessionFactory().getSession(this.testProperties);
sess.sql("select c1-c2 from testBug22038729 order by c1 desc").execute();
XProtocol xp = (XProtocol) pf.get(((SessionImpl) sess).getSession());
assertThrows(XProtocolError.class, "ERROR 1690 \\(22003\\) BIGINT UNSIGNED value is out of range .*", () -> {
xp.drainRows();
return xp;
});
// It was hanging
sess.close();
sess = new SessionFactory().getSession(this.testProperties);
SqlResult rs2 = sess.sql("call testBug22038729p(?, ?)").bind(10).bind("X").execute();
assertTrue(rs2.hasData());
assertTrue(rs2.hasNext());
r = rs2.next();
assertEquals(-10, r.getInt(0));
assertFalse(rs2.hasNext());
assertTrue(rs2.nextResult());
assertTrue(rs2.hasData());
assertTrue(rs2.hasNext());
r = rs2.next();
assertEquals(-9223372036854774808L, r.getLong(0));
assertThrows(XProtocolError.class, "ERROR 1690 \\(22003\\) BIGINT value is out of range .*", () -> rs2.hasNext());
// It was hanging
sess.close();
} finally {
sqlUpdate("drop table if exists testBug22038729");
sqlUpdate("drop procedure if exists testBug22038729p");
}
}
use of com.mysql.cj.protocol.x.XProtocol in project aws-mysql-jdbc by awslabs.
the class InternalXBaseTestCase method createTestProtocol.
/**
* Create a new {@link XProtocol} instance for testing.
*
* @return an XProtocol instance
*/
public XProtocol createTestProtocol() {
PropertySet ps = new DefaultPropertySet();
ps.initializeProperties(this.testProperties);
return new XProtocol(this.testHostInfo, ps);
}
Aggregations