Alternc  latest
Alternc logiel libre pour l'hébergement
Service.php
Go to the documentation of this file.
1 <?php
2 
3 /* TODO: implements logger !
4  */
5 
6 /**
7  * Service API used by server to export API methods
8  * this class can be used to implement an API service / endpoint
9  * a REST and POST api is provided as an example
10  */
12 
13  public $db; // PDO object
14  private $loggerList; // List of loggers
15  private $allowedAuth; // list of allowed authenticators
16  public $token; // Token (useful for called classes)
17 
18  const ERR_INVALID_ARGUMENT = 111801;
19  const ERR_METHOD_DENIED = 111802;
20  const ERR_INVALID_ANSWER = 111803;
21  const ERR_SETUID_FORBIDDEN = 111804;
22  const ERR_SETUID_USER_NOT_FOUND = 111805;
23  const ERR_OBJECT_NOT_FOUND = 111806;
24  const ERR_ACTION_NOT_FOUND = 111807;
25  const ERR_INVALID_TOKEN = 111808;
26 
27  /**
28  * Constructor of the Api Service Wrapper
29  *
30  * @param $options an hash with
31  * databaseAdapter: an already initialized PDO object
32  * see http://php.net/PDO
33  * loginAdapterList: (not mandatory) list of allowed authentication adapters (their codename)
34  * see Alternc/Api/Auth/*
35  * loggerAdapter: (not mandatory), a PSR3-Interface-compliant class or a list of it.
36  * see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md for more information
37  *
38  * @return create the object
39  */
40  function __construct($options) {
41 
42  // What DB shall we connect to?
43  // Note: it MUST be in this mode : $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
44  if (isset($options["databaseAdapter"]) && $options["databaseAdapter"] instanceof PDO) {
45  $this->db = $options["databaseAdapter"];
46  } else {
47  throw new \Exception("Missing required parameter databaseAdapter", self::ERR_INVALID_ARGUMENT);
48  }
49 
50  // Which login is allowed?
51  $this->allowedAuth = array();
52  if (isset($options["loginAdapterList"]) && is_array($options["loginAdapterList"])) {
53  foreach ($options["loginAdapterList"] as $lal) {
54  $this->allowedAuth[] = (string) $lal;
55  }
56  }
57 
58  // To which logger(s) shall we log to?
59  if (isset($options["loggerAdapter"])) {
60  if (!is_array($options["loggerAdapter"]))
61  $options["loggerAdapter"] = array($options["loggerAdapter"]);
62  foreach ($options["loggerAdapter"] as $la) {
63  if ($la instanceof Psr\Log\LoggerInterface)
64  $this->loggerList[] = $la;
65  }
66  }
67  }
68 
69  /**
70  * Authenticate into an AlternC server
71  * @param $auth hash with
72  * method: string describing the authentication name (in Alternc_Api_Auth_xxx)
73  * options: array list of parameters for the corresponding auth.
74  * if 'uid' is set in the option hash, the account MUST be an administrator one
75  * and as a result, the returned Api_Token will be set to this UID and not the admin one.
76  * @return Alternc_Api_Token an API Token
77  */
78  function auth($auth) {
79  if (!isset($auth["method"]) || !is_string($auth["method"])) {
80  throw new \Exception("Missing required parameter method", self::ERR_INVALID_ARGUMENT);
81  }
82  if (!isset($auth["options"]) || !is_array($auth["options"])) {
83  throw new \Exception("Missing required parameter options", self::ERR_INVALID_ARGUMENT);
84  }
85 
86  if (count($this->allowedAuth) && !in_array($auth["method"], $this->allowedAuth)) {
87  throw new \Exception("Method not allowed", self::ERR_METHOD_DENIED);
88  }
89  if (isset($auth["options"]["uid"]) && !intval($auth["options"]["uid"])) {
90  throw new \Exception("Invalid UID", self::ERR_INVALID_ARGUMENT);
91  }
92 
93  $adapterName = "Alternc_Api_Auth_" . ucfirst(strtolower($auth["method"]));
94 
95  $authAdapter = new $adapterName($this);
96 
97  $token = $authAdapter->auth($auth["options"]);
98 
99  // something went wrong user-side
100  if ($token instanceof Alternc_Api_Response)
101  return $token;
102  // something went *really* wrong (bad type):
103  if (!$token instanceof Alternc_Api_Token)
104  throw new \Exception("Invalid answer from Api_Auth_Interface", self::ERR_INVALID_ANSWER);
105 
106  if (isset($auth["options"]["uid"])) {
107  if (!$token->isAdmin) {
108  // Non-admin are not allowed to setuid
109  return new Alternc_Api_Response(array("code" => self::ERR_SETUID_FORBIDDEN, "message" => "This user is not allowed to set his uid"));
110  }
111  // Search for the requested user. We allow using *disabled* account here since we are admin
112  foreach ($this->db->query("SELECT uid FROM membres WHERE uid=" . intval($auth["options"]["uid"])) as $setuid) {
113  $token->uid = intval($setuid['uid']);
114  $stmt = $this->db->prepare("UPDATE token SET data=? WHERE token=?");
115  $stmt->execute(array($token->toJson(), $token->token));
116  return $token;
117  }
118  return new Alternc_Api_Response(array("code" => self::ERR_SETUID_USER_NOT_FOUND, "message" => "Can't find the user you want to setuid to"));
119  }
120  return $token;
121  }
122 
123  /**
124  * Manage an API Call
125  * @param Alternc_Api_Request $request The API call
126  * the request must have "object" and "action" elements, and a "token" to authenticate
127  * "options" are sent as it is to the Api Call.
128  * @return Alternc_Api_Response an API response
129  */
130  function call($request) {
131  if (!$request instanceof Alternc_Api_Request)
132  throw new \Exception("request must be an Alternc_Api_Request object", self::ERR_INVALID_ARGUMENT);
133 
134  // we set the token in the Service object, so that other classes can use it :)
135  $this->token = Alternc_Api_Token::tokenGet($request->token_hash, $this->db);
136  if ($this->token instanceof Alternc_Api_Response) // bad token
137  return $this->token;
138 
139  $className = "Alternc_Api_Object_" . ucfirst(strtolower($request->object));
140  if (!class_exists($className))
141  return new Alternc_Api_Response(array("code" => self::ERR_OBJECT_NOT_FOUND, "message" => "Object not found in this AlternC's instance"));
142 
143  $object = new $className($this);
144 
145  $action = $request->action;
146 
147  if (strpos($action, "-") !== false) {
148  // replace - by an uppercase letter:
149  $action = lcfirst(str_replace(" ", "", implode("", array_map("ucfirst", explode("-", $action)))));
150  }
151  if (!method_exists($object, $action))
152  return new Alternc_Api_Response(array("code" => self::ERR_ACTION_NOT_FOUND, "message" => "Action not found for this object in this AlternC's instance"));
153 
154  $request->token = $this->token; // we receive $request->token_hash as a STRING, but we transmit its object as an Alternc_Api_Token.
155  // TODO: log this Api Call
156  return $object->$action($request->options);
157  }
158 
159  /**
160  * Return documentation of the API, either general (no parameters)
161  * or for a specific action or auth class
162  * @param string $element the name of the object for which documentation is requested
163  * @return array a documentation hash (key/value)
164  */
165  function doc($element) {
166  if (substr($element, 0, 5) == "auth/") {
167  $adapterName = "Alternc_Api_Auth_" . ucfirst(strtolower(substr($element, 5)));
168  if (!class_exists($adapterName))
169  return false;
170  $authAdapter = new $adapterName($this);
171  return $authAdapter->documentation();
172  } else {
173  list($class, $action) = explode("/", $element);
174  $className = "Alternc_Api_Object_" . ucfirst(strtolower($class));
175  if (!class_exists($className))
176  return false;
177  $object = new $className($this);
178  if (!$action) {
179  return $authAdapter->documentation();
180  } else {
181  return $authAdapter->documentation($action);
182  }
183  }
184  }
185 
186  /**
187  * Getter for the databaseAdapter
188  * (used by authAdapter)
189  */
190  function getDb() {
191  return $this->db;
192  }
193 
194 }
195 
196 // class Alternc_Api_Service
Standard Request object for the AlternC API.
Definition: Request.php:8
Standard Response object for the AlternC API.
Definition: Response.php:7
Service API used by server to export API methods this class can be used to implement an API service /...
Definition: Service.php:11
const ERR_ACTION_NOT_FOUND
Definition: Service.php:24
const ERR_OBJECT_NOT_FOUND
Definition: Service.php:23
const ERR_INVALID_TOKEN
Definition: Service.php:25
getDb()
Getter for the databaseAdapter (used by authAdapter)
Definition: Service.php:190
__construct($options)
Constructor of the Api Service Wrapper.
Definition: Service.php:40
const ERR_SETUID_FORBIDDEN
Definition: Service.php:21
const ERR_SETUID_USER_NOT_FOUND
Definition: Service.php:22
call($request)
Manage an API Call.
Definition: Service.php:130
const ERR_METHOD_DENIED
Definition: Service.php:19
const ERR_INVALID_ARGUMENT
Definition: Service.php:18
auth($auth)
Authenticate into an AlternC server.
Definition: Service.php:78
const ERR_INVALID_ANSWER
Definition: Service.php:20
doc($element)
Return documentation of the API, either general (no parameters) or for a specific action or auth clas...
Definition: Service.php:165
Standard Token object for the AlternC API.
Definition: Token.php:7
static tokenGet($token, $db)
Check and return a token.
Definition: Token.php:102
$request