Skip to content
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

Add URI Signing cdnistd Claim Implementation #7822

Merged
merged 1 commit into from
May 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions plugins/experimental/uri_signing/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
URI Signing Plugin
==================

This remap plugin implements the draft URI Signing protocol documented [here](https://tools.ietf.org/html/draft-ietf-cdni-uri-signing-16):
This remap plugin implements the draft URI Signing protocol documented [here](https://tools.ietf.org/html/draft-ietf-cdni-uri-signing-21):

It takes a single argument: the name of a config file that contains key information.

Expand Down Expand Up @@ -130,7 +130,7 @@ The following claims are understood:
- `cdniuc`: Validated last, after key verificationD. **Only `regex` is supported!**
- `cdniets`: If cdnistt is 1, this must be present and non-zero.
- `cdnistt`: If present, must be 1.
- `cdnistd`: If present, must be 0.
- `cdnistd`: Renewal token cookies will have cdnistd path segments of the request in their path attribute.

### Unsupported Claims

Expand Down
78 changes: 70 additions & 8 deletions plugins/experimental/uri_signing/jwt.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ parse_jwt(json_t *raw)
}

struct jwt *jwt = malloc(sizeof *jwt);
jwt->raw = raw;
jwt->iss = json_string_value(json_object_get(raw, "iss"));
jwt->sub = json_string_value(json_object_get(raw, "sub"));
jwt->aud = json_object_get(raw, "aud");
Expand All @@ -78,7 +77,6 @@ jwt_delete(struct jwt *jwt)
}

json_decref(jwt->aud);
json_decref(jwt->raw);
free(jwt);
}

Expand Down Expand Up @@ -141,7 +139,7 @@ jwt_validate(struct jwt *jwt)
return false;
}

if (jwt->cdnistd != 0) {
if (jwt->cdnistd < 0) {
PluginDebug("Initial JWT Failure: unsupported value for cdnistd: %d", jwt->cdnistd);
return false;
}
Expand Down Expand Up @@ -263,7 +261,7 @@ void
renew_copy_raw(json_t *new_json, const char *name, json_t *old_json)
{
if (old_json) {
json_object_set_new(new_json, name, old_json);
json_object_set(new_json, name, old_json);
}
}

Expand All @@ -283,7 +281,7 @@ renew_copy_integer(json_t *new_json, const char *name, double old)
}

