[Configuration]
1. Authentication provider plugin framework 2. An instance of authentication provider plugin for OIDC (OpenID Connect)
This commit is contained in:
7
.github/workflows/build.yml
vendored
7
.github/workflows/build.yml
vendored
@@ -23,6 +23,13 @@ jobs:
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
- name: Build authentication plugin - oidc
|
||||
run: |
|
||||
cd kubernetes/config/authn_plugin/plugins/oidc
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
- name: Build examples
|
||||
run: |
|
||||
cd examples/
|
||||
|
||||
@@ -4,6 +4,7 @@ all:
|
||||
cd list_pod_incluster; make
|
||||
cd exec_provider; make
|
||||
cd generic; make
|
||||
cd auth_provider; make
|
||||
|
||||
clean:
|
||||
cd create_pod; make clean
|
||||
@@ -11,3 +12,4 @@ clean:
|
||||
cd list_pod_incluster; make clean
|
||||
cd exec_provider; make clean
|
||||
cd generic; make clean
|
||||
cd auth_provider; make clean
|
||||
|
||||
3
examples/auth_provider/.gitignore
vendored
Normal file
3
examples/auth_provider/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
list_pod_by_auth_provider_bin
|
||||
config_with_auth_provider
|
||||
config_with_auth_provider.*
|
||||
8
examples/auth_provider/Makefile
Normal file
8
examples/auth_provider/Makefile
Normal file
@@ -0,0 +1,8 @@
|
||||
INCLUDE:=-I../../kubernetes/include -I../../kubernetes/model -I../../kubernetes/api -I../../kubernetes/config
|
||||
LIBS:=-L../../kubernetes/build -lkubernetes -lcurl -lyaml -lpthread -lssl -lz
|
||||
CFLAGS:=-g
|
||||
|
||||
all:
|
||||
gcc main.c $(CFLAGS) $(INCLUDE) $(LIBS) -o list_pod_by_auth_provider_bin
|
||||
clean:
|
||||
rm ./list_pod_by_auth_provider_bin
|
||||
32
examples/auth_provider/config_with_auth_provider_sample
Normal file
32
examples/auth_provider/config_with_auth_provider_sample
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
clusters:
|
||||
- cluster:
|
||||
certificate-authority-data:
|
||||
server: https://host:6443
|
||||
name: kubernetes
|
||||
contexts:
|
||||
- context:
|
||||
cluster: kubernetes
|
||||
user: kubernetes-admin
|
||||
name: kubernetes-admin@kubernetes
|
||||
- context:
|
||||
cluster: kubernetes
|
||||
namespace: default
|
||||
user: theone
|
||||
name: theone@kubernetes
|
||||
current-context: theone@kubernetes
|
||||
kind: Config
|
||||
preferences: {}
|
||||
users:
|
||||
- name: theone
|
||||
user:
|
||||
auth-provider:
|
||||
name: oidc
|
||||
config:
|
||||
client-id:
|
||||
client-secret:
|
||||
id-token:
|
||||
idp-certificate-authority:
|
||||
idp-issuer-url:
|
||||
refresh-token:
|
||||
64
examples/auth_provider/main.c
Normal file
64
examples/auth_provider/main.c
Normal file
@@ -0,0 +1,64 @@
|
||||
#include <kube_config.h>
|
||||
#include <apiClient.h>
|
||||
#include <CoreV1API.h>
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
void list_pod(apiClient_t * apiClient)
|
||||
{
|
||||
v1_pod_list_t *pod_list = NULL;
|
||||
pod_list = CoreV1API_listNamespacedPod(apiClient, "default", /*namespace */
|
||||
NULL, /* pretty */
|
||||
0, /* allowWatchBookmarks */
|
||||
NULL, /* continue */
|
||||
NULL, /* fieldSelector */
|
||||
NULL, /* labelSelector */
|
||||
0, /* limit */
|
||||
NULL, /* resourceVersion */
|
||||
0, /* timeoutSeconds */
|
||||
0 /* watch */
|
||||
);
|
||||
printf("The return code of HTTP request=%ld\n", apiClient->response_code);
|
||||
if (pod_list) {
|
||||
printf("Get pod list:\n");
|
||||
listEntry_t *listEntry = NULL;
|
||||
v1_pod_t *pod = NULL;
|
||||
list_ForEach(listEntry, pod_list->items) {
|
||||
pod = listEntry->data;
|
||||
printf("\tThe pod name: %s\n", pod->metadata->name);
|
||||
}
|
||||
v1_pod_list_free(pod_list);
|
||||
pod_list = NULL;
|
||||
} else {
|
||||
printf("Cannot get any pod.\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *basePath = NULL;
|
||||
sslConfig_t *sslConfig = NULL;
|
||||
list_t *apiKeys = NULL;
|
||||
int rc = load_kube_config(&basePath, &sslConfig, &apiKeys, "./config_with_auth_provider");
|
||||
if (rc != 0) {
|
||||
printf("Cannot load kubernetes configuration.\n");
|
||||
return -1;
|
||||
}
|
||||
apiClient_t *apiClient = apiClient_create_with_base_path(basePath, sslConfig, apiKeys);
|
||||
if (!apiClient) {
|
||||
printf("Cannot create a kubernetes client.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
list_pod(apiClient);
|
||||
|
||||
apiClient_free(apiClient);
|
||||
apiClient = NULL;
|
||||
free_client_config(basePath, sslConfig, apiKeys);
|
||||
basePath = NULL;
|
||||
sslConfig = NULL;
|
||||
apiKeys = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -34,9 +34,12 @@ endif()
|
||||
set(SRCS
|
||||
config/kube_config_model.c
|
||||
config/kube_config_yaml.c
|
||||
config/kube_config_util.c
|
||||
config/kube_config.c
|
||||
config/incluster_config.c
|
||||
config/exec_provider.c
|
||||
config/authn_plugin/authn_plugin_util.c
|
||||
config/authn_plugin/authn_plugin.c
|
||||
src/list.c
|
||||
src/apiKey.c
|
||||
src/apiClient.c
|
||||
@@ -793,9 +796,12 @@ set(HDRS
|
||||
config/kube_config_common.h
|
||||
config/kube_config_model.h
|
||||
config/kube_config_yaml.h
|
||||
config/kube_config_util.h
|
||||
config/kube_config.h
|
||||
config/incluster_config.h
|
||||
config/exec_provider.h
|
||||
config/authn_plugin/authn_plugin_util.h
|
||||
config/authn_plugin/authn_plugin.h
|
||||
include/apiClient.h
|
||||
include/list.h
|
||||
include/binary.h
|
||||
|
||||
81
kubernetes/config/authn_plugin/authn_plugin.c
Normal file
81
kubernetes/config/authn_plugin/authn_plugin.c
Normal file
@@ -0,0 +1,81 @@
|
||||
#include "authn_plugin.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define PLUGIN_NAME_TEMPLATE "libkubernetes_%s.so"
|
||||
#define PLUGIN_LIB_NAME_SIZE 64
|
||||
|
||||
#define PLUGIN_FUNCTION_GET_TOKEN "get_token"
|
||||
#define PLUGIN_FUNCTION_IS_EXPIRED "is_expired"
|
||||
#define PLUGIN_FUNCTION_REFRESH "refresh"
|
||||
|
||||
authn_plugin_t *create_authn_plugin(const char *name)
|
||||
{
|
||||
static char fname[] = "create_authn_plugin()";
|
||||
|
||||
authn_plugin_t *plugin = calloc(1, sizeof(authn_plugin_t));
|
||||
if (!plugin) {
|
||||
fprintf(stderr, "%s: Cannot allocate memory for plugin library %s.[%s]\n", fname, name, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char plugin_lib_name[PLUGIN_LIB_NAME_SIZE];
|
||||
memset(plugin_lib_name, 0, sizeof(plugin_lib_name));
|
||||
snprintf(plugin_lib_name, sizeof(plugin_lib_name), PLUGIN_NAME_TEMPLATE, name);
|
||||
void *dlhandler = dlopen(plugin_lib_name, RTLD_LAZY);
|
||||
|
||||
if (!dlhandler) {
|
||||
fprintf(stderr, "%s: Cannot load the library %s.[%s]\n", fname, plugin_lib_name, dlerror());
|
||||
goto error;
|
||||
}
|
||||
|
||||
plugin->name = strdup(name);
|
||||
plugin->dlhandler = dlhandler;
|
||||
plugin->get_token = dlsym(dlhandler, PLUGIN_FUNCTION_GET_TOKEN);
|
||||
if (!plugin->get_token) {
|
||||
fprintf(stderr, "%s: Cannot find the function %s in library %s.[%s]\n", fname, PLUGIN_FUNCTION_GET_TOKEN, plugin_lib_name, dlerror());
|
||||
goto error;
|
||||
}
|
||||
plugin->is_expired = dlsym(dlhandler, PLUGIN_FUNCTION_IS_EXPIRED);
|
||||
if (!plugin->is_expired) {
|
||||
fprintf(stderr, "%s: Cannot find the function %s in library %s.[%s]\n", fname, PLUGIN_FUNCTION_IS_EXPIRED, plugin_lib_name, dlerror());
|
||||
goto error;
|
||||
}
|
||||
plugin->refresh = dlsym(dlhandler, PLUGIN_FUNCTION_REFRESH);
|
||||
if (!plugin->refresh) {
|
||||
fprintf(stderr, "%s: Cannot find the function %s in library %s.[%s]\n", fname, PLUGIN_FUNCTION_REFRESH, plugin_lib_name, dlerror());
|
||||
goto error;
|
||||
}
|
||||
|
||||
return plugin;
|
||||
|
||||
error:
|
||||
free_authn_plugin(plugin);
|
||||
plugin = NULL;
|
||||
return plugin;
|
||||
}
|
||||
|
||||
void free_authn_plugin(authn_plugin_t * plugin)
|
||||
{
|
||||
if (!plugin) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (plugin->dlhandler) {
|
||||
dlclose(plugin->dlhandler);
|
||||
plugin->dlhandler = NULL;
|
||||
}
|
||||
|
||||
if (plugin->name) {
|
||||
free(plugin->name);
|
||||
plugin->name = NULL;
|
||||
}
|
||||
|
||||
plugin->get_token = NULL;
|
||||
plugin->is_expired = NULL;
|
||||
plugin->refresh = NULL;
|
||||
|
||||
free(plugin);
|
||||
}
|
||||
25
kubernetes/config/authn_plugin/authn_plugin.h
Normal file
25
kubernetes/config/authn_plugin/authn_plugin.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef _AUTHN_PLUGIN_H
|
||||
#define _AUTHN_PLUGIN_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "../kube_config_model.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct authn_plugin_t {
|
||||
char *name;
|
||||
void *dlhandler;
|
||||
char *(*get_token) (kubeconfig_property_t *);
|
||||
bool (*is_expired) (kubeconfig_property_t *);
|
||||
int (*refresh) (kubeconfig_property_t *);
|
||||
} authn_plugin_t;
|
||||
|
||||
authn_plugin_t *create_authn_plugin(const char *);
|
||||
void free_authn_plugin(authn_plugin_t *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _AUTHN_PLUGIN_H */
|
||||
76
kubernetes/config/authn_plugin/authn_plugin_util.c
Normal file
76
kubernetes/config/authn_plugin/authn_plugin_util.c
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "authn_plugin_util.h"
|
||||
#include <errno.h>
|
||||
|
||||
int shc_request(char **p_http_response, int *p_http_response_length, char *type, const char *url, sslConfig_t * sc, list_t * apiKeys, list_t * contentType, char *post_data)
|
||||
{
|
||||
static char fname[] = "shc_request()";
|
||||
|
||||
apiClient_t *http_client = apiClient_create_with_base_path(url, sc, apiKeys);
|
||||
if (!http_client) {
|
||||
fprintf(stderr, "%s: Cannot create http client. [%s].\n", fname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
apiClient_invoke(http_client, NULL, NULL, NULL, NULL, NULL, contentType, post_data, type);
|
||||
|
||||
int rc = http_client->response_code;
|
||||
switch (rc) {
|
||||
case HTTP_RC_OK:
|
||||
*p_http_response = strndup((char *)http_client->dataReceived, http_client->dataReceivedLen);
|
||||
*p_http_response_length = http_client->dataReceivedLen;
|
||||
break;
|
||||
default:
|
||||
printf("%s: response_code=%ld\n", fname, http_client->response_code);
|
||||
if (http_client->dataReceived) {
|
||||
printf("%s: %s\n", fname, (char *)http_client->dataReceived);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (http_client->dataReceived) {
|
||||
free(http_client->dataReceived);
|
||||
http_client->dataReceived = NULL;
|
||||
http_client->dataReceivedLen = 0;
|
||||
}
|
||||
|
||||
if (http_client) {
|
||||
apiClient_free(http_client);
|
||||
http_client = NULL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
char *shc_get_string_from_json(const char *json_string, const char *key)
|
||||
{
|
||||
static char fname[] = "shc_get_string_from_json()";
|
||||
|
||||
char *res = NULL;
|
||||
|
||||
if (!json_string || !key) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cJSON *json = cJSON_Parse(json_string);
|
||||
if (!json) {
|
||||
fprintf(stderr, "%s: Cannot create JSON from string.[%s].\n", fname, cJSON_GetErrorPtr());
|
||||
return NULL;
|
||||
}
|
||||
cJSON *value = cJSON_GetObjectItem(json, key);
|
||||
if (!value) {
|
||||
fprintf(stderr, "%s: Cannot get the value for %s.\n", fname, key);
|
||||
goto end;
|
||||
}
|
||||
if (value->type != cJSON_String && value->type != cJSON_Object) {
|
||||
fprintf(stderr, "%s: The value for %s is invalid.\n", fname, key);
|
||||
goto end;
|
||||
}
|
||||
res = strdup(value->valuestring);
|
||||
|
||||
end:
|
||||
if (json) {
|
||||
cJSON_Delete(json);
|
||||
json = NULL;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
75
kubernetes/config/authn_plugin/authn_plugin_util.h
Normal file
75
kubernetes/config/authn_plugin/authn_plugin_util.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#ifndef _AUTHN_PLUGIN_UTIL_H
|
||||
#define _AUTHN_PLUGIN_UTIL_H
|
||||
|
||||
#include "../../include/apiClient.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HTTP_REQUEST_GET "GET"
|
||||
#define HTTP_REQUEST_POST "POST"
|
||||
#define HTTP_REQUEST_DELETE "DELETE"
|
||||
#define HTTP_REQUEST_PATCH "PATCH"
|
||||
|
||||
typedef enum shc_http_rc_t {
|
||||
HTTP_RC_OK = 200,
|
||||
HTTP_RC_UNAUTHORIZED = 400
|
||||
} shc_http_rc_t;
|
||||
|
||||
/*
|
||||
* shc_request
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Issue a http(s) request
|
||||
*
|
||||
* Return:
|
||||
*
|
||||
* HTTP request return code
|
||||
*
|
||||
* Parameter:
|
||||
*
|
||||
* IN:
|
||||
* request_type : HTTP_REQUEST_GET,HTTP_REQUEST_POST,HTTP_REQUEST_DELETE or HTTP_REQUEST_PATCH
|
||||
* url : http request url
|
||||
* sc : security context for SSL/TLS
|
||||
* apiKeys : key-value list including basic or bearer token for HTTP authentication
|
||||
* contentType : string list including HTTP content type
|
||||
* post_data : post data string when request_type is "POST"
|
||||
*
|
||||
* OUT:
|
||||
* p_http_response : pointer that pointing to HTTP response raw string, the memory is allocated in shc_request, but user should free it out of shc_request after it is useless.
|
||||
* p_http_response_length : pointer that pointing to the length of p_http_response
|
||||
*
|
||||
*/
|
||||
int shc_request(char **p_http_response, int *p_http_response_length, char *request_type, const char *url, sslConfig_t * sc, list_t * apiKeys, list_t * contentType, char *post_data);
|
||||
|
||||
/*
|
||||
* shc_get_string_from_json
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Get a string value from json by a key
|
||||
*
|
||||
* Return:
|
||||
*
|
||||
* char * : the value string
|
||||
* NULL : cannot find the value by key
|
||||
*
|
||||
* Parameter:
|
||||
*
|
||||
* IN:
|
||||
* json_string : a json string that includes key-value string
|
||||
* key : the key needs to find
|
||||
*
|
||||
* OUT:
|
||||
* None
|
||||
*
|
||||
*/
|
||||
char *shc_get_string_from_json(const char *json_string, const char *key);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _AUTHN_PLUGIN_UTIL_H */
|
||||
15
kubernetes/config/authn_plugin/plugins/oidc/CMakeLists.txt
Normal file
15
kubernetes/config/authn_plugin/plugins/oidc/CMakeLists.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
project (KubernetesClientAuthnPluginOIDC)
|
||||
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
|
||||
set(BIN_NAME "kubernetes_oidc")
|
||||
|
||||
include_directories(../../)
|
||||
include_directories(../../../)
|
||||
include_directories(../../../../include/)
|
||||
include_directories(../../../../external/)
|
||||
|
||||
aux_source_directory(. DIR_SRCS)
|
||||
|
||||
add_library(${BIN_NAME} SHARED ${DIR_SRCS})
|
||||
318
kubernetes/config/authn_plugin/plugins/oidc/libkubernetes_oidc.c
Normal file
318
kubernetes/config/authn_plugin/plugins/oidc/libkubernetes_oidc.c
Normal file
@@ -0,0 +1,318 @@
|
||||
#include "authn_plugin.h"
|
||||
#include "authn_plugin_util.h"
|
||||
#include "kube_config_util.h"
|
||||
#include "kube_config_common.h"
|
||||
#include "binary.h"
|
||||
#include "cJSON.h"
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define OIDC_ID_TOKEN_DELIM "."
|
||||
#define OIDC_ID_TOKEN_EXP "exp"
|
||||
#define OIDC_CONFIGURATION_URL_TEMPLATE "%s/.well-known/openid-configuration"
|
||||
#define OIDC_TOKEN_ENDPOINT "token_endpoint"
|
||||
#define OIDC_ID_TOKEN "id_token"
|
||||
#define OIDC_REFRESH_TOKEN "refresh_token"
|
||||
|
||||
#define JWT_PART2_BUFFER_SIZE 1024
|
||||
#define BASE64_PADDING_STRING_SIZE 4
|
||||
#define BASE64_PADDING_CHAR "="
|
||||
|
||||
#define REFRESH_TOKEN_CONTENT_TYPE "application/x-www-form-urlencoded"
|
||||
#define REFRESH_TOKEN_CREDENTIAL_TEMPLATE "%s:%s"
|
||||
#define REFRESH_TOKEN_POST_DATA_TEMPLATE "refresh_token=%s&grant_type=refresh_token"
|
||||
|
||||
#define OIDC_CONFIGURATION_URL_BUFFER_SIZE 1024
|
||||
#define REFRESH_TOKEN_CREDENTIAL_BUFFER_SIZE 1024
|
||||
#define REFRESH_TOKEN_POST_DATA_BUFFER_SIZE 1024
|
||||
|
||||
static time_t get_token_expiration_time(const char *token_string)
|
||||
{
|
||||
static char fname[] = "get_token_expiration_time()";
|
||||
|
||||
time_t expiration_time = 0;
|
||||
|
||||
if (!token_string || '\0' == token_string[0]) {
|
||||
return 0;
|
||||
}
|
||||
char *dup_token_string = strdup(token_string);
|
||||
if (!dup_token_string) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *p = NULL;
|
||||
p = strtok(dup_token_string, OIDC_ID_TOKEN_DELIM); /* jwt header */
|
||||
if (!p) {
|
||||
fprintf(stderr, "%s: The token <%s> is not a valid JWT token.\n", fname, token_string);
|
||||
goto end;
|
||||
}
|
||||
p = strtok(NULL, OIDC_ID_TOKEN_DELIM); /* jwt part2 */
|
||||
if (!p) {
|
||||
fprintf(stderr, "%s: The token <%s> is not a valid JWT token.\n", fname, token_string);
|
||||
goto end;
|
||||
}
|
||||
|
||||
int base64_padding_length = 4 - strlen(p) % 4;
|
||||
char base64_padding_string[BASE64_PADDING_STRING_SIZE];
|
||||
memset(base64_padding_string, 0, sizeof(base64_padding_string));
|
||||
for (int i = 0; i < base64_padding_length; i++) {
|
||||
strncat(base64_padding_string, BASE64_PADDING_CHAR, 1);
|
||||
}
|
||||
|
||||
char jwt_part2_string[JWT_PART2_BUFFER_SIZE];
|
||||
memset(jwt_part2_string, 0, sizeof(jwt_part2_string));
|
||||
snprintf(jwt_part2_string, sizeof(jwt_part2_string), "%s%s", p, base64_padding_string);
|
||||
|
||||
int decoded_bytes = 0;
|
||||
char *b64decode = base64decode(jwt_part2_string, strlen(jwt_part2_string), &decoded_bytes);
|
||||
if (!b64decode || 0 == decoded_bytes) {
|
||||
fprintf(stderr, "%s: Base64 decodes failed.\n", fname);
|
||||
goto end;
|
||||
}
|
||||
|
||||
cJSON *payload_JSON = cJSON_Parse(b64decode);
|
||||
if (!payload_JSON) {
|
||||
fprintf(stderr, "%s: Cannot create JSON from string.[%s].\n", fname, cJSON_GetErrorPtr());
|
||||
goto end;
|
||||
}
|
||||
cJSON *json_value = cJSON_GetObjectItem(payload_JSON, OIDC_ID_TOKEN_EXP);
|
||||
if (!json_value || json_value->type != cJSON_Number) {
|
||||
fprintf(stderr, "%s: Cannot get expiration time in id token.\n", fname);
|
||||
goto end;
|
||||
}
|
||||
expiration_time = json_value->valueint;
|
||||
|
||||
end:
|
||||
if (payload_JSON) {
|
||||
cJSON_Delete(payload_JSON);
|
||||
payload_JSON = NULL;
|
||||
}
|
||||
if (b64decode) {
|
||||
free(b64decode);
|
||||
b64decode = NULL;
|
||||
}
|
||||
if (dup_token_string) {
|
||||
free(dup_token_string);
|
||||
dup_token_string = NULL;
|
||||
}
|
||||
return expiration_time;
|
||||
}
|
||||
|
||||
char *get_token(kubeconfig_property_t * auth_provider)
|
||||
{
|
||||
return auth_provider->id_token;
|
||||
}
|
||||
|
||||
bool is_expired(kubeconfig_property_t * auth_provider)
|
||||
{
|
||||
static char fname[] = "is_expired()";
|
||||
|
||||
if (NULL == auth_provider->id_token) {
|
||||
fprintf(stderr, "%s: The id token is NULL.\n", fname);
|
||||
return true;
|
||||
} else if ('\0' == auth_provider->id_token[0]) {
|
||||
fprintf(stderr, "%s: The id token is empty.\n", fname);
|
||||
return true;
|
||||
}
|
||||
|
||||
time_t exp_time = get_token_expiration_time(auth_provider->id_token);
|
||||
if (exp_time < time(NULL)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
char *get_token_endpoint(const char *idp_issuer_url, sslConfig_t * sc)
|
||||
{
|
||||
static char fname[] = "get_token_endpoint()";
|
||||
|
||||
char *token_endpoint = NULL;
|
||||
|
||||
if (!idp_issuer_url || '\0' == idp_issuer_url[0]) {
|
||||
fprintf(stderr, "%s: The parameters idp_issuer_url is NULL or empty.\n", fname);
|
||||
return NULL;
|
||||
}
|
||||
if (!sc) {
|
||||
fprintf(stderr, "%s: SSL configuration is required.\n", fname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char oidc_configuration_url[OIDC_CONFIGURATION_URL_BUFFER_SIZE];
|
||||
memset(oidc_configuration_url, 0, sizeof(oidc_configuration_url));
|
||||
snprintf(oidc_configuration_url, sizeof(oidc_configuration_url), OIDC_CONFIGURATION_URL_TEMPLATE, idp_issuer_url);
|
||||
|
||||
char *http_response = NULL;
|
||||
int http_response_length = 0;
|
||||
int rc = shc_request(&http_response, &http_response_length, HTTP_REQUEST_GET, oidc_configuration_url, sc, NULL, NULL, NULL);
|
||||
if (HTTP_RC_OK != rc) {
|
||||
fprintf(stderr, "%s: Failed to get token endpoint.\n", fname);
|
||||
goto end;
|
||||
}
|
||||
|
||||
token_endpoint = shc_get_string_from_json(http_response, OIDC_TOKEN_ENDPOINT);
|
||||
|
||||
end:
|
||||
if (http_response) {
|
||||
free(http_response);
|
||||
http_response_length = 0;
|
||||
}
|
||||
|
||||
return token_endpoint;
|
||||
}
|
||||
|
||||
static int refresh_oidc_token(kubeconfig_property_t * auth_provider, const char *token_endpoint, sslConfig_t * sc)
|
||||
{
|
||||
static char fname[] = "refresh_oidc_token()";
|
||||
|
||||
int rc = 0;
|
||||
|
||||
if (!auth_provider || !token_endpoint || !sc) {
|
||||
fprintf(stderr, "%s: The parameters are not valid.\n", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
list_t *content_type = list_create();
|
||||
if (!content_type) {
|
||||
fprintf(stderr, "%s: Cannot create list for content type.[%s]\n", fname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
list_addElement(content_type, strdup(REFRESH_TOKEN_CONTENT_TYPE));
|
||||
|
||||
char refresh_token_credential[REFRESH_TOKEN_CREDENTIAL_BUFFER_SIZE];
|
||||
memset(refresh_token_credential, 0, sizeof(refresh_token_credential));
|
||||
snprintf(refresh_token_credential, sizeof(refresh_token_credential), REFRESH_TOKEN_CREDENTIAL_TEMPLATE, auth_provider->client_id, auth_provider->client_secret);
|
||||
char *base64_credential = base64encode(refresh_token_credential, strlen(refresh_token_credential));
|
||||
if (!base64_credential) {
|
||||
fprintf(stderr, "%s: Cannot encode refresh token with base64.\n", fname);
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
char basic_token_buffer[BASIC_TOKEN_BUFFER_SIZE];
|
||||
memset(basic_token_buffer, 0, sizeof(basic_token_buffer));
|
||||
snprintf(basic_token_buffer, sizeof(basic_token_buffer), BASIC_TOKEN_TEMPLATE, base64_credential);
|
||||
|
||||
list_t *api_keys = list_create();
|
||||
if (!api_keys) {
|
||||
fprintf(stderr, "%s: Cannot create list for refresh token.[%s]\n", fname, strerror(errno));
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
keyValuePair_t *keyPairToken = keyValuePair_create(strdup(AUTH_TOKEN_KEY), strdup(basic_token_buffer));
|
||||
list_addElement(api_keys, keyPairToken);
|
||||
|
||||
char refresh_token_post_data[REFRESH_TOKEN_POST_DATA_BUFFER_SIZE];
|
||||
memset(refresh_token_post_data, 0, sizeof(refresh_token_post_data));
|
||||
snprintf(refresh_token_post_data, sizeof(refresh_token_post_data), REFRESH_TOKEN_POST_DATA_TEMPLATE, auth_provider->refresh_token);
|
||||
|
||||
char *http_response = NULL;
|
||||
int http_response_length = 0;
|
||||
rc = shc_request(&http_response, &http_response_length, HTTP_REQUEST_POST, token_endpoint, sc, api_keys, content_type, refresh_token_post_data);
|
||||
if (HTTP_RC_OK == rc) {
|
||||
rc = 0; // update return code
|
||||
} else {
|
||||
fprintf(stderr, "%s: Failed to refresh OIDC token.\n", fname);
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
char *new_id_token = shc_get_string_from_json(http_response, OIDC_ID_TOKEN);
|
||||
if (new_id_token) {
|
||||
if (auth_provider->id_token) {
|
||||
free(auth_provider->id_token);
|
||||
auth_provider->id_token = NULL;
|
||||
}
|
||||
auth_provider->id_token = new_id_token;
|
||||
} else {
|
||||
fprintf(stderr, "%s: Failed to get the new OIDC token from the response.\n", fname);
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
char *new_refresh_token = shc_get_string_from_json(http_response, OIDC_REFRESH_TOKEN);
|
||||
if (new_refresh_token) {
|
||||
if (auth_provider->refresh_token) {
|
||||
free(auth_provider->refresh_token);
|
||||
auth_provider->refresh_token = NULL;
|
||||
}
|
||||
auth_provider->refresh_token = new_refresh_token;
|
||||
} else {
|
||||
rc = -1;
|
||||
fprintf(stderr, "%s: Failed to get the new refresh token from the response.\n", fname);
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
if (http_response) {
|
||||
free(http_response);
|
||||
http_response = NULL;
|
||||
http_response_length = 0;
|
||||
}
|
||||
if (base64_credential) {
|
||||
free(base64_credential);
|
||||
base64_credential = NULL;
|
||||
}
|
||||
if (api_keys) {
|
||||
clear_and_free_string_pair_list(api_keys);
|
||||
api_keys = NULL;
|
||||
}
|
||||
if (content_type) {
|
||||
clear_and_free_string_list(content_type);
|
||||
content_type = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int refresh(kubeconfig_property_t * auth_provider)
|
||||
{
|
||||
static char fname[] = "refresh()";
|
||||
|
||||
int rc = 0;
|
||||
|
||||
sslConfig_t *sc = NULL;
|
||||
if (auth_provider->idp_certificate_authority && '\0' != auth_provider->idp_certificate_authority[0]) {
|
||||
sc = sslConfig_create(NULL, NULL, auth_provider->idp_certificate_authority, 0);
|
||||
} else if (auth_provider->idp_certificate_authority_data && '\0' != auth_provider->idp_certificate_authority_data[0]) {
|
||||
char *idp_certificate_file = kubeconfig_mk_cert_key_tempfile(auth_provider->idp_certificate_authority_data);
|
||||
if (!idp_certificate_file) {
|
||||
fprintf(stderr, "%s: Failed to create the temporary file for certificate.\n", fname);
|
||||
return -1;
|
||||
}
|
||||
sc = sslConfig_create(NULL, NULL, idp_certificate_file, 0);
|
||||
free(idp_certificate_file);
|
||||
idp_certificate_file = NULL;
|
||||
} else {
|
||||
sc = sslConfig_create(NULL, NULL, NULL, 1);
|
||||
}
|
||||
if (!sc) {
|
||||
fprintf(stderr, "%s: Cannot create the SSL configuration.\n", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *token_endpoint = get_token_endpoint(auth_provider->idp_issuer_url, sc);
|
||||
if (!token_endpoint) {
|
||||
fprintf(stderr, "%s: Cannot get the token endpoint.\n", fname);
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
rc = refresh_oidc_token(auth_provider, token_endpoint, sc);
|
||||
if (-1 == rc) {
|
||||
fprintf(stderr, "%s: Failed to refresh OIDC token.\n", fname);
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
if (token_endpoint) {
|
||||
free(token_endpoint);
|
||||
token_endpoint = NULL;
|
||||
}
|
||||
if (sc) {
|
||||
if (NULL == auth_provider->idp_certificate_authority && auth_provider->idp_certificate_authority_data && '\0' != auth_provider->idp_certificate_authority_data[0]) {
|
||||
unsetSslConfig(sc);
|
||||
}
|
||||
sslConfig_free(sc);
|
||||
sc = NULL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -8,12 +8,13 @@
|
||||
#include "kube_config.h"
|
||||
#include "kube_config_yaml.h"
|
||||
#include "kube_config_common.h"
|
||||
#include "kube_config_util.h"
|
||||
#include "exec_provider.h"
|
||||
#include "authn_plugin/authn_plugin.h"
|
||||
|
||||
#define ENV_KUBECONFIG "KUBECONFIG"
|
||||
#define ENV_HOME "HOME"
|
||||
#define KUBE_CONFIG_DEFAULT_LOCATION "%s/.kube/config"
|
||||
#define KUBE_CONFIG_TEMPFILE_NAME_TEMPLATE "/tmp/kubeconfig-XXXXXX"
|
||||
|
||||
static int setBasePath(char **pBasePath, char *basePath)
|
||||
{
|
||||
@@ -25,82 +26,6 @@ static int setBasePath(char **pBasePath, char *basePath)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool is_cert_or_key_base64_encoded(const char *data)
|
||||
{
|
||||
if (NULL == strstr(data, "BEGIN")) {
|
||||
return true;
|
||||
} else {
|
||||
return false; // e.g. "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
|
||||
}
|
||||
}
|
||||
|
||||
static char *kubeconfig_mk_cert_key_tempfile(const char *data)
|
||||
{
|
||||
static char fname[] = "kubeconfig_mk_tempfile()";
|
||||
|
||||
const char *cert_key_data = NULL;
|
||||
int cert_key_data_bytes = 0;
|
||||
|
||||
bool is_data_base64_encoded = is_cert_or_key_base64_encoded(data);
|
||||
if (true == is_data_base64_encoded) {
|
||||
int decoded_bytes = 0;
|
||||
char *b64decode = base64decode(data, strlen(data), &decoded_bytes);
|
||||
if (!b64decode || 0 == decoded_bytes) {
|
||||
fprintf(stderr, "%s: Base64 decodes failed.\n", fname);
|
||||
return NULL;
|
||||
}
|
||||
cert_key_data = b64decode;
|
||||
cert_key_data_bytes = decoded_bytes;
|
||||
} else { // plain text, no need base64 decode
|
||||
cert_key_data = data;
|
||||
cert_key_data_bytes = strlen(cert_key_data);
|
||||
}
|
||||
|
||||
char tempfile_name_template[] = KUBE_CONFIG_TEMPFILE_NAME_TEMPLATE;
|
||||
int fd = mkstemp(tempfile_name_template);
|
||||
if (-1 == fd) {
|
||||
fprintf(stderr, "%s: Creating temp file for kubeconfig failed with error [%s]\n", fname, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int rc = write(fd, cert_key_data, cert_key_data_bytes);
|
||||
close(fd);
|
||||
if (true == is_data_base64_encoded && cert_key_data) {
|
||||
free((char *) cert_key_data); // cast "const char *" to "char *"
|
||||
cert_key_data = NULL;
|
||||
}
|
||||
if (-1 == rc) {
|
||||
fprintf(stderr, "%s: Writing temp file failed with error [%s]\n", fname, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return strdup(tempfile_name_template);
|
||||
}
|
||||
|
||||
static void kubeconfig_rm_tempfile(const char *filename)
|
||||
{
|
||||
if (filename) {
|
||||
unlink(filename);
|
||||
}
|
||||
}
|
||||
|
||||
static void unsetSslConfig(sslConfig_t * sslConfig)
|
||||
{
|
||||
if (!sslConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sslConfig->clientCertFile) {
|
||||
kubeconfig_rm_tempfile(sslConfig->clientCertFile);
|
||||
}
|
||||
if (sslConfig->clientKeyFile) {
|
||||
kubeconfig_rm_tempfile(sslConfig->clientKeyFile);
|
||||
}
|
||||
if (sslConfig->CACertFile) {
|
||||
kubeconfig_rm_tempfile(sslConfig->CACertFile);
|
||||
}
|
||||
}
|
||||
|
||||
static int setSslConfig(sslConfig_t ** pSslConfig, const kubeconfig_property_t * cluster, const kubeconfig_property_t * user)
|
||||
{
|
||||
int rc = 0;
|
||||
@@ -290,6 +215,53 @@ static int kubeconfig_update_exec_command_path(kubeconfig_property_t * exec, con
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int kuberconfig_auth_provider(kubeconfig_property_t * current_user, kubeconfig_t * kubeconfig)
|
||||
{
|
||||
static char fname[] = "kuberconfig_auth_provider()";
|
||||
|
||||
if (!current_user || !current_user->auth_provider || !kubeconfig) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
kubeconfig_property_t *auth_provider = current_user->auth_provider;
|
||||
if (!auth_provider->name) {
|
||||
fprintf(stderr, "%s: The name of auth provider is not specified.\n", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
authn_plugin_t *plugin = create_authn_plugin(auth_provider->name);
|
||||
if (!plugin) {
|
||||
fprintf(stderr, "%s: Cannot instantiate the auth provider plugin for %s.\n", fname, auth_provider->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
if (plugin->is_expired(auth_provider)) {
|
||||
rc = plugin->refresh(auth_provider);
|
||||
if (0 != rc) {
|
||||
fprintf(stderr, "%s: Cannot refresh token of auth provider <%s>.\n", fname, auth_provider->name);
|
||||
goto end;
|
||||
}
|
||||
rc = kubeyaml_save_kubeconfig(kubeconfig);
|
||||
if (0 != rc) {
|
||||
fprintf(stderr, "%s: Cannot persist to kubeconfig file: %s.\n", fname, kubeconfig->fileName);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
const char *token = plugin->get_token(auth_provider);
|
||||
if (!token) {
|
||||
fprintf(stderr, "%s: Cannot get token from auth provider <%s>.\n", fname, auth_provider->name);
|
||||
rc = -1;
|
||||
goto end;
|
||||
}
|
||||
current_user->token = strdup(token);
|
||||
|
||||
end:
|
||||
free_authn_plugin(plugin);
|
||||
plugin = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int load_kube_config(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApiKeys, const char *configFileName)
|
||||
{
|
||||
static char fname[] = "load_kube_config()";
|
||||
@@ -346,6 +318,14 @@ int load_kube_config(char **pBasePath, sslConfig_t ** pSslConfig, list_t ** pApi
|
||||
}
|
||||
}
|
||||
|
||||
if (current_user && current_user->auth_provider) {
|
||||
rc = kuberconfig_auth_provider(current_user, kubeconfig);
|
||||
if (0 != rc) {
|
||||
fprintf(stderr, "%s: Cannot get token from authentication provider.\n", fname);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
if (current_cluster && current_cluster->server) {
|
||||
rc = setBasePath(pBasePath, current_cluster->server);
|
||||
if (0 != rc) {
|
||||
@@ -388,17 +368,6 @@ void free_client_config(char *basePath, sslConfig_t * sslConfig, list_t * apiKey
|
||||
}
|
||||
|
||||
if (apiKeys) {
|
||||
listEntry_t *listEntry = NULL;
|
||||
list_ForEach(listEntry, apiKeys) {
|
||||
keyValuePair_t *pair = listEntry->data;
|
||||
if (pair->key) {
|
||||
free(pair->key);
|
||||
}
|
||||
if (pair->value) {
|
||||
free(pair->value);
|
||||
}
|
||||
keyValuePair_free(pair);
|
||||
}
|
||||
list_free(apiKeys);
|
||||
clear_and_free_string_pair_list(apiKeys);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ extern "C" {
|
||||
#define AUTH_TOKEN_KEY "Authorization"
|
||||
#define BEARER_TOKEN_TEMPLATE "Bearer %s"
|
||||
#define BEARER_TOKEN_BUFFER_SIZE 1024
|
||||
#define BASIC_TOKEN_TEMPLATE "Basic %s"
|
||||
#define BASIC_TOKEN_BUFFER_SIZE 1024
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -83,6 +83,10 @@ void kubeconfig_property_free(kubeconfig_property_t * property)
|
||||
free(property->password);
|
||||
property->password = NULL;
|
||||
}
|
||||
if (property->token) {
|
||||
free(property->token);
|
||||
property->token = NULL;
|
||||
}
|
||||
if (property->auth_provider) {
|
||||
kubeconfig_property_free(property->auth_provider);
|
||||
property->auth_provider = NULL;
|
||||
@@ -98,6 +102,10 @@ void kubeconfig_property_free(kubeconfig_property_t * property)
|
||||
free(property->cluster);
|
||||
property->cluster = NULL;
|
||||
}
|
||||
if (property->namespace) {
|
||||
free(property->namespace);
|
||||
property->namespace = NULL;
|
||||
}
|
||||
if (property->user) {
|
||||
free(property->user);
|
||||
property->user = NULL;
|
||||
@@ -146,10 +154,30 @@ void kubeconfig_property_free(kubeconfig_property_t * property)
|
||||
free(property->expiry);
|
||||
property->expiry = NULL;
|
||||
}
|
||||
if (property->idp_certificate_authority) {
|
||||
free(property->idp_certificate_authority);
|
||||
property->idp_certificate_authority = NULL;
|
||||
}
|
||||
if (property->idp_certificate_authority_data) {
|
||||
free(property->idp_certificate_authority_data);
|
||||
property->idp_certificate_authority_data = NULL;
|
||||
}
|
||||
if (property->client_id) {
|
||||
free(property->client_id);
|
||||
property->client_id = NULL;
|
||||
}
|
||||
if (property->client_secret) {
|
||||
free(property->client_secret);
|
||||
property->client_secret = NULL;
|
||||
}
|
||||
if (property->idp_issuer_url) {
|
||||
free(property->idp_issuer_url);
|
||||
property->idp_issuer_url = NULL;
|
||||
}
|
||||
if (property->refresh_token) {
|
||||
free(property->refresh_token);
|
||||
property->refresh_token = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
free(property);
|
||||
|
||||
@@ -45,6 +45,7 @@ extern "C" {
|
||||
union {
|
||||
struct { /* context */
|
||||
char *cluster;
|
||||
char *namespace;
|
||||
char *user;
|
||||
};
|
||||
struct { /* cluster */
|
||||
@@ -70,12 +71,17 @@ extern "C" {
|
||||
int args_count;
|
||||
};
|
||||
struct { /* user auth provider */
|
||||
char *id_token;
|
||||
char *cmd_path;
|
||||
char *access_token;
|
||||
char *client_id;
|
||||
char *client_secret;
|
||||
char *cmd_path;
|
||||
char *expires_on;
|
||||
char *expiry;
|
||||
char *id_token;
|
||||
char *idp_certificate_authority;
|
||||
char *idp_certificate_authority_data;
|
||||
char *idp_issuer_url;
|
||||
char *refresh_token;
|
||||
};
|
||||
};
|
||||
} kubeconfig_property_t;
|
||||
|
||||
123
kubernetes/config/kube_config_util.c
Normal file
123
kubernetes/config/kube_config_util.c
Normal file
@@ -0,0 +1,123 @@
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "../include/apiClient.h"
|
||||
|
||||
#define KUBE_CONFIG_TEMPFILE_NAME_TEMPLATE "/tmp/kubeconfig-XXXXXX"
|
||||
|
||||
static bool is_cert_or_key_base64_encoded(const char *data)
|
||||
{
|
||||
if (NULL == strstr(data, "BEGIN")) {
|
||||
return true;
|
||||
} else {
|
||||
return false; // e.g. "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
|
||||
}
|
||||
}
|
||||
|
||||
char *kubeconfig_mk_cert_key_tempfile(const char *data)
|
||||
{
|
||||
static char fname[] = "kubeconfig_mk_tempfile()";
|
||||
|
||||
const char *cert_key_data = NULL;
|
||||
int cert_key_data_bytes = 0;
|
||||
|
||||
bool is_data_base64_encoded = is_cert_or_key_base64_encoded(data);
|
||||
if (true == is_data_base64_encoded) {
|
||||
int decoded_bytes = 0;
|
||||
char *b64decode = base64decode(data, strlen(data), &decoded_bytes);
|
||||
if (!b64decode || 0 == decoded_bytes) {
|
||||
fprintf(stderr, "%s: Base64 decodes failed.\n", fname);
|
||||
return NULL;
|
||||
}
|
||||
cert_key_data = b64decode;
|
||||
cert_key_data_bytes = decoded_bytes;
|
||||
} else { // plain text, no need base64 decode
|
||||
cert_key_data = data;
|
||||
cert_key_data_bytes = strlen(cert_key_data);
|
||||
}
|
||||
|
||||
char tempfile_name_template[] = KUBE_CONFIG_TEMPFILE_NAME_TEMPLATE;
|
||||
int fd = mkstemp(tempfile_name_template);
|
||||
if (-1 == fd) {
|
||||
fprintf(stderr, "%s: Creating temp file for kubeconfig failed with error [%s]\n", fname, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int rc = write(fd, cert_key_data, cert_key_data_bytes);
|
||||
close(fd);
|
||||
if (true == is_data_base64_encoded && cert_key_data) {
|
||||
free((char *) cert_key_data); // cast "const char *" to "char *"
|
||||
cert_key_data = NULL;
|
||||
}
|
||||
if (-1 == rc) {
|
||||
fprintf(stderr, "%s: Writing temp file failed with error [%s]\n", fname, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return strdup(tempfile_name_template);
|
||||
}
|
||||
|
||||
static void kubeconfig_rm_tempfile(const char *filename)
|
||||
{
|
||||
if (filename) {
|
||||
unlink(filename);
|
||||
}
|
||||
}
|
||||
|
||||
void unsetSslConfig(sslConfig_t * sslConfig)
|
||||
{
|
||||
if (!sslConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sslConfig->clientCertFile) {
|
||||
kubeconfig_rm_tempfile(sslConfig->clientCertFile);
|
||||
}
|
||||
if (sslConfig->clientKeyFile) {
|
||||
kubeconfig_rm_tempfile(sslConfig->clientKeyFile);
|
||||
}
|
||||
if (sslConfig->CACertFile) {
|
||||
kubeconfig_rm_tempfile(sslConfig->CACertFile);
|
||||
}
|
||||
}
|
||||
|
||||
void clear_and_free_string_pair_list(list_t * list)
|
||||
{
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
|
||||
listEntry_t *listEntry = NULL;
|
||||
list_ForEach(listEntry, list) {
|
||||
keyValuePair_t *pair = listEntry->data;
|
||||
if (pair->key) {
|
||||
free(pair->key);
|
||||
pair->key = NULL;
|
||||
}
|
||||
if (pair->value) {
|
||||
free(pair->value);
|
||||
pair->value = NULL;
|
||||
}
|
||||
keyValuePair_free(pair);
|
||||
pair = NULL;
|
||||
}
|
||||
list_free(list);
|
||||
}
|
||||
|
||||
void clear_and_free_string_list(list_t * list)
|
||||
{
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
|
||||
listEntry_t *listEntry = NULL;
|
||||
list_ForEach(listEntry, list) {
|
||||
char *list_item = listEntry->data;
|
||||
free(list_item);
|
||||
list_item = NULL;
|
||||
}
|
||||
list_free(list);
|
||||
}
|
||||
100
kubernetes/config/kube_config_util.h
Normal file
100
kubernetes/config/kube_config_util.h
Normal file
@@ -0,0 +1,100 @@
|
||||
#ifndef _KUBE_CONFIG_UTIL_H
|
||||
#define _KUBE_CONFIG_UTIL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* kubeconfig_mk_cert_key_tempfile
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Create a temporary file to persist SSL/TLS certificate or key
|
||||
*
|
||||
* Return:
|
||||
*
|
||||
* char * : File name of created temporary file
|
||||
* NULL : Failed to create temporary file
|
||||
*
|
||||
* Parameter:
|
||||
*
|
||||
* IN:
|
||||
* data: raw data of SSL/TLS certificate or key
|
||||
*
|
||||
* OUT:
|
||||
* None
|
||||
*
|
||||
*/
|
||||
char *kubeconfig_mk_cert_key_tempfile(const char *data);
|
||||
|
||||
/*
|
||||
* unsetSslConfig
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* unset the SSL configuration
|
||||
*
|
||||
* Return:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Parameter:
|
||||
*
|
||||
* IN:
|
||||
* sslConfig: The SSL configuration
|
||||
*
|
||||
* OUT:
|
||||
* None
|
||||
*
|
||||
*/
|
||||
void unsetSslConfig(sslConfig_t * sslConfig);
|
||||
|
||||
/*
|
||||
* clear_and_free_string_pair_list
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* clear the content and free the memory for a string pair list
|
||||
*
|
||||
* Return:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Parameter:
|
||||
*
|
||||
* IN:
|
||||
* list: The string pair list needs to clear and free
|
||||
*
|
||||
* OUT:
|
||||
* None
|
||||
*
|
||||
*/
|
||||
void clear_and_free_string_pair_list(list_t * list);
|
||||
|
||||
/*
|
||||
* clear_and_free_string_list
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* clear the content and free the memory for a string list
|
||||
*
|
||||
* Return:
|
||||
*
|
||||
* None
|
||||
*
|
||||
* Parameter:
|
||||
*
|
||||
* IN:
|
||||
* list: The string list needs to clear and free
|
||||
*
|
||||
* OUT:
|
||||
* None
|
||||
*
|
||||
*/
|
||||
void clear_and_free_string_list(list_t * list);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _KUBE_CONFIG_UTIL_H */
|
||||
@@ -15,9 +15,12 @@ mapping :: = MAPPING - START(node node) * MAPPING - END
|
||||
#define KEY_APIVERSION "apiVersion"
|
||||
#define KEY_KIND "kind"
|
||||
#define KEY_CURRENT_CONTEXT "current-context"
|
||||
#define KEY_PREFERENCES "preferences"
|
||||
#define KEY_CLUSTERS "clusters"
|
||||
#define KEY_CLUSTER "cluster"
|
||||
#define KEY_CONTEXTS "contexts"
|
||||
#define KEY_CONTEXT "context"
|
||||
#define KEY_NAMESPACE "namespace"
|
||||
#define KEY_USERS "users"
|
||||
#define KEY_USER "user"
|
||||
#define KEY_NAME "name"
|
||||
@@ -27,6 +30,19 @@ mapping :: = MAPPING - START(node node) * MAPPING - END
|
||||
#define KEY_USER_EXEC_ENV_KEY "name"
|
||||
#define KEY_USER_EXEC_ENV_VALUE "value"
|
||||
#define KEY_USER_EXEC_ARGS "args"
|
||||
#define KEY_USER_AUTH_PROVIDER "auth-provider"
|
||||
#define KEY_USER_AUTH_PROVIDER_CONFIG "config"
|
||||
#define KEY_USER_AUTH_PROVIDER_CONFIG_ACCESS_TOKEN "access-token"
|
||||
#define KEY_USER_AUTH_PROVIDER_CONFIG_CLIENT_ID "client-id"
|
||||
#define KEY_USER_AUTH_PROVIDER_CONFIG_CLIENT_SECRET "client-secret"
|
||||
#define KEY_USER_AUTH_PROVIDER_CONFIG_CMD_PATH "cmd-path"
|
||||
#define KEY_USER_AUTH_PROVIDER_CONFIG_EXPIRES_ON "expires-on"
|
||||
#define KEY_USER_AUTH_PROVIDER_CONFIG_EXPIRY "expiry"
|
||||
#define KEY_USER_AUTH_PROVIDER_CONFIG_ID_TOKEN "id-token"
|
||||
#define KEY_USER_AUTH_PROVIDER_CONFIG_IDP_CERTIFICATE_AUTHORITY "idp-certificate-authority"
|
||||
#define KEY_USER_AUTH_PROVIDER_CONFIG_IDP_CERTIFICATE_AUTHORITY_DATA "idp-certificate-authority-data"
|
||||
#define KEY_USER_AUTH_PROVIDER_CONFIG_IDP_ISSUE_URL "idp-issuer-url"
|
||||
#define KEY_USER_AUTH_PROVIDER_CONFIG_REFRESH_TOKEN "refresh-token"
|
||||
#define KEY_CERTIFICATE_AUTHORITY_DATA "certificate-authority-data"
|
||||
#define KEY_SERVER "server"
|
||||
#define KEY_CLIENT_CERTIFICATE_DATA "client-certificate-data"
|
||||
@@ -180,6 +196,8 @@ static int parse_kubeconfig_yaml_property_mapping(kubeconfig_property_t * proper
|
||||
} else if (KUBECONFIG_PROPERTY_TYPE_CONTEXT == property->type) {
|
||||
if (0 == strcmp(key->data.scalar.value, KEY_CLUSTER)) {
|
||||
property->cluster = strdup(value->data.scalar.value);
|
||||
} else if (0 == strcmp(key->data.scalar.value, KEY_NAMESPACE)) {
|
||||
property->namespace = strdup(value->data.scalar.value);
|
||||
} else if (0 == strcmp(key->data.scalar.value, KEY_USER)) {
|
||||
property->user = strdup(value->data.scalar.value);
|
||||
}
|
||||
@@ -189,19 +207,58 @@ static int parse_kubeconfig_yaml_property_mapping(kubeconfig_property_t * proper
|
||||
} else if (0 == strcmp(key->data.scalar.value, KEY_USER_EXEC_COMMAND)) {
|
||||
property->command = strdup(value->data.scalar.value);
|
||||
}
|
||||
} else if (KUBECONFIG_PROPERTY_TYPE_USER_AUTH_PROVIDER == property->type) {
|
||||
if (0 == strcmp(key->data.scalar.value, KEY_USER_AUTH_PROVIDER_CONFIG_ACCESS_TOKEN)) {
|
||||
property->access_token = strdup(value->data.scalar.value);
|
||||
} else if (0 == strcmp(key->data.scalar.value, KEY_USER_AUTH_PROVIDER_CONFIG_CLIENT_ID)) {
|
||||
property->client_id = strdup(value->data.scalar.value);
|
||||
} else if (0 == strcmp(key->data.scalar.value, KEY_USER_AUTH_PROVIDER_CONFIG_CLIENT_SECRET)) {
|
||||
property->client_secret = strdup(value->data.scalar.value);
|
||||
} else if (0 == strcmp(key->data.scalar.value, KEY_USER_AUTH_PROVIDER_CONFIG_CMD_PATH)) {
|
||||
property->cmd_path = strdup(value->data.scalar.value);
|
||||
} else if (0 == strcmp(key->data.scalar.value, KEY_USER_AUTH_PROVIDER_CONFIG_EXPIRES_ON)) {
|
||||
property->expires_on = strdup(value->data.scalar.value);
|
||||
} else if (0 == strcmp(key->data.scalar.value, KEY_USER_AUTH_PROVIDER_CONFIG_EXPIRY)) {
|
||||
property->expiry = strdup(value->data.scalar.value);
|
||||
} else if (0 == strcmp(key->data.scalar.value, KEY_USER_AUTH_PROVIDER_CONFIG_ID_TOKEN)) {
|
||||
property->id_token = strdup(value->data.scalar.value);
|
||||
} else if (0 == strcmp(key->data.scalar.value, KEY_USER_AUTH_PROVIDER_CONFIG_IDP_CERTIFICATE_AUTHORITY)) {
|
||||
property->idp_certificate_authority = strdup(value->data.scalar.value);
|
||||
} else if (0 == strcmp(key->data.scalar.value, KEY_USER_AUTH_PROVIDER_CONFIG_IDP_CERTIFICATE_AUTHORITY_DATA)) {
|
||||
property->idp_certificate_authority_data = strdup(value->data.scalar.value);
|
||||
} else if (0 == strcmp(key->data.scalar.value, KEY_USER_AUTH_PROVIDER_CONFIG_IDP_ISSUE_URL)) {
|
||||
property->idp_issuer_url = strdup(value->data.scalar.value);
|
||||
} else if (0 == strcmp(key->data.scalar.value, KEY_USER_AUTH_PROVIDER_CONFIG_REFRESH_TOKEN)) {
|
||||
property->refresh_token = strdup(value->data.scalar.value);
|
||||
}
|
||||
}
|
||||
} else if (value->type == YAML_MAPPING_NODE) {
|
||||
if ((KUBECONFIG_PROPERTY_TYPE_USER == property->type) && (0 == strcmp(key->data.scalar.value, KEY_USER_EXEC))) {
|
||||
property->exec = kubeconfig_property_create(KUBECONFIG_PROPERTY_TYPE_USER_EXEC);
|
||||
if (property->exec) {
|
||||
int rc = parse_kubeconfig_yaml_property_mapping(property->exec, document, value);
|
||||
if (KUBECONFIG_PROPERTY_TYPE_USER == property->type) {
|
||||
int rc = 0;
|
||||
if (0 == strcmp(key->data.scalar.value, KEY_USER_EXEC)) {
|
||||
property->exec = kubeconfig_property_create(KUBECONFIG_PROPERTY_TYPE_USER_EXEC);
|
||||
if (!property->exec) {
|
||||
fprintf(stderr, "Cannot allocate memory for kubeconfig exec for user %s.\n", property->name);
|
||||
return -1;
|
||||
}
|
||||
rc = parse_kubeconfig_yaml_property_mapping(property->exec, document, value);
|
||||
if (0 != rc) {
|
||||
fprintf(stderr, "Cannot parse kubeconfig exec for user %s.\n", property->name);
|
||||
return -1;
|
||||
}
|
||||
} else if (0 == strcmp(key->data.scalar.value, KEY_USER_AUTH_PROVIDER)) {
|
||||
property->auth_provider = kubeconfig_property_create(KUBECONFIG_PROPERTY_TYPE_USER_AUTH_PROVIDER);
|
||||
if (!property->auth_provider) {
|
||||
fprintf(stderr, "Cannot allocate memory for kubeconfig auth provider for user %s.\n", property->name);
|
||||
return -1;
|
||||
}
|
||||
rc = parse_kubeconfig_yaml_property_mapping(property->auth_provider, document, value);
|
||||
if (0 != rc) {
|
||||
fprintf(stderr, "Cannot parse kubeconfig auth provider for user %s.\n", property->name);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Cannot allocate memory for kubeconfig exec for user %s.\n", property->name);
|
||||
return -1;
|
||||
parse_kubeconfig_yaml_property_mapping(property, document, value);
|
||||
}
|
||||
} else {
|
||||
parse_kubeconfig_yaml_property_mapping(property, document, value);
|
||||
@@ -530,3 +587,501 @@ int kubeyaml_parse_exec_crendential(ExecCredential_t * exec_credential, const ch
|
||||
yaml_parser_delete(&parser);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int append_key_stringvalue_to_mapping_node(yaml_document_t * output_document, int parent_node, const char *key_string, const char *value_string)
|
||||
{
|
||||
int key = yaml_document_add_scalar(output_document, NULL, (yaml_char_t *) key_string, -1, YAML_PLAIN_SCALAR_STYLE);
|
||||
if (!key) {
|
||||
return -1;
|
||||
}
|
||||
int value = yaml_document_add_scalar(output_document, NULL, (yaml_char_t *) value_string, -1, YAML_PLAIN_SCALAR_STYLE);
|
||||
if (!value) {
|
||||
return -1;
|
||||
}
|
||||
if (!yaml_document_append_mapping_pair(output_document, parent_node, key, value)) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int append_key_stringseq_to_mapping_node(yaml_document_t * output_document, int parent_node, const char *key_string, char **strings, int strings_count)
|
||||
{
|
||||
int key = yaml_document_add_scalar(output_document, NULL, (yaml_char_t *) key_string, -1, YAML_PLAIN_SCALAR_STYLE);
|
||||
if (!key) {
|
||||
return -1;
|
||||
}
|
||||
int seq = yaml_document_add_sequence(output_document, NULL, YAML_BLOCK_SEQUENCE_STYLE);
|
||||
if (!seq) {
|
||||
return -1;
|
||||
}
|
||||
if (!yaml_document_append_mapping_pair(output_document, parent_node, key, seq)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < strings_count; i++) {
|
||||
int value = yaml_document_add_scalar(output_document, NULL, (yaml_char_t *) strings[i], -1, YAML_PLAIN_SCALAR_STYLE);
|
||||
if (!value) {
|
||||
return -1;
|
||||
}
|
||||
if (!yaml_document_append_sequence_item(output_document, seq, value)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int append_auth_provider_config_to_mapping_node(yaml_document_t * output_document, int parent_node, const kubeconfig_property_t * auth_provider_config)
|
||||
{
|
||||
/* Add 'name': '' */
|
||||
if (auth_provider_config->name) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, parent_node, KEY_NAME, auth_provider_config->name)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'config': {} */
|
||||
int key = yaml_document_add_scalar(output_document, NULL, (yaml_char_t *) KEY_USER_AUTH_PROVIDER_CONFIG, -1, YAML_PLAIN_SCALAR_STYLE);
|
||||
if (!key) {
|
||||
return -1;
|
||||
}
|
||||
int map = yaml_document_add_mapping(output_document, NULL, YAML_BLOCK_MAPPING_STYLE);
|
||||
if (!map) {
|
||||
return -1;
|
||||
}
|
||||
if (!yaml_document_append_mapping_pair(output_document, parent_node, key, map)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add 'access-token': '' */
|
||||
if (auth_provider_config->access_token) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_USER_AUTH_PROVIDER_CONFIG_ACCESS_TOKEN, auth_provider_config->access_token)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'client-id': '' */
|
||||
if (auth_provider_config->client_id) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_USER_AUTH_PROVIDER_CONFIG_CLIENT_ID, auth_provider_config->client_id)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'client-secret': '' */
|
||||
if (auth_provider_config->client_secret) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_USER_AUTH_PROVIDER_CONFIG_CLIENT_SECRET, auth_provider_config->client_secret)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'cmd-path': '' */
|
||||
if (auth_provider_config->cmd_path) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_USER_AUTH_PROVIDER_CONFIG_CMD_PATH, auth_provider_config->cmd_path)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'expires-on': '' */
|
||||
if (auth_provider_config->expires_on) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_USER_AUTH_PROVIDER_CONFIG_EXPIRES_ON, auth_provider_config->expires_on)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'expiry': '' */
|
||||
if (auth_provider_config->expiry) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_USER_AUTH_PROVIDER_CONFIG_EXPIRY, auth_provider_config->expiry)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'id-token': '' */
|
||||
if (auth_provider_config->id_token) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_USER_AUTH_PROVIDER_CONFIG_ID_TOKEN, auth_provider_config->id_token)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'idp-certificate-authority': '' */
|
||||
if (auth_provider_config->idp_certificate_authority) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_USER_AUTH_PROVIDER_CONFIG_IDP_CERTIFICATE_AUTHORITY, auth_provider_config->idp_certificate_authority)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'idp-certificate-authority-data': '' */
|
||||
if (auth_provider_config->idp_certificate_authority_data) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_USER_AUTH_PROVIDER_CONFIG_IDP_CERTIFICATE_AUTHORITY_DATA, auth_provider_config->idp_certificate_authority_data)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'idp-issuer-url': '' */
|
||||
if (auth_provider_config->idp_issuer_url) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_USER_AUTH_PROVIDER_CONFIG_IDP_ISSUE_URL, auth_provider_config->idp_issuer_url)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'refresh-token': '' */
|
||||
if (auth_provider_config->refresh_token) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_USER_AUTH_PROVIDER_CONFIG_REFRESH_TOKEN, auth_provider_config->refresh_token)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int append_key_kvpseq_to_mapping_node(yaml_document_t * output_document, int parent_node, const char *key_string, keyValuePair_t ** kvps, int kvps_count)
|
||||
{
|
||||
int key = yaml_document_add_scalar(output_document, NULL, (yaml_char_t *) key_string, -1, YAML_PLAIN_SCALAR_STYLE);
|
||||
if (!key) {
|
||||
return -1;
|
||||
}
|
||||
int seq = yaml_document_add_sequence(output_document, NULL, YAML_BLOCK_SEQUENCE_STYLE);
|
||||
if (!seq) {
|
||||
return -1;
|
||||
}
|
||||
if (!yaml_document_append_mapping_pair(output_document, parent_node, key, seq)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < kvps_count; i++) {
|
||||
int map = yaml_document_add_mapping(output_document, NULL, YAML_BLOCK_MAPPING_STYLE);
|
||||
if (!map) {
|
||||
return -1;
|
||||
}
|
||||
if (!yaml_document_append_sequence_item(output_document, seq, map)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add 'name': '' */
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_USER_EXEC_ENV_KEY, kvps[i]->key)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add 'value': '' */
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_USER_EXEC_ENV_VALUE, kvps[i]->value)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int append_key_map_to_mapping_node(yaml_document_t * output_document, int parent_node, const char *key_string, const kubeconfig_property_t * property)
|
||||
{
|
||||
int key = yaml_document_add_scalar(output_document, NULL, (yaml_char_t *) key_string, -1, YAML_PLAIN_SCALAR_STYLE);
|
||||
if (!key) {
|
||||
return -1;
|
||||
}
|
||||
int map = yaml_document_add_mapping(output_document, NULL, YAML_BLOCK_MAPPING_STYLE);
|
||||
if (!map) {
|
||||
return -1;
|
||||
}
|
||||
if (!yaml_document_append_mapping_pair(output_document, parent_node, key, map)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!property) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (KUBECONFIG_PROPERTY_TYPE_CONTEXT == property->type) {
|
||||
/* Add 'cluster': '' */
|
||||
if (property->cluster) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_CLUSTER, property->cluster)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'namespace': '' */
|
||||
if (property->namespace) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_NAMESPACE, property->namespace)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'user': '' */
|
||||
if (property->user) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_USER, property->user)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else if (KUBECONFIG_PROPERTY_TYPE_CLUSTER == property->type) {
|
||||
/* Add 'certificate-authority-data': '' */
|
||||
if (property->certificate_authority_data) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_CERTIFICATE_AUTHORITY_DATA, property->certificate_authority_data)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'server': '' */
|
||||
if (property->server) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_SERVER, property->server)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else if (KUBECONFIG_PROPERTY_TYPE_USER == property->type) {
|
||||
/* Add 'auth-provider': {} */
|
||||
if (property->auth_provider) {
|
||||
if (-1 == append_key_map_to_mapping_node(output_document, map, KEY_USER_AUTH_PROVIDER, property->auth_provider)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'client-certificate-data': '' */
|
||||
if (property->client_certificate_data) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_CLIENT_CERTIFICATE_DATA, property->client_certificate_data)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'client-key-data': '' */
|
||||
if (property->client_key_data) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_CLIENT_KEY_DATA, property->client_key_data)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'exec': {} */
|
||||
if (property->exec) {
|
||||
if (-1 == append_key_map_to_mapping_node(output_document, map, KEY_USER_EXEC, property->exec)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else if (KUBECONFIG_PROPERTY_TYPE_USER_EXEC == property->type) {
|
||||
/* Add 'apiVersion': '' */
|
||||
if (property->apiVersion) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_APIVERSION, property->apiVersion)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'args': [] */
|
||||
if (property->args && property->args_count > 0) {
|
||||
if (-1 == append_key_stringseq_to_mapping_node(output_document, map, KEY_USER_EXEC_ARGS, property->args, property->args_count)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'command': '' */
|
||||
if (property->command) {
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_USER_EXEC_COMMAND, property->command)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'env': [] */
|
||||
if (property->envs && property->envs_count > 0) {
|
||||
if (-1 == append_key_kvpseq_to_mapping_node(output_document, map, KEY_USER_EXEC_ENV, property->envs, property->envs_count)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else if (KUBECONFIG_PROPERTY_TYPE_USER_AUTH_PROVIDER == property->type) {
|
||||
if (-1 == append_auth_provider_config_to_mapping_node(output_document, map, property)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int append_key_seq_to_top_mapping_node(yaml_document_t * output_document, int parent_node, const char *first_level_key_string, const char *second_level_key_string,
|
||||
kubeconfig_property_t ** properites, int properites_count)
|
||||
{
|
||||
int key = yaml_document_add_scalar(output_document, NULL, (yaml_char_t *) first_level_key_string, -1, YAML_PLAIN_SCALAR_STYLE);
|
||||
if (!key) {
|
||||
return -1;
|
||||
}
|
||||
int seq = yaml_document_add_sequence(output_document, NULL, YAML_BLOCK_SEQUENCE_STYLE);
|
||||
if (!seq) {
|
||||
return -1;
|
||||
}
|
||||
if (!yaml_document_append_mapping_pair(output_document, parent_node, key, seq)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < properites_count; i++) {
|
||||
/* Add {}. */
|
||||
int map = yaml_document_add_mapping(output_document, NULL, YAML_BLOCK_MAPPING_STYLE);
|
||||
if (!map) {
|
||||
return -1;
|
||||
}
|
||||
if (!yaml_document_append_sequence_item(output_document, seq, map)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NULL != strstr(second_level_key_string, KEY_CLUSTER) || NULL != strstr(second_level_key_string, KEY_CONTEXT)) {
|
||||
/* Add 'cluster/context': {} */
|
||||
if (-1 == append_key_map_to_mapping_node(output_document, map, second_level_key_string, properites[i])) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add 'name': '' */
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, map, KEY_NAME, properites[i]->name)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NULL != strstr(second_level_key_string, KEY_USER)) {
|
||||
/* Add 'user': {} */
|
||||
if (-1 == append_key_map_to_mapping_node(output_document, map, second_level_key_string, properites[i])) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fill_yaml_document(yaml_document_t * output_document, const kubeconfig_t * kubeconfig)
|
||||
{
|
||||
int root = yaml_document_add_mapping(output_document, NULL, YAML_BLOCK_MAPPING_STYLE);
|
||||
if (!root) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add 'apiVersion': '' */
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, root, KEY_APIVERSION, kubeconfig->apiVersion)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add 'clusters': {} */
|
||||
if (-1 == append_key_seq_to_top_mapping_node(output_document, root, KEY_CLUSTERS, KEY_CLUSTER, kubeconfig->clusters, kubeconfig->clusters_count)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add 'contexts': {} */
|
||||
if (-1 == append_key_seq_to_top_mapping_node(output_document, root, KEY_CONTEXTS, KEY_CONTEXT, kubeconfig->contexts, kubeconfig->contexts_count)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add 'current-context': '' */
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, root, KEY_CURRENT_CONTEXT, kubeconfig->current_context)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add 'kind': 'Config' */
|
||||
if (-1 == append_key_stringvalue_to_mapping_node(output_document, root, KEY_KIND, kubeconfig->kind)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add 'preferences': {} */
|
||||
if (-1 == append_key_map_to_mapping_node(output_document, root, KEY_PREFERENCES, NULL)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Add 'users': {} */
|
||||
if (-1 == append_key_seq_to_top_mapping_node(output_document, root, KEY_USERS, KEY_USER, kubeconfig->users, kubeconfig->users_count)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kubeyaml_save_kubeconfig(const kubeconfig_t * kubeconfig)
|
||||
{
|
||||
static char fname[] = "kubeyaml_save_kubeconfig()";
|
||||
|
||||
if (!kubeconfig) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set a file output. */
|
||||
FILE *output = NULL;
|
||||
if (kubeconfig->fileName) {
|
||||
output = fopen(kubeconfig->fileName, "wb");
|
||||
if (!output) {
|
||||
fprintf(stderr, "%s: Cannot open the file %s.[%s]\n", fname, kubeconfig->fileName, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "%s: The kubeconf file name needs be set by kubeconfig->fileName .\n", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
yaml_emitter_t emitter;
|
||||
yaml_document_t output_document;
|
||||
|
||||
memset(&emitter, 0, sizeof(emitter));
|
||||
memset(&output_document, 0, sizeof(output_document));
|
||||
|
||||
/* Initialize the emitter object. */
|
||||
if (!yaml_emitter_initialize(&emitter)) {
|
||||
fprintf(stderr, "%s: Could not initialize the emitter object\n", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Set the emitter parameters. */
|
||||
yaml_emitter_set_canonical(&emitter, 0);
|
||||
yaml_emitter_set_unicode(&emitter, 1);
|
||||
yaml_emitter_set_output_file(&emitter, output);
|
||||
|
||||
/* Create and emit the STREAM-START event. */
|
||||
if (!yaml_emitter_open(&emitter)) {
|
||||
goto emitter_error;
|
||||
}
|
||||
|
||||
/* Create a output_document object. */
|
||||
if (!yaml_document_initialize(&output_document, NULL, NULL, NULL, 0, 0)) {
|
||||
goto document_error;
|
||||
}
|
||||
|
||||
if (-1 == fill_yaml_document(&output_document, kubeconfig)) {
|
||||
goto document_error;
|
||||
}
|
||||
|
||||
/* Emit the event. */
|
||||
if (!yaml_emitter_dump(&emitter, &output_document)) {
|
||||
goto emitter_error;
|
||||
}
|
||||
yaml_emitter_flush(&emitter);
|
||||
|
||||
if (!yaml_emitter_close(&emitter)) {
|
||||
goto emitter_error;
|
||||
}
|
||||
|
||||
yaml_emitter_delete(&emitter);
|
||||
yaml_document_delete(&output_document);
|
||||
fclose(output);
|
||||
|
||||
return 0;
|
||||
|
||||
emitter_error:
|
||||
|
||||
switch (emitter.error) {
|
||||
case YAML_MEMORY_ERROR:
|
||||
fprintf(stderr, "%s: Memory error: Not enough memory for emitting\n", fname);
|
||||
break;
|
||||
|
||||
case YAML_WRITER_ERROR:
|
||||
fprintf(stderr, "%s: Writer error: %s\n", fname, emitter.problem);
|
||||
break;
|
||||
|
||||
case YAML_EMITTER_ERROR:
|
||||
fprintf(stderr, "%s: Emitter error: %s\n", fname, emitter.problem);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Couldn't happen. */
|
||||
fprintf(stderr, "%s: Internal error\n", fname);
|
||||
break;
|
||||
}
|
||||
|
||||
yaml_document_delete(&output_document);
|
||||
yaml_emitter_delete(&emitter);
|
||||
fclose(output);
|
||||
|
||||
return -1;
|
||||
|
||||
document_error:
|
||||
|
||||
fprintf(stderr, "%s: Memory error: Not enough memory for creating a document\n", fname);
|
||||
yaml_document_delete(&output_document);
|
||||
yaml_emitter_delete(&emitter);
|
||||
fclose(output);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,26 @@ extern "C" {
|
||||
*/
|
||||
int kubeyaml_parse_exec_crendential(ExecCredential_t * exec_credential, const char *exec_credential_string);
|
||||
|
||||
/*
|
||||
* kubeyaml_save_kubeconfig
|
||||
*
|
||||
* Description:
|
||||
*
|
||||
* Save the kubeconfig to the file specified by kubeconfig->fileName
|
||||
*
|
||||
* Return:
|
||||
*
|
||||
* 0 Success
|
||||
* -1 Failed
|
||||
*
|
||||
* Parameter:
|
||||
*
|
||||
* INT:
|
||||
* kubeconfig: kubernetes cluster configuration including kubeconfig->fileName: kubernetes cluster configuration file name
|
||||
*
|
||||
*/
|
||||
int kubeyaml_save_kubeconfig(const kubeconfig_t * kubeconfig);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
Reference in New Issue
Block a user