Skip to content

Commit 70da95c

Browse files
author
dsouza550
committed
Add URI Signing cdnistd Claim Implementation
Renewal tokens issued via the set-cookie response header now have an associated path attribute as documented here https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies. How that path attribure is generated is as according to spec on the latest URI Signing RFC. https://datatracker.ietf.org/doc/html/draft-ietf-cdni-uri-signing Also update associated documentation and python uri signing script to support cdnistd.
1 parent 258a413 commit 70da95c

File tree

8 files changed

+86
-16
lines changed

8 files changed

+86
-16
lines changed

plugins/experimental/uri_signing/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
URI Signing Plugin
22
==================
33

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

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

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

135135
### Unsupported Claims
136136

plugins/experimental/uri_signing/jwt.c

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ parse_jwt(json_t *raw)
5252
}
5353

5454
struct jwt *jwt = malloc(sizeof *jwt);
55-
jwt->raw = raw;
5655
jwt->iss = json_string_value(json_object_get(raw, "iss"));
5756
jwt->sub = json_string_value(json_object_get(raw, "sub"));
5857
jwt->aud = json_object_get(raw, "aud");
@@ -78,7 +77,6 @@ jwt_delete(struct jwt *jwt)
7877
}
7978

8079
json_decref(jwt->aud);
81-
json_decref(jwt->raw);
8280
free(jwt);
8381
}
8482

@@ -141,7 +139,7 @@ jwt_validate(struct jwt *jwt)
141139
return false;
142140
}
143141

