implement authentication
authorChristian Weiske <cweiske@cweiske.de>
Mon, 31 Mar 2014 18:54:29 +0000 (20:54 +0200)
committerChristian Weiske <cweiske@cweiske.de>
Mon, 31 Mar 2014 18:54:29 +0000 (20:54 +0200)
.gitignore
data/phancap.config.php.dist [new file with mode: 0644]
src/phancap/Authenticator.php [new file with mode: 0644]
src/phancap/Config.php
src/phancap/Options.php
www/get.php

index 7426688adeadbe4071cfd8049126c0a51efe9c11..f6997843096a06ca4c8047df0dbf32642fbc87c6 100644 (file)
@@ -1 +1,2 @@
 /www/imgcache
+/data/phancap.config.php
diff --git a/data/phancap.config.php.dist b/data/phancap.config.php.dist
new file mode 100644 (file)
index 0000000..9a83e7b
--- /dev/null
@@ -0,0 +1,6 @@
+<?php
+//username => secret key
+$access = array(
+    'bar' => 'bar',
+);
+?>
diff --git a/src/phancap/Authenticator.php b/src/phancap/Authenticator.php
new file mode 100644 (file)
index 0000000..e918e99
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+namespace phancap;
+
+class Authenticator
+{
+    public function authenticate(Config $config)
+    {
+        if ($config->access === false) {
+            throw new \Exception('Authentication not setup');
+        }
+        if ($config->access === true) {
+            //Access without restrictions allowed
+            return;
+        }
+
+        if (!isset($_GET['atoken'])) {
+            throw new \Exception('Parameter missing: atoken');
+        }
+        if (!isset($_GET['asignature'])) {
+            throw new \Exception('Parameter missing: asignature');
+        }
+        if (!isset($_GET['atimestamp'])) {
+            throw new \Exception('Parameter missing: atimestamp');
+        }
+
+        $token = $_GET['atoken'];
+        if (!array_key_exists($token, $config->access)) {
+            throw new \Exception('Unknown atoken');
+        }
+
+        $timestamp = (int) $_GET['atimestamp'];
+        if ($timestamp + $config->timestampLifetime < time()) {
+            throw new \Exception('atimestamp too old');
+        }
+
+        $signature = $_GET['asignature'];
+
+        $params = $_GET;
+        unset($params['asignature']);
+        $sigdata = $this->getSignatureData($params);
+
+        $verifiedSignature = hash_hmac('sha1', $sigdata, $config->access[$token]);
+        if ($signature !== $verifiedSignature) {
+            throw new \Exception('Invalid signature');
+        }
+    }
+
+
+    protected function getSignatureData($params)
+    {
+        ksort($params);
+        $encparams = array();
+        foreach ($params as $key => $value) {
+            $encparams[] = $key . '=' . rawurlencode($value);
+        }
+        return implode('&', $encparams);
+    }
+}
+?>
index d69bd04dc5aa382b6a165b922a7878110dd7ef73..10aae919a992cd4fe244e47b760aa47e2b81c1fe 100644 (file)
@@ -15,6 +15,21 @@ class Config
      */
     public $cacheDirUrl;
 
+    /**
+     * Credentials for access
+     * username => secret key (used for signature)
+     * @var array
+     */
+    public $access = false;
+
+    /**
+     * How long requests with an old timestamp may be used.
+     * 2 days default.
+     *
+     * @var integer
+     */
+    public $timestampLifetime = 172800;
+
 
     public function __construct()
     {
@@ -22,6 +37,25 @@ class Config
         $this->cacheDirUrl = $this->getCurrentUrlDir() . '/imgcache/';
     }
 
+    public function load()
+    {
+        $cfgFile = __DIR__ . '/../../data/phancap.config.php';
+        if (file_exists($cfgFile)) {
+            $this->loadFile($cfgFile);
+        }
+
+        $this->setupCheck();
+    }
+
+    protected function loadFile($filename)
+    {
+        include $filename;
+        $vars = get_defined_vars();
+        foreach ($vars as $k => $value) {
+            $this->$k = $value;
+        }
+    }
+
     public function setupCheck()
     {
         if (!is_dir($this->cacheDir)) {
index ee129e8ee9e15fc827712c19c3c79d991a818e60..ddc9bdd86301f7a9741e2a6ae7c23000d484121f 100644 (file)
@@ -54,6 +54,24 @@ class Options
             'default' => 'screen',
             'type'    => array('screen', 'page'),
         ),
+        /**
+         * Authentication
+         */
+        'atimestamp' => array(
+            'title'   => 'Timestamp the request has been generated',
+            'default' => null,
+            'type'    => 'skip',
+        ),
+        'atoken' => array(
+            'title'   => 'Access token (user name)',
+            'default' => null,
+            'type'    => 'skip',
+        ),
+        'asignature' => array(
+            'title'   => 'Access signature',
+            'default' => null,
+            'type'    => 'skip',
+        ),
     );
 
     public $values = array();
@@ -88,7 +106,7 @@ class Options
                 $this->values[$name] = $this->validateArray(
                     $arValues[$name], $arOption['type']
                 );
-            } else {
+            } else if ($arOption['type'] != 'skip') {
                 throw new \InvalidArgumentException(
                     'Unsupported option type: ' . $arOption['type']
                 );
index 6bb5c7f05cfdc9458e867c4403bf1e4f5b7d50b4..3d7395f057aaeb79989d1d09444cacdceb815b89 100644 (file)
@@ -13,7 +13,7 @@ if (file_exists(__DIR__ . '/../src/phancap/Autoloader.php')) {
 }
 
 $config = new Config();
-$config->setupCheck();
+$config->load();
 
 $options = new Options();
 try {
@@ -25,6 +25,16 @@ try {
     exit(1);
 }
 
+$auth = new Authenticator();
+try {
+    $auth->authenticate($config);
+} catch (\Exception $e) {
+    header('HTTP/1.0 401 Unauthorized');
+    header('Content-type: text/plain');
+    echo $e->getMessage() . "\n";
+    exit(1);
+}
+
 $rep = new Repository();
 $rep->setConfig($config);
 try {