token.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <stdbool.h>
  5. #include <curl/curl.h>
  6. #include "utils.h"
  7. #include "keystone.h"
  8. #include "cJSON.h"
  9. #include "curl.h"
  10. const char *token_header = "X-Subject-Token:";
  11. struct cache token_cache = { { 0 }, NULL };
  12. size_t grep_token(void *ptr, size_t size, size_t nmemb, void *s_) {
  13. if(strncasecmp(ptr, token_header, strlen(token_header)) != 0) {
  14. return size*nmemb;
  15. }
  16. struct string *s = s_;
  17. size_t new_len = s->len + size*nmemb;
  18. s->ptr = realloc(s->ptr, new_len+1);
  19. if (s->ptr == NULL) {
  20. fprintf(stderr, "realloc() failed\n");
  21. exit(EXIT_FAILURE);
  22. }
  23. memcpy(s->ptr+s->len, ptr, size*nmemb);
  24. s->ptr[new_len] = '\0';
  25. s->len = new_len;
  26. return size*nmemb;
  27. return 0;
  28. }
  29. /*
  30. A typical keystone token request looks like this:
  31. {"auth": {
  32. "identity": {
  33. "methods": [
  34. "password"
  35. ],
  36. "password": {
  37. "user": {
  38. "domain": {
  39. "name": "'$OS_USER_DOMAIN_NAME'"
  40. },
  41. "name": "'$OS_USERNAME'",
  42. "password": "'$OS_PASSWORD'"
  43. }
  44. }
  45. },
  46. "scope": {
  47. "project": {
  48. "domain": {
  49. "name": "'$OS_PROJECT_DOMAIN_NAME'"
  50. },
  51. "name": "'$OS_PROJECT_NAME'",
  52. "id": "'$OS_PROJECT_ID'"
  53. }
  54. }
  55. }}
  56. */
  57. char* token_request() {
  58. cJSON* tok_request_obj = cJSON_CreateObject();
  59. cJSON* auth_obj = cJSON_CreateObject();
  60. cJSON_AddItemToObject(tok_request_obj, "auth", auth_obj);
  61. cJSON* identity_obj = cJSON_CreateObject();
  62. cJSON_AddItemToObject(auth_obj, "identity", identity_obj);
  63. cJSON* methods_arr = cJSON_AddArrayToObject(identity_obj, "methods");
  64. cJSON* password_method_string = cJSON_CreateString("password");
  65. cJSON_AddItemToArray(methods_arr, password_method_string);
  66. cJSON* password_obj = cJSON_CreateObject();
  67. cJSON_AddItemToObject(identity_obj, "password", password_obj);
  68. cJSON* user_obj = cJSON_CreateObject();
  69. cJSON_AddItemToObject(password_obj, "user", user_obj);
  70. cJSON* identity_domain_obj = cJSON_CreateObject();
  71. if(cJSON_AddStringToObject(identity_domain_obj, "name", env[OS_USER_DOMAIN_NAME].val) == NULL) {
  72. WHEREAMI();
  73. goto tidy_token_request;
  74. }
  75. cJSON_AddItemToObject(user_obj, "domain", identity_domain_obj);
  76. if(cJSON_AddStringToObject(user_obj, "name", env[OS_USERNAME].val) == NULL) {
  77. WHEREAMI();
  78. goto tidy_token_request;
  79. }
  80. if(cJSON_AddStringToObject(user_obj, "password", env[OS_PASSWORD].val) == NULL) {
  81. WHEREAMI();
  82. goto tidy_token_request;
  83. }
  84. cJSON* scope_obj = cJSON_CreateObject();
  85. cJSON_AddItemToObject(auth_obj, "scope", scope_obj);
  86. cJSON* proj_obj = cJSON_CreateObject();
  87. cJSON_AddItemToObject(scope_obj, "project", proj_obj);
  88. cJSON* scope_domain_obj = cJSON_CreateObject();
  89. if(cJSON_AddStringToObject(scope_domain_obj, "name", env[OS_PROJECT_DOMAIN_NAME].val) == NULL) {
  90. WHEREAMI();
  91. goto tidy_token_request;
  92. }
  93. cJSON_AddItemToObject(proj_obj, "domain", scope_domain_obj);
  94. cJSON_AddStringToObject(proj_obj, "name", env[OS_PROJECT_NAME].val);
  95. cJSON_AddStringToObject(proj_obj, "id", env[OS_PROJECT_ID].val);
  96. char *tok_request_string = cJSON_PrintUnformatted(tok_request_obj);
  97. tidy_token_request:
  98. cJSON_Delete(tok_request_obj);
  99. return tok_request_string;
  100. }
  101. void get_token() {
  102. if(token_cache.data[0] != '\0') {
  103. // Clear existing data
  104. memset(token_cache.data, 0, sizeof(token_cache));
  105. }
  106. char* token_request_data = token_request();
  107. if(token_request_data == NULL) {
  108. WHEREAMI();
  109. fprintf(stderr, "Error retrieving token\n");
  110. }
  111. CURLcode err = curl_global_init(CURL_GLOBAL_NOTHING);
  112. if(err) {
  113. WHEREAMI();
  114. fprintf(stderr, "Something went wrong initialising libcurl (error %u)\n", err);
  115. exit(err);
  116. }
  117. char *tok_path = "auth/tokens?nocatalog";
  118. char tok_url[MAX_BUF_SZ] = { 0 };
  119. api_url_build(tok_url, env[OS_AUTH_URL].val, tok_path);
  120. CURL* handle = curl_easy_init();
  121. if(handle == NULL) {
  122. WHEREAMI();
  123. fprintf(stderr, "Something went wrong initialising curl session.\n");
  124. err = 1;
  125. goto easy_cleanup;
  126. }
  127. char errbuf[CURL_ERROR_SIZE] = { 0 };
  128. err = curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, errbuf);
  129. if(err) {
  130. WHEREAMI();
  131. fprintf(stderr, "Something went wrong preparing error buffer (error %u)\n", err);
  132. fprintf(stderr, "Current contents of buffer:\n%s\n", errbuf);
  133. goto easy_cleanup;
  134. }
  135. err = curl_easy_setopt(handle, CURLOPT_URL, tok_url);
  136. if(err) {
  137. WHEREAMI();
  138. fprintf(stderr, "Error %u: %s\n", err, errbuf);
  139. goto easy_cleanup;
  140. }
  141. struct curl_slist *H = NULL;
  142. H = curl_slist_append(H, "Content-Type: application/json");
  143. if(H == NULL) {
  144. WHEREAMI();
  145. fprintf(stderr, "Something went wrong setting token request header\n");
  146. goto easy_cleanup;
  147. }
  148. err = curl_easy_setopt(handle, CURLOPT_HTTPHEADER, H);
  149. if(err) {
  150. WHEREAMI();
  151. fprintf(stderr, "Error %u: %s\n", err, errbuf);
  152. goto easy_cleanup;
  153. }
  154. err = curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, grep_token);
  155. if(err) {
  156. WHEREAMI();
  157. fprintf(stderr, "Error %u: %s\n", err, errbuf);
  158. goto easy_cleanup;
  159. }
  160. struct string h;
  161. init_string(&h);
  162. err = curl_easy_setopt(handle, CURLOPT_HEADERDATA, &h);
  163. if(err) {
  164. WHEREAMI();
  165. fprintf(stderr, "Error %u: %s\n", err, errbuf);
  166. goto easy_cleanup;
  167. }
  168. err = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, string_stuffer);
  169. if(err) {
  170. WHEREAMI();
  171. fprintf(stderr, "Error %u: %s\n", err, errbuf);
  172. goto easy_cleanup;
  173. }
  174. struct string s;
  175. init_string(&s);
  176. err = curl_easy_setopt(handle, CURLOPT_WRITEDATA, &s);
  177. if(err) {
  178. WHEREAMI();
  179. fprintf(stderr, "Error %u: %s\n", err, errbuf);
  180. goto easy_cleanup;
  181. }
  182. err = curl_easy_setopt(handle, CURLOPT_POSTFIELDS, token_request_data);
  183. if(err) {
  184. WHEREAMI();
  185. fprintf(stderr, "Something went wrong setting token request data\n");
  186. goto easy_cleanup;
  187. }
  188. err = curl_easy_perform(handle);
  189. if(err) {
  190. WHEREAMI();
  191. fprintf(stderr, "Error %u: %s\n", err, errbuf);
  192. goto easy_cleanup;
  193. }
  194. cJSON *resp = cJSON_Parse(s.ptr);
  195. cJSON *_token = cJSON_GetObjectItem(resp, "token");
  196. cJSON *_expiry = cJSON_GetObjectItem(_token, "expires_at");
  197. token_cache.expires = cJSON_GetStringValue(_expiry);
  198. h.ptr[h.len - 1] = '\0'; // Remove trailing '\n'
  199. h.ptr[h.len - 2] = '\0'; // Remove trailing '\r'
  200. strncpy(token_cache.data, h.ptr + strlen(token_header) + 1, 256);
  201. if(h.ptr != NULL) {
  202. free(h.ptr);
  203. }
  204. easy_cleanup:
  205. if(H != NULL) {
  206. curl_slist_free_all(H);
  207. }
  208. if(handle != NULL) {
  209. curl_easy_cleanup(handle);
  210. }
  211. if(s.ptr != NULL) {
  212. free(s.ptr);
  213. }
  214. curl_global_cleanup();
  215. }
  216. static int create(int argc, char **argv) {
  217. get_token();
  218. printf("%s\n", token_cache.data);
  219. return 0;
  220. }
  221. static struct command subcommands[] = {
  222. CMD_DEF(create),
  223. { NULL, NULL }
  224. };
  225. int token(int argc, char **argv) {
  226. common_main(argc, argv, subcommands);
  227. return 0;
  228. }