use of com.mysql.cj.protocol.a.authentication.Sha256PasswordPlugin in project aws-mysql-jdbc by awslabs.
the class NativeAuthenticationProvider method loadAuthenticationPlugins.
/**
* Fill the authentication plugins map.
*
* Starts by filling the map with instances of the built-in authentication plugins. Then creates instances of plugins listed in the "authenticationPlugins"
* connection property and adds them to the map too.
*
* The key for the map entry is got by {@link AuthenticationPlugin#getProtocolPluginName()} thus it is possible to replace built-in plugins with custom
* implementations. To do it, the custom plugin should return one of the values "mysql_native_password", "mysql_clear_password", "sha256_password",
* "caching_sha2_password", "mysql_old_password", "authentication_ldap_sasl_client" or "authentication_kerberos_client" from its own getProtocolPluginName()
* method.
*/
@SuppressWarnings("unchecked")
private void loadAuthenticationPlugins() {
// default plugin
RuntimeProperty<String> defaultAuthenticationPluginProp = this.propertySet.getStringProperty(PropertyKey.defaultAuthenticationPlugin);
String defaultAuthenticationPluginValue = defaultAuthenticationPluginProp.getValue();
if (defaultAuthenticationPluginValue == null || "".equals(defaultAuthenticationPluginValue.trim())) {
throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("AuthenticationProvider.BadDefaultAuthenticationPlugin", new Object[] { defaultAuthenticationPluginValue }), getExceptionInterceptor());
}
// disabled plugins
String disabledPlugins = this.propertySet.getStringProperty(PropertyKey.disabledAuthenticationPlugins).getValue();
List<String> disabledAuthenticationPlugins;
if (disabledPlugins != null && !"".equals(disabledPlugins)) {
disabledAuthenticationPlugins = StringUtils.split(disabledPlugins, ",", true);
} else {
disabledAuthenticationPlugins = Collections.EMPTY_LIST;
}
this.authenticationPlugins = new HashMap<>();
List<AuthenticationPlugin<NativePacketPayload>> pluginsToInit = new LinkedList<>();
// built-in plugins
pluginsToInit.add(new Sha256PasswordPlugin());
pluginsToInit.add(new CachingSha2PasswordPlugin());
pluginsToInit.add(new MysqlOldPasswordPlugin());
pluginsToInit.add(new AuthenticationLdapSaslClientPlugin());
pluginsToInit.add(new AuthenticationKerberosClient());
pluginsToInit.add(new AuthenticationOciClient());
final boolean useAwsIam = this.propertySet.getBooleanProperty(PropertyKey.useAwsIam).getValue();
if (useAwsIam) {
try {
Class.forName("software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider");
} catch (ClassNotFoundException ex) {
throw ExceptionFactory.createException(Messages.getString("AuthenticationAwsIamPlugin.MissingSDK"));
}
final String host = this.protocol.getSocketConnection().getHost();
final int port = this.protocol.getSocketConnection().getPort();
final AwsIamAuthenticationTokenHelper tokenHelper = new AwsIamAuthenticationTokenHelper(host, port, this.propertySet.getStringProperty(PropertyKey.logger).getStringValue());
pluginsToInit.add(new AwsIamAuthenticationPlugin(tokenHelper));
pluginsToInit.add(new AwsIamClearAuthenticationPlugin(tokenHelper));
final String defaultPluginClassName = this.propertySet.getStringProperty(PropertyKey.defaultAuthenticationPlugin).getPropertyDefinition().getDefaultValue();
if (defaultAuthenticationPluginValue.equals(defaultPluginClassName)) {
defaultAuthenticationPluginValue = AwsIamAuthenticationPlugin.class.getName();
}
} else {
pluginsToInit.add(new MysqlNativePasswordPlugin());
pluginsToInit.add(new MysqlClearPasswordPlugin());
}
// plugins from authenticationPluginClasses connection parameter
String authenticationPluginClasses = this.propertySet.getStringProperty(PropertyKey.authenticationPlugins).getValue();
if (authenticationPluginClasses != null && !"".equals(authenticationPluginClasses.trim())) {
List<String> pluginsToCreate = StringUtils.split(authenticationPluginClasses, ",", true);
for (String className : pluginsToCreate) {
try {
pluginsToInit.add((AuthenticationPlugin<NativePacketPayload>) Class.forName(className).newInstance());
} catch (Throwable t) {
throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("AuthenticationProvider.BadAuthenticationPlugin", new Object[] { className }), t, this.exceptionInterceptor);
}
}
}
// add plugin instances
boolean defaultFound = false;
for (AuthenticationPlugin<NativePacketPayload> plugin : pluginsToInit) {
String pluginProtocolName = plugin.getProtocolPluginName();
String pluginClassName = plugin.getClass().getName();
boolean disabledByProtocolName = disabledAuthenticationPlugins.contains(pluginProtocolName);
boolean disabledByClassName = disabledAuthenticationPlugins.contains(pluginClassName);
if (disabledByProtocolName || disabledByClassName) {
// check if the default plugin is disabled
if (!defaultFound && (defaultAuthenticationPluginValue.equals(pluginProtocolName) || defaultAuthenticationPluginValue.equals(pluginClassName))) {
throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("AuthenticationProvider.BadDisabledAuthenticationPlugin", new Object[] { disabledByClassName ? pluginClassName : pluginProtocolName }), getExceptionInterceptor());
}
} else {
this.authenticationPlugins.put(pluginProtocolName, plugin);
if (!defaultFound && (defaultAuthenticationPluginValue.equals(pluginProtocolName) || defaultAuthenticationPluginValue.equals(pluginClassName))) {
this.clientDefaultAuthenticationPluginName = pluginProtocolName;
this.clientDefaultAuthenticationPluginExplicitelySet = defaultAuthenticationPluginProp.isExplicitlySet();
defaultFound = true;
}
}
}
// check if the default plugin is listed
if (!defaultFound) {
throw ExceptionFactory.createException(WrongArgumentException.class, Messages.getString("AuthenticationProvider.DefaultAuthenticationPluginIsNotListed", new Object[] { defaultAuthenticationPluginValue }), getExceptionInterceptor());
}
}
use of com.mysql.cj.protocol.a.authentication.Sha256PasswordPlugin in project aws-mysql-jdbc by awslabs.
the class ConnectionRegressionTest method testSha256PasswordPlugin.
/**
* Test for sha256_password authentication.
*
* @throws Exception
*/
@Test
public void testSha256PasswordPlugin() throws Exception {
assumeTrue(versionMeetsMinimum(5, 6, 5), "MySQL 5.6.5+ is required to run this test.");
assumeTrue((((MysqlConnection) this.conn).getSession().getServerSession().getCapabilities().getCapabilityFlags() & NativeServerSession.CLIENT_SSL) != 0, "This test requires server with SSL support.");
assumeTrue(pluginIsActive(this.stmt, "sha256_password"), "sha256_password plugin required to run this test");
assumeTrue(supportsTestCertificates(this.stmt), "This test requires the server configured with SSL certificates from ConnectorJ/src/test/config/ssl-test-certs");
String trustStorePath = "src/test/config/ssl-test-certs/ca-truststore";
System.setProperty("javax.net.ssl.trustStore", trustStorePath);
System.setProperty("javax.net.ssl.trustStorePassword", "password");
try {
// newer GPL servers, like 8.0.4+, are using OpenSSL and can use RSA encryption, while old ones compiled with yaSSL cannot
boolean withRSA = allowsRsa(this.stmt);
boolean withTestRsaKeys = supportsTestSha256PasswordKeys(this.stmt);
// create user with long password and sha256_password auth
if (!((MysqlConnection) this.conn).getSession().versionMeetsMinimum(8, 0, 5)) {
this.stmt.executeUpdate("SET @current_old_passwords = @@global.old_passwords");
}
createUser(this.stmt, "'wl5602user'@'%'", "IDENTIFIED WITH sha256_password");
this.stmt.executeUpdate("GRANT ALL ON *.* TO 'wl5602user'@'%'");
createUser(this.stmt, "'wl5602nopassword'@'%'", "identified WITH sha256_password");
this.stmt.executeUpdate("GRANT ALL ON *.* TO 'wl5602nopassword'@'%'");
if (!((MysqlConnection) this.conn).getSession().versionMeetsMinimum(8, 0, 5)) {
this.stmt.executeUpdate("SET GLOBAL old_passwords= 2");
this.stmt.executeUpdate("SET SESSION old_passwords= 2");
}
this.stmt.executeUpdate(((MysqlConnection) this.conn).getSession().versionMeetsMinimum(5, 7, 6) ? "ALTER USER 'wl5602user'@'%' IDENTIFIED BY 'pwd'" : "SET PASSWORD FOR 'wl5602user'@'%' = PASSWORD('pwd')");
this.stmt.executeUpdate("FLUSH PRIVILEGES");
final Properties propsNoRetrieval = new Properties();
propsNoRetrieval.setProperty(PropertyKey.USER.getKeyName(), "wl5602user");
propsNoRetrieval.setProperty(PropertyKey.PASSWORD.getKeyName(), "pwd");
final Properties propsNoRetrievalNoPassword = new Properties();
propsNoRetrievalNoPassword.setProperty(PropertyKey.USER.getKeyName(), "wl5602nopassword");
propsNoRetrievalNoPassword.setProperty(PropertyKey.PASSWORD.getKeyName(), "");
final Properties propsAllowRetrieval = new Properties();
propsAllowRetrieval.setProperty(PropertyKey.USER.getKeyName(), "wl5602user");
propsAllowRetrieval.setProperty(PropertyKey.PASSWORD.getKeyName(), "pwd");
propsAllowRetrieval.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
final Properties propsAllowRetrievalNoPassword = new Properties();
propsAllowRetrievalNoPassword.setProperty(PropertyKey.USER.getKeyName(), "wl5602nopassword");
propsAllowRetrievalNoPassword.setProperty(PropertyKey.PASSWORD.getKeyName(), "");
propsAllowRetrievalNoPassword.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
// 1. with client-default MysqlNativePasswordPlugin
propsNoRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), MysqlNativePasswordPlugin.class.getName());
propsAllowRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), MysqlNativePasswordPlugin.class.getName());
// 1.1. RSA
propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
assertThrows(SQLException.class, "Public Key Retrieval is not allowed", () -> getConnectionWithProps(dbUrl, propsNoRetrieval));
assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl5602nopassword", false);
if (withRSA) {
assertCurrentUser(dbUrl, propsAllowRetrieval, "wl5602user", false);
} else {
assertThrows(SQLException.class, "Access denied for user 'wl5602user'.*", () -> getConnectionWithProps(dbUrl, propsAllowRetrieval));
}
assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
// 1.2. over SSL
propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
assertCurrentUser(dbUrl, propsNoRetrieval, "wl5602user", true);
assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl5602nopassword", false);
assertCurrentUser(dbUrl, propsAllowRetrieval, "wl5602user", true);
assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
// 2. with client-default Sha256PasswordPlugin
propsNoRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
propsNoRetrievalNoPassword.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
propsAllowRetrieval.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
propsAllowRetrievalNoPassword.setProperty(PropertyKey.defaultAuthenticationPlugin.getKeyName(), Sha256PasswordPlugin.class.getName());
// 2.1. RSA
propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
assertThrows(SQLException.class, "Public Key Retrieval is not allowed", () -> getConnectionWithProps(dbUrl, propsNoRetrieval));
assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl5602nopassword", false);
if (withRSA) {
assertCurrentUser(dbUrl, propsAllowRetrieval, "wl5602user", false);
} else {
assertThrows(SQLException.class, "Access denied for user 'wl5602user'.*", () -> getConnectionWithProps(dbUrl, propsAllowRetrieval));
}
assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
// 2.2. over SSL
propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
assertCurrentUser(dbUrl, propsNoRetrieval, "wl5602user", true);
assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl5602nopassword", false);
assertCurrentUser(dbUrl, propsAllowRetrieval, "wl5602user", false);
assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
// 3. with serverRSAPublicKeyFile specified
propsNoRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
propsNoRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
propsAllowRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
propsAllowRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "src/test/config/ssl-test-certs/mykey.pub");
// 3.1. RSA
propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
if (withRSA && withTestRsaKeys) {
assertCurrentUser(dbUrl, propsNoRetrieval, "wl5602user", false);
assertCurrentUser(dbUrl, propsAllowRetrieval, "wl5602user", false);
} else {
assertThrows(SQLException.class, "Access denied for user 'wl5602user'.*", () -> getConnectionWithProps(dbUrl, propsNoRetrieval));
assertThrows(SQLException.class, "Access denied for user 'wl5602user'.*", () -> getConnectionWithProps(dbUrl, propsAllowRetrieval));
}
assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl5602nopassword", false);
assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
// 3.2. Runtime setServerRSAPublicKeyFile must be denied
if (withRSA && withTestRsaKeys) {
final Connection c2 = getConnectionWithProps(dbUrl, propsNoRetrieval);
assertThrows(PropertyNotModifiableException.class, "Dynamic change of ''serverRSAPublicKeyFile'' is not allowed.", () -> {
((JdbcConnection) c2).getPropertySet().getProperty(PropertyKey.serverRSAPublicKeyFile).setValue("src/test/config/ssl-test-certs/mykey.pub");
return null;
});
c2.close();
}
// 3.4. over SSL
propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
assertCurrentUser(dbUrl, propsNoRetrieval, "wl5602user", true);
assertCurrentUser(dbUrl, propsNoRetrievalNoPassword, "wl5602nopassword", false);
assertCurrentUser(dbUrl, propsAllowRetrieval, "wl5602user", true);
assertCurrentUser(dbUrl, propsAllowRetrievalNoPassword, "wl5602nopassword", false);
// 4. with wrong serverRSAPublicKeyFile specified
propsNoRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
propsNoRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
propsAllowRetrieval.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
propsAllowRetrievalNoPassword.setProperty(PropertyKey.serverRSAPublicKeyFile.getKeyName(), "unexistant/dummy.pub");
// 4.1. RSA
propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", () -> getConnectionWithProps(dbUrl, propsNoRetrieval));
assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", () -> getConnectionWithProps(dbUrl, propsNoRetrievalNoPassword));
assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", () -> getConnectionWithProps(dbUrl, propsAllowRetrieval));
assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", () -> getConnectionWithProps(dbUrl, propsAllowRetrievalNoPassword));
propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(dbUrl, propsNoRetrieval));
assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(dbUrl, propsNoRetrievalNoPassword));
assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(dbUrl, propsAllowRetrieval));
assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(dbUrl, propsAllowRetrievalNoPassword));
// 4.2. over SSL
propsNoRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
propsNoRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
propsAllowRetrieval.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
propsAllowRetrievalNoPassword.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.REQUIRED.name());
propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "false");
propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "false");
assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", () -> getConnectionWithProps(dbUrl, propsNoRetrieval));
assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", () -> getConnectionWithProps(dbUrl, propsNoRetrievalNoPassword));
assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", () -> getConnectionWithProps(dbUrl, propsAllowRetrieval));
assertThrows(SQLException.class, "Unable to read public key 'unexistant/dummy.pub'.*", () -> getConnectionWithProps(dbUrl, propsAllowRetrievalNoPassword));
propsNoRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
propsNoRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
propsAllowRetrieval.setProperty(PropertyKey.paranoid.getKeyName(), "true");
propsAllowRetrievalNoPassword.setProperty(PropertyKey.paranoid.getKeyName(), "true");
assertThrows(SQLException.class, "Unable to read public key ", new Callable<Void>() {
@SuppressWarnings("synthetic-access")
public Void call() throws Exception {
getConnectionWithProps(dbUrl, propsNoRetrieval);
return null;
}
});
assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(dbUrl, propsNoRetrievalNoPassword));
assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(dbUrl, propsAllowRetrieval));
assertThrows(SQLException.class, "Unable to read public key ", () -> getConnectionWithProps(dbUrl, propsAllowRetrievalNoPassword));
} finally {
if (!((MysqlConnection) this.conn).getSession().versionMeetsMinimum(8, 0, 5)) {
this.stmt.executeUpdate("SET GLOBAL old_passwords = @current_old_passwords");
}
}
}
Aggregations