You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by so...@apache.org on 2018/02/22 04:56:17 UTC
[trafficserver] 01/02: Added auth_directives to uri_signing.
This is an automated email from the ASF dual-hosted git repository.
sorber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit b7d3c83f89b5996e8febcb229040add04f44614b
Author: Chris Lemmons <ch...@comcast.com>
AuthorDate: Wed Feb 21 23:10:18 2018 +0000
Added auth_directives to uri_signing.
These directives exist to indicate that specific paths should be
considered "pre-authenticated". This allows users to override specific
paths where signing should not or cannot be used.
---
plugins/experimental/uri_signing/README.md | 29 ++++++++
plugins/experimental/uri_signing/config.c | 94 +++++++++++++++++++++++++-
plugins/experimental/uri_signing/config.h | 4 ++
plugins/experimental/uri_signing/jwt.c | 6 +-
plugins/experimental/uri_signing/jwt.h | 2 +-
plugins/experimental/uri_signing/parse.c | 2 +-
plugins/experimental/uri_signing/uri_signing.c | 7 +-
7 files changed, 136 insertions(+), 8 deletions(-)
diff --git a/plugins/experimental/uri_signing/README.md b/plugins/experimental/uri_signing/README.md
index 7a90bfd..fe242d8 100644
--- a/plugins/experimental/uri_signing/README.md
+++ b/plugins/experimental/uri_signing/README.md
@@ -46,6 +46,35 @@ If there is not precisely one renewal key, the plugin will not load.
Although the `kid` and `alg` parameters are optional in JWKs generally, both
members must be present in keys used for URI signing.
+### Auth Directives
+
+It's occasionally useful to allow un-signed access to specific paths. To
+that end, the `auth_directives` parameter is supported. It can be used
+like this:
+
+ {
+ "Kabletown URI Authority": {
+ "renewal_kid": "Second Key",
+ "auth_directives": [
+ { auth: "allow", uri: "uri-regex:.*crossdomain.xml" },
+ { auth: "deny", uri: "uri-regex:https?://[^/]*/public/secret.xml.*" },
+ { auth: "allow", uri: "uri-regex:https?://[^/]*/public/.*" },
+ { auth: "allow", uri: "uri-regex:.*favicon.ico" }
+ ]
+ "keys": [
+ ⋮
+ ]
+ }
+
+Each of the `auth_directives` will be evaluated in order for each url
+that does not have a valid token. If it matches an allowed path before
+it matches a denied one, it will be served anyway. If it matches no
+`auth_directives`, it will not be served.
+
+It's worth noting that multiple issuers can provide `auth_directives`.
+Each issuer will be processed in order and any issuer can provide access to
+a path.
+
Usage
-----
diff --git a/plugins/experimental/uri_signing/config.c b/plugins/experimental/uri_signing/config.c
index 3d698c5..83083f8 100644
--- a/plugins/experimental/uri_signing/config.c
+++ b/plugins/experimental/uri_signing/config.c
@@ -19,6 +19,7 @@
#include "uri_signing.h"
#include "config.h"
#include "timing.h"
+#include "jwt.h"
#include <ts/ts.h>
@@ -31,11 +32,19 @@
#define JSONError(err) PluginError("json-err: %s:%d:%d: %s", (err).source, (err).line, (err).column, (err).text)
+#define AUTH_DENY 0
+#define AUTH_ALLOW 1
+struct auth_directive {
+ char auth;
+ char *container;
+};
+
struct config {
struct hsearch_data *issuers;
cjose_jwk_t ***jwkis;
char **issuer_names;
struct signer signer;
+ struct auth_directive *auth_directives;
};
cjose_jwk_t **
@@ -46,6 +55,7 @@ find_keys(struct config *cfg, const char *issuer)
PluginDebug("Unable to locate any keys at %p for issuer %s in %p->%p", entry, issuer, cfg, cfg->issuers);
return NULL;
}
+
int n = 0;
for (cjose_jwk_t **jwks = entry->data; *jwks; ++jwks, ++n) {
;
@@ -94,6 +104,8 @@ config_new(size_t n)
cfg->signer.jwk = NULL;
cfg->signer.alg = NULL;
+ cfg->auth_directives = NULL;
+
PluginDebug("New config object created at %p", cfg);
return cfg;
}
@@ -122,6 +134,13 @@ config_delete(struct config *cfg)
if (cfg->signer.alg) {
free(cfg->signer.alg);
}
+
+ if (cfg->auth_directives) {
+ for (struct auth_directive *ad = cfg->auth_directives; ad->container; ++ad) {
+ free(ad->container);
+ }
+ free(cfg->auth_directives);
+ }
free(cfg);
}
@@ -172,7 +191,60 @@ read_config(const char *path)
json_t *jwks;
json_object_foreach(issuer_json, json_issuer, jwks)
{
- *issuer = strdup(json_issuer);
+ *issuer = strdup(json_issuer);
+
+ json_t *ad_json = json_object_get(jwks, "auth_directives");
+ if (ad_json) {
+ PluginDebug("Loading auth_directives.");
+ size_t ad_ct = json_array_size(ad_json);
+ if (ad_ct) {
+ PluginDebug("Loading %d new auth_directives.", (int)ad_ct);
+ struct auth_directive *ad = cfg->auth_directives;
+ if (cfg->auth_directives) {
+ /* We've already got directives, so extend them. */
+ PluginDebug("Extending existing auth_directives.");
+ size_t ad_old_ct = 0;
+ while (ad->container) {
+ ++ad;
+ ++ad_old_ct;
+ }
+ cfg->auth_directives = realloc(cfg->auth_directives, (ad_ct + ad_old_ct + 1) * sizeof *cfg->auth_directives);
+ ad = cfg->auth_directives + ad_old_ct;
+ } else {
+ ad = cfg->auth_directives = malloc((ad_ct + 1) * sizeof *cfg->auth_directives);
+ }
+ json_t *ad_obj;
+ for (size_t idx = 0; (idx < ad_ct) && (ad_obj = json_array_get(ad_json, idx)); ++idx, ++ad) {
+ json_t *uri_json = json_object_get(ad_obj, "uri");
+ json_t *auth_json = json_object_get(ad_obj, "auth");
+ if (uri_json) {
+ const char *uri = json_string_value(uri_json);
+ ad->container = strdup(uri ? uri : "");
+ ad->auth = AUTH_DENY;
+ if (auth_json) {
+ const char *auth = json_string_value(auth_json);
+ if (!auth) {
+ auth = "";
+ }
+ if (!strcmp(auth, "allow")) {
+ ad->auth = AUTH_ALLOW;
+ } else if (!strcmp(auth, "deny")) {
+ ad->auth = AUTH_DENY;
+ } else {
+ PluginError("auth_directive has unknown auth parameter '%s', defaulting to deny: %s", auth, uri);
+ }
+ } else {
+ PluginError("auth_directive is missing auth parameter, defaulting to deny: %s", uri);
+ }
+ PluginDebug("Adding auth_directive %d for %s.", (int)ad->auth, ad->container);
+ }
+ }
+ ad->container = NULL;
+ }
+ } else {
+ PluginDebug("No auth_directives to load for %s.", *issuer);
+ }
+
json_t *key_ary = json_object_get(jwks, "keys");
if (!key_ary) {
PluginError("Failed to get keys member from jwk for issuer %s", *issuer);
@@ -250,3 +322,23 @@ config_signer(struct config *cfg)
}
return &cfg->signer;
}
+
+bool
+uri_matches_auth_directive(struct config *cfg, const char *uri, size_t uri_ct)
+{
+ if (!cfg || !cfg->auth_directives || !uri) {
+ return false;
+ }
+
+ char *uri_s = malloc(uri_ct + 1);
+ memcpy(uri_s, uri, uri_ct);
+ uri_s[uri_ct] = 0;
+ for (const struct auth_directive *ad = cfg->auth_directives; ad->container; ++ad) {
+ if (jwt_check_uri(ad->container, uri_s)) {
+ free(uri_s);
+ return (ad->auth == AUTH_ALLOW);
+ }
+ }
+ free(uri_s);
+ return false;
+}
diff --git a/plugins/experimental/uri_signing/config.h b/plugins/experimental/uri_signing/config.h
index cfefcfa..75a82f2 100644
--- a/plugins/experimental/uri_signing/config.h
+++ b/plugins/experimental/uri_signing/config.h
@@ -16,6 +16,9 @@
* limitations under the License.
*/
+#include <stdbool.h>
+#include <stdlib.h>
+
struct config;
struct _cjose_jwk_int;
struct signer {
@@ -29,3 +32,4 @@ void config_delete(struct config *g);
struct signer *config_signer(struct config *);
struct _cjose_jwk_int **find_keys(struct config *cfg, const char *issuer);
struct _cjose_jwk_int *find_key_by_kid(struct config *cfg, const char *issuer, const char *kid);
+bool uri_matches_auth_directive(struct config *cfg, const char *uri, size_t uri_ct);
diff --git a/plugins/experimental/uri_signing/jwt.c b/plugins/experimental/uri_signing/jwt.c
index e34a7a1..d509659 100644
--- a/plugins/experimental/uri_signing/jwt.c
+++ b/plugins/experimental/uri_signing/jwt.c
@@ -145,17 +145,17 @@ jwt_validate(struct jwt *jwt)
}
bool
-jwt_check_uri(struct jwt *jwt, const char *uri)
+jwt_check_uri(const char *sub, const char *uri)
{
static const char CONT_URI_STR[] = "uri";
static const char CONT_URI_PATTERN_STR[] = "uri-pattern";
static const char CONT_URI_REGEX_STR[] = "uri-regex";
- if (!jwt || !uri) {
+ if (!sub || !*sub || !uri) {
return false;
}
- const char *kind = jwt->sub, *container = jwt->sub;
+ const char *kind = sub, *container = sub;
while (*container && *container != ':') {
++container;
}
diff --git a/plugins/experimental/uri_signing/jwt.h b/plugins/experimental/uri_signing/jwt.h
index bfe1f5f..786e6b9 100644
--- a/plugins/experimental/uri_signing/jwt.h
+++ b/plugins/experimental/uri_signing/jwt.h
@@ -35,7 +35,7 @@ struct jwt {
struct jwt *parse_jwt(json_t *raw);
void jwt_delete(struct jwt *jwt);
bool jwt_validate(struct jwt *jwt);
-bool jwt_check_uri(struct jwt *jwt, const char *uri);
+bool jwt_check_uri(const char *sub, 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);
diff --git a/plugins/experimental/uri_signing/parse.c b/plugins/experimental/uri_signing/parse.c
index cd8d7e8..ade5706 100644
--- a/plugins/experimental/uri_signing/parse.c
+++ b/plugins/experimental/uri_signing/parse.c
@@ -184,7 +184,7 @@ validate_jws(cjose_jws_t *jws, struct config *cfg, const char *uri, size_t uri_c
}
}
- if (!jwt_check_uri(jwt, uri)) {
+ if (!jwt_check_uri(jwt->sub, uri)) {
PluginDebug("Valid key for %16p that does not match uri.", jws);
goto jwt_fail;
}
diff --git a/plugins/experimental/uri_signing/uri_signing.c b/plugins/experimental/uri_signing/uri_signing.c
index c2062a1..0d81541 100644
--- a/plugins/experimental/uri_signing/uri_signing.c
+++ b/plugins/experimental/uri_signing/uri_signing.c
@@ -153,10 +153,10 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
const int max_cpi = 20;
int64_t checkpoints[20] = {0};
int cpi = 0;
+ int url_ct = 0;
+ const char *url = NULL;
const char *package = "URISigningPackage";
- int url_ct = 0;
- const char *url = NULL;
TSMBuffer mbuf;
TSMLoc ul;
@@ -246,6 +246,9 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
PluginDebug("Spent %" PRId64 " ns uri_signing verification of %.*s.", mark_timer(&t), url_ct, url);
return TSREMAP_NO_REMAP;
fail:
+ if (uri_matches_auth_directive((struct config *)ih, url, url_ct)) {
+ return TSREMAP_NO_REMAP;
+ }
PluginDebug("Invalid JWT for %.*s", url_ct, url);
TSHttpTxnSetHttpRetStatus(txnp, TS_HTTP_STATUS_FORBIDDEN);
PluginDebug("Spent %" PRId64 " ns uri_signing verification of %.*s.", mark_timer(&t), url_ct, url);
--
To stop receiving notification emails like this one, please contact
sorber@apache.org.