MXS-862: Implement GSSAPI backend authentication

The GSSAPI backend authentication is based on tokens.  The server first
sends the service principal name which is used for token generation. The
client then retrieves a token from the GSSAPI server which it sends to the
backend server. If the server can verify the authenticity of the token,
authentication is successful.

This module can be used with both GSSAPIAuth and MySQLAuth modules.
This commit is contained in:
Markus Makela
2016-10-05 22:59:25 +03:00
parent 5d96faedd8
commit a2a8562c39
5 changed files with 191 additions and 48 deletions

View File

@ -15,17 +15,127 @@
#include <maxscale/alloc.h>
#include <dcb.h>
#include <mysql_client_server_protocol.h>
#include <gssapi.h>
#include "gssapi_auth.h"
/**
* @file gssapi_backend_auth.c GSSAPI backend authenticator
*/
/** TODO: Document functions and GSSAPI specific code */
static bool send_new_auth_token(DCB *dcb)
{
bool rval = false;
OM_uint32 major = 0, minor = 0;
gss_ctx_id_t handle = NULL;
gss_buffer_desc in = {0, 0};
gss_buffer_desc out = {0, 0};
gss_buffer_desc target = {0, 0};
gss_name_t princ = GSS_C_NO_NAME;
gssapi_auth_t *auth = (gssapi_auth_t*)dcb->authenticator_data;
target.value = auth->principal_name;
target.length = auth->principal_name_len + 1;
major = gss_import_name(&minor, &target, GSS_C_NT_USER_NAME, &princ);
if (GSS_ERROR(major))
{
report_error(major, minor);
}
major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL,
&handle, princ, GSS_C_NO_OID, 0, 0,
GSS_C_NO_CHANNEL_BINDINGS, &in, NULL, &out, 0, 0);
if (GSS_ERROR(major))
{
report_error(major, minor);
}
else
{
GWBUF *buffer = gwbuf_alloc(MYSQL_HEADER_LEN + out.length);
if (buffer)
{
uint8_t *data = (uint8_t*)GWBUF_DATA(buffer);
gw_mysql_set_byte3(data, out.length);
data += 3;
*data++ = 0x03;
memcpy(data, out.value, out.length);
if (dcb_write(dcb, buffer))
{
rval = true;
}
}
major = gss_delete_sec_context(&minor, &handle, &in);
if (GSS_ERROR(major))
{
report_error(major, minor);
}
major = gss_release_name(&minor, &princ);
if (GSS_ERROR(major))
{
report_error(major, minor);
}
}
return rval;
}
bool extract_principal_name(DCB *dcb, GWBUF *buffer)
{
bool rval = false;
size_t buflen = gwbuf_length(buffer) - MYSQL_HEADER_LEN;
uint8_t databuf[buflen];
gwbuf_copy_data(buffer, MYSQL_HEADER_LEN, buflen, databuf);
uint8_t *data = databuf;
while (*data)
{
data++;
}
data++;
buflen -= data - databuf;
uint8_t *principal = MXS_MALLOC(buflen);
if (principal)
{
memcpy(principal, data, buflen);
gssapi_auth_t *auth = (gssapi_auth_t*)dcb->authenticator_data;
auth->principal_name = principal;
auth->principal_name_len = buflen;
rval = true;
}
return rval;
}
static int gssapi_backend_auth_extract(DCB *dcb, GWBUF *buffer)
{
gw_send_backend_auth(dcb);
return MXS_AUTH_SUCCEEDED;
int rval = MXS_AUTH_FAILED;
gssapi_auth_t *data = (gssapi_auth_t*)dcb->authenticator_data;
if (data->state == GSSAPI_AUTH_INIT && extract_principal_name(dcb, buffer))
{
rval = MXS_AUTH_INCOMPLETE;
}
else if (data->state == GSSAPI_AUTH_DATA_SENT)
{
/** Read authentication response */
if (mxs_mysql_is_ok_packet(buffer))
{
data->state = GSSAPI_AUTH_OK;
rval = MXS_AUTH_SUCCEEDED;
}
}
return rval;
}
static bool gssapi_backend_auth_connectssl(DCB *dcb)
@ -35,7 +145,24 @@ static bool gssapi_backend_auth_connectssl(DCB *dcb)
static int gssapi_backend_auth_authenticate(DCB *dcb)
{
return MXS_AUTH_SUCCEEDED;
int rval = MXS_AUTH_FAILED;
gssapi_auth_t *auth_data = (gssapi_auth_t*)dcb->authenticator_data;
if (auth_data->state == GSSAPI_AUTH_INIT)
{
if (send_new_auth_token(dcb))
{
rval = MXS_AUTH_INCOMPLETE;
auth_data->state = GSSAPI_AUTH_DATA_SENT;
}
}
else if (auth_data->state == GSSAPI_AUTH_OK)
{
rval = MXS_AUTH_SUCCEEDED;
}
return rval;
}
/**
@ -43,13 +170,13 @@ static int gssapi_backend_auth_authenticate(DCB *dcb)
*/
static GWAUTHENTICATOR MyObject =
{
gssapi_auth_alloc,
gssapi_backend_auth_extract, /* Extract data into structure */
gssapi_backend_auth_connectssl, /* Check if client supports SSL */
gssapi_backend_auth_authenticate, /* Authenticate user credentials */
NULL,
gssapi_auth_free,
NULL /* Load users from backend databases */
gssapi_auth_alloc, /* Allocate authenticator data */
gssapi_backend_auth_extract, /* Extract data into structure */
gssapi_backend_auth_connectssl, /* Check if client supports SSL */
gssapi_backend_auth_authenticate, /* Authenticate user credentials */
NULL, /* Client plugin will free shared data */
gssapi_auth_free, /* Free authenticator data */
NULL /* Load users from backend databases */
};
MODULE_INFO info =