Skip to content

Commit f22a8da

Browse files
committed
Allow the library user to explicitly set the "current" time.
For XRootD, we decided that the "time" the session token should be evaluated should be when the session starts and not when the operation is attempted; this allows session authorizations to live longer than the token (this matches how X.509 works -- expiration time is only checked at start). Hence, at the SciTokens library level we must allow the user to explicitly set the clock backward for token evaluation.
1 parent 4916492 commit f22a8da

File tree

4 files changed

+106
-11
lines changed

4 files changed

+106
-11
lines changed

src/scitokens.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,18 @@ int validator_validate(Validator validator, SciToken scitoken, char **err_msg) {
347347
}
348348

349349

350+
int validator_set_time(Validator validator, time_t now, char **err_msg) {
351+
if (validator == nullptr) {
352+
if (err_msg) {*err_msg = strdup("Validator may not be a null pointer");}
353+
return -1;
354+
}
355+
auto real_validator = reinterpret_cast<scitokens::Validator*>(validator);
356+
357+
real_validator->set_now(std::chrono::system_clock::from_time_t(now));
358+
359+
return 0;
360+
}
361+
350362
Enforcer enforcer_create(const char *issuer, const char **audience_list, char **err_msg) {
351363
if (issuer == nullptr) {
352364
if (err_msg) {*err_msg = strdup("Issuer may not be a null pointer");}
@@ -388,6 +400,19 @@ void enforcer_set_validate_profile(Enforcer enf, SciTokenProfile profile) {
388400
}
389401

390402

403+
int enforcer_set_time(Enforcer enf, time_t now, char **err_msg) {
404+
if (enf == nullptr) {
405+
if (err_msg) {*err_msg = strdup("Enforcer may not be a null pointer");}
406+
return -1;
407+
}
408+
auto real_enf = reinterpret_cast<scitokens::Enforcer*>(enf);
409+
410+
real_enf->set_now(std::chrono::system_clock::from_time_t(now));
411+
412+
return 0;
413+
}
414+
415+
391416
int enforcer_generate_acls(const Enforcer enf, const SciToken scitoken, Acl **acls, char **err_msg) {
392417
if (enf == nullptr) {
393418
if (err_msg) {*err_msg = strdup("Enforcer may not be a null pointer");}

src/scitokens.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
*/
66

77
#ifdef __cplusplus
8+
#include <ctime>
89
extern "C" {
10+
#else
11+
#include <time.h>
912
#endif
1013

1114
typedef void * SciTokenKey;
@@ -100,6 +103,12 @@ Validator validator_create();
100103
*/
101104
void validator_set_token_profile(Validator, SciTokenProfile profile);
102105

106+
/**
107+
* Set the time to use with the validator. Useful if you want to see if the token would
108+
* have been valid at some time in the past.
109+
*/
110+
int validator_set_time(Validator validator, time_t now, char **err_msg);
111+
103112
int validator_add(Validator validator, const char *claim, StringValidatorFunction validator_func, char **err_msg);
104113

105114
int validator_add_critical_claims(Validator validator, const char **claims, char **err_msg);
@@ -121,6 +130,12 @@ void enforcer_destroy(Enforcer);
121130
*/
122131
void enforcer_set_validate_profile(Enforcer, SciTokenProfile profile);
123132

133+
/**
134+
* Set the time to use with the enforcer. Useful if you want to see if the token would
135+
* have been valid at some time in the past.
136+
*/
137+
int enforcer_set_time(Enforcer enf, time_t now, char **err_msg);
138+
124139
int enforcer_generate_acls(const Enforcer enf, const SciToken scitokens, Acl **acls, char **err_msg);
125140

126141
void enforcer_acl_free(Acl *acls);

src/scitokens_internal.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@
66
#include <jwt-cpp/jwt.h>
77
#include <uuid/uuid.h>
88

9+
namespace {
10+
11+
struct FixedClock {
12+
jwt::date m_now;
13+
jwt::date now() const {return m_now;}
14+
};
15+
16+
}
17+
918
namespace jwt {
1019
template<typename json_traits>
1120
class decoded_jwt;
@@ -267,6 +276,10 @@ class Validator {
267276
typedef std::map<std::string, std::vector<std::pair<ClaimValidatorFunction, void*>>> ClaimValidatorMap;
268277

269278
public:
279+
Validator() : m_now(std::chrono::system_clock::now()) {}
280+
281+
void set_now(std::chrono::system_clock::time_point now) {m_now = now;}
282+
270283
void verify(const SciToken &scitoken) {
271284
const jwt::decoded_jwt<jwt::traits::kazuho_picojson> *jwt_decoded = scitoken.m_decoded.get();
272285
if (!jwt_decoded) {
@@ -343,7 +356,8 @@ class Validator {
343356
get_public_key_pem(jwt.get_issuer(), key_id, public_pem, algorithm);
344357
// std::cout << "Public PEM: " << public_pem << std::endl << "Algorithm: " << algorithm << std::endl;
345358
SciTokenKey key(key_id, algorithm, public_pem, "");
346-
auto verifier = jwt::verify()
359+
360+
auto verifier = jwt::verify<FixedClock, jwt::traits::kazuho_picojson>({m_now})
347361
.allow_algorithm(key);
348362

349363
verifier.verify(jwt);
@@ -528,6 +542,8 @@ class Validator {
528542
ClaimStringValidatorMap m_validators;
529543
ClaimValidatorMap m_claim_validators;
530544

545+
std::chrono::system_clock::time_point m_now;
546+
531547
std::vector<std::string> m_critical_claims;
532548
std::vector<std::string> m_allowed_issuers;
533549
};
@@ -556,6 +572,8 @@ class Enforcer {
556572
m_validator.add_critical_claims(critical_claims);
557573
}
558574

575+
void set_now(std::chrono::system_clock::time_point now) {m_validator.set_now(now);}
576+
559577
void set_validate_profile(SciToken::Profile profile) {
560578
m_validate_profile = profile;
561579
}

test/main.cpp

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "../src/scitokens.h"
22

3+
#include <memory>
4+
35
#include <gtest/gtest.h>
46

57
namespace {
@@ -77,6 +79,11 @@ class SerializeTest : public ::testing::Test {
7779
"1", ec_public, &err_msg);
7880
ASSERT_TRUE(rv == 0);
7981

82+
scitoken_set_lifetime(m_token.get(), 60);
83+
84+
m_audiences_array.push_back("https://demo.scitokens.org/");
85+
m_audiences_array.push_back(nullptr);
86+
8087
const char *groups[3] = {nullptr, nullptr, nullptr};
8188
const char group0[] = "group0";
8289
const char group1[] = "group1";
@@ -96,6 +103,8 @@ class SerializeTest : public ::testing::Test {
96103
using TokenPtr = std::unique_ptr<void, decltype(&scitoken_destroy)>;
97104
TokenPtr m_token{nullptr, scitoken_destroy};
98105

106+
std::vector<const char *> m_audiences_array;
107+
99108
TokenPtr m_read_token{nullptr, scitoken_destroy};
100109
};
101110

@@ -264,11 +273,7 @@ TEST_F(SerializeTest, EnforcerTest) {
264273
"https://demo.scitokens.org/", &err_msg);
265274
ASSERT_TRUE(rv == 0);
266275

267-
std::vector<const char *> audiences_array;
268-
audiences_array.push_back("https://demo.scitokens.org/");
269-
audiences_array.push_back(nullptr);
270-
271-
auto enforcer = enforcer_create("https://demo.scitokens.org/gtest", &audiences_array[0], &err_msg);
276+
auto enforcer = enforcer_create("https://demo.scitokens.org/gtest", &m_audiences_array[0], &err_msg);
272277
ASSERT_TRUE(enforcer != nullptr);
273278

274279
Acl acl;
@@ -304,11 +309,7 @@ TEST_F(SerializeTest, EnforcerScopeTest) {
304309
"https://demo.scitokens.org/", &err_msg);
305310
ASSERT_TRUE(rv == 0);
306311

307-
std::vector<const char *> audiences_array;
308-
audiences_array.push_back("https://demo.scitokens.org/");
309-
audiences_array.push_back(nullptr);
310-
311-
auto enforcer = enforcer_create("https://demo.scitokens.org/gtest", &audiences_array[0], &err_msg);
312+
auto enforcer = enforcer_create("https://demo.scitokens.org/gtest", &m_audiences_array[0], &err_msg);
312313
ASSERT_TRUE(enforcer != nullptr);
313314

314315
scitoken_set_serialize_profile(m_token.get(), SciTokenProfile::WLCG_1_0);
@@ -343,10 +344,46 @@ TEST_F(SerializeTest, EnforcerScopeTest) {
343344
}
344345
ASSERT_TRUE(found_read);
345346
ASSERT_TRUE(found_write);
347+
}
346348

349+
TEST_F(SerializeTest, ExplicitTime) {
350+
time_t now = time(NULL);
351+
char *err_msg;
347352

353+
scitoken_set_serialize_profile(m_token.get(), SciTokenProfile::WLCG_1_0);
354+
auto rv = scitoken_set_claim_string(m_token.get(), "scope",
355+
"storage.read:/", &err_msg);
348356

357+
char *token_value = nullptr;
358+
rv = scitoken_serialize(m_token.get(), &token_value, &err_msg);
359+
ASSERT_TRUE(rv == 0);
360+
361+
rv = scitoken_deserialize_v2(token_value, m_read_token.get(), nullptr, &err_msg);
362+
ASSERT_TRUE(rv == 0);
363+
364+
auto enforcer = enforcer_create("https://demo.scitokens.org/gtest", &m_audiences_array[0], &err_msg);
365+
ASSERT_TRUE(enforcer != nullptr);
366+
Acl *acls;
367+
rv = enforcer_generate_acls(enforcer, m_read_token.get(), &acls, &err_msg);
368+
if (rv) {
369+
printf("Failure when generating ACLs: %s\n", err_msg);
370+
}
371+
ASSERT_TRUE(rv == 0);
372+
ASSERT_TRUE(acls != nullptr);
373+
374+
enforcer_set_time(enforcer, time(NULL), &err_msg);
375+
rv = enforcer_generate_acls(enforcer, m_read_token.get(), &acls, &err_msg);
376+
ASSERT_TRUE(rv == 0);
377+
378+
enforcer_set_time(enforcer, time(NULL) + 100, &err_msg);
379+
rv = enforcer_generate_acls(enforcer, m_read_token.get(), &acls, &err_msg);
380+
ASSERT_FALSE(rv == 0);
381+
382+
enforcer_set_time(enforcer, time(NULL) - 100, &err_msg);
383+
rv = enforcer_generate_acls(enforcer, m_read_token.get(), &acls, &err_msg);
384+
ASSERT_FALSE(rv == 0);
349385

386+
enforcer_destroy(enforcer);
350387
}
351388

352389
}

0 commit comments

Comments
 (0)