Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for BEARER_TOKEN_FILE. #13

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion src/core/common/gfal_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,69 @@ static void gfal_setBearerToken(gfal2_context_t handle, const char *token)
gfal2_log(G_LOG_LEVEL_DEBUG, "Using BEARER token credentials from the env");
}

static void gfal_setBearerTokenFile(gfal2_context_t handle, const char *token_file)
{
GError *error = NULL;
gfal2_set_opt_string(handle, "BEARER", "TOKEN_FILE", token_file, &error);
g_clear_error(&error);
gfal2_log(G_LOG_LEVEL_DEBUG, "Using BEARER token credentials from file %s", token_file);
}

// Setup default credentials depending on the environment
static void gfal_initCredentialLocation(gfal2_context_t handle)
{
//check first if BEARER is on the env
// Bearer token discovery is done according to:
// https://github.com/WLCG-AuthZ-WG/bearer-token-discovery/blob/master/specification.md
//
// check first if BEARER is on the env
const char *token = getenv("BEARER_TOKEN");
if (token != NULL) {
gfal_setBearerToken(handle, token);
return;
}
// next, look to BEARER_TOKEN_FILE
const char *token_file = getenv("BEARER_TOKEN_FILE");
if (token_file && (0 == gfal2_cred_get_token_from_file(token_file, NULL))) {
gfal_setBearerTokenFile(handle, token_file);
return;
}
// next, check in the $XDG_RUNTIME_DIR
const char *runtime_dir = getenv("XDG_RUNTIME_DIR");
if (runtime_dir) {
// filename is of the form:
// $XDG_RUNTIME_DIR/bt_u$ID
// Assume that $ID is max 20 digits.
size_t runtime_dir_len = strlen(runtime_dir);
char *token_file_full = (char*)malloc(runtime_dir_len + 5 + 20 + 1);
if (!token_file_full) {
gfal2_log(G_LOG_LEVEL_ERROR, "Failed to allocate memory");
return;
}
sprintf(token_file_full, "%s/bt_u%u", runtime_dir, geteuid());
if (0 == gfal2_cred_get_token_from_file(token_file_full, NULL)) {
gfal_setBearerTokenFile(handle, token_file_full);
free(token_file_full);
return;
}
free(token_file_full);
}
// finally, check in /tmp for a bearer token.
{
// filename is of the form:
// /tmp/bt_u$ID
char *token_file_full = (char*)malloc(9 + 20 + 1);
if (!token_file_full) {
gfal2_log(G_LOG_LEVEL_ERROR, "Failed to allocate memory");
return;
}
sprintf(token_file_full, "/tmp/bt_u%u", geteuid());
if (0 == gfal2_cred_get_token_from_file(token_file_full, NULL)) {
gfal_setBearerTokenFile(handle, token_file_full);
free(token_file_full);
return;
}
free(token_file_full);
}
// X509_USER_PROXY
const char *proxy = getenv("X509_USER_PROXY");
if (proxy != NULL) {
Expand Down
58 changes: 57 additions & 1 deletion src/core/common/gfal_cred_mapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#include <gfal_api.h>
#include <string.h>
#include "gfal_handle.h"

#include <ctype.h>

typedef struct {
size_t prefix_len;
Expand Down Expand Up @@ -141,6 +141,8 @@ char *gfal2_cred_get(gfal2_context_t handle, const char *type, const char *url,
}
else if (strcmp(type, GFAL_CRED_BEARER) == 0) {
return gfal2_get_opt_string_with_default(handle, "BEARER", "TOKEN", NULL);
} else if (strcmp(type, GFAL_CRED_BEARER_FILE) == 0) {
return gfal2_get_opt_string_with_default(handle, "BEARER", "TOKEN_FILE", NULL);
}
return NULL;
}
Expand Down Expand Up @@ -200,3 +202,57 @@ void gfal2_cred_foreach(gfal2_context_t handle, gfal_cred_func_t callback, void
callback_data data = {callback, user_data};
g_list_foreach(handle->cred_mapping, foreach_callback_wrapper, &data);
}


int gfal2_cred_get_token_from_file(const char *token_file, char **value)
{
FILE *fp = fopen(token_file, "r");
if (!fp) {
gfal2_log(G_LOG_LEVEL_DEBUG, "Token file %s is not valid: %s", token_file, strerror(errno));
return -1;
}
char *line = NULL;
size_t len = 0;
int nread;
// We will try the token as long as its not commented out and non-empty.
while ((nread = getline(&line, &len, fp)) != -1) {
int found_nonspace = 0;
size_t idx;
for (idx = 0; idx < nread; idx++) {
if (line[idx] == '#') break; // ignore commented-out lines
if (line[idx] && !isspace(line[idx])) {
found_nonspace = 1;
break;
}
}
if (found_nonspace) {
fclose(fp);
gfal2_log(G_LOG_LEVEL_DEBUG, "Found a token in file %s", token_file);
if (value) {
*value = (char *)malloc(nread + 1);
if (!value) {
gfal2_log(G_LOG_LEVEL_ERROR, "Failed to allocate memory for token copy");
return -1;
}
strncpy(*value, line + idx, nread);
(*value)[nread] = '\0';
size_t idx2;
for (idx2 = 0; idx2 < nread - idx; idx2++)
{
if (!(*value)[idx2] || isspace((*value)[idx2])) {
(*value)[idx2] = '\0';
break;
}
}
}
return 0;
}
}
if (!feof(fp) && (nread == -1)) {
gfal2_log(G_LOG_LEVEL_DEBUG, "Error while reading token file %s: %s", token_file, strerror(errno));
} else {
gfal2_log(G_LOG_LEVEL_DEBUG, "Failed to find a token in file %s", token_file);
}
fclose(fp);
return -1;
}
17 changes: 17 additions & 0 deletions src/core/common/gfal_cred_mapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ extern "C"
#define GFAL_CRED_PASSWD "PASSWORD"
/// Bearer token-type credential
#define GFAL_CRED_BEARER "BEARER"
/// Bearer token-type credential located in a file.
// This is different from the BEARER type as the plugins
// should never cache the contents of the BEARER_FILE and
// reloaded it each time it is needed. This way, credentials
// can be updated outside the process.
#define GFAL_CRED_BEARER_FILE "BEARER_FILE"

/**
* Stores a credential value together with its type
Expand Down Expand Up @@ -131,6 +137,17 @@ int gfal2_cred_copy(gfal2_context_t dest, const gfal2_context_t src, GError **er
*/
void gfal2_cred_foreach(gfal2_context_t handle, gfal_cred_func_t callback, void *user_data);

/**
* Given a filename, read it and return any token that is present.
* On success, if value is non-null it will be allocated and set to the
* value of the found token.
*
* @param token_file The file to search for tokens.
* @param value Output; value of found token.
* @return 0 on success, -1 on error.
*/
int gfal2_cred_get_token_from_file(const char *token_file, char **value);

#ifdef __cplusplus
}
#endif
Expand Down
11 changes: 11 additions & 0 deletions src/plugins/http/gfal_http_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ char* GfalHttpPluginData::find_se_token(const Davix::Uri& uri, const OP& operati

if (strcmp(cred->type, GFAL_CRED_BEARER) == 0) {
cred_list->emplace_back(url_prefix, cred->value);
} else if (cred->value && strcmp(cred->type, GFAL_CRED_BEARER_FILE) == 0) {
char *token_contents;
if (0 == gfal2_cred_get_token_from_file(cred->value, &token_contents)) {
cred_list->emplace_back(url_prefix, token_contents);
}
}
};

Expand Down Expand Up @@ -183,6 +188,12 @@ char* GfalHttpPluginData::find_se_token(const Davix::Uri& uri, const OP& operati
char* token = gfal2_cred_get(handle, GFAL_CRED_BEARER, uri.getHost().c_str(), NULL, &error);
g_clear_error(&error);

if (!token) {
char *token_file = gfal2_cred_get(handle, GFAL_CRED_BEARER_FILE, uri.getHost().c_str(), NULL, &error);
g_clear_error(&error);
if (token_file) gfal2_cred_get_token_from_file(token_file, &token);
}

return token;
}

Expand Down