Skip to content

Commit

Permalink
mdb iamproxy auth support (#561)
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewOvvv authored Feb 5, 2024
1 parent ccd4dbf commit 0e44d13
Show file tree
Hide file tree
Showing 10 changed files with 327 additions and 2 deletions.
3 changes: 2 additions & 1 deletion sources/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ set(od_src
hashmap.c
hba.c
hba_reader.c
hba_rule.c)
hba_rule.c
mdb_iamproxy.c)

if (PAM_FOUND)
list(APPEND od_src pam.c)
Expand Down
13 changes: 13 additions & 0 deletions sources/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,19 @@ static inline int od_auth_frontend_cleartext(od_client_t *client)

od_extention_t *extentions = client->global->extentions;

/* support mdb_iamproxy authentication */
if (client->rule->enable_mdb_iamproxy_auth) {
int authentication_result = mdb_iamproxy_authenticate_user(
client->startup.user.value, client_token.password,
instance, client);
kiwi_password_free(&client_token);
machine_msg_free(msg);
if (authentication_result != OK_RESPONSE) {
goto auth_failed; // refence at line 80, 100 and etc
}
return OK_RESPONSE;
}

#ifdef LDAP_FOUND
if (client->rule->ldap_endpoint_name) {
od_debug(&instance->logger, "auth", client, NULL,
Expand Down
7 changes: 7 additions & 0 deletions sources/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ struct od_client {
int ldap_storage_password_len;
char *ldap_auth_dn;
#endif

/* external_id for logging additional ifno about client */
char *external_id;
};

static const size_t OD_CLIENT_DEFAULT_HASHMAP_SZ = 420;
Expand Down Expand Up @@ -108,6 +111,7 @@ static inline void od_client_init(od_client_t *client)
client->ldap_storage_password_len = 0;
client->ldap_auth_dn = NULL;
#endif
client->external_id = NULL;

kiwi_be_startup_init(&client->startup);
kiwi_vars_init(&client->vars);
Expand Down Expand Up @@ -146,6 +150,9 @@ static inline void od_client_free(od_client_t *client)
if (client->prep_stmt_ids) {
od_hashmap_free(client->prep_stmt_ids);
}
if (client->external_id) {
free(client->external_id);
}
free(client);
}

Expand Down
24 changes: 24 additions & 0 deletions sources/config_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ typedef enum {
OD_LAUTH_QUERY_USER,
OD_LAUTH_LDAP_SERVICE,
OD_LAUTH_PASSWORD_PASSTHROUGH,
OD_LAUTH_MDB_IAMPROXY_ENABLE,
OD_LAUTH_MDB_IAMPROXY_SOCKET_PATH,
OD_LQUANTILES,
OD_LMODULE,
OD_LLDAP_ENDPOINT,
Expand Down Expand Up @@ -275,6 +277,9 @@ static od_keyword_t od_config_keywords[] = {
od_keyword("password_passthrough", OD_LAUTH_PASSWORD_PASSTHROUGH),
od_keyword("load_module", OD_LMODULE),
od_keyword("hba_file", OD_LHBA_FILE),
od_keyword("enable_mdb_iamproxy_auth", OD_LAUTH_MDB_IAMPROXY_ENABLE),
od_keyword("mdb_iamproxy_socket_path",
OD_LAUTH_MDB_IAMPROXY_SOCKET_PATH),

/* ldap */
od_keyword("ldap_endpoint", OD_LLDAP_ENDPOINT),
Expand Down Expand Up @@ -1205,6 +1210,7 @@ static int od_config_reader_rule_settings(od_config_reader_t *reader,
od_extention_t *extentions,
od_storage_watchdog_t *watchdog)
{
rule->mdb_iamproxy_socket_path = NULL;
for (;;) {
od_token_t token;
int rc;
Expand Down Expand Up @@ -1293,6 +1299,24 @@ static int od_config_reader_rule_settings(od_config_reader_t *reader,
&rule->auth_module))
return NOT_OK_RESPONSE;
break;
/* mdb_iamproxy authentication */
case OD_LAUTH_MDB_IAMPROXY_ENABLE: {
if (!od_config_reader_yes_no(
reader, &rule->enable_mdb_iamproxy_auth))
return NOT_OK_RESPONSE;
if (rule->mdb_iamproxy_socket_path == NULL)
rule->mdb_iamproxy_socket_path =
"/var/run/iam-auth-proxy/iam-auth-proxy.sock";
break;
}
case OD_LAUTH_MDB_IAMPROXY_SOCKET_PATH: {
if (rule->mdb_iamproxy_socket_path != NULL)
free(rule->mdb_iamproxy_socket_path);
if (!od_config_reader_string(
reader, &rule->mdb_iamproxy_socket_path))
return NOT_OK_RESPONSE;
break;
}
#ifdef PAM_FOUND
/* auth_pam_service */
case OD_LAUTH_PAM_SERVICE:
Expand Down
2 changes: 1 addition & 1 deletion sources/frontend.c
Original file line number Diff line number Diff line change
Expand Up @@ -2340,4 +2340,4 @@ void od_frontend(void *arg)
od_router_unroute(router, client);
/* close frontend connection */
od_frontend_close(client);
}
}
11 changes: 11 additions & 0 deletions sources/logger.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,17 @@ od_logger_format(od_logger_t *logger, od_logger_level_t level, char *context,
if (od_unlikely(format_pos == format_end))
break;
switch (*format_pos) {
/* external_id */
case 'x': {
if (client && client->external_id != NULL) {
len = od_snprintf(dst_pos,
dst_end - dst_pos,
"%s",
client->external_id);
dst_pos += len;
break;
}
}
/* unixtime */
case 'n': {
time_t tm = time(NULL);
Expand Down
250 changes: 250 additions & 0 deletions sources/mdb_iamproxy.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@

/*
* Odyssey.
*
* Scalable PostgreSQL connection pooler.
*/

#include <odyssey.h>
#include <machinarium.h>
#include <limits.h>
#include <stdint.h>
#include <malloc.h>
#include <sys/poll.h>
#include <sys/un.h>
#include <sys/socket.h>

/*CONNECTION CALLBACK TYPES*/
#define MDB_IAMPROXY_CONN_ERROR -1
#define MDB_IAMPROXY_CONN_TIMEOUT -1
#define MDB_IAMPROXY_CONN_ACCEPTED 0
#define MDB_IAMPROXY_CONN_DENIED -1

#define MDB_IAMPROXY_RES_ERROR -1
#define MDB_IAMPROXY_RES_OK 0

/*AUTHENTICATION TIMEOUT LIMIT*/
#define MDB_IAMPROXY_DEFAULT_HEADER_SIZE 8
#define MDB_IAMPROXY_DEFAULT_CNT_CONNECTIONS 1
#define MDB_IAMPROXY_MAX_MSG_BODY_SIZE 1048576 // 1 Mb

#define MDB_IAMPROXY_DEFAULT_CONNECTION_TIMEOUT 1000
#define MDB_IAMPROXY_DEFAULT_RECEIVING_HEADER_TIMEOUT 4000
#define MDB_IAMPROXY_DEFAULT_RECEIVING_BODY_TIMEOUT 1000
#define MDB_IAMPROXY_DEFAULT_SENDING_TIMEOUT 1000

/*PAM SOCKET FILE*/
#define MDB_IAMPROXY_DEFAULT_SOCKET_FILE \
"/var/run/iam-auth-proxy/iam-auth-proxy.sock" // PAM SOCKET FILE place

void put_header(char dst[], uint64_t src)
{
for (int i = 0; i < MDB_IAMPROXY_DEFAULT_HEADER_SIZE; ++i) {
dst[i] = (src & 0xFF);
src >>= CHAR_BIT;
}
}

void fetch_header(uint64_t *dst, char src[])
{
for (int i = 0; i < MDB_IAMPROXY_DEFAULT_HEADER_SIZE; ++i) {
(*dst) |= (((uint64_t)src[i]) << (i * CHAR_BIT));
}
}

machine_msg_t *mdb_iamproxy_io_read(machine_io_t *io)
{
machine_msg_t *header;
machine_msg_t *msg;

uint64_t body_size = 0;
uint64_t received = 0;

/* RECEIVE HEADER */
header = machine_read(io, MDB_IAMPROXY_DEFAULT_HEADER_SIZE,
MDB_IAMPROXY_DEFAULT_RECEIVING_HEADER_TIMEOUT);
if (header == NULL) {
return NULL;
}
fetch_header(&body_size, (char *)machine_msg_data(header));
machine_msg_free(header);

if (body_size > MDB_IAMPROXY_MAX_MSG_BODY_SIZE) {
return NULL;
}
msg = machine_read(io, body_size,
MDB_IAMPROXY_DEFAULT_RECEIVING_BODY_TIMEOUT);
if (msg == NULL) {
return NULL;
}

return msg;
}

int mdb_iamproxy_io_write(machine_io_t *io, machine_msg_t *msg)
{
/*GET COMMON MSG INFO AND ALLOCATE BUFFER*/
int32_t send_result = MDB_IAMPROXY_RES_OK;
uint64_t body_size = machine_msg_size(
msg); // stores size of message (add one byte for 'c\0')

/* PREPARE HEADER BUFFER */
machine_msg_t *header =
machine_msg_create(MDB_IAMPROXY_DEFAULT_HEADER_SIZE);
if (header == NULL) {
send_result = MDB_IAMPROXY_RES_ERROR;
goto free_end;
}
put_header((char *)machine_msg_data(header), body_size);

/*SEND HEADER TO SOCKET*/
if (machine_write(io, header, MDB_IAMPROXY_DEFAULT_SENDING_TIMEOUT) <
0) {
send_result = MDB_IAMPROXY_RES_ERROR;
goto free_end;
}

/*SEND MSG TO SOCKET*/
if (machine_write(io, msg, MDB_IAMPROXY_DEFAULT_SENDING_TIMEOUT) < 0) {
send_result = MDB_IAMPROXY_RES_ERROR;
goto free_end;
}

free_end:
return send_result;
}

int mdb_iamproxy_authenticate_user(const char *username, const char *token,
od_instance_t *instance, od_client_t *client)
{
int32_t authentication_result =
MDB_IAMPROXY_CONN_DENIED; // stores authenticate status for user (default value: CONN_DENIED)
int32_t correct_sending =
MDB_IAMPROXY_CONN_ACCEPTED; // stores stutus of sending data to iam-auth-proxy
char *auth_status_char;
machine_msg_t *msg_username = NULL, *msg_token = NULL,
*auth_status = NULL, *external_user = NULL;

/*SOCKET SETUP*/
struct sockaddr *saddr;
struct sockaddr_un
exchange_socket; // socket for interprocceses connection
memset(&exchange_socket, 0, sizeof(exchange_socket));
exchange_socket.sun_family = AF_UNIX;
saddr = (struct sockaddr *)&exchange_socket;
od_snprintf(exchange_socket.sun_path, sizeof(exchange_socket.sun_path),
"%s", MDB_IAMPROXY_DEFAULT_SOCKET_FILE);

/*SETUP IO*/
machine_io_t *io;
io = machine_io_create();
if (io == NULL) {
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_end;
}

/*CONNECT TO SOCKET*/
int rc = machine_connect(io, saddr,
MDB_IAMPROXY_DEFAULT_CONNECTION_TIMEOUT);
if (rc == NOT_OK_RESPONSE) {
od_error(&instance->logger, "auth", client, NULL,
"failed to connect to %s", exchange_socket.sun_path);
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_end;
}

/*COMMUNICATE WITH SOCKET*/
msg_username = machine_msg_create(0);
if (msg_username == NULL) {
od_error(&instance->logger, "auth", client, NULL,
"failed to allocate msg_username");
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_io;
}
if (machine_msg_write(msg_username, username, strlen(username) + 1) <
0) {
od_error(&instance->logger, "auth", client, NULL,
"failed to send username to msg_username");
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_io;
}

msg_token = machine_msg_create(0);
if (msg_token == NULL) {
od_error(&instance->logger, "auth", client, NULL,
"failed to allocate msg_token");
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_io;
}
if (machine_msg_write(msg_token, token, strlen(token) + 1) < 0) {
od_error(&instance->logger, "auth", client, NULL,
"failed to write token to msg_token");
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_io;
}

correct_sending = mdb_iamproxy_io_write(
io, msg_username); // send USERNAME to socket
if (correct_sending !=
MDB_IAMPROXY_RES_OK) { // error during sending data to socket
od_error(&instance->logger, "auth", client, NULL,
"failed to send username to iam-auth-proxy");
authentication_result = correct_sending;
goto free_io;
}
correct_sending =
mdb_iamproxy_io_write(io, msg_token); // send TOKEN to socket
if (correct_sending !=
MDB_IAMPROXY_RES_OK) { // error during sending data to socket
od_error(&instance->logger, "auth", client, NULL,
"failed to send token to iam-auth-proxy");
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_io;
}

/*COMMUNUCATE WITH SOCKET*/
auth_status =
mdb_iamproxy_io_read(io); // recieve auth_status from socket
if (auth_status == NULL) { // recieving is not completed successfully
od_error(&instance->logger, "auth", client, NULL,
"failed to receive auth_status from iam-auth-proxy");
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_io;
}

auth_status_char = (char *)machine_msg_data(auth_status);
if ((unsigned)auth_status_char[0]) {
authentication_result = MDB_IAMPROXY_CONN_ACCEPTED;
} else {
authentication_result = MDB_IAMPROXY_CONN_DENIED;
}

external_user =
mdb_iamproxy_io_read(io); // recieve subject_id from socket
if (external_user == NULL) {
od_error(&instance->logger, "auth", client, NULL,
"failed to receive external_user from iam-auth-proxy");
authentication_result = MDB_IAMPROXY_CONN_ERROR;
goto free_auth_status;
}

client->external_id = malloc(machine_msg_size(external_user));
memcpy(client->external_id, (char *)machine_msg_data(external_user),
machine_msg_size(external_user));

od_log(&instance->logger, "auth", client, NULL,
"user '%s.%s', with client_id: %s was authenticated by iam with subject_id: %s",
client->startup.database.value, client->startup.user.value,
client->id.id, client->external_id);

/*FREE RESOURCES*/
free_external_user:
machine_msg_free(external_user);
free_auth_status:
machine_msg_free(auth_status);
free_io:
machine_io_free(io);
free_end:
/*RETURN RESULT*/
return authentication_result;
}
Loading

0 comments on commit 0e44d13

Please sign in to comment.