diff --git a/include/maxscale/authenticator.h b/include/maxscale/authenticator.h index 92ae1f09c..6e36e22f2 100644 --- a/include/maxscale/authenticator.h +++ b/include/maxscale/authenticator.h @@ -113,7 +113,8 @@ typedef struct mxs_authenticator #define MXS_AUTH_FAILED_SSL 3 /**< SSL authentication failed */ #define MXS_AUTH_INCOMPLETE 4 /**< Authentication is not yet complete */ #define MXS_AUTH_SSL_INCOMPLETE 5 /**< SSL connection is not yet complete */ -#define MXS_AUTH_NO_SESSION 6 +#define MXS_AUTH_SSL_COMPLETE 6 /**< SSL connection complete or not required */ +#define MXS_AUTH_NO_SESSION 7 /** Return values for the loadusers entry point */ #define MXS_AUTH_LOADUSERS_OK 0 /**< Users loaded successfully */ diff --git a/include/maxscale/ssl.h b/include/maxscale/ssl.h index 71e417e1d..0176b5332 100644 --- a/include/maxscale/ssl.h +++ b/include/maxscale/ssl.h @@ -76,4 +76,16 @@ bool ssl_required_by_dcb(struct dcb *dcb); bool ssl_required_but_not_negotiated(struct dcb *dcb); const char* ssl_method_type_to_string(ssl_method_type_t method_type); +/** + * Helper function for client ssl authentication. Authenticates and checks changes + * in ssl status. + * + * @param dcb Client dcb + * + * @return MXS_AUTH_FAILED_SSL or MXS_AUTH_FAILED on error. MXS_AUTH_SSL_INCOMPLETE + * if ssl authentication is in progress and should be retried, MXS_AUTH_SSL_COMPLETE + * if ssl authentication is complete or not required. + */ +int ssl_authenticate_check_status(struct dcb *dcb); + MXS_END_DECLS diff --git a/server/core/ssl.cc b/server/core/ssl.cc index a2aa79367..0f91442b6 100644 --- a/server/core/ssl.cc +++ b/server/core/ssl.cc @@ -29,10 +29,11 @@ #include #include #include -#include -#include -#include #include +#include +#include +#include +#include /** * @brief Check client's SSL capability and start SSL if appropriate. @@ -214,3 +215,35 @@ const char* ssl_method_type_to_string(ssl_method_type_t method_type) return "Unknown"; } } + +int ssl_authenticate_check_status(DCB* dcb) +{ + int rval = MXS_AUTH_FAILED; + /** + * We record the SSL status before and after ssl authentication. This allows + * us to detect if the SSL handshake is immediately completed, which means more + * data needs to be read from the socket. + */ + bool health_before = ssl_is_connection_healthy(dcb); + int ssl_ret = ssl_authenticate_client(dcb, dcb->authfunc.connectssl(dcb)); + bool health_after = ssl_is_connection_healthy(dcb); + + if (ssl_ret != 0) + { + rval = (ssl_ret == SSL_ERROR_CLIENT_NOT_SSL) ? MXS_AUTH_FAILED_SSL : MXS_AUTH_FAILED; + } + else if (!health_after) + { + rval = MXS_AUTH_SSL_INCOMPLETE; + } + else if (!health_before && health_after) + { + rval = MXS_AUTH_SSL_INCOMPLETE; + poll_add_epollin_event_to_dcb(dcb, NULL); + } + else if (health_before && health_after) + { + rval = MXS_AUTH_SSL_COMPLETE; + } + return rval; +} \ No newline at end of file diff --git a/server/modules/authenticator/MySQLAuth/mysql_auth.c b/server/modules/authenticator/MySQLAuth/mysql_auth.c index b74785cdf..685d15c26 100644 --- a/server/modules/authenticator/MySQLAuth/mysql_auth.c +++ b/server/modules/authenticator/MySQLAuth/mysql_auth.c @@ -285,11 +285,8 @@ static bool is_localhost_address(struct sockaddr_storage *addr) /** * @brief Authenticates a MySQL user who is a client to MaxScale. * - * First call the SSL authentication function, passing the DCB and a boolean - * indicating whether the client is SSL capable. If SSL authentication is - * successful, check whether connection is complete. Fail if we do not have a - * user name. Call other functions to validate the user, reloading the user - * data if the first attempt fails. + * First call the SSL authentication function. Call other functions to validate + * the user, reloading the user data if the first attempt fails. * * @param dcb Request handler DCB connected to the client * @return Authentication status @@ -298,40 +295,15 @@ static bool is_localhost_address(struct sockaddr_storage *addr) static int mysql_auth_authenticate(DCB *dcb) { - MySQLProtocol *protocol = DCB_PROTOCOL(dcb, MySQLProtocol); + int auth_ret = ssl_authenticate_check_status(dcb); MYSQL_session *client_data = (MYSQL_session *)dcb->data; - int auth_ret = MXS_AUTH_FAILED; - - /** - * We record the SSL status before and after the authentication. This allows - * us to detect if the SSL handshake is immediately completed which means more - * data needs to be read from the socket. - */ - - bool health_before = ssl_is_connection_healthy(dcb); - int ssl_ret = ssl_authenticate_client(dcb, dcb->authfunc.connectssl(dcb)); - bool health_after = ssl_is_connection_healthy(dcb); - - if (0 != ssl_ret) - { - auth_ret = (SSL_ERROR_CLIENT_NOT_SSL == ssl_ret) ? MXS_AUTH_FAILED_SSL : MXS_AUTH_FAILED; - } - else if (!health_after) - { - auth_ret = MXS_AUTH_SSL_INCOMPLETE; - } - else if (!health_before && health_after) - { - auth_ret = MXS_AUTH_SSL_INCOMPLETE; - poll_add_epollin_event_to_dcb(dcb, NULL); - } - else if (*client_data->user) + if (auth_ret == MXS_AUTH_SSL_COMPLETE && *client_data->user) { MXS_DEBUG("Receiving connection from '%s' to database '%s'.", client_data->user, client_data->db); MYSQL_AUTH *instance = (MYSQL_AUTH*)dcb->listener->auth_instance; - + MySQLProtocol *protocol = DCB_PROTOCOL(dcb, MySQLProtocol); auth_ret = validate_mysql_user(instance->handle, dcb, client_data, protocol->scramble, sizeof(protocol->scramble)); diff --git a/server/modules/authenticator/PAM/PAMAuth/pam_client_session.cc b/server/modules/authenticator/PAM/PAMAuth/pam_client_session.cc index 11b6827f0..7ed66d485 100644 --- a/server/modules/authenticator/PAM/PAMAuth/pam_client_session.cc +++ b/server/modules/authenticator/PAM/PAMAuth/pam_client_session.cc @@ -305,33 +305,11 @@ Buffer PamClientSession::create_auth_change_packet() const int PamClientSession::authenticate(DCB* dcb) { - int rval = MXS_AUTH_FAILED; + int rval = ssl_authenticate_check_status(dcb); MYSQL_session *ses = static_cast(dcb->data); - /** - * We record the SSL status before and after SSL-authentication. This allows - * us to detect if the SSL handshake is immediately completed which means more - * data needs to be read from the socket. - */ - bool health_before = ssl_is_connection_healthy(dcb); - int ssl_ret = ssl_authenticate_client(dcb, dcb->authfunc.connectssl(dcb)); - bool health_after = ssl_is_connection_healthy(dcb); - - if (0 != ssl_ret) + if (rval == MXS_AUTH_SSL_COMPLETE && *ses->user) { - rval = (SSL_ERROR_CLIENT_NOT_SSL == ssl_ret) ? MXS_AUTH_FAILED_SSL : MXS_AUTH_FAILED; - } - else if (!health_after) - { - rval = MXS_AUTH_SSL_INCOMPLETE; - } - else if (!health_before && health_after) - { - rval = MXS_AUTH_SSL_INCOMPLETE; - poll_add_epollin_event_to_dcb(dcb, NULL); - } - else if (*ses->user) - { - // SSL-connection has been established (or was not required) + rval = MXS_AUTH_FAILED; if (m_state == PAM_AUTH_INIT) { /** We need to send the authentication switch packet to change the