DoliStorage.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. <?php
  2. /*
  3. * Copyright (C) 2015 Frederic France <frederic.france@free.fr>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. /**
  19. * \file htdocs/includes/OAuth/Common/Storage/DoliStorage.php
  20. * \ingroup oauth
  21. * \brief Dolibarr token storage class
  22. */
  23. namespace OAuth\Common\Storage;
  24. use OAuth\Common\Token\TokenInterface;
  25. use OAuth\Common\Storage\Exception\TokenNotFoundException;
  26. use OAuth\Common\Storage\Exception\AuthorizationStateNotFoundException;
  27. use DoliDB;
  28. /**
  29. * Class to manage storage of OAUTH2 in Dolibarr
  30. */
  31. class DoliStorage implements TokenStorageInterface
  32. {
  33. /**
  34. * @var DoliDB Database handler
  35. */
  36. protected $db;
  37. /**
  38. * @var object|TokenInterface
  39. */
  40. protected $tokens;
  41. /**
  42. * @var string Error code (or message)
  43. */
  44. public $error;
  45. /**
  46. * @var string[] Several error codes (or messages)
  47. */
  48. public $errors = array();
  49. private $conf;
  50. private $key;
  51. //private $stateKey;
  52. private $keyforprovider;
  53. public $token;
  54. private $tenant;
  55. public $state;
  56. public $date_creation;
  57. public $date_modification;
  58. /**
  59. * @param DoliDB $db Database handler
  60. * @param Conf $conf Conf object
  61. * @param string $keyforprovider Key to manage several providers of the same type. For example 'abc' will be added to 'Google' to defined storage key.
  62. */
  63. public function __construct(DoliDB $db, $conf, $keyforprovider = '')
  64. {
  65. $this->db = $db;
  66. $this->conf = $conf;
  67. $this->keyforprovider = $keyforprovider;
  68. $this->token = '';
  69. $this->tokens = array();
  70. $this->states = array();
  71. //$this->key = $key;
  72. //$this->stateKey = $stateKey;
  73. }
  74. /**
  75. * {@inheritDoc}
  76. */
  77. public function retrieveAccessToken($service)
  78. {
  79. dol_syslog("retrieveAccessToken service=".$service);
  80. if ($this->hasAccessToken($service)) {
  81. return $this->tokens[$service];
  82. }
  83. throw new TokenNotFoundException('Token not found in db, are you sure you stored it?');
  84. }
  85. /**
  86. * {@inheritDoc}
  87. */
  88. public function storeAccessToken($service, TokenInterface $tokenobj)
  89. {
  90. global $conf;
  91. //var_dump("storeAccessToken");
  92. //var_dump($token);
  93. dol_syslog("storeAccessToken service=".$service);
  94. $servicepluskeyforprovider = $service;
  95. if (!empty($this->keyforprovider)) {
  96. // We clean the keyforprovider after the - to be sure it is not present
  97. $servicepluskeyforprovider = preg_replace('/\-'.preg_quote($this->keyforprovider, '/').'$/', '', $servicepluskeyforprovider);
  98. // Now we add the keyforprovider
  99. $servicepluskeyforprovider .= '-'.$this->keyforprovider;
  100. }
  101. include_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
  102. $serializedToken = serialize($tokenobj);
  103. if (!is_array($this->tokens)) {
  104. $this->tokens = array();
  105. }
  106. $this->tokens[$service] = $tokenobj;
  107. $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."oauth_token";
  108. $sql .= " WHERE service = '".$this->db->escape($servicepluskeyforprovider)."'";
  109. $sql .= " AND entity IN (".getEntity('oauth_token').")";
  110. $resql = $this->db->query($sql);
  111. if (! $resql) {
  112. dol_print_error($this->db);
  113. }
  114. $obj = $this->db->fetch_array($resql);
  115. if ($obj) {
  116. // update
  117. $sql = "UPDATE ".MAIN_DB_PREFIX."oauth_token";
  118. $sql.= " SET token = '".$this->db->escape(dolEncrypt($serializedToken))."'";
  119. $sql.= " WHERE rowid = ".((int) $obj['rowid']);
  120. $resql = $this->db->query($sql);
  121. if (!$resql) {
  122. dol_print_error($this->db);
  123. }
  124. } else {
  125. // save
  126. $sql = "INSERT INTO ".MAIN_DB_PREFIX."oauth_token (service, token, entity, datec)";
  127. $sql .= " VALUES ('".$this->db->escape($servicepluskeyforprovider)."', '".$this->db->escape(dolEncrypt($serializedToken))."', ".((int) $conf->entity).", ";
  128. $sql .= " '".$this->db->idate(dol_now())."'";
  129. $sql .= ")";
  130. $resql = $this->db->query($sql);
  131. if (!$resql) {
  132. dol_print_error($this->db);
  133. }
  134. }
  135. //print $sql;
  136. // allow chaining
  137. return $this;
  138. }
  139. /**
  140. * Load token and other data from a $service
  141. * Note: Token load are cumulated into array ->tokens when other properties are erased by last loaded token.
  142. *
  143. * @return void
  144. */
  145. public function hasAccessToken($service)
  146. {
  147. // get from db
  148. dol_syslog("hasAccessToken service=".$service);
  149. $servicepluskeyforprovider = $service;
  150. if (!empty($this->keyforprovider)) {
  151. // We clean the keyforprovider after the - to be sure it is not present
  152. $servicepluskeyforprovider = preg_replace('/\-'.preg_quote($this->keyforprovider, '/').'$/', '', $servicepluskeyforprovider);
  153. // Now we add the keyforprovider
  154. $servicepluskeyforprovider .= '-'.$this->keyforprovider;
  155. }
  156. $sql = "SELECT token, datec, tms, state FROM ".MAIN_DB_PREFIX."oauth_token";
  157. $sql .= " WHERE service = '".$this->db->escape($servicepluskeyforprovider)."'";
  158. $sql .= " AND entity IN (".getEntity('oauth_token').")";
  159. $resql = $this->db->query($sql);
  160. if (! $resql) {
  161. dol_print_error($this->db);
  162. }
  163. $result = $this->db->fetch_array($resql);
  164. if ($result) {
  165. include_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
  166. $tokenobj = unserialize(dolDecrypt($result['token']));
  167. $this->token = dolDecrypt($result['token']);
  168. $this->date_creation = $this->db->jdate($result['datec']);
  169. $this->date_modification = $this->db->jdate($result['tms']);
  170. $this->state = $result['state'];
  171. } else {
  172. $tokenobj = '';
  173. $this->token = '';
  174. $this->date_creation = null;
  175. $this->date_modification = null;
  176. $this->state = '';
  177. }
  178. $this->tokens[$service] = $tokenobj;
  179. return is_array($this->tokens)
  180. && isset($this->tokens[$service])
  181. && $this->tokens[$service] instanceof TokenInterface;
  182. }
  183. /**
  184. * {@inheritDoc}
  185. */
  186. public function clearToken($service)
  187. {
  188. dol_syslog("clearToken service=".$service);
  189. // TODO
  190. // get previously saved tokens
  191. //$tokens = $this->retrieveAccessToken($service);
  192. //if (is_array($tokens) && array_key_exists($service, $tokens)) {
  193. // unset($tokens[$service]);
  194. $sql = "DELETE FROM ".MAIN_DB_PREFIX."oauth_token";
  195. $sql .= " WHERE service = '".$this->db->escape($service.($this->keyforprovider?'-'.$this->keyforprovider:''))."'";
  196. $sql .= " AND entity IN (".getEntity('oauth_token').")";
  197. $resql = $this->db->query($sql);
  198. //}
  199. // allow chaining
  200. return $this;
  201. }
  202. /**
  203. * {@inheritDoc}
  204. */
  205. public function clearAllTokens()
  206. {
  207. // TODO Remove token using a loop on each $service
  208. /*
  209. $servicepluskeyforprovider = $service;
  210. if (!empty($this->keyforprovider)) {
  211. // We clean the keyforprovider after the - to be sure it is not present
  212. $servicepluskeyforprovider = preg_replace('/\-'.preg_quote($this->keyforprovider, '/').'$/', '', $servicepluskeyforprovider);
  213. // Now we add the keyforprovider
  214. $servicepluskeyforprovider .= '-'.$this->keyforprovider;
  215. }
  216. */
  217. // allow chaining
  218. return $this;
  219. }
  220. /**
  221. * {@inheritDoc}
  222. */
  223. public function retrieveAuthorizationState($service)
  224. {
  225. if ($this->hasAuthorizationState($service)) {
  226. return $this->states[$service];
  227. }
  228. dol_syslog('State not found in db, are you sure you stored it?', LOG_WARNING);
  229. throw new AuthorizationStateNotFoundException('State not found in db, are you sure you stored it?');
  230. }
  231. /**
  232. * {@inheritDoc}
  233. */
  234. public function storeAuthorizationState($service, $state)
  235. {
  236. global $conf;
  237. dol_syslog("storeAuthorizationState service=".$service." state=".$state);
  238. if (!isset($this->states) || !is_array($this->states)) {
  239. $this->states = array();
  240. }
  241. //$states[$service] = $state;
  242. $this->states[$service] = $state;
  243. //$newstate = preg_replace('/\-.*$/', '', $state);
  244. $newstate = $state;
  245. $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."oauth_token";
  246. $sql .= " WHERE service = '".$this->db->escape($service.($this->keyforprovider?'-'.$this->keyforprovider:''))."'";
  247. $sql .= " AND entity IN (".getEntity('oauth_token').")";
  248. $resql = $this->db->query($sql);
  249. if (! $resql) {
  250. dol_print_error($this->db);
  251. }
  252. $obj = $this->db->fetch_array($resql);
  253. if ($obj) {
  254. // update
  255. $sql = "UPDATE ".MAIN_DB_PREFIX."oauth_token";
  256. $sql.= " SET state = '".$this->db->escape($newstate)."'";
  257. $sql.= " WHERE rowid = ".((int) $obj['rowid']);
  258. $resql = $this->db->query($sql);
  259. } else {
  260. // insert (should not happen)
  261. $sql = "INSERT INTO ".MAIN_DB_PREFIX."oauth_token (service, state, entity)";
  262. $sql.= " VALUES ('".$this->db->escape($service.($this->keyforprovider?'-'.$this->keyforprovider:''))."', '".$this->db->escape($newstate)."', ".((int) $conf->entity).")";
  263. $resql = $this->db->query($sql);
  264. }
  265. // allow chaining
  266. return $this;
  267. }
  268. /**
  269. * {@inheritDoc}
  270. */
  271. public function hasAuthorizationState($service)
  272. {
  273. // get state from db
  274. dol_syslog("hasAuthorizationState service=".$service);
  275. $sql = "SELECT state FROM ".MAIN_DB_PREFIX."oauth_token";
  276. $sql .= " WHERE service = '".$this->db->escape($service.($this->keyforprovider?'-'.$this->keyforprovider:''))."'";
  277. $sql .= " AND entity IN (".getEntity('oauth_token').")";
  278. $resql = $this->db->query($sql);
  279. $result = $this->db->fetch_array($resql);
  280. $states = array();
  281. $states[$service] = $result['state'];
  282. $this->states[$service] = $states[$service];
  283. return is_array($states)
  284. && isset($states[$service])
  285. && null !== $states[$service];
  286. }
  287. /**
  288. * {@inheritDoc}
  289. */
  290. public function clearAuthorizationState($service)
  291. {
  292. // TODO
  293. // get previously saved tokens
  294. if (is_array($this->states) && array_key_exists($service, $this->states)) {
  295. unset($this->states[$service]);
  296. // Replace the stored tokens array
  297. //$this->conf->set($this->stateKey, $states);
  298. }
  299. // allow chaining
  300. return $this;
  301. }
  302. /**
  303. * {@inheritDoc}
  304. */
  305. public function clearAllAuthorizationStates()
  306. {
  307. // TODO
  308. // allow chaining
  309. return $this;
  310. }
  311. /**
  312. * Return the token
  313. *
  314. * @return string String for the tenant used to create the token
  315. */
  316. public function getTenant()
  317. {
  318. // Set/Reset tenant now so it will be defined for.
  319. // TODO We must store it into the table llx_oauth_token
  320. $this->tenant = getDolGlobalString('OAUTH_MICROSOFT'.($this->keyforprovider ? '-'.$this->keyforprovider : '').'_TENANT');
  321. return $this->tenant;
  322. }
  323. }