Loading server_side/README.md 0 → 100644 +1 −0 Original line number Diff line number Diff line TODO server_side/c/auth.c +106 −135 Original line number Diff line number Diff line Loading @@ -15,15 +15,10 @@ #include "cjwt/cjwt.h" #include "log.h" struct MemoryStruct { char *memory; size_t size; }; static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct MemoryStruct *mem = (struct MemoryStruct *) userp; memory_struct *mem = (memory_struct *) userp; char *ptr = realloc(mem->memory, mem->size + realsize + 1); if (!ptr) { Loading @@ -41,78 +36,36 @@ WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) { } int verify_token(const char *token, oidc_token_content_t *token_info) { CURL *curl; CURLcode res; struct MemoryStruct chunk; const unsigned char *key= NULL; const char *token_kid = NULL; const cJSON *key_itr = NULL; const cJSON *keyset = NULL; const cJSON *kid = NULL; const cJSON *user = NULL; cJSON *keyset_json = NULL; cjwt_t *jwt = NULL; cjwt_header_t *jwt_header = NULL; cjwt_code_t cjwt_return_value = CJWTE_OK; cJSON *keyset_json = fetch_jwks(); chunk.memory = malloc(1); /* will be grown as needed by realloc above */ chunk.size = 0; /* no data at this point */ // Get Key Id from token cjwt_return_value = cjwt_get_header(token, strlen(token), OPT_ALLOW_ANY_TIME, &jwt_header); if(CJWTE_OK != cjwt_return_value) { logit("Could not get KID: %s\n", token); free(chunk.memory); cjwt_header_destroy(jwt_header); return 1; } token_kid = jwt_header->kid; // Fetch Jwks to decrypt token curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); long http_code = 0; if (curl) { curl_easy_setopt(curl, CURLOPT_URL, config.jwks_url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &chunk); curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 0); res = curl_easy_perform(curl); if (res != CURLE_OK) { logit("curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); cjwt_header_destroy(jwt_header); return 1; } else { curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code); } curl_easy_cleanup(curl); } curl_global_cleanup(); if (http_code != 200) { free(chunk.memory); cjwt_header_destroy(jwt_header); return 1; } keyset_json = cJSON_Parse(chunk.memory); if (keyset_json == NULL) { const char *error_ptr = cJSON_GetErrorPtr(); if (error_ptr != NULL) { logit("Error before: %s\n", error_ptr); } free(chunk.memory); return 1; } // Get Key Id from token cjwt_header_t *jwt_header = NULL; cjwt_code_t cjwt_return_value = cjwt_get_header(token, strlen(token), OPT_ALLOW_ANY_TIME, &jwt_header); if(CJWTE_OK != cjwt_return_value) { logit("Could not get KID: %s\n", token); cjwt_header_destroy(jwt_header); return 1; } const char *token_kid = jwt_header->kid; // Search for correct key keyset = cJSON_GetObjectItemCaseSensitive(keyset_json, "keys"); const cJSON *keyset = cJSON_GetObjectItemCaseSensitive(keyset_json, "keys"); const unsigned char *key = NULL; const cJSON *key_itr = NULL; const cJSON *kid = NULL; cJSON_ArrayForEach(key_itr, keyset) { kid = cJSON_GetObjectItemCaseSensitive(key_itr, "kid"); Loading @@ -130,43 +83,31 @@ int verify_token(const char *token, oidc_token_content_t *token_info) { // Handle not finding the correct key if (!key) { logit("Could not find correct key in keyset. Token: %s\n", token); free(chunk.memory); return 1; } // Load Cert here char* loaded_cert = load_cert(key); cJSON_Delete(keyset_json); if (loaded_cert == NULL) { logit("Loaded cert is null. Token: %s\n", token); free(chunk.memory); cJSON_Delete(keyset_json); return 1; } // Actually validate token now cjwt_t *jwt = NULL; cjwt_return_value = cjwt_decode(token, strlen(token), 0, (uint8_t *)loaded_cert, strlen(loaded_cert), time(NULL), 0, &jwt); free(loaded_cert); if (CJWTE_OK != cjwt_return_value) { logit("There was an issue while decoding token: %d\n", cjwt_return_value); // free memory free(chunk.memory); free(loaded_cert); // This should recursively free all CJSON stuff from JWKS cJSON_Delete(keyset_json); cjwt_destroy(jwt); return 1; } user = cJSON_GetObjectItemCaseSensitive(jwt->private_claims, "preferred_username"); const cJSON *user = cJSON_GetObjectItemCaseSensitive(jwt->private_claims, "preferred_username"); if (!cJSON_IsString(user) || (user->valuestring == NULL)) { logit("Could not find 'preferred_username' claim.\n"); // free memory free(chunk.memory); free(loaded_cert); // This should recursively free all CJSON stuff from JWKS cJSON_Delete(keyset_json); cjwt_destroy(jwt); return 1; } Loading @@ -174,22 +115,51 @@ int verify_token(const char *token, oidc_token_content_t *token_info) { token_info->user = malloc(strlen(user->valuestring)); strcpy(token_info->user, user->valuestring); // free memory free(chunk.memory); free(loaded_cert); // This should recursively free all CJSON stuff from JWKS cJSON_Delete(keyset_json); cjwt_destroy(jwt); return 0; } char *load_cert(const char* x509) { cJSON* fetch_jwks() { memory_struct mem; EVP_PKEY *pkey = NULL; BIO *certbio = NULL; BIO *keybio = NULL; X509 *cert = NULL; mem.memory = malloc(1); /* will be grown as needed by realloc above */ mem.size = 0; /* no data at this point */ // Fetch Jwks to decrypt token CURL *curl; CURLcode res; curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); long http_code = 0; if (curl) { curl_easy_setopt(curl, CURLOPT_URL, config.jwks_url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &mem); curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 0); res = curl_easy_perform(curl); if (res != CURLE_OK) { logit("curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); return NULL; } else { curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code); } curl_easy_cleanup(curl); } curl_global_cleanup(); if (http_code != 200) { free(mem.memory); return NULL; } cJSON *keyset_json = cJSON_Parse(mem.memory); free(mem.memory); return keyset_json; } char *load_cert(const char* x509) { /* ---------------------------------------------------------- * * These function calls initialize openssl for correct work. * Loading @@ -206,7 +176,8 @@ char *load_cert(const char* x509) { strcat(x509_formatted, x509); strcat(x509_formatted, footer); certbio = BIO_new(BIO_s_mem()); X509 *cert = NULL; BIO *certbio = BIO_new(BIO_s_mem()); BIO_write(certbio, x509_formatted, strlen(x509_formatted) + 1); if (! (cert = PEM_read_bio_X509(certbio, NULL, 0, NULL))) { logit("Error reading cert into memory. x509: %s\n", x509_formatted); Loading @@ -214,29 +185,29 @@ char *load_cert(const char* x509) { free(x509_formatted); return NULL; } BIO_free_all(certbio); free(x509_formatted); EVP_PKEY *pkey = NULL; if ((pkey = X509_get_pubkey(cert)) == NULL) { logit("Error getting public key.\n"); BIO_free_all(certbio); X509_free(cert); return NULL; } keybio = BIO_new(BIO_s_mem()); X509_free(cert); BIO *keybio = BIO_new(BIO_s_mem()); if(!PEM_write_bio_PUBKEY(keybio, pkey)) { logit("Error writing public key data in PEM format\n"); BIO_free_all(certbio); EVP_PKEY_free(pkey); X509_free(cert); return NULL; } char* key_buf = (char*) malloc(EVP_PKEY_bits(pkey) + 1); memset(key_buf, 0, EVP_PKEY_bits(pkey) + 1); BIO_read(keybio, key_buf, EVP_PKEY_bits(pkey)); EVP_PKEY_free(pkey); X509_free(cert); BIO_free_all(certbio); BIO_free_all(keybio); return key_buf; } No newline at end of file server_side/c/auth.h +7 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,11 @@ #include "config.h" typedef struct MemoryStruct { char *memory; size_t size; } memory_struct; typedef struct oidc_token_content_t { char *user; Loading @@ -12,6 +17,8 @@ typedef struct oidc_token_content_t int verify_token(const char* token, oidc_token_content_t *token_info); cJSON* fetch_jwks(); char *load_cert(const char* x509); Loading server_side/c/main.c +16 −14 Original line number Diff line number Diff line Loading @@ -5,19 +5,21 @@ #include "auth.h" int main(int argc, char *argv[]) { // int res = parse_config("/Users/35y/projects/ndip/oidc-pam/server_side/oidc-pam.json", &config); // printf("res: %d\n",res); // if (res ==1) { // exit(1); // } // printf("%s %s %s %d\n",config.client_id,config.client_secret,config.introspection_url,config.enable_2fa); printf("args: %s %s\n", argv[1], argv[2]); // oidc_token_content_t token_info; // res = introspect_token("sssss", &token_info); // printf("active: %d\n",token_info.active); // if (res == 1) { // exit(1); // } // cJSON_Delete(config.parsed_object); // cJSON_Delete(token_info.parsed_object); int res = parse_config(argv[1], &config); printf("res: %d\n",res); if (res ==1) { exit(1); } printf("%s %s %d\n",config.jwks_url,config.log_file,config.enable_2fa); oidc_token_content_t token_info; res = verify_token(argv[2], &token_info); printf("user: %s\n",token_info.user); if (res == 1) { exit(1); } cJSON_Delete(config.parsed_object); free(token_info.user); } server_side/oidc-pam-test.json 0 → 100644 +6 −0 Original line number Diff line number Diff line { "jwks_url": "https://login.microsoftonline.com/db3dbd43-4c4b-4544-9f8a-0553f9f5f25e/discovery/v2.0/keys", "check_2fa": false, "enable_log": true, "log_file": "/home/gzi/tmp/oidc.log" } Loading
server_side/c/auth.c +106 −135 Original line number Diff line number Diff line Loading @@ -15,15 +15,10 @@ #include "cjwt/cjwt.h" #include "log.h" struct MemoryStruct { char *memory; size_t size; }; static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct MemoryStruct *mem = (struct MemoryStruct *) userp; memory_struct *mem = (memory_struct *) userp; char *ptr = realloc(mem->memory, mem->size + realsize + 1); if (!ptr) { Loading @@ -41,78 +36,36 @@ WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) { } int verify_token(const char *token, oidc_token_content_t *token_info) { CURL *curl; CURLcode res; struct MemoryStruct chunk; const unsigned char *key= NULL; const char *token_kid = NULL; const cJSON *key_itr = NULL; const cJSON *keyset = NULL; const cJSON *kid = NULL; const cJSON *user = NULL; cJSON *keyset_json = NULL; cjwt_t *jwt = NULL; cjwt_header_t *jwt_header = NULL; cjwt_code_t cjwt_return_value = CJWTE_OK; cJSON *keyset_json = fetch_jwks(); chunk.memory = malloc(1); /* will be grown as needed by realloc above */ chunk.size = 0; /* no data at this point */ // Get Key Id from token cjwt_return_value = cjwt_get_header(token, strlen(token), OPT_ALLOW_ANY_TIME, &jwt_header); if(CJWTE_OK != cjwt_return_value) { logit("Could not get KID: %s\n", token); free(chunk.memory); cjwt_header_destroy(jwt_header); return 1; } token_kid = jwt_header->kid; // Fetch Jwks to decrypt token curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); long http_code = 0; if (curl) { curl_easy_setopt(curl, CURLOPT_URL, config.jwks_url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &chunk); curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 0); res = curl_easy_perform(curl); if (res != CURLE_OK) { logit("curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); cjwt_header_destroy(jwt_header); return 1; } else { curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code); } curl_easy_cleanup(curl); } curl_global_cleanup(); if (http_code != 200) { free(chunk.memory); cjwt_header_destroy(jwt_header); return 1; } keyset_json = cJSON_Parse(chunk.memory); if (keyset_json == NULL) { const char *error_ptr = cJSON_GetErrorPtr(); if (error_ptr != NULL) { logit("Error before: %s\n", error_ptr); } free(chunk.memory); return 1; } // Get Key Id from token cjwt_header_t *jwt_header = NULL; cjwt_code_t cjwt_return_value = cjwt_get_header(token, strlen(token), OPT_ALLOW_ANY_TIME, &jwt_header); if(CJWTE_OK != cjwt_return_value) { logit("Could not get KID: %s\n", token); cjwt_header_destroy(jwt_header); return 1; } const char *token_kid = jwt_header->kid; // Search for correct key keyset = cJSON_GetObjectItemCaseSensitive(keyset_json, "keys"); const cJSON *keyset = cJSON_GetObjectItemCaseSensitive(keyset_json, "keys"); const unsigned char *key = NULL; const cJSON *key_itr = NULL; const cJSON *kid = NULL; cJSON_ArrayForEach(key_itr, keyset) { kid = cJSON_GetObjectItemCaseSensitive(key_itr, "kid"); Loading @@ -130,43 +83,31 @@ int verify_token(const char *token, oidc_token_content_t *token_info) { // Handle not finding the correct key if (!key) { logit("Could not find correct key in keyset. Token: %s\n", token); free(chunk.memory); return 1; } // Load Cert here char* loaded_cert = load_cert(key); cJSON_Delete(keyset_json); if (loaded_cert == NULL) { logit("Loaded cert is null. Token: %s\n", token); free(chunk.memory); cJSON_Delete(keyset_json); return 1; } // Actually validate token now cjwt_t *jwt = NULL; cjwt_return_value = cjwt_decode(token, strlen(token), 0, (uint8_t *)loaded_cert, strlen(loaded_cert), time(NULL), 0, &jwt); free(loaded_cert); if (CJWTE_OK != cjwt_return_value) { logit("There was an issue while decoding token: %d\n", cjwt_return_value); // free memory free(chunk.memory); free(loaded_cert); // This should recursively free all CJSON stuff from JWKS cJSON_Delete(keyset_json); cjwt_destroy(jwt); return 1; } user = cJSON_GetObjectItemCaseSensitive(jwt->private_claims, "preferred_username"); const cJSON *user = cJSON_GetObjectItemCaseSensitive(jwt->private_claims, "preferred_username"); if (!cJSON_IsString(user) || (user->valuestring == NULL)) { logit("Could not find 'preferred_username' claim.\n"); // free memory free(chunk.memory); free(loaded_cert); // This should recursively free all CJSON stuff from JWKS cJSON_Delete(keyset_json); cjwt_destroy(jwt); return 1; } Loading @@ -174,22 +115,51 @@ int verify_token(const char *token, oidc_token_content_t *token_info) { token_info->user = malloc(strlen(user->valuestring)); strcpy(token_info->user, user->valuestring); // free memory free(chunk.memory); free(loaded_cert); // This should recursively free all CJSON stuff from JWKS cJSON_Delete(keyset_json); cjwt_destroy(jwt); return 0; } char *load_cert(const char* x509) { cJSON* fetch_jwks() { memory_struct mem; EVP_PKEY *pkey = NULL; BIO *certbio = NULL; BIO *keybio = NULL; X509 *cert = NULL; mem.memory = malloc(1); /* will be grown as needed by realloc above */ mem.size = 0; /* no data at this point */ // Fetch Jwks to decrypt token CURL *curl; CURLcode res; curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); long http_code = 0; if (curl) { curl_easy_setopt(curl, CURLOPT_URL, config.jwks_url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &mem); curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0"); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 0); res = curl_easy_perform(curl); if (res != CURLE_OK) { logit("curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); return NULL; } else { curl_easy_getinfo (curl, CURLINFO_RESPONSE_CODE, &http_code); } curl_easy_cleanup(curl); } curl_global_cleanup(); if (http_code != 200) { free(mem.memory); return NULL; } cJSON *keyset_json = cJSON_Parse(mem.memory); free(mem.memory); return keyset_json; } char *load_cert(const char* x509) { /* ---------------------------------------------------------- * * These function calls initialize openssl for correct work. * Loading @@ -206,7 +176,8 @@ char *load_cert(const char* x509) { strcat(x509_formatted, x509); strcat(x509_formatted, footer); certbio = BIO_new(BIO_s_mem()); X509 *cert = NULL; BIO *certbio = BIO_new(BIO_s_mem()); BIO_write(certbio, x509_formatted, strlen(x509_formatted) + 1); if (! (cert = PEM_read_bio_X509(certbio, NULL, 0, NULL))) { logit("Error reading cert into memory. x509: %s\n", x509_formatted); Loading @@ -214,29 +185,29 @@ char *load_cert(const char* x509) { free(x509_formatted); return NULL; } BIO_free_all(certbio); free(x509_formatted); EVP_PKEY *pkey = NULL; if ((pkey = X509_get_pubkey(cert)) == NULL) { logit("Error getting public key.\n"); BIO_free_all(certbio); X509_free(cert); return NULL; } keybio = BIO_new(BIO_s_mem()); X509_free(cert); BIO *keybio = BIO_new(BIO_s_mem()); if(!PEM_write_bio_PUBKEY(keybio, pkey)) { logit("Error writing public key data in PEM format\n"); BIO_free_all(certbio); EVP_PKEY_free(pkey); X509_free(cert); return NULL; } char* key_buf = (char*) malloc(EVP_PKEY_bits(pkey) + 1); memset(key_buf, 0, EVP_PKEY_bits(pkey) + 1); BIO_read(keybio, key_buf, EVP_PKEY_bits(pkey)); EVP_PKEY_free(pkey); X509_free(cert); BIO_free_all(certbio); BIO_free_all(keybio); return key_buf; } No newline at end of file
server_side/c/auth.h +7 −0 Original line number Diff line number Diff line Loading @@ -3,6 +3,11 @@ #include "config.h" typedef struct MemoryStruct { char *memory; size_t size; } memory_struct; typedef struct oidc_token_content_t { char *user; Loading @@ -12,6 +17,8 @@ typedef struct oidc_token_content_t int verify_token(const char* token, oidc_token_content_t *token_info); cJSON* fetch_jwks(); char *load_cert(const char* x509); Loading
server_side/c/main.c +16 −14 Original line number Diff line number Diff line Loading @@ -5,19 +5,21 @@ #include "auth.h" int main(int argc, char *argv[]) { // int res = parse_config("/Users/35y/projects/ndip/oidc-pam/server_side/oidc-pam.json", &config); // printf("res: %d\n",res); // if (res ==1) { // exit(1); // } // printf("%s %s %s %d\n",config.client_id,config.client_secret,config.introspection_url,config.enable_2fa); printf("args: %s %s\n", argv[1], argv[2]); // oidc_token_content_t token_info; // res = introspect_token("sssss", &token_info); // printf("active: %d\n",token_info.active); // if (res == 1) { // exit(1); // } // cJSON_Delete(config.parsed_object); // cJSON_Delete(token_info.parsed_object); int res = parse_config(argv[1], &config); printf("res: %d\n",res); if (res ==1) { exit(1); } printf("%s %s %d\n",config.jwks_url,config.log_file,config.enable_2fa); oidc_token_content_t token_info; res = verify_token(argv[2], &token_info); printf("user: %s\n",token_info.user); if (res == 1) { exit(1); } cJSON_Delete(config.parsed_object); free(token_info.user); }
server_side/oidc-pam-test.json 0 → 100644 +6 −0 Original line number Diff line number Diff line { "jwks_url": "https://login.microsoftonline.com/db3dbd43-4c4b-4544-9f8a-0553f9f5f25e/discovery/v2.0/keys", "check_2fa": false, "enable_log": true, "log_file": "/home/gzi/tmp/oidc.log" }