144-
if (jwt->cdnistd != 0) {
142+
if (jwt->cdnistd < 0) {
145143
PluginDebug("Initial JWT Failure: unsupported value for cdnistd: %d", jwt->cdnistd);
146144
return false;
147145
}
@@ -263,7 +261,7 @@ void
263261
renew_copy_raw(json_t *new_json, const char *name, json_t *old_json)
264262
{
265263
if (old_json) {
266-
json_object_set_new(new_json, name, old_json);
264+
json_object_set(new_json, name, old_json);
267265
}
268266
}
269267

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

285283
char *
286-
renew(struct jwt *jwt, const char *iss, cjose_jwk_t *jwk, const char *alg, const char *package)
284+
renew(struct jwt *jwt, const char *iss, cjose_jwk_t *jwk, const char *alg, const char *package, const char *uri, size_t uri_ct)
287285
{
288286
char *s = NULL;
289287
if (jwt->cdnistt != 1) {
@@ -296,6 +294,65 @@ renew(struct jwt *jwt, const char *iss, cjose_jwk_t *jwk, const char *alg, const
296294
return NULL;
297295
}
298296

297+
int buff_ct = uri_ct + 2;
298+
int normal_err;
299+
char *normal_uri = (char *)TSmalloc(buff_ct);
300+
memset(normal_uri, 0, buff_ct);
301+
302+
normal_err = normalize_uri(uri, uri_ct, normal_uri, buff_ct);
303+
304+
if (normal_err) {
305+
goto fail_normal;
306+
}
307+
308+
/* Determine Path String Based on cdnistd claim */
309+
size_t normal_size = strlen(normal_uri);
310+
const char *path_start = normal_uri;
311+
const char *path_end = NULL;
312+
const char *uri_end = normal_uri + normal_size;
313+
char *path_string = NULL;
314+
size_t path_size = normal_size + 1;
315+
316+
path_string = (char *)TSmalloc(path_size);
317+
memset(path_string, 0, path_size);
318+
PluginDebug("Renewing JWT. Stripped URI: %s", uri);
319+
320+
if (jwt->cdnistd == 0) {
321+
PluginDebug("STD is 0 - Setting Cookie Path to Path=/");
322+
snprintf(path_string, 2, "%s", "/");
323+
} else {
324+
PluginDebug("STD is greater than 0. Calculating Path");
325+
int slash_count = 0;
326+
/* Search for 3rd '/' to mark start of path */
327+
while (path_start != uri_end && slash_count < 3) {
328+
++path_start;
329+
if (*path_start == '/') {
330+
slash_count++;
331+
}
332+
}
333+
if (path_start == uri_end) {
334+
PluginDebug("STD is greater than number of path segments. Cannot Renew Token!");
335+
goto fail_path;
336+
}
337+
PluginDebug("Searching through path: %s", path_start);
338+
/* Now search through path for cdnistd number of segments */
339+
slash_count = 0;
340+
path_end = path_start + 1;
341+
while (path_end != uri_end && slash_count < jwt->cdnistd) {
342+
++path_end;
343+
if (*path_end == '/') {
344+
slash_count++;
345+
}
346+
}
347+
if (path_end == uri_end) {
348+
PluginDebug("STD is greater than number of path segments. Cannot Renew Token!");
349+
goto fail_path;
350+
}
351+
path_size = path_end - path_start + 1;
352+
snprintf(path_string, path_size, "%s", path_start);
353+
PluginDebug("Setting Cookie Path to %s", path_string);
354+
}
355+
299356
json_t *new_json = json_object();
300357
renew_copy_string(new_json, "iss", iss); /* use issuer of new signing key */
301358
renew_copy_string(new_json, "sub", jwt->sub);
@@ -348,15 +405,20 @@ renew(struct jwt *jwt, const char *iss, cjose_jwk_t *jwk, const char *alg, const
348405
goto fail_jws;
349406
}
350407

351-
const char *fmt = "%s=%s";
408+
const char *fmt = "%s=%s; Path=%s";
352409
size_t s_ct;
353-
s = malloc(s_ct = (1 + snprintf(NULL, 0, fmt, package, jws_str)));
354-
snprintf(s, s_ct, fmt, package, jws_str);
410+
s = malloc(s_ct = (1 + snprintf(NULL, 0, fmt, package, jws_str, path_string)));
411+
snprintf(s, s_ct, fmt, package, jws_str, path_string);
412+
PluginDebug("Cookie returned from renew function: %s", s);
355413
fail_jws:
356414
cjose_jws_release(jws);
357415
fail_hdr:
358416
cjose_header_release(hdr);
359417
fail_json:
360418
free(pt);
419+
fail_path:
420+
TSfree(path_string);
421+
fail_normal:
422+
TSfree(normal_uri);
361423
return s;
362424
}

plugins/experimental/uri_signing/jwt.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
#include <jansson.h>
2323

2424
struct jwt {
25-
json_t *raw;
2625
const char *iss;
2726
const char *sub;
2827
json_t *aud;
@@ -45,4 +44,5 @@ bool jwt_check_aud(json_t *aud, const char *id);
4544
bool jwt_check_uri(const char *cdniuc, const char *uri);
4645

4746
struct _cjose_jwk_int;
48-
char *renew(struct jwt *jwt, const char *iss, struct _cjose_jwk_int *jwk, const char *alg, const char *package);
47+
char *renew(struct jwt *jwt, const char *iss, struct _cjose_jwk_int *jwk, const char *alg, const char *package, const char *uri,
48+
size_t uri_ct);

plugins/experimental/uri_signing/python_signer/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ The config file should be a JSON object that contains the following:
2727
- `cdniets`: Must be set if using cdnistt. Provides means of setting Expiry Times when generating subsequent tokens. It denotes
2828
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
2929
next signed JWT.
30+
- `cdnistd`: Integer value representing number of path segments that renewal token cookies should valid for. This is used when
31+
generating the path attribute of the cookies containing renewal tokens.
3032
- `keys`: A list of json objects, each one representing a key. Each key should have the following attributes:
3133
- `alg`: The Cryptographic algorithm to be used with the key.
3234
- `kid`: The key identifier

plugins/experimental/uri_signing/python_signer/example_config.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
"iss": "Example Issuer",
33
"token_lifetime": 90,
44
"aud": "Caching Software",
5-
"cdnistt": true,
6-
"cdniets": 30,
5+
"cdnistt": true,
6+
"cdnistd": 2,
7+
"cdniets": 30,
78
"keys": [
89
{
910
"alg": "HS256",

plugins/experimental/uri_signing/python_signer/uri_signer.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,13 +94,18 @@ def main():
9494
else:
9595
claimset["cdniets"] = 30
9696

97+
if "cdnistd" in config.keys():
98+
claimset["cdnistd"] = config["cdnistd"]
99+
97100
# process override args - simple
98101
if args.iss:
99102
claimset["iss"] = args.iss[0]
100103
if args.exp:
101104
claimset["exp"] = args.exp[0]
102105
if args.aud:
103106
claimset["aud"] = args.aud[0]
107+
if args.cdnistd:
108+
claimset["cdnistd"] = args.cdnistd[0]
104109

105110
# process override args - complex
106111
if args.cdnistt:

plugins/experimental/uri_signing/unit_tests/uri_signing_test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ TEST_CASE("1", "[JWSParsingTest]")
161161

162162
SECTION("JWT Parsing with unsupported value for cdnistd claim")
163163
{
164-
REQUIRE(!jwt_parsing_helper("{\"cdniets\":30,\"cdnistt\":1,\"cdnistd\":4,\"iss\":\"Content Access "
164+
REQUIRE(!jwt_parsing_helper("{\"cdniets\":30,\"cdnistt\":1,\"cdnistd\":-2,\"iss\":\"Content Access "
165165
"Manager\",\"cdniuc\":\"uri-regex:http://foobar.local/testDir/*\"}"));
166166
}
167167
fprintf(stderr, "\n");

plugins/experimental/uri_signing/uri_signing.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
328328
/* There has been a validated JWT found in either the cookie or url */
329329

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

334334
if (cpi < max_cpi) {

0 commit comments

Comments
 (0)