Repository: trafficserver
Updated Branches:
  refs/heads/master e70d480da -> 666001cfa


Add new secure link example plugin

Add an example plugin demonstrating one method of authorizing URL
access based on a shared secret.

This closes #27.


Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/666001cf
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/666001cf
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/666001cf

Branch: refs/heads/master
Commit: 666001cfa2eed84c9b571bac5194060637aadcfa
Parents: e70d480
Author: Pavel Yatsukhnenko <[email protected]>
Authored: Tue Feb 25 16:19:26 2014 -0800
Committer: James Peach <[email protected]>
Committed: Tue Feb 25 16:21:36 2014 -0800

----------------------------------------------------------------------
 example/Makefile.am               |   2 +
 example/secure-link/readme.txt    |  19 ++++
 example/secure-link/secure-link.c | 192 +++++++++++++++++++++++++++++++++
 3 files changed, 213 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/666001cf/example/Makefile.am
----------------------------------------------------------------------
diff --git a/example/Makefile.am b/example/Makefile.am
index b79bbee..c459991 100644
--- a/example/Makefile.am
+++ b/example/Makefile.am
@@ -37,6 +37,7 @@ plugins = \
   remap.la \
   replace-header.la \
   response-header-1.la \
+  secure-link.la \
   server-transform.la \
   thread-1.la \
   version.la
@@ -68,6 +69,7 @@ server_transform_la_SOURCES = 
server-transform/server-transform.c
 thread_1_la_SOURCES = thread-1/thread-1.c
 psi_la_SOURCES = thread-pool/psi.c thread-pool/thread.c
 version_la_SOURCES = version/version.c
