test-oauth2-jwt.c (dovecot-2.3.16) | : | test-oauth2-jwt.c (dovecot-2.3.17) | ||
---|---|---|---|---|
skipping to change at line 235 | skipping to change at line 235 | |||
return tokenbuf; | return tokenbuf; | |||
} | } | |||
#define save_key(algo, key) save_key_to(algo, "default", (key)) | #define save_key(algo, key) save_key_to(algo, "default", (key)) | |||
#define save_key_to(algo, name, key) save_key_azp_to(algo, "default", name, (key )) | #define save_key_to(algo, name, key) save_key_azp_to(algo, "default", name, (key )) | |||
static void save_key_azp_to(const char *algo, const char *azp, | static void save_key_azp_to(const char *algo, const char *azp, | |||
const char *name, const char *keydata) | const char *name, const char *keydata) | |||
{ | { | |||
const char *error; | const char *error; | |||
struct dict_op_settings set = { | ||||
.username = "testuser", | ||||
}; | ||||
struct dict_transaction_context *ctx = | struct dict_transaction_context *ctx = | |||
dict_transaction_begin(keys_dict); | dict_transaction_begin(keys_dict, &set); | |||
algo = t_str_ucase(algo); | algo = t_str_ucase(algo); | |||
dict_set(ctx, t_strconcat(DICT_PATH_SHARED, azp, "/", algo, "/", | dict_set(ctx, t_strconcat(DICT_PATH_SHARED, azp, "/", algo, "/", | |||
name, NULL), | name, NULL), | |||
keydata); | keydata); | |||
if (dict_transaction_commit(&ctx, &error) < 0) | if (dict_transaction_commit(&ctx, &error) < 0) | |||
i_error("dict_set(%s) failed: %s", name, error); | i_error("dict_set(%s) failed: %s", name, error); | |||
} | } | |||
static void sign_jwt_token_hs256(buffer_t *tokenbuf, buffer_t *key) | static void sign_jwt_token_hs256(buffer_t *tokenbuf, buffer_t *key) | |||
{ | { | |||
skipping to change at line 475 | skipping to change at line 478 | |||
.key_values = { NULL }, | .key_values = { NULL }, | |||
.error = "Missing 'sub' field", | .error = "Missing 'sub' field", | |||
}, | }, | |||
{ /* missing sub field */ | { /* missing sub field */ | |||
.exp = now+500, | .exp = now+500, | |||
.iat = 0, | .iat = 0, | |||
.nbf = 0, | .nbf = 0, | |||
.key_values = { NULL }, | .key_values = { NULL }, | |||
.error = "Missing 'sub' field", | .error = "Missing 'sub' field", | |||
}, | }, | |||
{ /* no expiration */ | ||||
.key_values = { | ||||
"sub", "testuser", | ||||
NULL | ||||
}, | ||||
.error = "Missing 'exp' field", | ||||
}, | ||||
{ /* non-ISO date as iat */ | { /* non-ISO date as iat */ | |||
.exp = now+500, | .exp = now+500, | |||
.iat = 0, | .iat = 0, | |||
.nbf = 0, | .nbf = 0, | |||
.key_values = { "sub", "testuser", "iat", | .key_values = { "sub", "testuser", "iat", | |||
"1.1.2019 16:00", NULL }, | "1.1.2019 16:00", NULL }, | |||
.error = "Malformed 'iat' field" | .error = "Malformed 'iat' field" | |||
}, | }, | |||
{ /* expired token */ | { /* expired token */ | |||
.exp = now-500, | .exp = now-500, | |||
skipping to change at line 547 | skipping to change at line 557 | |||
test_assert_idx(is_jwt == TRUE, i); | test_assert_idx(is_jwt == TRUE, i); | |||
if (test_case->error != NULL) { | if (test_case->error != NULL) { | |||
test_assert_strcmp(test_case->error, error); | test_assert_strcmp(test_case->error, error); | |||
} | } | |||
test_assert(error != NULL); | test_assert(error != NULL); | |||
} T_END; | } T_END; | |||
test_end(); | test_end(); | |||
} | } | |||
static void test_jwt_valid_token(void) | ||||
{ | ||||
test_begin("JWT valid token tests"); | ||||
time_t now = time(NULL); | ||||
struct test_cases { | ||||
time_t exp; | ||||
time_t iat; | ||||
time_t nbf; | ||||
const char *key_values[20]; | ||||
} test_cases[] = { | ||||
{ /* valid token */ | ||||
.exp = now + 500, | ||||
.key_values = { | ||||
"sub", "testuser", | ||||
NULL | ||||
}, | ||||
}, | ||||
{ | ||||
.exp = now + 500, | ||||
.nbf = now - 500, | ||||
.iat = now - 250, | ||||
.key_values = { | ||||
"sub", "testuser", | ||||
NULL | ||||
}, | ||||
}, | ||||
{ /* token issued in advance */ | ||||
.exp = now + 500, | ||||
.nbf = now - 500, | ||||
.iat = now - 3600, | ||||
.key_values = { | ||||
"sub", "testuser", | ||||
NULL, | ||||
}, | ||||
}, | ||||
}; | ||||
for (size_t i = 0; i < N_ELEMENTS(test_cases); i++) T_BEGIN { | ||||
const struct test_cases *test_case = &test_cases[i]; | ||||
ARRAY_TYPE(oauth2_field) fields; | ||||
t_array_init(&fields, 8); | ||||
for (unsigned int i = 0; test_case->key_values[i] != NULL; i += 2 | ||||
) { | ||||
struct oauth2_field *field = array_append_space(&fields); | ||||
field->name = test_case->key_values[i]; | ||||
field->value = test_case->key_values[i+1]; | ||||
} | ||||
buffer_t *tokenbuf = | ||||
create_jwt_token_fields("HS256", test_case->exp, | ||||
test_case->iat, test_case->nbf, | ||||
&fields); | ||||
sign_jwt_token_hs256(tokenbuf, hs_sign_key); | ||||
struct oauth2_request req; | ||||
const char *error = NULL; | ||||
bool is_jwt; | ||||
test_assert_idx(parse_jwt_token(&req, str_c(tokenbuf), | ||||
&is_jwt, &error) == 0, i); | ||||
test_assert_idx(is_jwt == TRUE, i); | ||||
test_assert_idx(error == NULL, i); | ||||
if (error != NULL) | ||||
i_error("JWT validation error: %s", error); | ||||
} T_END; | ||||
test_end(); | ||||
} | ||||
static void test_jwt_dates(void) | static void test_jwt_dates(void) | |||
{ | { | |||
test_begin("JWT Token dates"); | test_begin("JWT Token dates"); | |||
/* simple check to make sure ISO8601 dates work too */ | /* simple check to make sure ISO8601 dates work too */ | |||
ARRAY_TYPE(oauth2_field) fields; | ARRAY_TYPE(oauth2_field) fields; | |||
t_array_init(&fields, 8); | t_array_init(&fields, 8); | |||
struct oauth2_field *field; | struct oauth2_field *field; | |||
struct tm tm_b; | struct tm tm_b; | |||
struct tm *tm; | struct tm *tm; | |||
skipping to change at line 784 | skipping to change at line 864 | |||
test_end(); | test_end(); | |||
} | } | |||
static void test_do_init(void) | static void test_do_init(void) | |||
{ | { | |||
const char *error; | const char *error; | |||
struct dcrypt_settings dcrypt_set = { | struct dcrypt_settings dcrypt_set = { | |||
.module_dir = "../lib-dcrypt/.libs", | .module_dir = "../lib-dcrypt/.libs", | |||
}; | }; | |||
struct dict_settings dict_set = { | struct dict_settings dict_set = { | |||
.username = "testuser", | ||||
.value_type = DICT_DATA_TYPE_STRING, | ||||
.base_dir = ".", | .base_dir = ".", | |||
}; | }; | |||
i_unlink_if_exists(".keys"); | i_unlink_if_exists(".keys"); | |||
dict_driver_register(&dict_driver_file); | dict_driver_register(&dict_driver_file); | |||
if (dict_init("file:.keys", &dict_set, &keys_dict, &error) < 0) | if (dict_init("file:.keys", &dict_set, &keys_dict, &error) < 0) | |||
i_fatal("dict_init(file:.keys): %s", error); | i_fatal("dict_init(file:.keys): %s", error); | |||
if (!dcrypt_initialize(NULL, &dcrypt_set, &error)) { | if (!dcrypt_initialize(NULL, &dcrypt_set, &error)) { | |||
i_error("No functional dcrypt backend found - " | i_error("No functional dcrypt backend found - " | |||
"skipping some tests: %s", error); | "skipping some tests: %s", error); | |||
skipping to change at line 826 | skipping to change at line 904 | |||
buffer_free(&hs_sign_key); | buffer_free(&hs_sign_key); | |||
dcrypt_deinitialize(); | dcrypt_deinitialize(); | |||
} | } | |||
int main(void) | int main(void) | |||
{ | { | |||
static void (*test_functions[])(void) = { | static void (*test_functions[])(void) = { | |||
test_do_init, | test_do_init, | |||
test_jwt_hs_token, | test_jwt_hs_token, | |||
test_jwt_token_escape, | test_jwt_token_escape, | |||
test_jwt_valid_token, | ||||
test_jwt_bad_valid_token, | test_jwt_bad_valid_token, | |||
test_jwt_broken_token, | test_jwt_broken_token, | |||
test_jwt_dates, | test_jwt_dates, | |||
test_jwt_key_files, | test_jwt_key_files, | |||
test_jwt_kid_escape, | test_jwt_kid_escape, | |||
test_jwt_rs_token, | test_jwt_rs_token, | |||
test_jwt_ps_token, | test_jwt_ps_token, | |||
test_jwt_ec_token, | test_jwt_ec_token, | |||
test_do_deinit, | test_do_deinit, | |||
NULL | NULL | |||
End of changes. 6 change blocks. | ||||
3 lines changed or deleted | 83 lines changed or added |