char *
renew(struct jwt *jwt, const char *iss, cjose_jwk_t *jwk, const char *alg, const char *package)
renew(struct jwt *jwt, const char *iss, cjose_jwk_t *jwk, const char *alg, const char *package, const char *uri, size_t uri_ct)
{
char *s = NULL;
if (jwt->cdnistt != 1) {
Expand All @@ -296,6 +294,65 @@ renew(struct jwt *jwt, const char *iss, cjose_jwk_t *jwk, const char *alg, const
return NULL;
}

int buff_ct = uri_ct + 2;
int normal_err;
char *normal_uri = (char *)TSmalloc(buff_ct);
memset(normal_uri, 0, buff_ct);

normal_err = normalize_uri(uri, uri_ct, normal_uri, buff_ct);

if (normal_err) {
goto fail_normal;
}

/* Determine Path String Based on cdnistd claim */
size_t normal_size = strlen(normal_uri);
const char *path_start = normal_uri;
const char *path_end = NULL;
const char *uri_end = normal_uri + normal_size;
char *path_string = NULL;
size_t path_size = normal_size + 1;

path_string = (char *)TSmalloc(path_size);
memset(path_string, 0, path_size);
PluginDebug("Renewing JWT. Stripped URI: %s", uri);

if (jwt->cdnistd == 0) {
PluginDebug("STD is 0 - Setting Cookie Path to Path=/");
snprintf(path_string, 2, "%s", "/");
} else {
PluginDebug("STD is greater than 0. Calculating Path");
int slash_count = 0;
/* Search for 3rd '/' to mark start of path */
while (path_start != uri_end && slash_count < 3) {
++path_start;
if (*path_start == '/') {
slash_count++;
}
}
if (path_start == uri_end) {
PluginDebug("STD is greater than number of path segments. Cannot Renew Token!");
goto fail_path;
}
PluginDebug("Searching through path: %s", path_start);
/* Now search through path for cdnistd number of segments */
slash_count = 0;
path_end = path_start + 1;
while (path_end != uri_end && slash_count < jwt->cdnistd) {
++path_end;
if (*path_end == '/') {
slash_count++;
}
}
if (path_end == uri_end) {
PluginDebug("STD is greater than number of path segments. Cannot Renew Token!");
goto fail_path;
}
path_size = path_end - path_start + 1;
snprintf(path_string, path_size, "%s", path_start);
PluginDebug("Setting Cookie Path to %s", path_string);
}

json_t *new_json = json_object();
renew_copy_string(new_json, "iss", iss); /* use issuer of new signing key */
renew_copy_string(new_json, "sub", jwt->sub);
Expand Down Expand Up @@ -348,15 +405,20 @@ renew(struct jwt *jwt, const char *iss, cjose_jwk_t *jwk, const char *alg, const
goto fail_jws;
}

const char *fmt = "%s=%s";
const char *fmt = "%s=%s; Path=%s";
size_t s_ct;
s = malloc(s_ct = (1 + snprintf(NULL, 0, fmt, package, jws_str)));
snprintf(s, s_ct, fmt, package, jws_str);
s = malloc(s_ct = (1 + snprintf(NULL, 0, fmt, package, jws_str, path_string)));
snprintf(s, s_ct, fmt, package, jws_str, path_string);
PluginDebug("Cookie returned from renew function: %s", s);
fail_jws:
cjose_jws_release(jws);
fail_hdr:
cjose_header_release(hdr);
fail_json:
free(pt);
fail_path:
TSfree(path_string);
fail_normal:
TSfree(normal_uri);
return s;
}
4 changes: 2 additions & 2 deletions plugins/experimental/uri_signing/jwt.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#include <jansson.h>

struct jwt {
json_t *raw;
const char *iss;
const char *sub;
json_t *aud;
Expand All @@ -45,4 +44,5 @@ bool jwt_check_aud(json_t *aud, const char *id);
bool jwt_check_uri(const char *cdniuc, const char *uri);

struct _cjose_jwk_int;
char *renew(struct jwt *jwt, const char *iss, struct _cjose_jwk_int *jwk, const char *alg, const char *package);
char *renew(struct jwt *jwt, const char *iss, struct _cjose_jwk_int *jwk, const char *alg, const char *package, const char *uri,
size_t uri_ct);
2 changes: 2 additions & 0 deletions plugins/experimental/uri_signing/python_signer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ The config file should be a JSON object that contains the following:
- `cdniets`: Must be set if using cdnistt. Provides means of setting Expiry Times when generating subsequent tokens. It denotes
the number of seconds to be added to the time at which the JWT is verified that gives the value of the Expiry Time claim of the
next signed JWT.
- `cdnistd`: Integer value representing number of path segments that renewal token cookies should valid for. This is used when
generating the path attribute of the cookies containing renewal tokens.
- `keys`: A list of json objects, each one representing a key. Each key should have the following attributes:
- `alg`: The Cryptographic algorithm to be used with the key.
- `kid`: The key identifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
"iss": "Example Issuer",
"token_lifetime": 90,
"aud": "Caching Software",
"cdnistt": true,
"cdniets": 30,
"cdnistt": true,
"cdnistd": 2,
"cdniets": 30,
"keys": [
{
"alg": "HS256",
Expand Down
5 changes: 5 additions & 0 deletions plugins/experimental/uri_signing/python_signer/uri_signer.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,18 @@ def main():
else:
claimset["cdniets"] = 30

if "cdnistd" in config.keys():
claimset["cdnistd"] = config["cdnistd"]

# process override args - simple
if args.iss:
claimset["iss"] = args.iss[0]
if args.exp:
claimset["exp"] = args.exp[0]
if args.aud:
claimset["aud"] = args.aud[0]
if args.cdnistd:
claimset["cdnistd"] = args.cdnistd[0]

# process override args - complex
if args.cdnistt:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ TEST_CASE("1", "[JWSParsingTest]")

SECTION("JWT Parsing with unsupported value for cdnistd claim")
{
REQUIRE(!jwt_parsing_helper("{\"cdniets\":30,\"cdnistt\":1,\"cdnistd\":4,\"iss\":\"Content Access "
REQUIRE(!jwt_parsing_helper("{\"cdniets\":30,\"cdnistt\":1,\"cdnistd\":-2,\"iss\":\"Content Access "
"Manager\",\"cdniuc\":\"uri-regex:http://foobar.local/testDir/*\"}"));
}
fprintf(stderr, "\n");
Expand Down
2 changes: 1 addition & 1 deletion plugins/experimental/uri_signing/uri_signing.c
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
/* There has been a validated JWT found in either the cookie or url */

struct signer *signer = config_signer((struct config *)ih);
char *cookie = renew(jwt, signer->issuer, signer->jwk, signer->alg, package);
char *cookie = renew(jwt, signer->issuer, signer->jwk, signer->alg, package, strip_uri, strip_ct);
jwt_delete(jwt);

if (cpi < max_cpi) {
Expand Down