Skip to content

Commit 3c5b8fc

Browse files
authored
Merge pull request #111 from jhiemstrawisc/keycache_config2
Add configuration API to set keycache update/expiration intervals
2 parents fc1ae50 + da568ed commit 3c5b8fc

File tree

6 files changed

+194
-14
lines changed

6 files changed

+194
-14
lines changed

configs/export-symbols

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ global:
44
validator*;
55
enforcer*;
66
keycache*;
7-
7+
config*;
8+
89
local:
910
*;
1011
};

src/scitokens.cpp

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
1+
#include <atomic>
22
#include <exception>
3-
43
#include <string.h>
54

5+
66
#include "scitokens.h"
77
#include "scitokens_internal.h"
88

9+
/**
10+
* GLOBALS
11+
*/
12+
std::atomic_int configurer::Configuration::m_next_update_delta{600};
13+
std::atomic_int configurer::Configuration::m_expiry_delta{4 * 24 * 3600};
14+
915
SciTokenKey scitoken_key_create(const char *key_id, const char *alg,
1016
const char *public_contents,
1117
const char *private_contents, char **err_msg) {
@@ -942,3 +948,69 @@ int keycache_set_jwks(const char *issuer, const char *jwks, char **err_msg) {
942948
}
943949
return 0;
944950
}
951+
952+
int config_set_int(const char *key, int value, char **err_msg) {
953+
if (!key) {
954+
if (err_msg) {
955+
*err_msg = strdup("A key must be provided.");
956+
}
957+
return -1;
958+
}
959+
960+
std::string _key = key;
961+
962+
if (_key == "keycache.update_interval_s") {
963+
if (value < 0) {
964+
if (err_msg) {
965+
*err_msg = strdup("Update interval must be positive.");
966+
}
967+
return -1;
968+
}
969+
configurer::Configuration::set_next_update_delta(value);
970+
return 0;
971+
}
972+
973+
if (_key == "keycache.expiration_interval_s") {
974+
if (value < 0 ) {
975+
if (err_msg) {
976+
*err_msg = strdup("Expiry interval must be positive.");
977+
}
978+
return -1;
979+
}
980+
configurer::Configuration::set_expiry_delta(value);
981+
return 0;
982+
}
983+
984+
else {
985+
if (err_msg) {
986+
*err_msg = strdup("Key not recognized.");
987+
}
988+
return -1;
989+
}
990+
}
991+
992+
int config_get_int(const char *key, char **err_msg) {
993+
if (!key) {
994+
if (err_msg) {
995+
*err_msg = strdup("A key must be provided.");
996+
}
997+
return -1;
998+
}
999+
1000+
std::string _key = key;
1001+
1002+
if (_key == "keycache.update_interval_s") {
1003+
return configurer::Configuration::get_next_update_delta();
1004+
}
1005+
1006+
if (_key == "keycache.expiration_interval_s") {
1007+
return configurer::Configuration::get_expiry_delta();
1008+
}
1009+
1010+
else {
1011+
if (err_msg) {
1012+
*err_msg = strdup("Key not recognized.");
1013+
}
1014+
return -1;
1015+
}
1016+
}

src/scitokens.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ typedef void *SciToken;
1919
typedef void *Validator;
2020
typedef void *Enforcer;
2121
typedef void *SciTokenStatus;
22+
typedef void *Configuration;
2223

2324
typedef int (*StringValidatorFunction)(const char *value, char **err_msg);
2425
typedef struct Acl_s {
@@ -289,6 +290,26 @@ int keycache_get_cached_jwks(const char *issuer, char **jwks, char **err_msg);
289290
*/
290291
int keycache_set_jwks(const char *issuer, const char *jwks, char **err_msg);
291292

293+
/**
294+
* API for managing scitokens configuration parameters.
295+
*/
296+
297+
/**
298+
* Update scitokens parameters.
299+
* Takes in key/value pairs and assigns the input value to whatever
300+
* configuration variable is indicated by the key.
301+
* Returns 0 on success, and non-zero for invalid keys or values.
302+
*/
303+
int config_set_int(const char *key, int value, char **err_msg);
304+
305+
/**
306+
* Get current scitokens parameters.
307+
* Returns the value associated with the supplied input key on success, and -1
308+
* on failure This assumes there are no keys for which a negative return value
309+
* is permissible.
310+
*/
311+
int config_get_int(const char *key, char **err_msg);
312+
292313
#ifdef __cplusplus
293314
}
294315
#endif

src/scitokens_internal.cpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -546,11 +546,6 @@ std::string normalize_absolute_path(const std::string &path) {
546546
return result.empty() ? "/" : result;
547547
}
548548

549-
void get_default_expiry_time(int &next_update_delta, int &expiry_delta) {
550-
next_update_delta = 600;
551-
expiry_delta = 4 * 24 * 3600;
552-
}
553-
554549
} // namespace
555550

