adding Alternc_Api_Token and Alternc_Api_Auth_SharedSecret + Alternc_Api_Auth_Interface
This commit is contained in:
parent
e36cdb7293
commit
57c1077ebb
|
@ -0,0 +1,22 @@
|
|||
|
||||
|
||||
-- used by Alternc_Api_Auth_Sharedsecret
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `sharedsecret` (
|
||||
`uid` int(10) unsigned NOT NULL,
|
||||
`secret` varchar(32) NOT NULL,
|
||||
PRIMARY KEY (`uid`,`secret`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Shared secrets used by Alternc_Api_Auth_Sharedsecret';
|
||||
|
||||
|
||||
-- used by Alternc_Api_Token
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `token` (
|
||||
`token` varchar(32) NOT NULL,
|
||||
`expire` datetime NOT NULL,
|
||||
`data` text NOT NULL,
|
||||
PRIMARY KEY (`token`),
|
||||
KEY `expire` (`expire`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Tokens used by API callers';
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Authentication API used by server to authenticate a user using a
|
||||
* specific method.
|
||||
*/
|
||||
interface Alternc_Api_Auth_Interface {
|
||||
|
||||
/**
|
||||
* contructor :
|
||||
* $service is an Alternc_Api_Service object having a getDb() method
|
||||
*/
|
||||
function __constructor($service);
|
||||
|
||||
|
||||
/**
|
||||
* auth takes options specific to the auth itself
|
||||
* returns an Alternc_Api_Token object
|
||||
*/
|
||||
function auth($options);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Authentication API used by server to authenticate a user using a
|
||||
* SHARED SECRET (ApiKey)
|
||||
*/
|
||||
class Alternc_Api_Auth_Sharedsecret implements Alternc_Api_Auth_Interface {
|
||||
|
||||
|
||||
private $db; // PDO object
|
||||
|
||||
const ERR_INVALID_ARGUMENT = 1111801;
|
||||
|
||||
/**
|
||||
* Constructor of the Shared Secret Api Auth
|
||||
*
|
||||
* @param $service an Alternc_Api_Service object
|
||||
* @return create the object
|
||||
*/
|
||||
function __constructor($service) {
|
||||
|
||||
if (!($service instanceof Alternc_Api_Service))
|
||||
throw new \Exception("Invalid argument (service)",ERR_INVALID_ARGUMENT);
|
||||
|
||||
$this->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 secret is a valid shared secret for this user.
|
||||
* @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["secret"]) || !is_string($options["secret"])) {
|
||||
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);
|
||||
}
|
||||
|
||||
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, 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"));
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
} // class Alternc_Api_Auth_Sharedsecret
|
||||
|
|
@ -6,6 +6,13 @@
|
|||
*/
|
||||
class Alternc_Api_Response {
|
||||
|
||||
/**
|
||||
* Error codes
|
||||
*/
|
||||
const ERR_DISABLED_ACCOUNT = 221801;
|
||||
const ERR_INVALID_AUTH = 221802;
|
||||
|
||||
|
||||
/**
|
||||
* Result code. 0 means success
|
||||
*
|
||||
|
@ -34,16 +41,30 @@ class Alternc_Api_Response {
|
|||
*/
|
||||
public $metadata;
|
||||
|
||||
|
||||
/**
|
||||
* initialize a response object
|
||||
* @param options any of the public above
|
||||
*/
|
||||
public function __constructor($options=array()) {
|
||||
$os=array("code","message","content","metadata");
|
||||
foreach ($os as $o) {
|
||||
if (isset($options[$o])) $this->$o=$options[$o];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Formats response to json
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toJson (){
|
||||
|
||||
public function toJson (){
|
||||
return json_encode(get_object_vars($this));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
} // class Alternc_Api_Response
|
||||
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Service API used by server to export API methods
|
||||
*/
|
||||
class Alternc_Api_Service {
|
||||
|
||||
|
||||
private $db; // PDO object
|
||||
private $loggerList; // List of loggers
|
||||
private $allowedAuth; // list of allowed authenticators
|
||||
|
||||
const ERR_INVALID_ARGUMENT = 111801;
|
||||
const ERR_METHOD_DENIED = 111802;
|
||||
|
||||
/**
|
||||
* Constructor of the Api Service Wrapper
|
||||
*
|
||||
* @param $options an hash with
|
||||
* databaseAdapter: an already initialized PDO object
|
||||
* see http://php.net/PDO
|
||||
* loginAdapterList: (not mandatory) list of allowed authentication adapters (their codename)
|
||||
* see Alternc/Api/Auth/*
|
||||
* loggerAdapter: (not mandatory), a PSR3-Interface-compliant class or a list of it.
|
||||
* see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md for more information
|
||||
*
|
||||
* @return create the object
|
||||
*/
|
||||
|
||||
function __construct($options) {
|
||||
|
||||
// What DB shall we connect to?
|
||||
// Note: it MUST be in this mode : $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
if (isset($options["databaseAdapter"]) && $options["databaseAdapter"] instanceof PDO) {
|
||||
$this->db=$options["databaseAdapter"];
|
||||
} else {
|
||||
throw new \Exception("Missing required parameter databaseAdapter", self::ERR_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
// Which login is allowed?
|
||||
$this->allowedAuth=array();
|
||||
if (isset($options["loginAdapterList"]) && is_array($options["loginAdapterList"]) ) {
|
||||
foreach($options["loginAdapterList"] as $lal) {
|
||||
$this->allowedAuth[] = (string)$lal;
|
||||
}
|
||||
}
|
||||
|
||||
// To which logger(s) shall we log to?
|
||||
if (isset($options["loggerAdapter"])) {
|
||||
if (!is_array($options["loggerAdapter"])) $options["loggerAdapter"]=array($options["loggerAdapter"]);
|
||||
foreach($options["loggerAdapter"] as $la) {
|
||||
if ($la instanceof Psr\Log\LoggerInterface)
|
||||
$this->loggerList[]=$la;
|
||||
}
|
||||
}
|
||||
|
||||
} // __construct
|
||||
|
||||
|
||||
/**
|
||||
* Authenticate into an AlternC server
|
||||
* @param $auth hash with
|
||||
* method: string describing the authentication name (in Alternc_Api_Auth_xxx)
|
||||
* options: array list of parameters for the corresponding auth.
|
||||
* if 'uid' is set in the option hash, the account MUST be an administrator one
|
||||
* and as a result, the returned Api_Token will be set to this UID and not the admin one.
|
||||
* @return Alternc_Api_Token an API Token
|
||||
*/
|
||||
function auth($auth) {
|
||||
if (!isset($auth["method"]) || !is_string($auth["method"])) {
|
||||
throw new \Exception("Missing required parameter method", self::ERR_INVALID_ARGUMENT);
|
||||
}
|
||||
if (!isset($auth["options"]) || !is_array($auth["options"])) {
|
||||
throw new \Exception("Missing required parameter options", self::ERR_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
if (count($this->allowedAuth) && !in_array($auth["method"],$this->allowedAuth)) {
|
||||
throw new \Exception("Method not allowed", self::ERR_METHOD_DENIED);
|
||||
}
|
||||
|
||||
$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();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Manage an API Call
|
||||
* @param Alternc_Api_Request $request The API call
|
||||
* @return Alternc_Api_Response an API response
|
||||
*/
|
||||
function call($request) {
|
||||
|
||||
return new Alternc_Api_Response();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Getter for the databaseAdapter
|
||||
* (used by authAdapter)
|
||||
*/
|
||||
function getDb() {
|
||||
return $this->db;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // class Alternc_Api_Service
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Standard Token object for the AlternC API
|
||||
*
|
||||
*/
|
||||
class Alternc_Api_Token {
|
||||
|
||||
|
||||
const ERR_DATABASE_ERROR=112001;
|
||||
const ERR_INVALID_ARGUMENT=112002;
|
||||
const ERR_MISSING_ARGUMENT=112003;
|
||||
|
||||
/**
|
||||
* AlternC User-Id
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $uid;
|
||||
|
||||
/**
|
||||
* Is this an admin account ?
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $isAdmin;
|
||||
|
||||
/**
|
||||
* The Token itself
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $token;
|
||||
|
||||
|
||||
/**
|
||||
* how long (seconds) is a token valid
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public static $tokenDuration = 2678400; // default is a month
|
||||
|
||||
|
||||
/**
|
||||
* initialize a token object
|
||||
* @param options any of the public above
|
||||
* may contain a dbAdapter, in that case create() will be available
|
||||
*/
|
||||
public function __constructor($options=array()) {
|
||||
|
||||
if (isset($options["uid"]) && is_int($options["uid"]))
|
||||
$this->uid=$options["uid"];
|
||||
|
||||
if (isset($options["isAdmin"]) && is_bool($options["isAdmin"]))
|
||||
$this->isAdmin=$options["isAdmin"];
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Formats response to json
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toJson (){
|
||||
return json_encode(
|
||||
array("uid"=>$this->uid,
|
||||
"isAdmin" => $this->isAdmin,
|
||||
"token" => $this->token)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new token in the DB for the associated user/admin
|
||||
*
|
||||
* @return string the token (32 chars)
|
||||
*/
|
||||
public static function tokenGenerate($options,$db) {
|
||||
if (!($db instanceof PDO)) {
|
||||
throw new \Exception("No DB Object, can't create",self::ERR_DATABASE_ERROR);
|
||||
}
|
||||
if (!isset($options["uid"]) || !isset($options["isAdmin"])) {
|
||||
throw new \Exception("Missing Arguments (uid,isAdmin)",self::ERR_MISSING_ARGUMENT);
|
||||
}
|
||||
|
||||
$token=new Alternc_Api_Token($options);
|
||||
|
||||
do {
|
||||
$token->token = $token->tokenRandom();
|
||||
$rows = $db->exec("INSERT IGNORE INTO token SET token=?, expire=DATE_ADD(NOW(), INTERVAL ? SECONDS), data=?",
|
||||
array($token,$token->tokenDuration, $token->toJson())
|
||||
);
|
||||
} while ($rows==0); // prevent collisions
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check and return a token
|
||||
* @param $token string a 32-chars token
|
||||
* @param $db PDO a PDO object for token table access
|
||||
*
|
||||
* @return Alternc_Api_Token object or NULL
|
||||
*/
|
||||
public static function tokenGet($token,$db) {
|
||||
if (!($db instanceof PDO)) {
|
||||
throw new \Exception("No DB Object, can't create",self::ERR_DATABASE_ERROR);
|
||||
}
|
||||
if (!is_string($token) || !preg_match("#^[a-zA-Z0-9]{32}$#",$token)) {
|
||||
throw new \Exception("Invalid argument (token)",self::ERR_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
foreach($db->query("SELECT * FROM token WHERE token=?", array($token)) as $tok) {
|
||||
return new Alternc_Api_Token( json_decode($tok->data,true) );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate a new random token
|
||||
* @return string
|
||||
*/
|
||||
public function tokenRandom(){
|
||||
$chars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
$s="";
|
||||
for($i=0;$i<32;$i++)
|
||||
$s.=substr($chars,rand(0,61),1);
|
||||
return $s;
|
||||
}
|
||||
|
||||
|
||||
} // class Alternc_Api_Response
|
||||
|
Loading…
Reference in New Issue