This is an automated email from the ASF dual-hosted git repository.

rrm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new a0c267c  Add URI Signing cdnistd Claim Implementation (#7822)
a0c267c is described below

commit a0c267cdc88586679ccba4ec3e394f386d52f806
Author: Dylan Souza <[email protected]>
AuthorDate: Wed May 19 09:34:12 2021 -0600

    Add URI Signing cdnistd Claim Implementation (#7822)
    
    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.
    
    Co-authored-by: dsouza550 <[email protected]>
---
 plugins/experimental/uri_signing/README.md         |  4 +-
 plugins/experimental/uri_signing/jwt.c             | 78 +++++++++++++++++++---
 plugins/experimental/uri_signing/jwt.h             |  4 +-
 .../uri_signing/python_signer/README.md            |  2 +
 .../uri_signing/python_signer/example_config.json  |  5 +-
 .../uri_signing/python_signer/uri_signer.py        |  5 ++
 .../uri_signing/unit_tests/uri_signing_test.cc     |  2 +-
 plugins/experimental/uri_signing/uri_signing.c     |  2 +-
 8 files changed, 86 insertions(+), 16 deletions(-)

diff --git a/plugins/experimental/uri_signing/README.md 
b/plugins/experimental/uri_signing/README.md
index 02d7c20..cf0bb55 100644
--- a/plugins/experimental/uri_signing/README.md
+++ b/plugins/experimental/uri_signing/README.md
@@ -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.
 
@@ -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
 
diff --git a/plugins/experimental/uri_signing/jwt.c 
b/plugins/experimental/uri_signing/jwt.c
index f14ecb6..1ba45f6 100644
--- a/plugins/experimental/uri_signing/jwt.c
+++ b/plugins/experimental/uri_signing/jwt.c
@@ -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");
@@ -78,7 +77,6 @@ jwt_delete(struct jwt *jwt)
   }
 
   json_decref(jwt->aud);
-  json_decref(jwt->raw);
   free(jwt);
 }
 
@@ -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;
   }
@@ -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);
   }
 }
 
@@ -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) {
@@ -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);
@@ -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;
 }
diff --git a/plugins/experimental/uri_signing/jwt.h 
b/plugins/experimental/uri_signing/jwt.h
index 1e4d58f..6f61fc4 100644
--- a/plugins/experimental/uri_signing/jwt.h
+++ b/plugins/experimental/uri_signing/jwt.h
@@ -22,7 +22,6 @@
 #include <jansson.h>
 
 struct jwt {
-  json_t *raw;
   const char *iss;
   const char *sub;
   json_t *aud;
@@ -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);
diff --git a/plugins/experimental/uri_signing/python_signer/README.md 
b/plugins/experimental/uri_signing/python_signer/README.md
index daa41bb..3dddbfb 100644
--- a/plugins/experimental/uri_signing/python_signer/README.md
+++ b/plugins/experimental/uri_signing/python_signer/README.md
@@ -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
diff --git a/plugins/experimental/uri_signing/python_signer/example_config.json 
b/plugins/experimental/uri_signing/python_signer/example_config.json
index 4039796..103edec 100644
--- a/plugins/experimental/uri_signing/python_signer/example_config.json
+++ b/plugins/experimental/uri_signing/python_signer/example_config.json
@@ -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",
diff --git a/plugins/experimental/uri_signing/python_signer/uri_signer.py 
b/plugins/experimental/uri_signing/python_signer/uri_signer.py
index b22eed0..8045a1e 100755
--- a/plugins/experimental/uri_signing/python_signer/uri_signer.py
+++ b/plugins/experimental/uri_signing/python_signer/uri_signer.py
@@ -94,6 +94,9 @@ 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]
@@ -101,6 +104,8 @@ def main():
         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:
diff --git a/plugins/experimental/uri_signing/unit_tests/uri_signing_test.cc 
b/plugins/experimental/uri_signing/unit_tests/uri_signing_test.cc
index 20b2104..92454d6 100644
--- a/plugins/experimental/uri_signing/unit_tests/uri_signing_test.cc
+++ b/plugins/experimental/uri_signing/unit_tests/uri_signing_test.cc
@@ -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");
diff --git a/plugins/experimental/uri_signing/uri_signing.c 
b/plugins/experimental/uri_signing/uri_signing.c
index d70bd56..3f14365 100644
--- a/plugins/experimental/uri_signing/uri_signing.c
+++ b/plugins/experimental/uri_signing/uri_signing.c
@@ -328,7 +328,7 @@ check_auth:
   /* 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) {

Reply via email to