-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Private key filename #44
Changes from 7 commits
96628d4
e253f66
3b030cb
e8d239c
960d1e1
f227c31
ef43c38
73d00a6
a65cf84
9e41652
56d5452
aa60a20
b1c1cf3
59be9fa
11daa1d
6f789cb
183117e
701ea13
88bb13e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
// Taken with modifications from https://gist.github.com/niuk/6365b819a86a7e0b92d82328fcf87da5 | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
|
||
#include <openssl/ssl.h> | ||
#include <openssl/err.h> | ||
|
||
#define CPPHTTPLIB_OPENSSL_SUPPORT | ||
#ifndef NOMINMAX | ||
#define NOMINMAX | ||
#endif | ||
#include <httplib.hpp> | ||
|
||
#include <json.hpp> | ||
using json = nlohmann::json; | ||
namespace duckdb | ||
{ | ||
|
||
char get_base64_char(char byte) { | ||
if (byte < 26) { | ||
return 'A' + byte; | ||
} else if (byte < 52) { | ||
return 'a' + byte - 26; | ||
} else if (byte < 62) { | ||
return '0' + byte - 52; | ||
} else if (byte == 62) { | ||
return '-'; | ||
} else if (byte == 63) { | ||
return '_'; | ||
} else { | ||
fprintf(stderr, "BAD BYTE: %02x\n", byte); | ||
exit(1); | ||
return 0; | ||
} | ||
} | ||
|
||
// To execute C, please define "int main()" | ||
void base64encode(char *output, const char *input, size_t input_length) { | ||
size_t input_index = 0; | ||
size_t output_index = 0; | ||
for (; input_index < input_length; ++output_index) { | ||
switch (output_index % 4) { | ||
case 0: | ||
output[output_index] = get_base64_char((0xfc & input[input_index]) >> 2); | ||
break; | ||
case 1: | ||
output[output_index] = get_base64_char(((0x03 & input[input_index]) << 4) | ((0xf0 & input[input_index + 1]) >> 4)); | ||
++input_index; | ||
break; | ||
case 2: | ||
output[output_index] = get_base64_char(((0x0f & input[input_index]) << 2) | ((0xc0 & input[input_index + 1]) >> 6)); | ||
++input_index; | ||
break; | ||
case 3: | ||
output[output_index] = get_base64_char(0x3f & input[input_index]); | ||
++input_index; | ||
break; | ||
default: | ||
exit(1); | ||
} | ||
} | ||
|
||
output[output_index] = '\0'; | ||
} | ||
|
||
std::string get_token(const std::string& filename) { | ||
const char *header = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; | ||
|
||
/* Create jwt claim set */ | ||
json jwt_claim_set; | ||
std::time_t t = std::time(NULL); | ||
std::ifstream ifs(filename); | ||
json credentials_file = json::parse(ifs); | ||
std::string email = credentials_file["client_email"].get<std::string>(); | ||
|
||
jwt_claim_set["iss"] = email; /* service account email address */ | ||
jwt_claim_set["scope"] = "https://www.googleapis.com/auth/spreadsheets" /* scope of requested access token */; | ||
jwt_claim_set["aud"] = "https://accounts.google.com/o/oauth2/token"; /* intended target of the assertion for an access token */ | ||
jwt_claim_set["iat"] = std::to_string(t); /* issued time */ | ||
// Since we get a new token on every request (and max request time is 3 minutes), | ||
// set the limit to 10 minutes. (Max that Google allows is 1 hour) | ||
jwt_claim_set["exp"] = std::to_string(t+600); /* expire time*/ | ||
|
||
char header_64[1024]; | ||
base64encode(header_64, header, strlen(header)); | ||
|
||
char claim_set_64[1024]; | ||
base64encode(claim_set_64, jwt_claim_set.dump().c_str(), strlen(jwt_claim_set.dump().c_str())); | ||
|
||
char input[1024]; | ||
int input_length = sprintf(input, "%s.%s", header_64, claim_set_64); | ||
Check warning on line 92 in src/gsheets_get_token.cpp
|
||
|
||
unsigned char *digest = SHA256((const unsigned char *)input, input_length, NULL); | ||
char digest_str[1024]; | ||
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) { | ||
sprintf(digest_str + i * 2, "%02x", digest[i]); | ||
Check warning on line 97 in src/gsheets_get_token.cpp
|
||
} | ||
|
||
digest_str[SHA256_DIGEST_LENGTH * 2] = '\0'; | ||
|
||
std::string private_key_string = credentials_file["private_key"].get<std::string>(); | ||
|
||
BIO* bio = BIO_new(BIO_s_mem()); | ||
const void * private_key_pointer = private_key_string.c_str(); | ||
int private_key_length = std::strlen(private_key_string.c_str()); | ||
BIO_write(bio, private_key_pointer, private_key_length); | ||
EVP_PKEY* evp_key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL); | ||
RSA* rsa = EVP_PKEY_get1_RSA(evp_key); | ||
Check warning on line 109 in src/gsheets_get_token.cpp
|
||
|
||
if (rsa != NULL) { | ||
unsigned char sigret[4096] = {}; | ||
unsigned int siglen; | ||
if (RSA_sign(NID_sha256, digest, SHA256_DIGEST_LENGTH, sigret, &siglen, rsa)) { | ||
Check warning on line 114 in src/gsheets_get_token.cpp
|
||
if (RSA_verify(NID_sha256, digest, SHA256_DIGEST_LENGTH, sigret, siglen, rsa)) { | ||
Check warning on line 115 in src/gsheets_get_token.cpp
|
||
char signature_64[1024]; | ||
base64encode(signature_64, (const char *)sigret, siglen); | ||
|
||
char jwt[1024]; | ||
sprintf(jwt, "%s.%s", input, signature_64); | ||
Check warning on line 120 in src/gsheets_get_token.cpp
|
||
|
||
duckdb_httplib_openssl::Client cli("https://oauth2.googleapis.com"); | ||
duckdb_httplib_openssl::Params params; | ||
params.emplace("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"); | ||
params.emplace("assertion", jwt); | ||
auto result = cli.Post("/token", params); | ||
return (result -> body); | ||
} else { | ||
printf("Could not verify RSA signature."); | ||
} | ||
} else { | ||
unsigned long err = ERR_get_error(); | ||
printf("RSA_sign failed: %lu, %s\n", err, ERR_error_string(err, NULL)); | ||
} | ||
|
||
RSA_free(rsa); | ||
Check warning on line 136 in src/gsheets_get_token.cpp
|
||
} | ||
std::string failure_message = "{\"status\":\"failed\"}"; | ||
|
||
return failure_message; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
#pragma once | ||
|
||
#include <string> | ||
#include <stdlib.h> | ||
|
||
namespace duckdb { | ||
|
||
char get_base64_char(char byte); | ||
|
||
void base64encode(char *output, const char *input, size_t input_length) ; | ||
|
||
std::string get_token(const std::string& filename) ; | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2017 yhirose | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think google would normally refer to this as key_file