PageRenderTime 56ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/yiisoft/yii2-authclient/OAuth1.php

https://gitlab.com/itlboy/yii2-starter-installed
PHP | 402 lines | 213 code | 50 blank | 139 comment | 23 complexity | cebb339461cbfa94586cc3e91392a585 MD5 | raw file
  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\authclient;
  8. use Yii;
  9. use yii\base\InvalidParamException;
  10. use yii\httpclient\Request;
  11. use yii\web\HttpException;
  12. /**
  13. * OAuth1 serves as a client for the OAuth 1/1.0a flow.
  14. *
  15. * In order to acquire access token perform following sequence:
  16. *
  17. * ```php
  18. * use yii\authclient\OAuth1;
  19. *
  20. * $oauthClient = new OAuth1();
  21. * $requestToken = $oauthClient->fetchRequestToken(); // Get request token
  22. * $url = $oauthClient->buildAuthUrl($requestToken); // Get authorization URL
  23. * return Yii::$app->getResponse()->redirect($url); // Redirect to authorization URL
  24. * // After user returns at our site:
  25. * $accessToken = $oauthClient->fetchAccessToken($requestToken); // Upgrade to access token
  26. * ```
  27. *
  28. * @see http://oauth.net/
  29. *
  30. * @author Paul Klimov <klimov.paul@gmail.com>
  31. * @since 2.0
  32. */
  33. abstract class OAuth1 extends BaseOAuth
  34. {
  35. /**
  36. * @var string protocol version.
  37. */
  38. public $version = '1.0';
  39. /**
  40. * @var string OAuth consumer key.
  41. */
  42. public $consumerKey;
  43. /**
  44. * @var string OAuth consumer secret.
  45. */
  46. public $consumerSecret;
  47. /**
  48. * @var string OAuth request token URL.
  49. */
  50. public $requestTokenUrl;
  51. /**
  52. * @var string request token HTTP method.
  53. */
  54. public $requestTokenMethod = 'GET';
  55. /**
  56. * @var string OAuth access token URL.
  57. */
  58. public $accessTokenUrl;
  59. /**
  60. * @var string access token HTTP method.
  61. */
  62. public $accessTokenMethod = 'GET';
  63. /**
  64. * @var array|null list of the request methods, which require adding 'Authorization' header.
  65. * By default only POST requests will have 'Authorization' header.
  66. * You may set this option to `null` in order to make all requests to use 'Authorization' header.
  67. * @since 2.1.1
  68. */
  69. public $authorizationHeaderMethods = ['POST'];
  70. /**
  71. * Fetches the OAuth request token.
  72. * @param array $params additional request params.
  73. * @return OAuthToken request token.
  74. */
  75. public function fetchRequestToken(array $params = [])
  76. {
  77. $this->setAccessToken(null);
  78. $defaultParams = [
  79. 'oauth_consumer_key' => $this->consumerKey,
  80. 'oauth_callback' => $this->getReturnUrl(),
  81. //'xoauth_displayname' => Yii::$app->name,
  82. ];
  83. if (!empty($this->scope)) {
  84. $defaultParams['scope'] = $this->scope;
  85. }
  86. $request = $this->createRequest()
  87. ->setMethod($this->requestTokenMethod)
  88. ->setUrl($this->requestTokenUrl)
  89. ->setData(array_merge($defaultParams, $params));
  90. $response = $this->sendRequest($request);
  91. $token = $this->createToken([
  92. 'params' => $response
  93. ]);
  94. $this->setState('requestToken', $token);
  95. return $token;
  96. }
  97. /**
  98. * Composes user authorization URL.
  99. * @param OAuthToken $requestToken OAuth request token.
  100. * @param array $params additional request params.
  101. * @return string authorize URL
  102. * @throws InvalidParamException on failure.
  103. */
  104. public function buildAuthUrl(OAuthToken $requestToken = null, array $params = [])
  105. {
  106. if (!is_object($requestToken)) {
  107. $requestToken = $this->getState('requestToken');
  108. if (!is_object($requestToken)) {
  109. throw new InvalidParamException('Request token is required to build authorize URL!');
  110. }
  111. }
  112. $params['oauth_token'] = $requestToken->getToken();
  113. return $this->composeUrl($this->authUrl, $params);
  114. }
  115. /**
  116. * Fetches OAuth access token.
  117. * @param string $oauthToken OAuth token returned with redirection back to client.
  118. * @param OAuthToken $requestToken OAuth request token.
  119. * @param string $oauthVerifier OAuth verifier.
  120. * @param array $params additional request params.
  121. * @return OAuthToken OAuth access token.
  122. * @throws InvalidParamException on failure.
  123. * @throws HttpException in case oauth token miss-matches request token.
  124. */
  125. public function fetchAccessToken($oauthToken = null, OAuthToken $requestToken = null, $oauthVerifier = null, array $params = [])
  126. {
  127. if ($oauthToken === null) {
  128. if (isset($_REQUEST['oauth_token'])) {
  129. $oauthToken = $_REQUEST['oauth_token'];
  130. }
  131. }
  132. if (!is_object($requestToken)) {
  133. $requestToken = $this->getState('requestToken');
  134. if (!is_object($requestToken)) {
  135. throw new InvalidParamException('Request token is required to fetch access token!');
  136. }
  137. }
  138. if (strcmp($requestToken->getToken(), $oauthToken) !== 0) {
  139. throw new HttpException(400, 'Invalid auth state parameter.');
  140. }
  141. $this->removeState('requestToken');
  142. $defaultParams = [
  143. 'oauth_consumer_key' => $this->consumerKey,
  144. 'oauth_token' => $requestToken->getToken()
  145. ];
  146. if ($oauthVerifier === null) {
  147. if (isset($_REQUEST['oauth_verifier'])) {
  148. $oauthVerifier = $_REQUEST['oauth_verifier'];
  149. }
  150. }
  151. if (!empty($oauthVerifier)) {
  152. $defaultParams['oauth_verifier'] = $oauthVerifier;
  153. }
  154. $request = $this->createRequest()
  155. ->setMethod($this->accessTokenMethod)
  156. ->setUrl($this->accessTokenUrl)
  157. ->setData(array_merge($defaultParams, $params));
  158. $this->signRequest($request, $requestToken);
  159. $response = $this->sendRequest($request);
  160. $token = $this->createToken([
  161. 'params' => $response
  162. ]);
  163. $this->setAccessToken($token);
  164. return $token;
  165. }
  166. /**
  167. * @inheritdoc
  168. */
  169. public function createRequest()
  170. {
  171. $request = parent::createRequest();
  172. $request->on(Request::EVENT_BEFORE_SEND, [$this, 'beforeRequestSend']);
  173. return $request;
  174. }
  175. /**
  176. * @inheritdoc
  177. */
  178. public function createApiRequest()
  179. {
  180. $request = parent::createApiRequest();
  181. // ensure correct event handlers order :
  182. $request->off(Request::EVENT_BEFORE_SEND, [$this, 'beforeRequestSend']);
  183. $request->on(Request::EVENT_BEFORE_SEND, [$this, 'beforeRequestSend']);
  184. return $request;
  185. }
  186. /**
  187. * Handles [[Request::EVENT_BEFORE_SEND]] event.
  188. * Ensures every request has been signed up before sending.
  189. * @param \yii\httpclient\RequestEvent $event event instance.
  190. * @since 2.1
  191. */
  192. public function beforeRequestSend($event)
  193. {
  194. $this->signRequest($event->request);
  195. }
  196. /**
  197. * @inheritdoc
  198. */
  199. public function applyAccessTokenToRequest($request, $accessToken)
  200. {
  201. $data = $request->getData();
  202. $data['oauth_consumer_key'] = $this->consumerKey;
  203. $data['oauth_token'] = $accessToken->getToken();
  204. $request->setData($data);
  205. }
  206. /**
  207. * Gets new auth token to replace expired one.
  208. * @param OAuthToken $token expired auth token.
  209. * @return OAuthToken new auth token.
  210. */
  211. public function refreshAccessToken(OAuthToken $token)
  212. {
  213. // @todo
  214. return null;
  215. }
  216. /**
  217. * Composes default [[returnUrl]] value.
  218. * @return string return URL.
  219. */
  220. protected function defaultReturnUrl()
  221. {
  222. $params = $_GET;
  223. unset($params['oauth_token']);
  224. $params[0] = Yii::$app->controller->getRoute();
  225. return Yii::$app->getUrlManager()->createAbsoluteUrl($params);
  226. }
  227. /**
  228. * Generates nonce value.
  229. * @return string nonce value.
  230. */
  231. protected function generateNonce()
  232. {
  233. return md5(microtime() . mt_rand());
  234. }
  235. /**
  236. * Generates timestamp.
  237. * @return integer timestamp.
  238. */
  239. protected function generateTimestamp()
  240. {
  241. return time();
  242. }
  243. /**
  244. * Generate common request params like version, timestamp etc.
  245. * @return array common request params.
  246. */
  247. protected function generateCommonRequestParams()
  248. {
  249. $params = [
  250. 'oauth_version' => $this->version,
  251. 'oauth_nonce' => $this->generateNonce(),
  252. 'oauth_timestamp' => $this->generateTimestamp(),
  253. ];
  254. return $params;
  255. }
  256. /**
  257. * Sign given request with [[signatureMethod]].
  258. * @param \yii\httpclient\Request $request request instance.
  259. * @param OAuthToken|null $token OAuth token to be used for signature, if not set [[accessToken]] will be used.
  260. * @since 2.1 this method is public.
  261. */
  262. public function signRequest($request, $token = null)
  263. {
  264. $params = $request->getData();
  265. if (isset($params['oauth_signature_method'])) {
  266. // avoid double sign of request
  267. return;
  268. }
  269. if (empty($params)) {
  270. $params = $this->generateCommonRequestParams();
  271. } else {
  272. $params = array_merge($this->generateCommonRequestParams(), $params);
  273. }
  274. $url = $request->getFullUrl();
  275. $signatureMethod = $this->getSignatureMethod();
  276. $params['oauth_signature_method'] = $signatureMethod->getName();
  277. $signatureBaseString = $this->composeSignatureBaseString($request->getMethod(), $url, $params);
  278. $signatureKey = $this->composeSignatureKey($token);
  279. $params['oauth_signature'] = $signatureMethod->generateSignature($signatureBaseString, $signatureKey);
  280. $request->setData($params);
  281. if ($this->authorizationHeaderMethods === null || in_array(strtoupper($request->getMethod()), array_map('strtoupper', $this->authorizationHeaderMethods), true)) {
  282. $authorizationHeader = $this->composeAuthorizationHeader($params);
  283. if (!empty($authorizationHeader)) {
  284. $request->addHeaders($authorizationHeader);
  285. }
  286. }
  287. }
  288. /**
  289. * Creates signature base string, which will be signed by [[signatureMethod]].
  290. * @param string $method request method.
  291. * @param string $url request URL.
  292. * @param array $params request params.
  293. * @return string base signature string.
  294. */
  295. protected function composeSignatureBaseString($method, $url, array $params)
  296. {
  297. unset($params['oauth_signature']);
  298. uksort($params, 'strcmp'); // Parameters are sorted by name, using lexicographical byte value ordering. Ref: Spec: 9.1.1
  299. $parts = [
  300. strtoupper($method),
  301. $url,
  302. http_build_query($params, '', '&', PHP_QUERY_RFC3986)
  303. ];
  304. $parts = array_map('rawurlencode', $parts);
  305. return implode('&', $parts);
  306. }
  307. /**
  308. * Composes request signature key.
  309. * @param OAuthToken|null $token OAuth token to be used for signature key.
  310. * @return string signature key.
  311. */
  312. protected function composeSignatureKey($token = null)
  313. {
  314. $signatureKeyParts = [
  315. $this->consumerSecret
  316. ];
  317. if ($token === null) {
  318. $token = $this->getAccessToken();
  319. }
  320. if (is_object($token)) {
  321. $signatureKeyParts[] = $token->getTokenSecret();
  322. } else {
  323. $signatureKeyParts[] = '';
  324. }
  325. $signatureKeyParts = array_map('rawurlencode', $signatureKeyParts);
  326. return implode('&', $signatureKeyParts);
  327. }
  328. /**
  329. * Composes authorization header.
  330. * @param array $params request params.
  331. * @param string $realm authorization realm.
  332. * @return array authorization header in format: [name => content].
  333. */
  334. protected function composeAuthorizationHeader(array $params, $realm = '')
  335. {
  336. $header = 'OAuth';
  337. $headerParams = [];
  338. if (!empty($realm)) {
  339. $headerParams[] = 'realm="' . rawurlencode($realm) . '"';
  340. }
  341. foreach ($params as $key => $value) {
  342. if (substr_compare($key, 'oauth', 0, 5)) {
  343. continue;
  344. }
  345. $headerParams[] = rawurlencode($key) . '="' . rawurlencode($value) . '"';
  346. }
  347. if (!empty($headerParams)) {
  348. $header .= ' ' . implode(', ', $headerParams);
  349. }
  350. return ['Authorization' => $header];
  351. }
  352. }