Skip to content

Commit c984e8d

Browse files
committed
AC-14075::Replace carlos-mg89/oauth with PHP Native Functions
1 parent df92deb commit c984e8d

File tree

2 files changed

+360
-68
lines changed
  • dev/tests/api-functional

2 files changed

+360
-68
lines changed
Lines changed: 313 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
7+
namespace Magento\TestFramework\Authentication\Rest;
8+
9+
use Magento\Framework\Oauth\NonceGeneratorInterface;
10+
use Magento\Framework\Url;
11+
use Magento\Framework\Oauth\Helper\Utility;
12+
use Magento\TestFramework\Helper\Bootstrap;
13+
use Magento\TestFramework\Inspection\Exception;
14+
use Magento\Framework\HTTP\ClientFactory;
15+
16+
class OauthService
17+
{
18+
/**
19+
* @var \Magento\Framework\Url
20+
*/
21+
protected Url $urlProvider;
22+
23+
/**
24+
* @var \Magento\Framework\HTTP\ClientFactory
25+
*/
26+
protected ClientFactory $clientFactory;
27+
28+
/**
29+
* @var \Magento\Framework\Oauth\NonceGeneratorInterface
30+
*/
31+
protected NonceGeneratorInterface $_nonceGenerator;
32+
33+
/**
34+
* @var \Magento\Framework\Oauth\Helper\Utility
35+
*/
36+
private Utility $_httpUtility;
37+
38+
/**
39+
* @var string
40+
*/
41+
protected string $consumerKey;
42+
43+
/**
44+
* @var string
45+
*/
46+
protected string $consumerSecret;
47+
48+
/**
49+
* @param Url $urlProvider
50+
* @param ClientFactory $clientFactory
51+
* @param NonceGeneratorInterface $nonceGenerator
52+
* @param Utility $utility
53+
*/
54+
public function __construct(
55+
Url $urlProvider,
56+
ClientFactory $clientFactory,
57+
NonceGeneratorInterface $nonceGenerator,
58+
Utility $utility
59+
)
60+
{
61+
$this->urlProvider = $urlProvider;
62+
$this->clientFactory = $clientFactory;
63+
$this->_nonceGenerator = $nonceGenerator;
64+
$this->_httpUtility = $utility;
65+
}
66+
67+
/**
68+
* Return current OauthService object after setting required key values
69+
*
70+
* @param string $consumerKey
71+
* @param string $consumerSecret
72+
* @return OauthService
73+
*/
74+
public function create(string $consumerKey, string $consumerSecret)
75+
{
76+
$this->consumerKey = $consumerKey;
77+
$this->consumerSecret = $consumerSecret;
78+
return $this;
79+
}
80+
81+
/**
82+
* Builds the authorization header array.
83+
*
84+
* @param array $params
85+
* @return array
86+
*/
87+
public function getBasicAuthorizationParams(array $params): array
88+
{
89+
$headerParams = [
90+
'oauth_nonce' => $this->_nonceGenerator->generateNonce(),
91+
'oauth_timestamp' => (string)$this->_nonceGenerator->generateTimestamp(),
92+
'oauth_version' => '1.0',
93+
"oauth_signature_method" => \Magento\Framework\Oauth\Oauth::SIGNATURE_SHA256,
94+
"oauth_callback" => TESTS_BASE_URL
95+
];
96+
return array_merge($headerParams, $params);
97+
}
98+
99+
/**
100+
* Get request token.
101+
*
102+
* @return array
103+
* @throws \Exception
104+
*/
105+
public function getRequestToken(): array
106+
{
107+
$authParameters = ['oauth_consumer_key' => $this->consumerKey];
108+
$authParameters = $this->getBasicAuthorizationParams($authParameters);
109+
$requestUrl = $this->getRequestTokenEndpoint();
110+
$headers = ['Authorization' => $this->buildAuthorizationHeaderToRequestToken($authParameters, $this->consumerSecret, $requestUrl)];
111+
112+
$responseBody = $this->fetchResponse($requestUrl, [], $headers);
113+
return $this->parseResponseBody($responseBody);
114+
}
115+
116+
/**
117+
* Get request token endpoint.
118+
* @return string
119+
* @throws \Exception
120+
*/
121+
public function getRequestTokenEndpoint(): string
122+
{
123+
return $this->urlProvider->getRebuiltUrl(TESTS_BASE_URL . '/oauth/token/request');
124+
}
125+
126+
/**
127+
* @param string $url
128+
* @param array $requestBody
129+
* @param array $headers
130+
* @param string $method
131+
* @return string
132+
*/
133+
public function fetchResponse(string $url, array $requestBody, array $headers, string $method = 'POST'): string
134+
{
135+
$httpClient = $this->clientFactory->create();
136+
$httpClient->setHeaders($headers);
137+
$httpClient->setOption(CURLOPT_FAILONERROR, true);
138+
if ($method === 'GET') {
139+
$httpClient->get($url);
140+
} else {
141+
$httpClient->post($url, $requestBody);
142+
}
143+
144+
return $httpClient->getBody();
145+
}
146+
147+
/**
148+
* @param array $params
149+
* @param string $consumerSecret
150+
* @param string $requestUrl
151+
* @param string $signatureMethod
152+
* @param string $httpMethod
153+
* @return string
154+
*/
155+
public function buildAuthorizationHeaderToRequestToken(
156+
array $params,
157+
string $consumerSecret,
158+
string $requestUrl,
159+
string $signatureMethod = \Magento\Framework\Oauth\Oauth::SIGNATURE_SHA256,
160+
string $httpMethod = 'POST'
161+
): string
162+
{
163+
$params['oauth_signature'] = $this->_httpUtility->sign(
164+
$params,
165+
$signatureMethod,
166+
$consumerSecret,
167+
null,
168+
$httpMethod,
169+
$requestUrl
170+
);
171+
172+
return $this->_httpUtility->toAuthorizationHeader($params);
173+
}
174+
175+
/**
176+
* @param array $token
177+
* @param string $verifier
178+
* @return array
179+
* @throws \Exception
180+
*/
181+
public function getAccessToken(array $token, string $verifier): array
182+
{
183+
$authParameters = ['oauth_consumer_key' => $this->consumerKey];
184+
$authParameters = $this->getBasicAuthorizationParams($authParameters);
185+
186+
$bodyParams = [
187+
'oauth_verifier' => $verifier,
188+
];
189+
190+
$authorizationHeader = [
191+
'Authorization' => $this->buildAuthorizationHeaderForAPIRequest(
192+
$authParameters,
193+
$this->consumerSecret,
194+
$this->getAccessTokenEndpoint(),
195+
$token,
196+
$bodyParams
197+
),
198+
];
199+
$responseBody = $this->fetchResponse($this->getAccessTokenEndpoint(), $bodyParams, $authorizationHeader);
200+
return $this->parseResponseBody($responseBody);
201+
}
202+
203+
/**
204+
* @param array $params
205+
* @param string $consumerSecret
206+
* @param string $requestUrl
207+
* @param array $token
208+
* @param array|null $bodyParams
209+
* @param string $signatureMethod
210+
* @param string $httpMethod
211+
* @return string
212+
*/
213+
protected function buildAuthorizationHeaderForAPIRequest(
214+
array $params,
215+
string $consumerSecret,
216+
string $requestUrl,
217+
array $token,
218+
?array $bodyParams = null,
219+
string $signatureMethod = \Magento\Framework\Oauth\Oauth::SIGNATURE_SHA256,
220+
string $httpMethod = 'POST'
221+
): string
222+
{
223+
224+
if (isset($params['oauth_callback'])) {
225+
unset($params['oauth_callback']);
226+
}
227+
228+
$params = array_merge($params, ['oauth_token' => $token['oauth_token']]);
229+
$params = array_merge($params, $bodyParams);
230+
231+
$params['oauth_signature'] = $this->_httpUtility->sign(
232+
$params,
233+
$signatureMethod,
234+
$consumerSecret,
235+
$token['oauth_token_secret'],
236+
$httpMethod,
237+
$requestUrl
238+
);
239+
240+
return $this->_httpUtility->toAuthorizationHeader($params);
241+
}
242+
243+
/**
244+
* @param array $token
245+
* @param string $method
246+
* @return array
247+
*/
248+
public function validateAccessToken(array $token, string $method = 'GET'): array
249+
{
250+
$authParameters = ['oauth_consumer_key' => $this->consumerKey];
251+
$authParameters = $this->getBasicAuthorizationParams($authParameters);
252+
253+
//Need to add Accept header else Magento errors out with 503
254+
$extraAuthenticationHeaders = ['Accept' => 'application/json'];
255+
256+
$authorizationHeader = [
257+
'Authorization' => $this->buildAuthorizationHeaderForAPIRequest(
258+
$authParameters,
259+
$this->consumerSecret,
260+
$this->getTestApiEndpoint(),
261+
$token,
262+
[],
263+
\Magento\Framework\Oauth\Oauth::SIGNATURE_SHA256,
264+
$method
265+
),
266+
];
267+
268+
$headers = array_merge($authorizationHeader, $extraAuthenticationHeaders);
269+
270+
$responseBody = $this->fetchResponse($this->getTestApiEndpoint(), [], $headers, $method);
271+
272+
return json_decode($responseBody);
273+
}
274+
275+
/**
276+
* @return string
277+
*/
278+
public function getAccessTokenEndpoint(): string
279+
{
280+
return $this->urlProvider->getRebuiltUrl(TESTS_BASE_URL . '/oauth/token/access');
281+
}
282+
283+
284+
/**
285+
* Returns the TestModule1 Rest API endpoint.
286+
*
287+
* @return string
288+
*/
289+
public function getTestApiEndpoint(): string
290+
{
291+
$defaultStoreCode = Bootstrap::getObjectManager()->get(\Magento\Store\Model\StoreManagerInterface::class)
292+
->getStore()->getCode();
293+
return $this->urlProvider->getRebuiltUrl(TESTS_BASE_URL . '/rest/' . $defaultStoreCode . '/V1/testmodule1');
294+
}
295+
296+
/**
297+
* Parse response body and return data in array.
298+
*
299+
* @param string $responseBody
300+
* @return array
301+
* @throws \Exception
302+
*/
303+
protected function parseResponseBody(string $responseBody): array
304+
{
305+
parse_str($responseBody, $data);
306+
if (!is_array($data)) {
307+
throw new Exception('Unable to parse response.');
308+
} elseif (isset($data['error'])) {
309+
throw new Exception("Error occurred: '{$data['error']}'");
310+
}
311+
return $data;
312+
}
313+
}

0 commit comments

Comments
 (0)