+secure_link_la_SOURCES = secure-link/secure-link.c
 
 # The following examples do not build:
 #

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/666001cf/example/secure-link/readme.txt
----------------------------------------------------------------------
diff --git a/example/secure-link/readme.txt b/example/secure-link/readme.txt
new file mode 100644
index 0000000..e79dab0
--- /dev/null
+++ b/example/secure-link/readme.txt
@@ -0,0 +1,19 @@
+The secure-link plugin allows Traffic Server to protect resources by verifying
+checksum value passed in the request and computed for the request.
+Checksum is the md5 digest of concatenation of several params:
+  [secret] + [Client IP Address] + [HTTP Query Path] + [expire]
+The plugin can be used in the plugins chain in remap.config and it expects two 
@pparams:
+1. secret - the word, which is known only to the application that generated 
link
+   and Traffic Server.
+2. policy - if set to 'strict' and checksums not match or expire value
+   lower than current time the client will receive 403 Frobidden response.
+   Used for debugging.
+
+For example request
+  
http://foo.example.com/d41d8cd98f00b204e9800998ecf8427e/52b9ed11/path/to/secret/document.pdf
+may be remapped to
+  
http://bar.example.com/path/to/secret/document.pdf?st=d41d8cd98f00b204e9800998ecf8427e&ex=52b9ed11
+and then passed to secure-link plugin, which compare 'st' and 'ex' GET params
+with computed md5 checksum and current time respectively.
+If check passed the plugin removes 'st' and 'ex' GET params and passes down
+the processing chain;

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/666001cf/example/secure-link/secure-link.c
----------------------------------------------------------------------
diff --git a/example/secure-link/secure-link.c 
b/example/secure-link/secure-link.c
new file mode 100644
index 0000000..67a75b3
--- /dev/null
+++ b/example/secure-link/secure-link.c
@@ -0,0 +1,192 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  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.
+ */
+
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <openssl/md5.h>
+
+#include "ts/ts.h"
+#include "ts/remap.h"
+
+#define PLUGIN_NAME "secure_link"
+
+typedef struct {
+  char *secret;
+  uint8_t strict;
+} secure_link_info;
+
+TSRemapStatus
+TSRemapDoRemap(void *ih, TSHttpTxn rh, TSRemapRequestInfo* rri)
+{
+  int i, len;
+  time_t t, e;
+  MD5_CTX ctx;
+  struct sockaddr_in *in;
+  const char *qh, *ph, *ip;
+  char *s, *ptr, *val, hash[32];
+  unsigned char md[MD5_DIGEST_LENGTH];
+  secure_link_info *sli = (secure_link_info *)ih;
+  char *token = NULL, *expire = NULL, *path = NULL;
+
+  in = (struct sockaddr_in *)TSHttpTxnClientAddrGet(rh);
+  ip = inet_ntoa(in->sin_addr);
+  s = TSUrlStringGet(rri->requestBufp, rri->requestUrl, &len);
+  TSDebug(PLUGIN_NAME, "request [%.*s] from [%s]", len, s, ip);
+  TSfree(s);
+
+  qh = TSUrlHttpQueryGet(rri->requestBufp, rri->requestUrl, &len);
+  if(qh && len > 0) {
+    s = (char *)TSstrndup(qh, len);
+    if((ptr = strtok(s, "&")) != NULL) {
+      do {
+        if((val = strchr(ptr, '=')) != NULL) {
+          *val++ = '\0';
+          if(strcmp(ptr, "st") == 0) {
+            token = TSstrdup(val);
+          } else if(strcmp(ptr, "ex") == 0) {
+            expire = TSstrdup(val);
+          }
+        } else {
+          TSError("Invalid parameter [%s]", ptr);
+          break;
+        }
+      } while((ptr = strtok(NULL, "&")) != NULL);
+    }
+    TSfree(s);
+  } else {
+    TSError("TSUrlHttpQueryGet returns empty value");
+    /* this is just example, so set fake params to prevent plugin crash */
+    token = TSstrdup("d41d8cd98f00b204e9800998ecf8427e");
+    expire = TSstrdup("00000000");
+  }
+
+  ph = TSUrlPathGet(rri->requestBufp, rri->requestUrl, &len);
+  if(ph && len > 0) {
+    s = TSstrndup(ph, len);
+    if((ptr = strrchr(s, '/')) != NULL) {
+      *++ptr = '\0';
+    }
+    path = TSstrdup(s);
+    TSfree(s);
+  } else {
+    TSError("TSUrlPathGet returns empty value");
+    /* this is just example, so set fake params to prevent plugin crash */
+    path = TSstrdup("example/");
+  }
+  MD5_Init(&ctx);
+  MD5_Update(&ctx, sli->secret, strlen(sli->secret));
+  MD5_Update(&ctx, ip, strlen(ip));
+  MD5_Update(&ctx, path, strlen(path));
+  MD5_Update(&ctx, expire, strlen(expire));
+  MD5_Final(md, &ctx);
+  for(i = 0; i < MD5_DIGEST_LENGTH; i++) {
+    sprintf(&hash[i * 2], "%02x", md[i]);
+  }
+  time(&t);
+  e = strtol(expire, NULL, 16);
+  i = TSREMAP_DID_REMAP;
+  if(e < t || strcmp(hash, token) != 0) {
+    if(e < t) {
+      TSDebug(PLUGIN_NAME, "link expired: [%lu] vs [%lu]", t, e);
+    } else {
+      TSDebug(PLUGIN_NAME, "tokens mismatch: [%s] vs [%s]", hash, token);
+    }
+    if(sli->strict) {
+      TSDebug(PLUGIN_NAME, "request is DENY");
+      TSHttpTxnSetHttpRetStatus(rh, TS_HTTP_STATUS_FORBIDDEN);
+      i = TSREMAP_NO_REMAP;
+    } else {
+      TSDebug(PLUGIN_NAME, "request is PASS");
+    }
+  }
+  if(i == TSREMAP_DID_REMAP) {
+    if(TSUrlHttpQuerySet(rri->requestBufp, rri->requestUrl, "", -1) == 
TS_SUCCESS) {
+      s = TSUrlStringGet(rri->requestBufp, rri->requestUrl, &len);
+      TSDebug(PLUGIN_NAME, "new request string is [%.*s]", len, s);
+      TSfree(s);
+    } else {
+      i = TSREMAP_NO_REMAP;
+    }
+  }
+  TSfree(expire);
+  TSfree(token);
+  TSfree(path);
+  return i;
+}
+
+TSReturnCode
+TSRemapNewInstance(int argc, char **argv, void **ih, char *errbuf, int 
errbuf_size)
+{
+  int i;
+  char *ptr;
+  secure_link_info *sli;
+
+  sli = (secure_link_info *)TSmalloc(sizeof(secure_link_info));
+  sli->secret = NULL;
+  sli->strict = 0;
+
+  for(i = 2; i < argc; i++) {
+    if((ptr = strchr(argv[i], ':')) != NULL) {
+      *ptr++ = '\0';
+      if(strcmp(argv[i], "secret") == 0) {
+        if(sli->secret != NULL) {
+          TSfree(sli->secret);
+        }
+        sli->secret = TSstrdup(ptr);
+      } else if(strcmp(argv[i], "policy") == 0) {
+        sli->strict = !strcasecmp(ptr, "strict");
+      } else {
+        TSDebug(PLUGIN_NAME, "Unknown parameter [%s]", argv[i]);
+      }
+    } else {
+      TSError("Invalid parameter [%s]", argv[i]);
+    }
+  }
+
+  if(sli->secret == NULL) {
+    sli->secret = TSstrdup("");
+  }
+
+  *ih = (void *)sli;
+  return TS_SUCCESS;
+}
+
+void
+TSRemapDeleteInstance(void *ih)
+{
+  secure_link_info *sli = (secure_link_info *)ih;
+
+  TSfree(sli->secret);
+  TSfree(sli);
+}
+
+TSReturnCode
+TSRemapInit(TSRemapInterface *api_info, char *errbuf, int errbuf_size)
+{
+  return TS_SUCCESS;
+}

Reply via email to