Bug #64055 Allow auth_socket plugin to work with Connector/J
Submitted: 17 Jan 2012 20:54 Modified: 10 Oct 2012 23:05
Reporter: Philip Clay Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / J Severity:S4 (Feature request)
Version:5.1.18 OS:Linux
Assigned to: John Russell CPU Architecture:Any
Tags: auth_socket, junixsocket

[17 Jan 2012 20:54] Philip Clay
Description:
I use a Connector/J with a custom SocketFactory provided by junixsocket
(http://code.google.com/p/junixsocket/wiki/ConnectingToMySQL).
This socket factory allows connecting to mysql via unix domain sockets, rather than TCP sockets.

I have applied the patch to junixsocket which allows the SO_PEERCRED socket
option to be passed by the client as detailed at
http://code.google.com/p/junixsocket/issues/detail?id=18

I use the auth_socket authentication module on the server side to allow
users to authenticate via SO_PEERCRED.

When connecting to mysql via Connector/J with the custom socket factory, I expected auth_socket to be able to successfully authenticate the user without having to supply a password.

Instead, I received the following error:

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Client does not support authentication protocol requested by server; consider upgrading MySQL client

Upon further investigation, I determined the reason for this error is that the server side requires that the client have the CLIENT_PLUGIN_AUTH capability.
This can be seen in sql/sql_acl.cc:find_mpvio_user.

The Connector/J client does not support this capability, as can be seen in MysqlIO.doHandshake (the capability is never added MysqlIO.clientParam before that value is sent over during the handshake.)

In a debugging session, I modified the value of clientParam to include the CLIENT_PLUGIN_AUTH capability on the client side, before it is sent to the server. After doing so, the server side auth_socket plugin successfully authenticated the client user (without needing a password).

I would like for Connector/J to support authentication using auth_socket (obviously, only if junixsocket is used, and junixsocket supports setting the SO_PEERCRED socket option)

This is useful for server side java, so that db credentials do not need to be stored and used by the java process.  We can concentrate on securing the OS and application, without having to worry about securing additional db credentials, therefore reducing the attack surface.

How to repeat:
Enable the auth_socket plugin in the mysqld configuration:

[mysqld]
plugin-load=auth_socket=auth_socket.so

Create a mysql user that must use auth_socket to authenticate...

http://dev.mysql.com/doc/refman/5.5/en/socket-authentication-plugin.html

CREATE USER 'yourosusername'@'localhost' IDENTIFIED WITH auth_socket;

Obtain junixsocket source, and apply the patch as detailed at
http://code.google.com/p/junixsocket/issues/detail?id=18

Compile the native junixsocket library.

Then use it to connect to mysql using Connector/J as follows (must run as yourosusername):

    public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver").newInstance();
        Properties props = new Properties();
        props.put("user", System.getProperty("user.name"));
        props.put("socketFactory", AFUNIXDatabaseSocketFactory.class.getName());
        props.put("junixsocket.file", "/var/run/mysqld/mysqld.sock");

        Connection conn = DriverManager.getConnection("jdbc:mysql://", props);
        System.out.println(conn);

        ResultSet rs = conn.createStatement()
            .executeQuery("SHOW GRANTS");
        while (rs.next()) {
            System.out.println(rs.getString(1));
        }
        rs.close();
        conn.close();
    }

You will receive the error message as detailed in the description section above.

Suggested fix:
The behavior I desire can be easily accomplished by the following in MysqlIO:

    private static final int CLIENT_PLUGIN_AUTH = 524288;
    //...
    doHandshake() {
        //...
        this.clientParam |= CLIENT_PLUGIN_AUTH;
    }

However, I do not know the additional ramifications of setting this flag.
Obviously, Connector/J does not support ALL plugins.  And it does not even support auth_socket without the use of junixsocket.  So, there is probably some additional work involved in making sure the proper error is received when a plugin that the client does not support is requested by the server.

The fix could be something as simple allowing a user to set this flag somehow, and rely on the user's knowledge of the environment to ensure that the flag is set correctly.

Or, the fix could be to always set the CLIENT_PLUGIN_AUTH flag in Connector/J, and make sure the proper behavior occurs when the server side requests an unsupported plugin.  (Although, how to determine what plugins are supported might be difficult).
[18 Jan 2012 8:32] Valeriy Kravchuk
Thank you for the feature request.
[22 Mar 2012 7:54] Tonci Grgin
Fixed.
[10 Oct 2012 23:05] John Russell
Added to changelog for 5.1.21: 

Connector/J applications can now connect to MySQL servers that use
the PAM authentication system. See http://dev.mysql.com/doc/refman/5.5/en/connector-j-using-pam.html for details about the Connector/J
support, and http://dev.mysql.com/doc/refman/5.5/en/pam-authentication-plugin.html for information about this authentication feature of the
MySQL server.