From 0897effdc7d99250cf4ca332b8c428d27dc5849a Mon Sep 17 00:00:00 2001 From: Benjamin Sonntag Date: Fri, 19 Sep 2014 17:30:57 +0200 Subject: [PATCH] adding Login auth + adding *description* in Api_Auth_Interface + implementing SetUid Auth in Service --- lib/Alternc/Api/Auth/Interface.php | 7 +++ lib/Alternc/Api/Auth/Login.php | 75 +++++++++++++++++++++++++++ lib/Alternc/Api/Auth/Sharedsecret.php | 24 +++++++-- lib/Alternc/Api/Service.php | 38 ++++++++++++-- 4 files changed, 135 insertions(+), 9 deletions(-) create mode 100644 lib/Alternc/Api/Auth/Login.php diff --git a/lib/Alternc/Api/Auth/Interface.php b/lib/Alternc/Api/Auth/Interface.php index 4254991a..626027e3 100644 --- a/lib/Alternc/Api/Auth/Interface.php +++ b/lib/Alternc/Api/Auth/Interface.php @@ -19,5 +19,12 @@ interface Alternc_Api_Auth_Interface { */ function auth($options); + + /** + * instructions on how to use this Auth class + * @return array("fields" => array("fields to send, required or not"), "description" => "description of this auth") + */ + function instructions(); + } diff --git a/lib/Alternc/Api/Auth/Login.php b/lib/Alternc/Api/Auth/Login.php new file mode 100644 index 00000000..d95ceba5 --- /dev/null +++ b/lib/Alternc/Api/Auth/Login.php @@ -0,0 +1,75 @@ +db = $service->getDb(); + + } // __construct + + + /** + * Authenticate a user + * + * @param $options options, depending on the auth scheme, including uid for setuid users + * here, login is the alternc username, and password is the password for this username. + * @return an Alternc_Api_Token + */ + function auth($options) { + + if (!isset($options["login"]) || !is_string($options["login"])) { + throw new \Exception("Missing required parameter login", self::ERR_INVALID_ARGUMENT); + } + if (!isset($options["password"]) || !is_string($options["password"])) { + throw new \Exception("Missing required parameter password", self::ERR_INVALID_ARGUMENT); + } + + if (!preg_match("#^[0-9a-zA-Z-]{1,32}$#",$options["login"])) { // FIXME : normalize this on AlternC !!! + throw new \Exception("Invalid login", self::ERR_INVALID_LOGIN); + } + + $stmt = $db->query("SELECT m.enabled,m.uid,m.login,m.su FROM membres m WHERE m.login=? AND m.password=?;",array($options["login"],$options["password"]),PDO::FETCH_CLASS); + $me=$stmt->fetch(); + if (!$me) + return new Alternc_Api_Response(array("code"=>ERR_INVALID_AUTH, "message" => "Invalid login or password")); + if (!$me->enabled) + return new Alternc_Api_Response(array("code"=>ERR_DISABLED_ACCOUNT, "message" => "Account is disabled")); + + return Alternc_Api_Token::tokenGenerate( + array("uid"=>$me->uid, "isAdmin"=>($me->su!=0) ), + $this->db + ); + } + + + /** + * instructions on how to use this Auth class + * @return array("fields" => array("fields to send, required or not"), "description" => "description of this auth") + */ + function instructions() { + return array("fields" => array("login" => "AlternC user account", "password" => "AlternC's user password stored in membres table."), + "description" => "Authenticate against an AlternC user and password, the same as for the control panel" + ); + } + + +} // class Alternc_Api_Auth_Login + diff --git a/lib/Alternc/Api/Auth/Sharedsecret.php b/lib/Alternc/Api/Auth/Sharedsecret.php index d5ddfe18..26d1ec56 100644 --- a/lib/Alternc/Api/Auth/Sharedsecret.php +++ b/lib/Alternc/Api/Auth/Sharedsecret.php @@ -10,6 +10,11 @@ class Alternc_Api_Auth_Sharedsecret implements Alternc_Api_Auth_Interface { private $db; // PDO object const ERR_INVALID_ARGUMENT = 1111801; + const ERR_INVALID_SECRET = 1111802; + const ERR_INVALID_LOGIN = 1111803; + const ERR_INVALID_LOGIN = 1111804; + const ERR_DISABLED_ACCOUNT = 1111805; + /** * Constructor of the Shared Secret Api Auth @@ -43,19 +48,19 @@ class Alternc_Api_Auth_Sharedsecret implements Alternc_Api_Auth_Interface { throw new \Exception("Missing required parameter secret", self::ERR_INVALID_ARGUMENT); } if (!preg_match("#^[0-9a-zA-Z]{32}$#",$options["secret"])) { - throw new \Exception("Invalid shared secret", self::ERR_INVALID_ARGUMENT); + return new Alternc_Api_Response( array("code" => self::ERR_INVALID_SECRET, "message" => "Invalid shared secret syntax") ); } if (!preg_match("#^[0-9a-zA-Z-]{1,32}$#",$options["login"])) { // FIXME : normalize this on AlternC !!! - throw new \Exception("Invalid login", self::ERR_INVALID_LOGIN); + return new Alternc_Api_Response( array("code" => self::ERR_INVALID_LOGIN, "message" => "Invalid login") ); } $stmt = $db->query("SELECT m.enabled,m.uid,m.login,m.su FROM membres m, sharedsecret s WHERE s.uid=m.uid AND m.login=? AND s.secret=?;",array($options["login"],$options["secret"]),PDO::FETCH_CLASS); $me=$stmt->fetch(); if (!$me) - return new Alternc_Api_Response(array("code"=>ERR_INVALID_AUTH, "message" => "Invalid shared secret")); + return new Alternc_Api_Response( array("code" => self::ERR_INVALID_AUTH, "message" => "Invalid shared secret") ); if (!$me->enabled) - return new Alternc_Api_Response(array("code"=>ERR_DISABLED_ACCOUNT, "message" => "Account is disabled")); + return new Alternc_Api_Response( array("code" => self::ERR_DISABLED_ACCOUNT, "message" => "Account is disabled") ); return Alternc_Api_Token::tokenGenerate( array("uid"=>$me->uid, "isAdmin"=>($me->su!=0) ), @@ -64,5 +69,16 @@ class Alternc_Api_Auth_Sharedsecret implements Alternc_Api_Auth_Interface { } + /** + * instructions on how to use this Auth class + * @return array("fields" => array("fields to send, required or not"), "description" => "description of this auth") + */ + function instructions() { + return array("fields" => array("login" => "AlternC user account", "secret" => "API Key, Shared secrets, valid for this account, stored in sharedsecret table."), + "description" => "Authenticate against an Api Key, also called SharedSecret. distinct from the account's password, can be plenty and revoked independently" + ); + } + + } // class Alternc_Api_Auth_Sharedsecret diff --git a/lib/Alternc/Api/Service.php b/lib/Alternc/Api/Service.php index 6b8ecd9e..a7473aa5 100644 --- a/lib/Alternc/Api/Service.php +++ b/lib/Alternc/Api/Service.php @@ -1,6 +1,7 @@ allowedAuth) && !in_array($auth["method"],$this->allowedAuth)) { throw new \Exception("Method not allowed", self::ERR_METHOD_DENIED); } + if (isset($auth["options"]["uid"]) && !is_int($auth["options"]["uid"])) { + throw new \Exception("Invalid UID", self::ERR_INVALID_ARGUMENT); + } $adapterName = "Alternc_Api_Auth_".ucfirst(strtolower($auth["method"])); $authAdapter = new $adapterName($this); - return $authAdapter->auth($auth["options"]); - // table des tokens : token, expire, json_encode('uid','is_admin') - // return new Alternc_Api_Token(); + $token = $authAdapter->auth($auth["options"]); + + // something went wrong user-side + if ($token instanceof Alternc_Api_Response) + return $token; + // something went *really* wrong (bad type): + if (!$token instanceof Alternc_Api_Token) + throw new \Exception("Invalid answer from Api_Auth_Interface", self::ERR_INVALID_ANSWER); + + if (isset($auth["options"]["uid"])) { + if (!$token->isAdmin) { + // Non-admin are not allowed to setuid + return new Alternc_Api_Response( array("code" => self::ERR_SETUID_FORBIDDEN, "message" => "This user is not allowed to set his uid") ); + } + // Search for the requested user. We allow using *disabled* account here since we are admin + foreach($db->query("SELECT uid FROM membres WHERE uid=?",array($auth["options"]["uid"])) as $setuid) { + $token->uid=$setuid; + $db->exec("UPDATE token SET uid=? WHERE token=?",array( $token->uid, $token->token) ); + return $token; + } + return new Alternc_Api_Response( array("code" => self::ERR_SETUID_USER_NOT_FOUND, "message" => "Can't find the user you want to setuid to") ); + } + return $token; } @@ -107,7 +134,8 @@ class Alternc_Api_Service { function getDb() { return $this->db; } - + + } // class Alternc_Api_Service