* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ /** * \file htdocs/includes/OAuth/Common/Storage/DoliStorage.php * \ingroup oauth * \brief Dolibarr token storage class */ namespace OAuth\Common\Storage; use OAuth\Common\Token\TokenInterface; use OAuth\Common\Storage\Exception\TokenNotFoundException; use OAuth\Common\Storage\Exception\AuthorizationStateNotFoundException; use DoliDB; /** * Class to manage storage of OAUTH2 in Dolibarr */ class DoliStorage implements TokenStorageInterface { /** * @var DoliDB Database handler */ protected $db; /** * @var object|TokenInterface */ protected $tokens; /** * @var string Error code (or message) */ public $error; /** * @var string[] Several error codes (or messages) */ public $errors = array(); private $conf; private $key; //private $stateKey; private $keyforprovider; public $token; private $tenant; public $state; public $date_creation; public $date_modification; /** * @param DoliDB $db Database handler * @param Conf $conf Conf object * @param string $keyforprovider Key to manage several providers of the same type. For example 'abc' will be added to 'Google' to defined storage key. */ public function __construct(DoliDB $db, $conf, $keyforprovider = '') { $this->db = $db; $this->conf = $conf; $this->keyforprovider = $keyforprovider; $this->token = ''; $this->tokens = array(); $this->states = array(); //$this->key = $key; //$this->stateKey = $stateKey; } /** * {@inheritDoc} */ public function retrieveAccessToken($service) { dol_syslog("retrieveAccessToken service=".$service); if ($this->hasAccessToken($service)) { return $this->tokens[$service]; } throw new TokenNotFoundException('Token not found in db, are you sure you stored it?'); } /** * {@inheritDoc} */ public function storeAccessToken($service, TokenInterface $tokenobj) { global $conf; //var_dump("storeAccessToken"); //var_dump($token); dol_syslog("storeAccessToken service=".$service); $servicepluskeyforprovider = $service; if (!empty($this->keyforprovider)) { // We clean the keyforprovider after the - to be sure it is not present $servicepluskeyforprovider = preg_replace('/\-'.preg_quote($this->keyforprovider, '/').'$/', '', $servicepluskeyforprovider); // Now we add the keyforprovider $servicepluskeyforprovider .= '-'.$this->keyforprovider; } include_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php'; $serializedToken = serialize($tokenobj); if (!is_array($this->tokens)) { $this->tokens = array(); } $this->tokens[$service] = $tokenobj; $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."oauth_token"; $sql .= " WHERE service = '".$this->db->escape($servicepluskeyforprovider)."'"; $sql .= " AND entity IN (".getEntity('oauth_token').")"; $resql = $this->db->query($sql); if (! $resql) { dol_print_error($this->db); } $obj = $this->db->fetch_array($resql); if ($obj) { // update $sql = "UPDATE ".MAIN_DB_PREFIX."oauth_token"; $sql.= " SET token = '".$this->db->escape(dolEncrypt($serializedToken))."'"; $sql.= " WHERE rowid = ".((int) $obj['rowid']); $resql = $this->db->query($sql); if (!$resql) { dol_print_error($this->db); } } else { // save $sql = "INSERT INTO ".MAIN_DB_PREFIX."oauth_token (service, token, entity, datec)"; $sql .= " VALUES ('".$this->db->escape($servicepluskeyforprovider)."', '".$this->db->escape(dolEncrypt($serializedToken))."', ".((int) $conf->entity).", "; $sql .= " '".$this->db->idate(dol_now())."'"; $sql .= ")"; $resql = $this->db->query($sql); if (!$resql) { dol_print_error($this->db); } } //print $sql; // allow chaining return $this; } /** * Load token and other data from a $service * Note: Token load are cumulated into array ->tokens when other properties are erased by last loaded token. * * @return void */ public function hasAccessToken($service) { // get from db dol_syslog("hasAccessToken service=".$service); $servicepluskeyforprovider = $service; if (!empty($this->keyforprovider)) { // We clean the keyforprovider after the - to be sure it is not present $servicepluskeyforprovider = preg_replace('/\-'.preg_quote($this->keyforprovider, '/').'$/', '', $servicepluskeyforprovider); // Now we add the keyforprovider $servicepluskeyforprovider .= '-'.$this->keyforprovider; } $sql = "SELECT token, datec, tms, state FROM ".MAIN_DB_PREFIX."oauth_token"; $sql .= " WHERE service = '".$this->db->escape($servicepluskeyforprovider)."'"; $sql .= " AND entity IN (".getEntity('oauth_token').")"; $resql = $this->db->query($sql); if (! $resql) { dol_print_error($this->db); } $result = $this->db->fetch_array($resql); if ($result) { include_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php'; $tokenobj = unserialize(dolDecrypt($result['token'])); $this->token = dolDecrypt($result['token']); $this->date_creation = $this->db->jdate($result['datec']); $this->date_modification = $this->db->jdate($result['tms']); $this->state = $result['state']; } else { $tokenobj = ''; $this->token = ''; $this->date_creation = null; $this->date_modification = null; $this->state = ''; } $this->tokens[$service] = $tokenobj; return is_array($this->tokens) && isset($this->tokens[$service]) && $this->tokens[$service] instanceof TokenInterface; } /** * {@inheritDoc} */ public function clearToken($service) { dol_syslog("clearToken service=".$service); // TODO // get previously saved tokens //$tokens = $this->retrieveAccessToken($service); //if (is_array($tokens) && array_key_exists($service, $tokens)) { // unset($tokens[$service]); $sql = "DELETE FROM ".MAIN_DB_PREFIX."oauth_token"; $sql .= " WHERE service = '".$this->db->escape($service.($this->keyforprovider?'-'.$this->keyforprovider:''))."'"; $sql .= " AND entity IN (".getEntity('oauth_token').")"; $resql = $this->db->query($sql); //} // allow chaining return $this; } /** * {@inheritDoc} */ public function clearAllTokens() { // TODO Remove token using a loop on each $service /* $servicepluskeyforprovider = $service; if (!empty($this->keyforprovider)) { // We clean the keyforprovider after the - to be sure it is not present $servicepluskeyforprovider = preg_replace('/\-'.preg_quote($this->keyforprovider, '/').'$/', '', $servicepluskeyforprovider); // Now we add the keyforprovider $servicepluskeyforprovider .= '-'.$this->keyforprovider; } */ // allow chaining return $this; } /** * {@inheritDoc} */ public function retrieveAuthorizationState($service) { if ($this->hasAuthorizationState($service)) { return $this->states[$service]; } dol_syslog('State not found in db, are you sure you stored it?', LOG_WARNING); throw new AuthorizationStateNotFoundException('State not found in db, are you sure you stored it?'); } /** * {@inheritDoc} */ public function storeAuthorizationState($service, $state) { global $conf; dol_syslog("storeAuthorizationState service=".$service." state=".$state); if (!isset($this->states) || !is_array($this->states)) { $this->states = array(); } //$states[$service] = $state; $this->states[$service] = $state; //$newstate = preg_replace('/\-.*$/', '', $state); $newstate = $state; $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."oauth_token"; $sql .= " WHERE service = '".$this->db->escape($service.($this->keyforprovider?'-'.$this->keyforprovider:''))."'"; $sql .= " AND entity IN (".getEntity('oauth_token').")"; $resql = $this->db->query($sql); if (! $resql) { dol_print_error($this->db); } $obj = $this->db->fetch_array($resql); if ($obj) { // update $sql = "UPDATE ".MAIN_DB_PREFIX."oauth_token"; $sql.= " SET state = '".$this->db->escape($newstate)."'"; $sql.= " WHERE rowid = ".((int) $obj['rowid']); $resql = $this->db->query($sql); } else { // insert (should not happen) $sql = "INSERT INTO ".MAIN_DB_PREFIX."oauth_token (service, state, entity)"; $sql.= " VALUES ('".$this->db->escape($service.($this->keyforprovider?'-'.$this->keyforprovider:''))."', '".$this->db->escape($newstate)."', ".((int) $conf->entity).")"; $resql = $this->db->query($sql); } // allow chaining return $this; } /** * {@inheritDoc} */ public function hasAuthorizationState($service) { // get state from db dol_syslog("hasAuthorizationState service=".$service); $sql = "SELECT state FROM ".MAIN_DB_PREFIX."oauth_token"; $sql .= " WHERE service = '".$this->db->escape($service.($this->keyforprovider?'-'.$this->keyforprovider:''))."'"; $sql .= " AND entity IN (".getEntity('oauth_token').")"; $resql = $this->db->query($sql); $result = $this->db->fetch_array($resql); $states = array(); $states[$service] = $result['state']; $this->states[$service] = $states[$service]; return is_array($states) && isset($states[$service]) && null !== $states[$service]; } /** * {@inheritDoc} */ public function clearAuthorizationState($service) { // TODO // get previously saved tokens if (is_array($this->states) && array_key_exists($service, $this->states)) { unset($this->states[$service]); // Replace the stored tokens array //$this->conf->set($this->stateKey, $states); } // allow chaining return $this; } /** * {@inheritDoc} */ public function clearAllAuthorizationStates() { // TODO // allow chaining return $this; } /** * Return the token * * @return string String for the tenant used to create the token */ public function getTenant() { // Set/Reset tenant now so it will be defined for. // TODO We must store it into the table llx_oauth_token $this->tenant = getDolGlobalString('OAUTH_MICROSOFT'.($this->keyforprovider ? '-'.$this->keyforprovider : '').'_TENANT'); return $this->tenant; } }