556551
void SciToken::deserialize(const std::string &data,
@@ -695,8 +690,9 @@ std::unique_ptr<AsyncStatus> Validator::get_public_keys_from_web_continue(
695690
// TODO: take expiration time from the cache-control header in the
696691
// response.
697692

698-
int next_update_delta, expiry_delta;
699-
get_default_expiry_time(next_update_delta, expiry_delta);
693+
int next_update_delta =
694+
configurer::Configuration::get_next_update_delta();
695+
int expiry_delta = configurer::Configuration::get_expiry_delta();
700696
status->m_next_update = now + next_update_delta;
701697
status->m_expires = now + expiry_delta;
702698
status->m_keys = json_obj;
@@ -738,8 +734,8 @@ bool Validator::store_jwks(const std::string &issuer,
738734
picojson::value jwks;
739735
std::string err = picojson::parse(jwks, jwks_str);
740736
auto now = std::time(NULL);
741-
int next_update_delta, expiry_delta;
742-
get_default_expiry_time(next_update_delta, expiry_delta);
737+
int next_update_delta = configurer::Configuration::get_next_update_delta();
738+
int expiry_delta = configurer::Configuration::get_expiry_delta();
743739
int64_t next_update = now + next_update_delta, expires = now + expiry_delta;
744740
if (!err.empty()) {
745741
throw JsonException(err);
@@ -980,8 +976,8 @@ bool scitokens::Validator::store_public_ec_key(const std::string &issuer,
980976
picojson::value top_value(top_obj);
981977

982978
auto now = std::time(NULL);
983-
int next_update_delta, expiry_delta;
984-
get_default_expiry_time(next_update_delta, expiry_delta);
979+
int next_update_delta = configurer::Configuration::get_next_update_delta();
980+
int expiry_delta = configurer::Configuration::get_expiry_delta();
985981
return store_public_keys(issuer, top_value, now + next_update_delta,
986982
now + expiry_delta);
987983
}

src/scitokens_internal.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <sstream>
44
#include <unordered_map>
55

6+
#include <atomic>
67
#include <curl/curl.h>
78
#include <jwt-cpp/jwt.h>
89
#include <uuid/uuid.h>
@@ -29,6 +30,24 @@ struct kazuho_picojson;
2930
}
3031
} // namespace jwt
3132

33+
namespace configurer {
34+
class Configuration {
35+
public:
36+
Configuration() {}
37+
static void set_next_update_delta(int _next_update_delta) {
38+
m_next_update_delta = _next_update_delta;
39+
}
40+
static int get_next_update_delta() { return m_next_update_delta; }
41+
static void set_expiry_delta(int _expiry_delta) {
42+
m_expiry_delta = _expiry_delta;
43+
}
44+
static int get_expiry_delta() { return m_expiry_delta; }
45+
private:
46+
static std::atomic_int m_next_update_delta;
47+
static std::atomic_int m_expiry_delta;
48+
};
49+
} // namespace configurer
50+
3251
namespace scitokens {
3352

3453
namespace internal {

test/main.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,77 @@ TEST_F(KeycacheTest, SetGetTest) {
165165
EXPECT_EQ(demo_scitokens2, jwks_str);
166166
}
167167

168+
TEST_F(KeycacheTest, InvalidConfigKeyTest) {
169+
char *err_msg;
170+
int new_update_interval = 400;
171+
std::string key = "invalid key";
172+
auto rv = config_set_int(key.c_str(), new_update_interval, &err_msg);
173+
ASSERT_FALSE(rv == 0);
174+
175+
const char *key2 = nullptr;
176+
rv = config_set_int(key2, new_update_interval, &err_msg);
177+
ASSERT_FALSE(rv == 0);
178+
}
179+
180+
TEST_F(KeycacheTest, SetGetUpdateTest) {
181+
char *err_msg;
182+
int new_update_interval = 400;
183+
std::string key = "keycache.update_interval_s";
184+
auto rv = config_set_int(key.c_str(), new_update_interval, &err_msg);
185+
ASSERT_TRUE(rv == 0);
186+
187+
rv = config_get_int(key.c_str(), &err_msg);
188+
EXPECT_EQ(rv, new_update_interval);
189+
}
190+
191+
TEST_F(KeycacheTest, SetGetExpirationTest) {
192+
char *err_msg;
193+
int new_expiration_interval = 2 * 24 * 3600;
194+
std::string key = "keycache.expiration_interval_s";
195+
auto rv = config_set_int(key.c_str(), new_expiration_interval, &err_msg);
196+
ASSERT_TRUE(rv == 0);
197+
198+
rv = config_get_int(key.c_str(), &err_msg);
199+
EXPECT_EQ(rv, new_expiration_interval);
200+
}
201+
202+
TEST_F(KeycacheTest, SetInvalidUpdateTest) {
203+
char *err_msg;
204+
int new_update_interval = -1;
205+
std::string key = "keycache.update_interval_s";
206+
auto rv = config_set_int(key.c_str(), new_update_interval, &err_msg);
207+
ASSERT_FALSE(rv == 0);
208+
}
209+
210+
TEST_F(KeycacheTest, SetInvalidExpirationTest) {
211+
char *err_msg;
212+
int new_expiration_interval = -2 * 24 * 3600;
213+
std::string key = "keycache.expiration_interval_s";
214+
auto rv = config_set_int(key.c_str(), new_expiration_interval, &err_msg);
215+
ASSERT_FALSE(rv == 0);
216+
}
217+
218+
TEST_F(KeycacheTest, RefreshExpiredTest) {
219+
char *err_msg, *jwks;
220+
int new_expiration_interval = 0;
221+
std::string key = "keycache.expiration_interval_s";
222+
auto rv = config_set_int(key.c_str(), new_expiration_interval, &err_msg);
223+
ASSERT_TRUE(rv == 0);
224+
225+
rv = keycache_refresh_jwks(demo_scitokens_url.c_str(), &err_msg);
226+
ASSERT_TRUE(rv == 0);
227+
228+
sleep(1);
229+
230+
rv = keycache_get_cached_jwks(demo_scitokens_url.c_str(), &jwks, &err_msg);
231+
ASSERT_TRUE(rv == 0);
232+
ASSERT_TRUE(jwks != nullptr);
233+
std::string jwks_str(jwks);
234+
free(jwks);
235+
236+
EXPECT_EQ(jwks_str, "{\"keys\": []}");
237+
}
238+
168239
class SerializeTest : public ::testing::Test {
169240
protected:
170241
void SetUp() override {

0 commit comments

Comments
 (0)