From 1ab8462266738c1e53a40801ea6d5dd82f639d88 Mon Sep 17 00:00:00 2001 From: Dominique Fournier Date: Mon, 9 Dec 2019 13:13:40 +0000 Subject: [PATCH] authjwt : Update to use the local cache to store the identifier data. git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@5814 bf3deb0d-5f1a-0410-827f-c0cc1f45334c --- Tests/authjwtTest.php | 89 ++++++++++++++++++++++++----------------- authjwt.php | 93 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 129 insertions(+), 53 deletions(-) diff --git a/Tests/authjwtTest.php b/Tests/authjwtTest.php index 1895b07..2ab3a36 100644 --- a/Tests/authjwtTest.php +++ b/Tests/authjwtTest.php @@ -7,18 +7,32 @@ /** Test the authjwt.php file */ class authjwtTest extends PHPUnit_Framework_TestCase { - /** Generate a JWT valid token + public function __construct () + { + $this->cacheDir = "/tmp/testDFWJWT-".time (); + $this->serverKey = "123456789012345678901234"; + $this->cipherKey = "EC17kIvjD66fBJHbQRkPguhu"; + $this->token = null; + } + + public function __destruct () + { + exec ("rm -rf $this->cacheDir"); + } + + /** Create a valid token as email is provided * payload = ["email" => "toto@example.com", "password" => "ToTo"]; */ - public function testCreateKey1 () + public function testJWT1 () // {{{ { - $jwt = new jwt (); - $this->serverKey = $jwt->createKey (); - $payload = ["email" => "toto@example.com", "password" => "ToTo"]; - $this->cipherKey = "123456789012345678901234"; - $this->token = $jwt->encode ($payload, $this->serverKey, "HS256", - $this->cipherKey); + $authjwt = new authjwt (); + $authjwt->cacheDir = $this->cacheDir; + $authjwt->serverKey = $this->serverKey; + $authjwt->cipherKey = $this->cipherKey; + $auth = ["email" => "toto@example.com", "password" => "ToTo"]; + $this->token = $authjwt->createJwtToken ($auth); + $this->assertSame (strlen ($this->token), 145); } // }}} @@ -29,11 +43,11 @@ class authjwtTest extends PHPUnit_Framework_TestCase { $authjwt = new authjwt (); $_SERVER["HTTP_AUTHENTICATION"] = "Bearer ".$this->token; + $authjwt->cacheDir = $this->cacheDir; $authjwt->serverKey = $this->serverKey; $authjwt->cipherKey = $this->cipherKey; $authjwt->authentication ("unused", "unused"); $res = $authjwt->getdetails (); - unset ($res["bearer"]); $this->assertSame ($res, ["email" => "toto@example.com", "password" => "ToTo"]); } @@ -47,6 +61,7 @@ class authjwtTest extends PHPUnit_Framework_TestCase $this->expectException ("Exception", "JWT Signature not readable", 403); $authjwt = new authjwt (); $_SERVER["HTTP_AUTHENTICATION"] = "Bearer ".$this->token."NO"; + $authjwt->cacheDir = $this->cacheDir; $authjwt->serverKey = $this->serverKey; $authjwt->cipherKey = $this->cipherKey; $authjwt->authentication ("unused", "unused"); @@ -62,6 +77,7 @@ class authjwtTest extends PHPUnit_Framework_TestCase $this->expectException ("Exception", "JWT with Empty algorithm", 403); $authjwt = new authjwt (); $_SERVER["HTTP_AUTHENTICATION"] = "Bearer "."NO".$this->token; + $authjwt->cacheDir = $this->cacheDir; $authjwt->serverKey = $this->serverKey; $authjwt->cipherKey = $this->cipherKey; $authjwt->authentication ("unused", "unused"); @@ -77,6 +93,7 @@ class authjwtTest extends PHPUnit_Framework_TestCase $this->expectException ("Exception", "No Authentication available", 401); $authjwt = new authjwt (); unset ($_SERVER["HTTP_AUTHENTICATION"]); + $authjwt->cacheDir = $this->cacheDir; $authjwt->serverKey = $this->serverKey; $authjwt->cipherKey = $this->cipherKey; $authjwt->authentication ("unused", "unused"); @@ -93,6 +110,7 @@ class authjwtTest extends PHPUnit_Framework_TestCase 401); $authjwt = new authjwt (); $_SERVER["HTTP_AUTHENTICATION"] = "Bearer"; + $authjwt->cacheDir = $this->cacheDir; $authjwt->serverKey = $this->serverKey; $authjwt->cipherKey = $this->cipherKey; $authjwt->authentication ("unused", "unused"); @@ -105,15 +123,15 @@ class authjwtTest extends PHPUnit_Framework_TestCase public function testInvalidToken5 () // {{{ { - $this->expectException ("Exception", "No email available in Bearer", 403); - $jwt = new jwt (); - $payload = ["password" => "ToTo"]; - $token = $jwt->encode ($payload, $this->serverKey, "HS256", - $this->cipherKey); + $this->expectException ("Exception", + "AuthJWT : No email available in auth", 403); + $auth = ["password" => "ToTo"]; $authjwt = new authjwt (); - $_SERVER["HTTP_AUTHENTICATION"] = "Bearer $token"; + $authjwt->cacheDir = $this->cacheDir; $authjwt->serverKey = $this->serverKey; $authjwt->cipherKey = $this->cipherKey; + $token = $authjwt->createJwtToken ($auth); + $_SERVER["HTTP_AUTHENTICATION"] = "Bearer $token"; $authjwt->authentication ("unused", "unused"); $res = $authjwt->getdetails (); } @@ -124,20 +142,31 @@ class authjwtTest extends PHPUnit_Framework_TestCase public function testAnonymous1 () // {{{ { - $jwt = new jwt (); - $payload = ["email" => "anonymous"]; - $token = $jwt->encode ($payload, $this->serverKey, "HS256", - $this->cipherKey); + $this->expectException ("Exception", + "AuthJWT : can not create token for anonymous", 403); + $auth = ["email" => "anonymous"]; $authjwt = new authjwt (); - $_SERVER["HTTP_AUTHENTICATION"] = "Bearer $token"; + $authjwt->cacheDir = $this->cacheDir; $authjwt->serverKey = $this->serverKey; $authjwt->cipherKey = $this->cipherKey; + $token = $authjwt->createJwtToken ($auth); + $_SERVER["HTTP_AUTHENTICATION"] = "Bearer $token"; $authjwt->authentication ("unused", "unused"); $res = $authjwt->getdetails (); - $this->assertSame ($res, - array ("lastname" => "anonymous", - "firstname" => "", - "email" => "anonymous")); + } + // }}} + + /** Logout + */ + public function testLogout1 () + // {{{ + { + $authjwt = new authjwt (); + $authjwt->cacheDir = $this->cacheDir; + $authjwt->serverKey = $this->serverKey; + $authjwt->cipherKey = $this->cipherKey; + $_SERVER["HTTP_AUTHENTICATION"] = "Bearer $this->token"; + $res = $authjwt->logout (); } // }}} @@ -175,16 +204,4 @@ class authjwtTest extends PHPUnit_Framework_TestCase $res = $authjwt->overwritepassword ("unused", "unused"); } // }}} - - /** Not needed function logout - */ - public function testUnusedFunctions4 () - // {{{ - { - $this->expectException ("Exception", - "The logout is not available for JWT users", 405); - $authjwt = new authjwt (); - $res = $authjwt->logout (); - } - // }}} } diff --git a/authjwt.php b/authjwt.php index 9b7553b..115c3ef 100644 --- a/authjwt.php +++ b/authjwt.php @@ -5,6 +5,7 @@ */ require_once ("domframework/jwt.php"); +require_once ("domframework/uuid.php"); /** User authentication against JSON Web Token * To use it, the $serverKey must be defined. It can be created by example, @@ -27,6 +28,14 @@ class authjwt extends auth */ public $allowedAlg = null; + /** The algorithm to use, in $allowedAlg list + */ + public $algorithm = "HS256"; + + /** The directory to store the user credentials + */ + public $cacheDir = "data/jwtCache"; + // INTERNAL PROPERTIES /** If the user is valid, return the payload in details */ @@ -36,7 +45,8 @@ class authjwt extends auth */ private $token = null; - /** No connection to JWT */ + /** No connection to JWT + */ public function connect () // {{{ { @@ -51,6 +61,7 @@ class authjwt extends auth * @param string $password Password not used (wait for Bearer) */ public function authentication ($email, $password) + // {{{ { if (! isset ($_SERVER["HTTP_AUTHENTICATION"])) throw new \Exception ("No Authentication available", 401); @@ -58,44 +69,74 @@ class authjwt extends auth throw new \Exception ("No Bearer Authentication available", 401); $token = substr ($_SERVER["HTTP_AUTHENTICATION"], 7); $jwt = new jwt (); - $payload = $jwt->decode ($token, $this->serverKey, $this->allowedAlg, + $uuid = $jwt->decode ($token, $this->serverKey, $this->allowedAlg, $this->cipherKey); + $cachefile = new cachefile (); + $cachefile->directory = $this->cacheDir; + $payload = $cachefile->read ((string)$uuid); // The JWT was tested in authparams. End of process - if (! empty ($payload)) + if (empty ($uuid) || empty ($payload) || ! key_exists ("email", $payload)) { - $this->payload = (array)$payload; - $this->payload["bearer"] = substr ($_SERVER["HTTP_AUTHENTICATION"], 7); - } - else - { - $this->payload = array ("lastname" => "anonymous", - "firstname" => "", - "email" => "anonymous"); - throw new \Exception ("No email available in Bearer", 403); + return array ("lastname" => "anonymous", + "firstname" => "", + "email" => "anonymous"); } + $this->payload = $payload; + return $payload; } + // }}} /** Return all the parameters recorded for the authenticate user */ public function getdetails () + // {{{ { - if ($this->payload["email"] === "anonymous") + if (key_exists ("email", $this->payload) && + $this->payload["email"] === "anonymous") return array ("lastname" => "anonymous", "firstname" => "", "email" => "anonymous"); return $this->payload; } + // }}} + + /** Save the auth data in cache directory and return the JWT token + * Do not allow to store data if the $auth is anonymous + * @param array $auth The authentication to save + * @return JWT token string + */ + public function createJwtToken ($auth) + // {{{ + { + if ($this->serverKey === null) + return ""; + if (! key_exists ("email", $auth)) + throw new \Exception ("AuthJWT : No email available in auth", 403); + if ($auth["email"] === "anonymous") + throw new \Exception ("AuthJWT : can not create token for anonymous", + 403); + $uuid = uuid::uuid4 (); + $cachefile = new cachefile (); + $cachefile->directory = $this->cacheDir; + $cachefile->write ($uuid, $auth); + $jwt = new jwt (); + return $jwt->encode ($uuid, + $this->serverKey, $this->algorithm, $this->cipherKey); + } + // }}} /** Method to change the password : unavailable in SESSION auth * @param string $oldpassword The old password (to check if the user have the - * rights to change the password) + * rights to change the password) * @param string $newpassword The new password to be recorded */ public function changepassword ($oldpassword, $newpassword) + // {{{ { throw new \Exception (dgettext ("domframework", "The password can't be change for JWT users"), 405); } + // }}} /** Method to overwrite the password (without oldpassword check) * Must be reserved to the administrators. For the users, use changepassword @@ -104,15 +145,33 @@ class authjwt extends auth * @param string $newpassword The new password to be recorded */ public function overwritepassword ($email, $newpassword) + // {{{ { throw new \Exception (dgettext ("domframework", "The password can't be overwrite for JWT users"), 405); } + // }}} - /** Remove the information from the session */ + /** Remove the information from the session + */ public function logout () + // {{{ { - throw new \Exception (dgettext ("domframework", - "The logout is not available for JWT users"), 405); + if (! isset ($_SERVER["HTTP_AUTHENTICATION"])) + throw new \Exception ("No Authentication available", 401); + if (substr ($_SERVER["HTTP_AUTHENTICATION"], 0, 7) !== "Bearer ") + throw new \Exception ("No Bearer Authentication available", 401); + $token = substr ($_SERVER["HTTP_AUTHENTICATION"], 7); + $jwt = new jwt (); + $uuid = $jwt->decode ($token, $this->serverKey, $this->allowedAlg, + $this->cipherKey); + $cachefile = new cachefile (); + $cachefile->directory = $this->cacheDir; + $payload = $cachefile->read ((string)$uuid); + if (empty ($uuid) || empty ($payload) || ! key_exists ("email", $payload)) + throw new \Exception ("Can not found the token : no logout", 403); + $cachefile->delete ($uuid); + return true; } + // }}} }