From 8ebd6f86c4bba79239a927a123f1c4a2b4d807bf Mon Sep 17 00:00:00 2001 From: Vincent Zanotti Date: Mon, 3 Jan 2011 21:08:48 +0100 Subject: [PATCH] Implements PlSession::apiAuth. The authentication is based on a HMAC signature, which takes into account the resource, the payload, and the current timestamp. It effectively blocks any replay beyond "the same method, within 10 seconds", which is deemed an acceptable risk, as long as API methods are idempotent. Signed-off-by: Vincent Zanotti --- classes/xorgsession.php | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ configs/platal.ini | 16 ++++++++++++++++ core | 2 +- 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/classes/xorgsession.php b/classes/xorgsession.php index f46107c..83bf850 100644 --- a/classes/xorgsession.php +++ b/classes/xorgsession.php @@ -258,6 +258,54 @@ class XorgSession extends PlSession } } + /** + * The authentication schema is based on three query parameters: + * ?user=×tamp=&sig= + * where: + * - hruid is the hruid of the querying user + * - timestamp is the current UNIX timestamp, which has to be within a + * given distance of the server-side UNIX timestamp + * - sig is the HMAC of "###" using + * a known secret of the user as the key. + * + * At the moment, the shared secret of the user is the sha1 hash of its + * password. This is temporary, though, until better support for tokens is + * implemented in plat/al. + * TODO(vzanotti): Switch to dedicated secrets for authentication. + */ + public function apiAuth($method, $resource, $payload) + { + // Verify that the timestamp is within acceptable bounds. + $timestamp = Env::i('timestamp', 0); + if (abs($timestamp - time()) > Platal::globals()->api->timestamp_tolerance) { + return null; + } + + // Retrieve the user corresponding to the forlife. Note that at the + // moment, other aliases are also accepted. + $user = User::getSilent(Env::s('user', '')); + if (is_null($user) || !$user->isActive()) { + return null; + } + + // Determine the list of tokens associated with the user. At the moment, + // this is just the sha1 of the password. + $tokens = array($user->password()); + + // For each token, try to validate the signature. + $message = implode('#', array($method, $resource, $payload, $timestamp)); + $signature = Env::s('sig'); + foreach ($tokens as $token) { + $expected_signature = hash_hmac( + Platal::globals()->api->hmac_algo, $message, $token); + if ($signature == $expected_signature) { + return $user; + } + } + + return null; + } + public function tokenAuth($login, $token) { $res = XDB::query('SELECT a.uid, a.hruid diff --git a/configs/platal.ini b/configs/platal.ini index 7263936..7459807 100644 --- a/configs/platal.ini +++ b/configs/platal.ini @@ -156,6 +156,21 @@ register_skin = "register" econfiance = "" +; The API section contains the configuration for the web services. +[Api] + +; $globals->api->hmac_algo +; Algorithm to use for HMAC-based authentication of API requests. Note that this +; value is shared with clients, and must be changed in all places at once. +hmac_algo = "sha256" + +; $globals->api->timestamp_tolerance +; Maximum number of seconds of drift allowed between the client-side UNIX clock +; and the server-side clock. This should be big enough to also allow for network +; latency, but not too high, to limit replay opportunities. +timestamp_tolerance = 10 + + ; The banana section contains the configuration of the forums. [Banana] @@ -214,6 +229,7 @@ gmaps_hl = "fr" ; Default location preference. gmaps_gl = "fr" + ; The lists section contains parameters used to interact with mailman. [Lists] diff --git a/core b/core index a59a444..504647c 160000 --- a/core +++ b/core @@ -1 +1 @@ -Subproject commit a59a4446b3f96e25620e98d4aab14860dd2ee951 +Subproject commit 504647c51aac2a34a4c3f11f33cc4fa6eecdb64f -- 2.1.4