Provider.php 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Integration\Model\Oauth\Token;
  7. use Magento\Authorization\Model\UserContextInterface;
  8. use Magento\Framework\Encryption\Helper\Security;
  9. use Magento\Framework\Oauth\TokenProviderInterface;
  10. use Magento\Integration\Model\Oauth\Token;
  11. class Provider implements TokenProviderInterface
  12. {
  13. /**
  14. * @var \Magento\Integration\Model\Oauth\ConsumerFactory
  15. */
  16. protected $_consumerFactory;
  17. /**
  18. * @var \Magento\Integration\Model\Oauth\TokenFactory
  19. */
  20. protected $_tokenFactory;
  21. /**
  22. * @var \Psr\Log\LoggerInterface
  23. */
  24. protected $logger;
  25. /**
  26. * @param \Magento\Integration\Model\Oauth\ConsumerFactory $consumerFactory
  27. * @param \Magento\Integration\Model\Oauth\TokenFactory $tokenFactory
  28. * @param \Psr\Log\LoggerInterface $logger
  29. */
  30. public function __construct(
  31. \Magento\Integration\Model\Oauth\ConsumerFactory $consumerFactory,
  32. \Magento\Integration\Model\Oauth\TokenFactory $tokenFactory,
  33. \Psr\Log\LoggerInterface $logger
  34. ) {
  35. $this->_consumerFactory = $consumerFactory;
  36. $this->_tokenFactory = $tokenFactory;
  37. $this->logger = $logger;
  38. }
  39. /**
  40. * {@inheritdoc}
  41. */
  42. public function validateConsumer($consumer)
  43. {
  44. // Must use consumer within expiration period.
  45. if (!$consumer->isValidForTokenExchange()) {
  46. throw new \Magento\Framework\Oauth\Exception(
  47. __('Consumer key has expired')
  48. );
  49. }
  50. return true;
  51. }
  52. /**
  53. * {@inheritdoc}
  54. */
  55. public function createRequestToken($consumer)
  56. {
  57. $token = $this->getIntegrationTokenByConsumerId($consumer->getId());
  58. if ($token->getType() != Token::TYPE_VERIFIER) {
  59. throw new \Magento\Framework\Oauth\Exception(
  60. __('Cannot create request token because consumer token is not a verifier token')
  61. );
  62. }
  63. $requestToken = $token->createRequestToken($token->getId(), $consumer->getCallbackUrl());
  64. return ['oauth_token' => $requestToken->getToken(), 'oauth_token_secret' => $requestToken->getSecret()];
  65. }
  66. /**
  67. * {@inheritdoc}
  68. */
  69. public function validateRequestToken($requestToken, $consumer, $oauthVerifier)
  70. {
  71. $token = $this->_getToken($requestToken);
  72. if (!$this->_isTokenAssociatedToConsumer($token, $consumer)) {
  73. throw new \Magento\Framework\Oauth\Exception(
  74. __('Request token is not associated with the specified consumer')
  75. );
  76. }
  77. // The pre-auth token has a value of "request" in the type when it is requested and created initially.
  78. // In this flow (token flow) the token has to be of type "request" else its marked as reused.
  79. if (Token::TYPE_REQUEST != $token->getType()) {
  80. throw new \Magento\Framework\Oauth\Exception(
  81. __('Token is already being used')
  82. );
  83. }
  84. $this->_validateVerifierParam($oauthVerifier, $token->getVerifier());
  85. return $token->getSecret();
  86. }
  87. /**
  88. * {@inheritdoc}
  89. */
  90. public function getAccessToken($consumer)
  91. {
  92. $consumerId = $consumer->getId();
  93. $token = $this->getIntegrationTokenByConsumerId($consumerId);
  94. if (Token::TYPE_REQUEST != $token->getType()) {
  95. throw new \Magento\Framework\Oauth\Exception(
  96. __('Cannot get access token because consumer token is not a request token')
  97. );
  98. }
  99. $accessToken = $token->convertToAccess();
  100. $this->logger->info(
  101. 'Request token ' . $token->getToken() . ' was exchanged to obtain access token for consumer ' . $consumerId
  102. );
  103. return ['oauth_token' => $accessToken->getToken(), 'oauth_token_secret' => $accessToken->getSecret()];
  104. }
  105. /**
  106. * {@inheritdoc}
  107. */
  108. public function validateAccessTokenRequest($accessToken, $consumer)
  109. {
  110. $token = $this->_getToken($accessToken);
  111. if (!$this->_isTokenAssociatedToConsumer($token, $consumer)) {
  112. throw new \Magento\Framework\Oauth\Exception(
  113. __('Token is not associated with the specified consumer')
  114. );
  115. }
  116. if (Token::TYPE_ACCESS != $token->getType()) {
  117. throw new \Magento\Framework\Oauth\Exception(
  118. __('Token is not an access token')
  119. );
  120. }
  121. if ($token->getRevoked()) {
  122. throw new \Magento\Framework\Oauth\Exception(
  123. __('Access token has been revoked')
  124. );
  125. }
  126. return $token->getSecret();
  127. }
  128. /**
  129. * {@inheritdoc}
  130. */
  131. public function validateAccessToken($accessToken)
  132. {
  133. $token = $this->_getToken($accessToken);
  134. // Make sure a consumer is associated with the token.
  135. $this->_getConsumer($token->getConsumerId());
  136. if (Token::TYPE_ACCESS != $token->getType()) {
  137. throw new \Magento\Framework\Oauth\Exception(
  138. __('Token is not an access token')
  139. );
  140. }
  141. if ($token->getRevoked()) {
  142. throw new \Magento\Framework\Oauth\Exception(
  143. __('Access token has been revoked')
  144. );
  145. }
  146. return $token->getConsumerId();
  147. }
  148. /**
  149. * {@inheritdoc}
  150. */
  151. public function validateOauthToken($oauthToken)
  152. {
  153. return strlen($oauthToken) == \Magento\Framework\Oauth\Helper\Oauth::LENGTH_TOKEN;
  154. }
  155. /**
  156. * {@inheritdoc}
  157. */
  158. public function getConsumerByKey($consumerKey)
  159. {
  160. if (strlen($consumerKey) != \Magento\Framework\Oauth\Helper\Oauth::LENGTH_CONSUMER_KEY) {
  161. throw new \Magento\Framework\Oauth\Exception(
  162. __('Consumer key is not the correct length')
  163. );
  164. }
  165. $consumer = $this->_consumerFactory->create()->loadByKey($consumerKey);
  166. if (!$consumer->getId()) {
  167. throw new \Magento\Framework\Oauth\Exception(
  168. __('A consumer having the specified key does not exist')
  169. );
  170. }
  171. return $consumer;
  172. }
  173. /**
  174. * Validate 'oauth_verifier' parameter.
  175. *
  176. * @param string $oauthVerifier
  177. * @param string $tokenVerifier
  178. * @return void
  179. * @throws \Magento\Framework\Oauth\Exception
  180. */
  181. protected function _validateVerifierParam($oauthVerifier, $tokenVerifier)
  182. {
  183. if (!is_string($oauthVerifier)) {
  184. throw new \Magento\Framework\Oauth\Exception(
  185. __('Verifier is invalid')
  186. );
  187. }
  188. if (!$this->validateOauthToken($oauthVerifier)) {
  189. throw new \Magento\Framework\Oauth\Exception(
  190. __('Verifier is not the correct length')
  191. );
  192. }
  193. if (!Security::compareStrings($tokenVerifier, $oauthVerifier)) {
  194. throw new \Magento\Framework\Oauth\Exception(
  195. __('Token verifier and verifier token do not match')
  196. );
  197. }
  198. }
  199. /**
  200. * Get consumer by consumer_id for a given token.
  201. *
  202. * @param int $consumerId
  203. * @return \Magento\Framework\Oauth\ConsumerInterface
  204. * @throws \Magento\Framework\Oauth\Exception
  205. */
  206. protected function _getConsumer($consumerId)
  207. {
  208. $consumer = $this->_consumerFactory->create()->load($consumerId);
  209. if (!$consumer->getId()) {
  210. throw new \Magento\Framework\Oauth\Exception(
  211. __(
  212. 'A consumer with the ID %1 does not exist',
  213. [$consumerId]
  214. )
  215. );
  216. }
  217. return $consumer;
  218. }
  219. /**
  220. * Load token object and validate it.
  221. *
  222. * @param string $token
  223. * @return Token
  224. * @throws \Magento\Framework\Oauth\Exception
  225. */
  226. protected function _getToken($token)
  227. {
  228. if (!$this->validateOauthToken($token)) {
  229. throw new \Magento\Framework\Oauth\Exception(
  230. __('The token length is invalid. Check the length and try again.')
  231. );
  232. }
  233. $tokenObj = $this->_tokenFactory->create()->load($token, 'token');
  234. if (!$tokenObj->getId()) {
  235. throw new \Magento\Framework\Oauth\Exception(
  236. __('Specified token does not exist')
  237. );
  238. }
  239. return $tokenObj;
  240. }
  241. /**
  242. * Load token object given a consumer Id.
  243. *
  244. * @param int $consumerId - The Id of the consumer.
  245. * @return Token
  246. * @throws \Magento\Framework\Oauth\Exception
  247. */
  248. public function getIntegrationTokenByConsumerId($consumerId)
  249. {
  250. /** @var \Magento\Integration\Model\Oauth\Token $token */
  251. $token = $this->_tokenFactory->create();
  252. $token->loadByConsumerIdAndUserType($consumerId, UserContextInterface::USER_TYPE_INTEGRATION);
  253. if (!$token->getId()) {
  254. throw new \Magento\Framework\Oauth\Exception(
  255. __(
  256. 'A token with consumer ID %1 does not exist',
  257. [$consumerId]
  258. )
  259. );
  260. }
  261. return $token;
  262. }
  263. /**
  264. * Check if token belongs to the same consumer.
  265. *
  266. * @param Token $token
  267. * @param \Magento\Framework\Oauth\ConsumerInterface $consumer
  268. * @return bool
  269. */
  270. protected function _isTokenAssociatedToConsumer($token, $consumer)
  271. {
  272. return $token->getConsumerId() == $consumer->getId();
  273. }
  274. }