You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2017/12/20 20:49:42 UTC
[trafficserver] branch master updated: Add pparam to url_sig plugin
to make it authenticate pristine URL, eliminate sheme check,
other minor changes.
This is an automated email from the ASF dual-hosted git repository.
amc 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 5fe7236 Add pparam to url_sig plugin to make it authenticate pristine URL, eliminate sheme check, other minor changes.
5fe7236 is described below
commit 5fe7236975506514ed79d9f624c28bb84e60af60
Author: Walt Karas <wk...@yahoo-inc.com>
AuthorDate: Tue Nov 7 17:11:10 2017 +0000
Add pparam to url_sig plugin to make it authenticate pristine URL, eliminate sheme check, other minor changes.
---
doc/admin-guide/plugins/url_sig.en.rst | 10 +-
plugins/experimental/url_sig/sign.pl | 8 +-
plugins/experimental/url_sig/url_sig.c | 236 +++++++++++--------
tests/gold_tests/logging/ccid_ctid.test.py | 2 +-
tests/gold_tests/pluginTest/url_sig/run_sign.sh | 138 +++++++++++
tests/gold_tests/pluginTest/url_sig/url_sig.config | 17 ++
tests/gold_tests/pluginTest/url_sig/url_sig.gold | 24 ++
.../gold_tests/pluginTest/url_sig/url_sig.test.py | 261 +++++++++++++++++++++
8 files changed, 592 insertions(+), 104 deletions(-)
diff --git a/doc/admin-guide/plugins/url_sig.en.rst b/doc/admin-guide/plugins/url_sig.en.rst
index cabbcf1..caee1cf 100644
--- a/doc/admin-guide/plugins/url_sig.en.rst
+++ b/doc/admin-guide/plugins/url_sig.en.rst
@@ -110,12 +110,14 @@ To require a valid signature, verified by a key from the list you generated
earlier, modify your :file:`remap.config` configuration to include this plugin
for any rules you wish it to affect.
-Two parameters for each remap rule are required::
+Two parameters for each remap rule are required, and a third one is optional::
- @plugin=url_sig.so @pparam=<config file>
+ @plugin=url_sig.so @pparam=<config file> @pparam=pristineurl
The first simply enables this plugin for the rule. The second specifies the
-location of the configuration file containing your signing keys.
+location of the configuration file containing your signing keys. The third one,
+if present, causes authentication to be performed on the original (pristine) URL
+as received from the client. (The value of the parameter is not case sensitive.)
For example, if we wanted to restrict all paths under a ``/download`` directory
on our website ``foo.com`` we might have a remap line like this::
@@ -184,7 +186,7 @@ Key Index
Parts
Configures which components of the URL to use for signature verification.
- The value of this paramerts is a string of ones and zeroes, each enabling
+ The value of this parameter is a string of ones and zeroes, each enabling
or disabling the use of a URL part for signatures. The URL scheme (e.g.
``http://``) is never part of the signature. The first number of this
parameter's value indicates whether to include the FQDN, and all remaining
diff --git a/plugins/experimental/url_sig/sign.pl b/plugins/experimental/url_sig/sign.pl
index 7f2cc7b..66fa729 100755
--- a/plugins/experimental/url_sig/sign.pl
+++ b/plugins/experimental/url_sig/sign.pl
@@ -48,7 +48,9 @@ if ( !defined($key) || !defined($url) || !defined($duration) || !defined($keyind
exit(1);
}
-$url =~ s/^http:\/\///;
+my $url_prefix = $url;
+$url_prefix =~ s/^([^:]*:\/\/).*$/$1/;
+$url =~ s/^[^:]+:\/\///;
my $i = 0;
my $part_active = 0;
my $j = 0;
@@ -97,13 +99,13 @@ else {
if ($urlHasParams == -1) {
my $qstring = ( split( /\?/, $string ) )[1];
- print "curl -s -o /dev/null -v --max-redirs 0 'http://" . $url . "?" . $qstring . $digest . "'\n";
+ print "curl -s -o /dev/null -v --max-redirs 0 '" . $url_prefix . $url . "?" . $qstring . $digest . "'\n";
}
else {
my $url_noparams = ( split( /\?/, $url ) )[0];
my $qstring = ( split( /\?/, $string ) )[1];
- print "curl -s -o /dev/null -v --max-redirs 0 'http://" . $url_noparams . "?" . $qstring . $digest . "'\n";
+ print "curl -s -o /dev/null -v --max-redirs 0 '" . $url_prefix . $url_noparams . "?" . $qstring . $digest . "'\n";
}
sub help {
diff --git a/plugins/experimental/url_sig/url_sig.c b/plugins/experimental/url_sig/url_sig.c
index ad583c9..537ef35 100644
--- a/plugins/experimental/url_sig/url_sig.c
+++ b/plugins/experimental/url_sig/url_sig.c
@@ -38,6 +38,7 @@
#include <arpa/inet.h>
#include <limits.h>
#include <ctype.h>
+#include <stdint.h>
#ifdef HAVE_PCRE_PCRE_H
#include <pcre/pcre.h>
@@ -48,7 +49,7 @@
#include <ts/ts.h>
#include <ts/remap.h>
-static const char *PLUGIN_NAME = "url_sig";
+static const char PLUGIN_NAME[] = "url_sig";
struct config {
TSHttpStatus err_status;
@@ -56,6 +57,7 @@ struct config {
char keys[MAX_KEY_NUM][MAX_KEY_LEN];
pcre *regex;
pcre_extra *regex_extra;
+ int pristine_url_flag;
};
static void
@@ -83,12 +85,12 @@ TSReturnCode
TSRemapInit(TSRemapInterface *api_info, char *errbuf, int errbuf_size)
{
if (!api_info) {
- strncpy(errbuf, "[tsremap_init] - Invalid TSRemapInterface argument", (size_t)(errbuf_size - 1));
+ snprintf(errbuf, errbuf_size, "[tsremap_init] - Invalid TSRemapInterface argument");
return TS_ERROR;
}
if (api_info->tsremap_version < TSREMAP_VERSION) {
- snprintf(errbuf, errbuf_size - 1, "[TSRemapInit] - Incorrect API version %ld.%ld", api_info->tsremap_version >> 16,
+ snprintf(errbuf, errbuf_size, "[TSRemapInit] - Incorrect API version %ld.%ld", api_info->tsremap_version >> 16,
(api_info->tsremap_version & 0xffff));
return TS_ERROR;
}
@@ -104,9 +106,11 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_s
char config_filepath_buf[PATH_MAX], *config_file;
struct config *cfg;
- if (argc != 3) {
- snprintf(errbuf, errbuf_size - 1,
- "[TSRemapNewKeyInstance] - Argument count wrong (%d)... Need exactly two pparam= (config file name)", argc);
+ if ((argc < 3) || (argc > 4)) {
+ snprintf(errbuf, errbuf_size,
+ "[TSRemapNewInstance] - Argument count wrong (%d)... config file path is required first pparam, \"pristineurl\" is"
+ "optional second pparam.",
+ argc);
return TS_ERROR;
}
TSDebug(PLUGIN_NAME, "Initializing remap function of %s -> %s with config from %s", argv[0], argv[1], argv[2]);
@@ -120,7 +124,7 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_s
TSDebug(PLUGIN_NAME, "config file name: %s", config_file);
FILE *file = fopen(config_file, "r");
if (file == NULL) {
- snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Error opening file %s", config_file);
+ snprintf(errbuf, errbuf_size, "[TSRemapNewInstance] - Error opening file %s", config_file);
return TS_ERROR;
}
@@ -152,8 +156,7 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_s
*pos = '\0';
}
if (pos == NULL || strlen(value) >= MAX_KEY_LEN) {
- snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Maximum key length (%d) exceeded on line %d", MAX_KEY_LEN - 1,
- line_no);
+ snprintf(errbuf, errbuf_size, "[TSRemapNewInstance] - Maximum key length (%d) exceeded on line %d", MAX_KEY_LEN - 1, line_no);
fclose(file);
free_cfg(cfg);
return TS_ERROR;
@@ -170,12 +173,12 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_s
}
TSDebug(PLUGIN_NAME, "key number %d == %s", keynum, value);
if (keynum >= MAX_KEY_NUM || keynum < 0) {
- snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Key number (%d) >= MAX_KEY_NUM (%d) or NaN", keynum, MAX_KEY_NUM);
+ snprintf(errbuf, errbuf_size, "[TSRemapNewInstance] - Key number (%d) >= MAX_KEY_NUM (%d) or NaN", keynum, MAX_KEY_NUM);
fclose(file);
free_cfg(cfg);
return TS_ERROR;
}
- strncpy(&cfg->keys[keynum][0], value, MAX_KEY_LEN - 1);
+ snprintf(&cfg->keys[keynum][0], MAX_KEY_LEN, "%s", value);
} else if (strncmp(line, "error_url", 9) == 0) {
if (atoi(value)) {
cfg->err_status = atoi(value);
@@ -214,32 +217,40 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_s
}
}
+ fclose(file);
+
+ if (argc > 3) {
+ if (strcasecmp(argv[3], "pristineurl") == 0) {
+ cfg->pristine_url_flag = 1;
+
+ } else {
+ snprintf(errbuf, errbuf_size, "[TSRemapNewInstance] - second pparam (if present) must be pristineurl");
+ free_cfg(cfg);
+ return TS_ERROR;
+ }
+ }
+
switch (cfg->err_status) {
case TS_HTTP_STATUS_MOVED_TEMPORARILY:
if (cfg->err_url == NULL) {
- snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Invalid config, err_status == 302, but err_url == NULL");
- fclose(file);
+ snprintf(errbuf, errbuf_size, "[TSRemapNewInstance] - Invalid config, err_status == 302, but err_url == NULL");
free_cfg(cfg);
return TS_ERROR;
}
break;
case TS_HTTP_STATUS_FORBIDDEN:
if (cfg->err_url != NULL) {
- snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Invalid config, err_status == 403, but err_url != NULL");
- fclose(file);
+ snprintf(errbuf, errbuf_size, "[TSRemapNewInstance] - Invalid config, err_status == 403, but err_url != NULL");
free_cfg(cfg);
return TS_ERROR;
}
break;
default:
- snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Return code %d not supported", cfg->err_status);
- fclose(file);
+ snprintf(errbuf, errbuf_size, "[TSRemapNewInstance] - Return code %d not supported", cfg->err_status);
free_cfg(cfg);
return TS_ERROR;
}
- fclose(file);
-
*ih = (void *)cfg;
return TS_SUCCESS;
}
@@ -251,7 +262,7 @@ TSRemapDeleteInstance(void *ih)
}
static void
-err_log(char *url, char *msg)
+err_log(const char *url, const char *msg)
{
if (msg && url) {
TSDebug(PLUGIN_NAME, "[URL=%s]: %s", url, msg);
@@ -264,18 +275,18 @@ err_log(char *url, char *msg)
// See the README. All Signing parameters must be concatenated to the end
// of the url and any application query parameters.
static char *
-getAppQueryString(char *query_string, unsigned int query_length)
+getAppQueryString(const char *query_string, int query_length)
{
int done = 0;
char *p;
- char buf[MAX_QUERY_LEN];
+ char buf[MAX_QUERY_LEN + 1];
- if (query_length >= sizeof(buf)) {
+ if (query_length > MAX_QUERY_LEN) {
TSDebug(PLUGIN_NAME, "Cannot process the query string as the length exceeds %d bytes", MAX_QUERY_LEN);
return NULL;
}
- memset(buf, 0, MAX_QUERY_LEN);
- strncpy(buf, query_string, min(query_length, sizeof(buf) - 1));
+ memset(buf, 0, sizeof(buf));
+ strncpy(buf, query_string, query_length);
p = buf;
TSDebug(PLUGIN_NAME, "query_string: %s, query_length: %d", query_string, query_length);
@@ -289,7 +300,7 @@ getAppQueryString(char *query_string, unsigned int query_length)
case 'P':
case 'S':
done = 1;
- if (*(p - 1) == '&') {
+ if ((p > buf) && (*(p - 1) == '&')) {
*(p - 1) = '\0';
} else {
(*p = '\0');
@@ -317,13 +328,13 @@ getAppQueryString(char *query_string, unsigned int query_length)
TSRemapStatus
TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
{
- struct config *cfg;
- cfg = (struct config *)ih;
+ const struct config *cfg = (const struct config *)ih;
- int url_len = 0;
- time_t expiration = 0;
- int algorithm = -1;
- int keyindex = -1;
+ int url_len = 0;
+ int current_url_len = 0;
+ uint64_t expiration = 0;
+ int algorithm = -1;
+ int keyindex = -1;
int cmp_res;
int rval;
unsigned int i = 0;
@@ -331,7 +342,8 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
unsigned int sig_len = 0;
/* all strings are locally allocated except url... about 25k per instance */
- char *url;
+ char *const current_url = TSUrlStringGet(rri->requestBufp, rri->requestUrl, ¤t_url_len);
+ const char *url = current_url;
char signed_part[8192] = {'\0'}; // this initializes the whole array and is needed
char urltokstr[8192] = {'\0'};
char client_ip[CIP_STRLEN] = {'\0'};
@@ -339,33 +351,42 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
unsigned char sig[MAX_SIG_SIZE + 1];
char sig_string[2 * MAX_SIG_SIZE + 1];
- /* these are just pointers into other allocations */
- char *signature = NULL;
- char *parts = NULL;
- char *part = NULL;
- char *p = NULL, *pp = NULL;
- char *query = NULL, *app_qry = NULL;
-
int retval, sockfd;
socklen_t peer_len;
struct sockaddr_in peer;
- url = TSUrlStringGet(rri->requestBufp, rri->requestUrl, &url_len);
-
- if (url_len >= MAX_REQ_LEN - 1) {
- err_log(url, "URL string too long");
+ if (current_url_len >= MAX_REQ_LEN - 1) {
+ err_log(current_url, "URL string too long.");
goto deny;
}
+ if (cfg->pristine_url_flag) {
+ TSMBuffer mbuf;
+ TSMLoc ul;
+ TSReturnCode rc = TSHttpTxnPristineUrlGet(txnp, &mbuf, &ul);
+ if (rc != TS_SUCCESS) {
+ TSError("[url_sig] Failed call to TSHttpTxnPristineUrlGet()");
+ goto deny;
+ }
+ url = TSUrlStringGet(mbuf, ul, &url_len);
+ if (url_len >= MAX_REQ_LEN - 1) {
+ err_log(url, "Pristine URL string too long.");
+ goto deny;
+ }
+
+ } else {
+ url_len = current_url_len;
+ }
+
TSDebug(PLUGIN_NAME, "%s", url);
- query = strstr(url, "?");
+ const char *query = strchr(url, '?');
if (cfg->regex) {
int offset = 0, options = 0;
int ovector[30];
- int len = url_len;
- char *anchor = strstr(url, "#");
+ int len = url_len;
+ const char *anchor = strchr(url, '#');
if (query && !anchor) {
len -= (query - url);
} else if (anchor && !query) {
@@ -383,26 +404,26 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
goto deny;
}
- if (strncmp(url, "http://", strlen("http://")) != 0) {
- err_log(url, "Invalid URL scheme - only http supported");
- goto deny;
- }
-
/* first, parse the query string */
query++; /* get rid of the ? */
TSDebug(PLUGIN_NAME, "Query string is:%s", query);
// Client IP - this one is optional
- p = strstr(query, CIP_QSTRING "=");
- if (p != NULL) {
- p += strlen(CIP_QSTRING + 1);
- pp = strstr(p, "&");
- if ((pp - p) > CIP_STRLEN - 1 || (pp - p) < 4) {
+ const char *cp = strstr(query, CIP_QSTRING "=");
+ if (cp != NULL) {
+ int len_cip_qstring = strlen(CIP_QSTRING);
+ cp += len_cip_qstring - 1;
+ const char *cpp = strchr(cp, '&');
+ if (!cpp) {
+ err_log(url, "All required values after IP address string missing");
+ goto deny;
+ }
+ if (!cpp || (cpp - cp) > CIP_STRLEN - 1 || (cpp - cp) < 4) {
err_log(url, "IP address string too long or short");
goto deny;
}
- strncpy(client_ip, p + strlen(CIP_QSTRING) + 1, min((pp - p - (strlen(CIP_QSTRING) + 1)), sizeof(client_ip) - 1));
- client_ip[pp - p - (strlen(CIP_QSTRING) + 1)] = '\0';
+ memcpy(client_ip, cp + len_cip_qstring + 1, (cpp - cp - (len_cip_qstring + 1)));
+ client_ip[cpp - cp - (len_cip_qstring + 1)] = '\0';
TSDebug(PLUGIN_NAME, "CIP: -%s-", client_ip);
retval = TSHttpTxnClientFdGet(txnp, &sockfd);
if (retval != TS_SUCCESS) {
@@ -422,24 +443,23 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
}
}
// Expiration
- p = strstr(query, EXP_QSTRING "=");
- if (p != NULL) {
- p += strlen(EXP_QSTRING) + 1;
- expiration = atoi(p);
- if (expiration == 0 || expiration < time(NULL)) {
+ cp = strstr(query, EXP_QSTRING "=");
+ if (cp != NULL) {
+ cp += strlen(EXP_QSTRING) + 1;
+ if (sscanf(cp, "%" SCNu64, &expiration) != 1 || (time_t)expiration < time(NULL)) {
err_log(url, "Invalid expiration, or expired");
goto deny;
}
- TSDebug(PLUGIN_NAME, "Exp: %d", (int)expiration);
+ TSDebug(PLUGIN_NAME, "Exp: %" PRIu64, expiration);
} else {
err_log(url, "Expiration query string not found");
goto deny;
}
// Algorithm
- p = strstr(query, ALG_QSTRING "=");
- if (p != NULL) {
- p += strlen(ALG_QSTRING) + 1;
- algorithm = atoi(p);
+ cp = strstr(query, ALG_QSTRING "=");
+ if (cp != NULL) {
+ cp += strlen(ALG_QSTRING) + 1;
+ algorithm = atoi(cp);
// The check for a valid algorithm is later.
TSDebug(PLUGIN_NAME, "Algorithm: %d", algorithm);
} else {
@@ -447,10 +467,10 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
goto deny;
}
// Key index
- p = strstr(query, KIN_QSTRING "=");
- if (p != NULL) {
- p += strlen(KIN_QSTRING) + 1;
- keyindex = atoi(p);
+ cp = strstr(query, KIN_QSTRING "=");
+ if (cp != NULL) {
+ cp += strlen(KIN_QSTRING) + 1;
+ keyindex = atoi(cp);
if (keyindex < 0 || keyindex >= MAX_KEY_NUM || 0 == cfg->keys[keyindex][0]) {
err_log(url, "Invalid key index");
goto deny;
@@ -461,21 +481,27 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
goto deny;
}
// Parts
- p = strstr(query, PAR_QSTRING "=");
- if (p != NULL) {
- p += strlen(PAR_QSTRING) + 1;
- parts = p; // NOTE parts is not NULL terminated it is terminated by "&" of next param
- p = strstr(parts, "&");
- TSDebug(PLUGIN_NAME, "Parts: %.*s", (int)(p - parts), parts);
+ const char *parts = NULL;
+ cp = strstr(query, PAR_QSTRING "=");
+ if (cp != NULL) {
+ cp += strlen(PAR_QSTRING) + 1;
+ parts = cp; // NOTE parts is not NULL terminated it is terminated by "&" of next param
+ cp = strchr(parts, '&');
+ if (cp) {
+ TSDebug(PLUGIN_NAME, "Parts: %.*s", (int)(cp - parts), parts);
+ } else {
+ TSDebug(PLUGIN_NAME, "Parts: %s", parts);
+ }
} else {
err_log(url, "PartsSigned query string not found");
goto deny;
}
// And finally, the sig (has to be last)
- p = strstr(query, SIG_QSTRING "=");
- if (p != NULL) {
- p += strlen(SIG_QSTRING) + 1;
- signature = p; // NOTE sig is not NULL terminated, it has to be 20 chars
+ const char *signature = NULL;
+ cp = strstr(query, SIG_QSTRING "=");
+ if (cp != NULL) {
+ cp += strlen(SIG_QSTRING) + 1;
+ signature = cp;
if ((algorithm == USIG_HMAC_SHA1 && strlen(signature) < SHA1_SIG_SIZE) ||
(algorithm == USIG_HMAC_MD5 && strlen(signature) < MD5_SIG_SIZE)) {
err_log(url, "Signature query string too short (< 20)");
@@ -487,13 +513,20 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
}
/* have the query string, and parameters passed initial checks */
- TSDebug(PLUGIN_NAME, "Found all needed parameters: C=%s E=%d A=%d K=%d P=%s S=%s", client_ip, (int)expiration, algorithm,
+ TSDebug(PLUGIN_NAME, "Found all needed parameters: C=%s E=%" PRIu64 " A=%d K=%d P=%s S=%s", client_ip, expiration, algorithm,
keyindex, parts, signature);
/* find the string that was signed - cycle through the parts letters, adding the part of the fqdn/path if it is 1 */
- p = strstr(url, "?");
- memcpy(urltokstr, &url[strlen("http://")], p - url - strlen("http://"));
- part = strtok_r(urltokstr, "/", &p);
+ cp = strchr(url, '?');
+ // Skip scheme and initial forward slashes.
+ const char *skip = strchr(url, ':');
+ if (!skip || skip[1] != '/' || skip[2] != '/') {
+ goto deny;
+ }
+ skip += 3;
+ memcpy(urltokstr, skip, cp - skip);
+ char *strtok_r_p;
+ const char *part = strtok_r(urltokstr, "/", &strtok_r_p);
while (part != NULL) {
if (parts[j] == '1') {
strncat(signed_part, part, sizeof(signed_part) - strlen(signed_part) - 1);
@@ -503,12 +536,12 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
parts[j + 1] == '1') { // This remembers the last part, meaning, if there are no more valid letters in parts
j++; // will keep repeating the value of the last one
}
- part = strtok_r(NULL, "/", &p);
+ part = strtok_r(NULL, "/", &strtok_r_p);
}
signed_part[strlen(signed_part) - 1] = '?'; // chop off the last /, replace with '?'
- p = strstr(query, SIG_QSTRING "=");
- strncat(signed_part, query, min((p - query) + strlen(SIG_QSTRING) + 1, sizeof(signed_part) - strlen(signed_part) - 1));
+ cp = strstr(query, SIG_QSTRING "=");
+ strncat(signed_part, query, (cp - query) + strlen(SIG_QSTRING) + 1);
TSDebug(PLUGIN_NAME, "Signed string=\"%s\"", signed_part);
@@ -556,7 +589,10 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
/* ********* Deny ********* */
deny:
- TSfree(url);
+ if (url != current_url) {
+ TSfree((void *)url);
+ }
+ TSfree((void *)current_url);
switch (cfg->err_status) {
case TS_HTTP_STATUS_MOVED_TEMPORARILY:
@@ -570,7 +606,7 @@ deny:
rri->redirect = 1;
break;
default:
- TSHttpTxnErrorBodySet(txnp, TSstrdup("Authorization Denied"), strlen("Authorization Denied") - 1, TSstrdup("text/plain"));
+ TSHttpTxnErrorBodySet(txnp, TSstrdup("Authorization Denied"), sizeof("Authorization Denied") - 1, TSstrdup("text/plain"));
break;
}
/* Always set the return status */
@@ -580,15 +616,23 @@ deny:
/* ********* Allow ********* */
allow:
- if (query != NULL) {
- app_qry = getAppQueryString(query, strlen(query));
+ if (url != current_url) {
+ TSfree((void *)url);
+ }
+
+ const char *current_query = strchr(current_url, '?');
+ const char *app_qry = NULL;
+ if (current_query != NULL) {
+ current_query++;
+ app_qry = getAppQueryString(current_query, strlen(current_query));
}
- TSfree(url);
+ TSfree((void *)current_url);
+
/* drop the query string so we can cache-hit */
if (app_qry != NULL) {
rval = TSUrlHttpQuerySet(rri->requestBufp, rri->requestUrl, app_qry, strlen(app_qry));
- TSfree(app_qry);
+ TSfree((void *)app_qry);
} else {
rval = TSUrlHttpQuerySet(rri->requestBufp, rri->requestUrl, NULL, 0);
}
diff --git a/tests/gold_tests/logging/ccid_ctid.test.py b/tests/gold_tests/logging/ccid_ctid.test.py
index ab783e1..5236313 100644
--- a/tests/gold_tests/logging/ccid_ctid.test.py
+++ b/tests/gold_tests/logging/ccid_ctid.test.py
@@ -41,7 +41,7 @@ ts.addSSLfile("../remap/ssl/server.key")
ts.Variables.ssl_port = 4443
ts.Disk.records_config.update({
- # 'proxy.config.diags.debug.enabled': '1',
+ # 'proxy.config.diags.debug.enabled': 1,
'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir),
'proxy.config.ssl.server.private_key.path': '{0}'.format(ts.Variables.SSLDir),
'proxy.config.http.server_ports': 'ipv4:{0} ipv4:{1}:proto=http2;http:ssl'.format(ts.Variables.port, ts.Variables.ssl_port)
diff --git a/tests/gold_tests/pluginTest/url_sig/run_sign.sh b/tests/gold_tests/pluginTest/url_sig/run_sign.sh
new file mode 100755
index 0000000..fcc404c
--- /dev/null
+++ b/tests/gold_tests/pluginTest/url_sig/run_sign.sh
@@ -0,0 +1,138 @@
+# Script to run sign.pl script. Single parameter is number 1 or greater selecting a set of script parameters.
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Generate one or more sets of arguments for the sign.pl perl script.
+#
+cmd_args ()
+{
+if [[ "$1" = "" ]] ; then
+ SELECT=1
+else
+ SELECT="$1"
+fi
+
+FOREVER="$((60 * 60 * 24 * 365 * 1000))"
+
+case "$SELECT" in
+1)
+ echo "--url http://one.two.three/foo/abcde/qrstuvwxyz"
+ echo "--useparts 1"
+ echo "--algorithm 1"
+ echo "--duration $FOREVER"
+ echo "--keyindex 7"
+ echo "--key dqsgopTSM_doT6iAysasQVUKaPykyb6e"
+ ;;
+2)
+ echo "--client 127.0.0.1"
+ echo "--url http://four.five.six/foo/abcde/qrstuvwxyz"
+ echo "--useparts 1"
+ echo "--algorithm 1"
+ echo "--duration $FOREVER"
+ echo "--keyindex 15"
+ echo "--key 9MuXIiZ70HPi_qhqfSgdu9oJHpcj9yaO"
+ ;;
+3)
+ echo "--url http://seven.eight.nine/foo/abcde/qrstuvwxyz"
+ echo "--useparts 1"
+ echo "--algorithm 2"
+ echo "--duration $FOREVER"
+ echo "--keyindex 0"
+ echo "--key hV3wqyq1QxJeF76JkzHf93tuLYv_abw5"
+ ;;
+4)
+ echo "--client 127.0.0.1"
+ echo "--url http://seven.eight.nine/foo/abcde/qrstuvwxyz"
+ echo "--useparts 010"
+ echo "--algorithm 2"
+ echo "--duration $FOREVER"
+ echo "--keyindex 13"
+ echo "--key CGRDwMO96_vRjFCfks6oxkeV7IdTnA6f"
+ ;;
+5)
+ echo "--client 127.0.0.1"
+ echo "--url http://seven.eight.nine/foo/abcde/qrstuvwxyz"
+ echo "--useparts 101"
+ echo "--algorithm 2"
+ echo "--duration $FOREVER"
+ echo "--keyindex 13"
+ echo "--key CGRDwMO96_vRjFCfks6oxkeV7IdTnA6f"
+ ;;
+*h*)
+ ;;
+*)
+ echo "run_sign.sh: bad seletion parameter" 1>&2
+ exit 1
+ ;;
+esac
+}
+
+# Find the path to the sign.pl script in the url_sig (source) directory.
+#
+find_cmd ()
+{
+local D T='..'
+while [[ ! -d $T/.git ]]
+do
+ if [[ ! -d $T/.. ]] ; then
+ echo "Working directory not in a git repo" 1>&2
+ exit 1
+ fi
+ T="$T/.."
+done
+
+for D in $( find $T -name url_sig -type d )
+do
+ if [[ -x $D/sign.pl ]] ; then
+ echo "$D/sign.pl"
+ return 0
+ fi
+done
+
+echo "cannot find sign.pl script" 1>&2
+exit 1
+}
+
+FOUND=N
+echo "$PERL5LIB" | tr ':' ' ' | while read D
+do
+ if [[ -f $D/Digest/HMAC_MD5.pm ]] ; then
+ FOUND=Y
+ break
+ fi
+done
+
+if [[ $FOUND = N ]] ; then
+ P=$( find / 2>/dev/null | grep -F Digest/HMAC_MD5.pm | head -1 )
+ if [[ ! -f $P ]] ; then
+ echo "Cannot find HMAC_MD5.pm" 1>&2
+ exit 1
+ fi
+ export PERL5LIB="$PERL5LIB:$( dirname $( dirname $P ) )"
+fi
+
+CMD=$( find_cmd )
+if [[ "$?" != 0 ]] ; then
+ exit 1
+fi
+
+ARGS=$( cmd_args "$1" )
+if [[ "$?" != 0 ]] ; then
+ exit 1
+fi
+
+$CMD $ARGS | tr ' ' '\n' | tail -1
diff --git a/tests/gold_tests/pluginTest/url_sig/url_sig.config b/tests/gold_tests/pluginTest/url_sig/url_sig.config
new file mode 100644
index 0000000..7c10a6b
--- /dev/null
+++ b/tests/gold_tests/pluginTest/url_sig/url_sig.config
@@ -0,0 +1,17 @@
+key0 = hV3wqyq1QxJeF76JkzHf93tuLYv_abw5
+key1 = nIpyXbVqPFVN7y8yMlfgFBLnOqDSufMy
+key2 = 4UED1ELmHkEcXrS_7yEYPKtgUZdGWaP2
+key3 = mv2vPGJpq2iFDbiV3dJG4ZqCAzRTIpTD
+key4 = 2cnob1tuGEiYhwJLYRLa5bfyuZH1zI0S
+key5 = poC7zK9IrDl3rljvuZ0bbMP3e5f0woKt
+key6 = _k8diypYMebSCEEjYNszZbG906JZI6Bx
+key7 = dqsgopTSM_doT6iAysasQVUKaPykyb6e
+key8 = AzM3mhTDEkyJjyqQctv0NVxCL3FmXDzW
+key9 = iRHQE9ucS44oAhdXmM148wMTJAO4XAVV
+key10 = b1OMb39dGhMSg_wArQnvqGIBgQGFjnNl
+key11 = YpA8qBkvohdamogQ4zTuoPw50PbezdL0
+key12 = 4Q4OCnY_gmcDuw5756Wk1XG7PEi24g1_
+key13 = CGRDwMO96_vRjFCfks6oxkeV7IdTnA6f
+key14 = sXTWfNyHkN2SJ9eKifetPzfcg0_rNhXM
+key15 = 9MuXIiZ70HPi_qhqfSgdu9oJHpcj9yaO
+error_url = 403
diff --git a/tests/gold_tests/pluginTest/url_sig/url_sig.gold b/tests/gold_tests/pluginTest/url_sig/url_sig.gold
new file mode 100644
index 0000000..35f62da
--- /dev/null
+++ b/tests/gold_tests/pluginTest/url_sig/url_sig.gold
@@ -0,0 +1,24 @@
+< HTTP/1.1 403 Forbidden
+Authorization Denied* Trying 127.0.0.1...
+< HTTP/1.1 403 Forbidden
+Authorization Denied* Trying 127.0.0.1...
+< HTTP/1.1 403 Forbidden
+Authorization Denied* Trying 127.0.0.1...
+< HTTP/1.1 403 Forbidden
+Authorization Denied* Trying 127.0.0.1...
+< HTTP/1.1 403 Forbidden
+Authorization Denied* Trying 127.0.0.1...
+< HTTP/1.1 403 Forbidden
+Authorization Denied* Trying 127.0.0.1...
+< HTTP/1.1 403 Forbidden
+Authorization Denied* Trying 127.0.0.1...
+< HTTP/1.1 403 Forbidden
+Authorization Denied* Trying 127.0.0.1...
+< HTTP/1.1 403 Forbidden
+Authorization Denied* Trying 127.0.0.1...
+< HTTP/1.1 200 OK
+< HTTP/1.1 200 OK
+< HTTP/1.1 200 OK
+< HTTP/1.1 200 OK
+< HTTP/1.1 200 OK
+< HTTP/1.1 200 OK
diff --git a/tests/gold_tests/pluginTest/url_sig/url_sig.test.py b/tests/gold_tests/pluginTest/url_sig/url_sig.test.py
new file mode 100644
index 0000000..78b0228
--- /dev/null
+++ b/tests/gold_tests/pluginTest/url_sig/url_sig.test.py
@@ -0,0 +1,261 @@
+'''
+'''
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import subprocess
+Test.Summary = '''
+Test url_sig plugin
+'''
+
+Test.SkipUnless(
+ Condition.HasATSFeature('TS_USE_TLS_ALPN'),
+)
+
+# Skip if plugins not present.
+Test.SkipUnless(Condition.PluginExists('url_sig.so'))
+Test.SkipUnless(Condition.PluginExists('balancer.so'))
+
+# Set up to check the output after the tests have run.
+#
+url_sig_log_id = Test.Disk.File("url_sig_short.log")
+url_sig_log_id.Content = "url_sig.gold"
+
+server = Test.MakeOriginServer("server")
+
+request_header = {
+ "headers": "GET /foo/abcde/qrstuvwxyz HTTP/1.1\r\nHost: just.any.thing\r\n\r\n", "timestamp": "1469733493.993", "body": ""
+}
+# expected response from the origin server
+response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": ""}
+# add response to the server dictionary
+server.addResponse("sessionfile.log", request_header, response_header)
+
+# Define default ATS
+ts = Test.MakeATSProcess("ts", select_ports=False)
+
+ts.addSSLfile("../../remap/ssl/server.pem")
+ts.addSSLfile("../../remap/ssl/server.key")
+
+ts.Variables.ssl_port = 4443
+
+ts.Disk.records_config.update({
+ # 'proxy.config.diags.debug.enabled': 1,
+ # 'proxy.config.diags.debug.tags': 'http|url_sig',
+ 'proxy.config.http.cache.http': 0, # Make sure each request is forwarded to the origin server.
+ 'proxy.config.proxy_name': 'Poxy_Proxy', # This will be the server name.
+ 'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir),
+ 'proxy.config.ssl.server.private_key.path': '{0}'.format(ts.Variables.SSLDir),
+ 'proxy.config.http.server_ports': (
+ 'ipv4:{0} ipv4:{1}:proto=http:ssl'.format(ts.Variables.port, ts.Variables.ssl_port))
+})
+
+ts.Disk.ssl_multicert_config.AddLine(
+ 'dest_ip=* ssl_cert_name=server.pem ssl_key_name=server.key'
+)
+
+# Use unchanged incoming URL.
+#
+ts.Disk.remap_config.AddLine(
+ 'map http://one.two.three/ http://127.0.0.1:{}/'.format(server.Variables.Port) +
+ ' @plugin=url_sig.so @pparam={}/url_sig.config'.format(Test.TestDirectory)
+)
+
+# Use unchanged incoming HTTPS URL.
+#
+ts.Disk.remap_config.AddLine(
+ 'map https://one.two.three/ http://127.0.0.1:{}/'.format(server.Variables.Port) +
+ ' @plugin=url_sig.so @pparam={}/url_sig.config'.format(Test.TestDirectory)
+)
+
+# Use pristine URL, incoming URL unchanged.
+#
+ts.Disk.remap_config.AddLine(
+ 'map http://four.five.six/ http://127.0.0.1:{}/'.format(server.Variables.Port) +
+ ' @plugin=url_sig.so @pparam={}/url_sig.config @pparam=pristineurl'.format(Test.TestDirectory)
+)
+
+# Use pristine URL, incoming URL changed.
+#
+ts.Disk.remap_config.AddLine(
+ 'map http://seven.eight.nine/ http://dummy' +
+ ' @plugin=balancer.so @pparam=--policy=hash,url @pparam=127.0.0.1:{}'.format(server.Variables.Port) +
+ ' @plugin=url_sig.so @pparam={}/url_sig.config @pparam=PristineUrl'.format(Test.TestDirectory)
+)
+
+# Ask the OS if the port is ready for connect()
+#
+def CheckPort(Port):
+ return lambda: 0 == subprocess.call('netstat --listen --tcp -n | grep -q :{}'.format(Port), shell=True)
+
+# Validation failure tests.
+
+LogTee = " 2>&1 | tee -a {}/url_sig_long.log".format(Test.RunDirectory)
+
+# Bad client / MD5 / P=101 / URL pristine / URL altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.StartBefore(ts, ready=CheckPort(ts.Variables.ssl_port))
+tr.Processes.Default.StartBefore(server, ready=CheckPort(server.Variables.Port))
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+ "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+ "foo/abcde/qrstuvwxyz?C=127.0.0.2&E=33046620008&A=2&K=13&P=101&S=d1f352d4f1d931ad2f441013402d93f8'" +
+ LogTee
+)
+
+# With client / MD5 / P=010 / URL pristine / URL altered -- Expired.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+ "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+ "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=1&A=2&K=13&P=010&S=f237aad1fa010234d7bf8108a0e36387'" +
+ LogTee
+)
+
+# With client / No algorithm / P=101 / URL pristine / URL altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+ "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+ "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046620008&K=13&P=101&S=d1f352d4f1d931ad2f441013402d93f8'" +
+ LogTee
+)
+
+# With client / Bad algorithm / P=101 / URL pristine / URL altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+ "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+ "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046620008&A=3&K=13&P=101&S=d1f352d4f1d931ad2f441013402d93f8'" +
+ LogTee
+)
+
+# With client / MD5 / No parts / URL pristine / URL altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+ "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+ "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046620008&A=2&K=13&S=d1f352d4f1d931ad2f441013402d93f8'" +
+ LogTee
+)
+
+# With client / MD5 / P=10 (bad) / URL pristine / URL altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+ "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+ "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046620008&A=2&K=13&P=10&S=d1f352d4f1d931ad2f441013402d93f8'" +
+ LogTee
+)
+
+# With client / MD5 / P=101 / URL pristine / URL altered -- No signature.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+ "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+ "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046620008&A=2&K=13&P=101'" +
+ LogTee
+)
+
+# With client / MD5 / P=101 / URL pristine / URL altered -- Bad signature.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+ "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+ "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046620008&A=2&K=13&P=101&S=d1f452d4f1d931ad2f441013402d93f8'" +
+ LogTee
+)
+
+# With client / MD5 / P=101 / URL pristine / URL altered -- Spurious &.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+ "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+ "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046620008&A=2&&K=13&P=101&S=d1f352d4f1d931ad2f441013402d93f8#'" +
+ LogTee
+)
+
+# Success tests.
+
+# No client / SHA1 / P=1 / URL not pristine / URL not altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+ "curl --verbose --proxy http://127.0.0.1:{} 'http://one.two.three/".format(ts.Variables.port) +
+ "foo/abcde/qrstuvwxyz?E=33046618506&A=1&K=7&P=1&S=acae22b0e1ba6ea6fbb5d26018dbf152558e98cb'" +
+ LogTee
+)
+
+# With client / SHA1 / P=1 / URL pristine / URL not altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+ "curl --verbose --proxy http://127.0.0.1:{} 'http://four.five.six/".format(ts.Variables.port) +
+ "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046618556&A=1&K=15&P=1&S=f4103561a23adab7723a89b9831d77e0afb61d92'" +
+ LogTee
+)
+
+# No client / MD5 / P=1 / URL pristine / URL altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+ "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+ "foo/abcde/qrstuvwxyz?E=33046618586&A=2&K=0&P=1&S=0364efa28afe345544596705b92d20ac'" +
+ LogTee
+)
+
+# With client / MD5 / P=010 / URL pristine / URL altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+ "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+ "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046619717&A=2&K=13&P=010&S=f237aad1fa010234d7bf8108a0e36387'" +
+ LogTee
+)
+
+# With client / MD5 / P=101 / URL pristine / URL altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+ "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+ "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046620008&A=2&K=13&P=101&S=d1f352d4f1d931ad2f441013402d93f8'" +
+ LogTee
+)
+
+# No client / SHA1 / P=1 / URL not pristine / URL not altered -- HTTPS.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+ "curl --verbose --http1.1 --insecure --header 'Host: one.two.three' 'https://127.0.0.1:{}/".format(ts.Variables.ssl_port) +
+ "foo/abcde/qrstuvwxyz?E=33046618506&A=1&K=7&P=1&S=acae22b0e1ba6ea6fbb5d26018dbf152558e98cb'" +
+ LogTee + " ; grep -F -e '< HTTP' -e Authorization {0}/url_sig_long.log > {0}/url_sig_short.log ".format(ts.RunDirectory)
+)
--
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].