PageRenderTime 24ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/application/Espo/Core/ExternalAccount/Clients/OAuth2Abstract.php

https://gitlab.com/johanlindberg/irvato-crm
PHP | 228 lines | 167 code | 34 blank | 27 comment | 41 complexity | bfb740912b9b4a6029f38e483bc4c10a MD5 | raw file
  1. <?php
  2. /************************************************************************
  3. * This file is part of EspoCRM.
  4. *
  5. * EspoCRM - Open Source CRM application.
  6. * Copyright (C) 2014-2015 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
  7. * Website: http://www.espocrm.com
  8. *
  9. * EspoCRM is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * EspoCRM is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with EspoCRM. If not, see http://www.gnu.org/licenses/.
  21. *
  22. * The interactive user interfaces in modified source and object code versions
  23. * of this program must display Appropriate Legal Notices, as required under
  24. * Section 5 of the GNU General Public License version 3.
  25. *
  26. * In accordance with Section 7(b) of the GNU General Public License version 3,
  27. * these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
  28. ************************************************************************/
  29. namespace Espo\Core\ExternalAccount\Clients;
  30. use \Espo\Core\Exceptions\Error;
  31. use \Espo\Core\ExternalAccount\OAuth2\Client;
  32. abstract class OAuth2Abstract implements IClient
  33. {
  34. protected $client = null;
  35. protected $manager = null;
  36. protected $paramList = array(
  37. 'endpoint',
  38. 'tokenEndpoint',
  39. 'clientId',
  40. 'clientSecret',
  41. 'tokenType',
  42. 'accessToken',
  43. 'refreshToken',
  44. 'redirectUri',
  45. );
  46. protected $clientId = null;
  47. protected $clientSecret = null;
  48. protected $accessToken = null;
  49. protected $refreshToken = null;
  50. protected $redirectUri = null;
  51. public function __construct($client, array $params = array(), $manager = null)
  52. {
  53. $this->client = $client;
  54. $this->setParams($params);
  55. $this->manager = $manager;
  56. }
  57. public function getParam($name)
  58. {
  59. if (in_array($name, $this->paramList)) {
  60. return $this->$name;
  61. }
  62. }
  63. public function setParam($name, $value)
  64. {
  65. if (in_array($name, $this->paramList)) {
  66. $methodName = 'set' . ucfirst($name);
  67. if (method_exists($this->client, $methodName)) {
  68. $this->client->$methodName($value);
  69. }
  70. $this->$name = $value;
  71. }
  72. }
  73. public function setParams(array $params)
  74. {
  75. foreach ($this->paramList as $name) {
  76. if (!empty($params[$name])) {
  77. $this->setParam($name, $params[$name]);
  78. }
  79. }
  80. }
  81. protected function afterTokenRefreshed($data)
  82. {
  83. if ($this->manager) {
  84. $this->manager->storeAccessToken(spl_object_hash($this), $data);
  85. }
  86. }
  87. public function getAccessTokenFromAuthorizationCode($code)
  88. {
  89. $r = $this->client->getAccessToken($this->getParam('tokenEndpoint'), Client::GRANT_TYPE_AUTHORIZATION_CODE, array(
  90. 'code' => $code,
  91. 'redirect_uri' => $this->getParam('redirectUri')
  92. ));
  93. if ($r['code'] == 200) {
  94. $data = array();
  95. if (!empty($r['result'])) {
  96. $data['accessToken'] = $r['result']['access_token'];
  97. $data['tokenType'] = $r['result']['token_type'];
  98. $data['refreshToken'] = $r['result']['refresh_token'];
  99. }
  100. return $data;
  101. }
  102. return null;
  103. }
  104. abstract protected function getPingUrl();
  105. public function ping()
  106. {
  107. if (empty($this->accessToken) || empty($this->clientId) || empty($this->clientSecret)) {
  108. return false;
  109. }
  110. $url = $this->getPingUrl();
  111. try {
  112. $this->request($url);
  113. return true;
  114. } catch (\Exception $e) {
  115. return false;
  116. }
  117. }
  118. public function request($url, $params = null, $httpMethod = Client::HTTP_METHOD_GET, $contentType = null, $allowRenew = true)
  119. {
  120. $httpHeaders = array();
  121. if (!empty($contentType)) {
  122. $httpHeaders['Content-Type'] = $contentType;
  123. switch ($contentType) {
  124. case Client::CONTENT_TYPE_MULTIPART_FORM_DATA:
  125. $httpHeaders['Content-Length'] = strlen($params);
  126. break;
  127. case Client::CONTENT_TYPE_APPLICATION_JSON:
  128. $httpHeaders['Content-Length'] = strlen($params);
  129. break;
  130. }
  131. }
  132. $r = $this->client->request($url, $params, $httpMethod, $httpHeaders);
  133. $code = null;
  134. if (!empty($r['code'])) {
  135. $code = $r['code'];
  136. }
  137. if ($code >= 200 && $code < 300) {
  138. return $r['result'];
  139. } else {
  140. $handledData = $this->handleErrorResponse($r);
  141. if ($allowRenew && is_array($handledData)) {
  142. if ($handledData['action'] == 'refreshToken') {
  143. if ($this->refreshToken()) {
  144. return $this->request($url, $params, $httpMethod, $contentType, false);
  145. }
  146. } else if ($handledData['action'] == 'renew') {
  147. return $this->request($url, $params, $httpMethod, $contentType, false);
  148. }
  149. }
  150. }
  151. throw new Error("Error after requesting {$httpMethod} {$url}.", $code);
  152. }
  153. protected function refreshToken()
  154. {
  155. if (!empty($this->refreshToken)) {
  156. $r = $this->client->getAccessToken($this->getParam('tokenEndpoint'), Client::GRANT_TYPE_REFRESH_TOKEN, array(
  157. 'refresh_token' => $this->refreshToken,
  158. ));
  159. if ($r['code'] == 200) {
  160. if (is_array($r['result'])) {
  161. if (!empty($r['result']['access_token'])) {
  162. $data = array();
  163. $data['accessToken'] = $r['result']['access_token'];
  164. $data['tokenType'] = $r['result']['token_type'];
  165. $this->setParams($data);
  166. $this->afterTokenRefreshed($data);
  167. return true;
  168. }
  169. }
  170. }
  171. }
  172. }
  173. protected function handleErrorResponse($r)
  174. {
  175. if ($r['code'] == 401 && !empty($r['result'])) {
  176. $result = $r['result'];
  177. if (strpos($r['header'], 'error=invalid_token') !== false) {
  178. return array(
  179. 'action' => 'refreshToken'
  180. );
  181. } else {
  182. return array(
  183. 'action' => 'renew'
  184. );
  185. }
  186. } else if ($r['code'] == 400 && !empty($r['result'])) {
  187. if ($r['result']['error'] == 'invalid_token') {
  188. return array(
  189. 'action' => 'refreshToken'
  190. );
  191. }
  192. }
  193. }
  194. }