MXS-862: Refactor backend authentication handling

The backend responses are now read in one place and the functions just
read the data. The protocol level will now handle the packet gathering
process and the authentication part just inspects the data.

Backend connections now load authenticators when they are being
connected. In the future, this enables the use of authentication modules
for backend connection.
This commit is contained in:
Markus Makela
2016-09-22 09:42:05 +03:00
parent cd11971d5d
commit 35d9b35609
10 changed files with 599 additions and 843 deletions

File diff suppressed because it is too large Load Diff

View File

@ -312,7 +312,7 @@ int MySQLSendHandshake(DCB* dcb)
memcpy(mysql_plugin_data, server_scramble + 8, 12);
const char* plugin_name = dcb->authfunc.plugin_name ?
dcb->authfunc.plugin_name : DEFAULT_AUTH_PLUGIN_NAME;
dcb->authfunc.plugin_name : DEFAULT_MYSQL_AUTH_PLUGIN;
int plugin_name_len = strlen(plugin_name);
mysql_payload_size =
@ -512,7 +512,7 @@ int gw_read_client_event(DCB* dcb)
* will be changed to MYSQL_IDLE (see below).
*
*/
case MYSQL_AUTH_SENT:
case MXS_AUTH_STATE_MESSAGE_READ:
/* After this call read_buffer will point to freed data */
if (nbytes_read < 3 || (0 == max_bytes && nbytes_read <
(MYSQL_GET_PACKET_LEN((uint8_t *) GWBUF_DATA(read_buffer)) + 4)) ||
@ -533,12 +533,12 @@ int gw_read_client_event(DCB* dcb)
* result in a call that comes to this section of code.
*
*/
case MYSQL_IDLE:
case MXS_AUTH_STATE_COMPLETE:
/* After this call read_buffer will point to freed data */
return_code = gw_read_normal_data(dcb, read_buffer, nbytes_read);
break;
case MYSQL_AUTH_FAILED:
case MXS_AUTH_STATE_FAILED:
gwbuf_free(read_buffer);
return_code = 1;
break;
@ -601,7 +601,7 @@ gw_read_do_authentication(DCB *dcb, GWBUF *read_buffer, int nbytes_read)
{
SESSION *session;
protocol->protocol_auth_state = MYSQL_AUTH_RECV;
protocol->protocol_auth_state = MXS_AUTH_STATE_RESPONSE_SENT;
/**
* Create session, and a router session for it.
* If successful, there will be backend connection(s)
@ -619,7 +619,7 @@ gw_read_do_authentication(DCB *dcb, GWBUF *read_buffer, int nbytes_read)
ss_dassert(session->state != SESSION_STATE_ALLOC &&
session->state != SESSION_STATE_DUMMY);
protocol->protocol_auth_state = MYSQL_IDLE;
protocol->protocol_auth_state = MXS_AUTH_STATE_COMPLETE;
/**
* Send an AUTH_OK packet to the client,
* packet sequence is # packet_number
@ -640,7 +640,7 @@ gw_read_do_authentication(DCB *dcb, GWBUF *read_buffer, int nbytes_read)
MXS_AUTH_INCOMPLETE != auth_val &&
MXS_AUTH_SSL_INCOMPLETE != auth_val)
{
protocol->protocol_auth_state = MYSQL_AUTH_FAILED;
protocol->protocol_auth_state = MXS_AUTH_STATE_FAILED;
mysql_client_auth_error_handling(dcb, auth_val);
/**
* Close DCB and which will release MYSQL_session
@ -1106,7 +1106,7 @@ int gw_write_client_event(DCB *dcb)
protocol = (MySQLProtocol *)dcb->protocol;
CHK_PROTOCOL(protocol);
if (protocol->protocol_auth_state == MYSQL_IDLE)
if (protocol->protocol_auth_state == MXS_AUTH_STATE_COMPLETE)
{
dcb_drain_writeq(dcb);
goto return_1;
@ -1207,7 +1207,7 @@ static void gw_process_one_new_client(DCB *client_dcb)
MySQLSendHandshake(client_dcb);
// client protocol state change
protocol->protocol_auth_state = MYSQL_AUTH_SENT;
protocol->protocol_auth_state = MXS_AUTH_STATE_MESSAGE_READ;
/**
* Set new descriptor to event set. At the same time,

View File

@ -50,6 +50,7 @@
#include <skygw_utils.h>
#include <log_manager.h>
#include <netinet/tcp.h>
#include <modutil.h>
static server_command_t* server_command_init(server_command_t* srvcmd, mysql_server_cmd_t cmd);
@ -78,7 +79,7 @@ MySQLProtocol* mysql_protocol_init(DCB* dcb, int fd)
goto return_p;
}
p->protocol_state = MYSQL_PROTOCOL_ALLOC;
p->protocol_auth_state = MYSQL_ALLOC;
p->protocol_auth_state = MXS_AUTH_STATE_INIT;
p->current_command = MYSQL_COM_UNDEFINED;
p->protocol_command.scom_cmd = MYSQL_COM_UNDEFINED;
p->protocol_command.scom_nresponse_packets = 0;
@ -143,28 +144,20 @@ const char* gw_mysql_protocol_state2string (int state)
{
switch(state)
{
case MYSQL_ALLOC:
return "MySQL Protocl struct allocated";
case MYSQL_PENDING_CONNECT:
return "MySQL Backend socket PENDING connect";
case MYSQL_CONNECTED:
return "MySQL Backend socket CONNECTED";
case MYSQL_AUTH_SENT:
return "MySQL Authentication handshake has been sent";
case MYSQL_AUTH_RECV:
return "MySQL Received user, password, db and capabilities";
case MYSQL_AUTH_FAILED:
return "MySQL Authentication failed";
case MYSQL_IDLE:
return "MySQL authentication is succesfully done.";
case MYSQL_AUTH_SSL_REQ:
return "MYSQL_AUTH_SSL_REQ";
case MYSQL_AUTH_SSL_HANDSHAKE_DONE:
return "MYSQL_AUTH_SSL_HANDSHAKE_DONE";
case MYSQL_AUTH_SSL_HANDSHAKE_FAILED:
return "MYSQL_AUTH_SSL_HANDSHAKE_FAILED";
case MYSQL_AUTH_SSL_HANDSHAKE_ONGOING:
return "MYSQL_AUTH_SSL_HANDSHAKE_ONGOING";
case MXS_AUTH_STATE_INIT:
return "Authentication initialized";
case MXS_AUTH_STATE_PENDING_CONNECT:
return "Network connection pending";
case MXS_AUTH_STATE_CONNECTED:
return "Network connection created";
case MXS_AUTH_STATE_MESSAGE_READ:
return "Read server handshake";
case MXS_AUTH_STATE_RESPONSE_SENT:
return "Response to handshake sent";
case MXS_AUTH_STATE_FAILED:
return "Authentication failed";
case MXS_AUTH_STATE_COMPLETE:
return "Authentication is complete.";
default:
return "MySQL (unknown protocol state)";
}
@ -992,3 +985,43 @@ char *create_auth_fail_str(char *username,
retblock:
return errstr;
}
/**
* @brief Read a complete packet from a DCB
*
* Read a complete packet from a connected DCB. If data was read, @c readbuf
* will point to the head of the read data. If no data was read, @c readbuf will
* be set to NULL.
*
* @param dcb DCB to read from
* @param readbuf Pointer to a buffer where the data is stored
* @return True on success, false if an error occurred while data was being read
*/
bool read_complete_packet(DCB *dcb, GWBUF **readbuf)
{
bool rval = false;
GWBUF *localbuf = NULL;
if (dcb_read(dcb, &localbuf, 0) >= 0)
{
rval = true;
dcb->last_read = hkheartbeat;
GWBUF *packets = modutil_get_complete_packets(&localbuf);
if (packets)
{
/** A complete packet was read */
*readbuf = packets;
}
if (localbuf)
{
/** Store any extra data in the DCB's readqueue */
spinlock_acquire(&dcb->authlock);
dcb->dcb_readqueue = gwbuf_append(dcb->dcb_readqueue, localbuf);
spinlock_release(&dcb->authlock);
}
}
return rval;
}