Skip to content

Commit 69ee14d

Browse files
committed
Merge branch 'ACP2E-2969' of https://github.com/adobe-commerce-tier-4/magento2ce into ACP2E-2969
2 parents b6bf3dd + 459ebb5 commit 69ee14d

File tree

7 files changed

+274
-99
lines changed

7 files changed

+274
-99
lines changed

app/code/Magento/Integration/Test/Unit/Oauth/OauthTest.php

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class OauthTest extends TestCase
5555
/** @var \Magento\Framework\Oauth\Oauth */
5656
private $_oauth;
5757

58-
/** @var \Zend_Oauth_Http_Utility */
58+
/** @var Utility */
5959
private $utility;
6060

6161
/** @var DateTime */
@@ -160,9 +160,7 @@ protected function setUp(): void
160160
$this->_oauthHelperMock = $this->getMockBuilder(Oauth::class)
161161
->setConstructorArgs([new Random()])
162162
->getMock();
163-
$this->utility = $this->getMockBuilder(Utility::class)
164-
->onlyMethods(['sign'])
165-
->getMock();
163+
$this->utility = $this->createMock(Utility::class);
166164
$this->_dateMock = $this->getMockBuilder(DateTime::class)
167165
->disableOriginalConstructor()
168166
->getMock();
@@ -791,7 +789,13 @@ public function testValidateAccessToken()
791789
public function testBuildAuthorizationHeader()
792790
{
793791
$signature = 'valid_signature';
794-
$this->utility->expects($this->any())->method('sign')->willReturn($signature);
792+
$this->utility->expects($this->once())->method('sign')->willReturn($signature);
793+
$this->utility->expects($this->once())
794+
->method('toAuthorizationHeader')
795+
->willReturn('OAuth oauth_nonce="tyukmnjhgfdcvxstyuioplkmnhtfvert",oauth_timestamp="1657789046",' .
796+
'oauth_version="1.0",oauth_consumer_key="edf957ef88492f0a32eb7e1731e85da2",' .
797+
'oauth_consumer_secret="asdawwewefrtyh2f0a32eb7e1731e85d",oauth_token="7c0709f789e1f38a17aa4b9a28e1b06c",' .
798+
'oauth_token_secret="a6agsfrsfgsrjjjjyy487939244ssggg",oauth_signature="valid_signature"');
795799

796800
$this->_setupConsumer(false);
797801
$this->_oauthHelperMock->expects(

dev/tests/api-functional/framework/Magento/TestFramework/Authentication/Rest/OauthClient.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
use OAuth\OAuth1\Signature\SignatureInterface;
1919
use OAuth\OAuth1\Token\StdOAuth1Token;
2020
use OAuth\OAuth1\Token\TokenInterface;
21+
use Laminas\OAuth\Http\Utility as HTTPUtility;
22+
use Magento\Framework\Oauth\Helper\Signature\Hmac256;
2123

2224
/**
2325
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -56,7 +58,7 @@ public function __construct(
5658
$storage = new \OAuth\Common\Storage\Memory();
5759
}
5860
if (!isset($helper)) {
59-
$helper = new Utility();
61+
$helper = new Utility(new HTTPUtility(), new Hmac256());
6062
}
6163
if (!isset($signature)) {
6264
$signature = new \Magento\TestFramework\Authentication\Rest\OauthClient\Signature($helper, $credentials);

dev/tests/api-functional/framework/Magento/TestFramework/Authentication/Rest/OauthClient/Signature.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ function ($carry, $item) {
4949

5050
return $this->helper->sign(
5151
$signatureData,
52-
'SHA256',
52+
$this->algorithm,
5353
$this->credentials->getConsumerSecret(),
5454
$this->tokenSecret,
5555
$method,
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
<?php
2+
/**
3+
* Copyright 2024 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Framework\Oauth\Helper\Signature;
9+
10+
use Laminas\Crypt\Hmac as HMACEncryption;
11+
12+
class Hmac256
13+
{
14+
/**
15+
* Sign a request
16+
*
17+
* @param array $params
18+
* @param string $algo
19+
* @param string $consumerSecret
20+
* @param string|null $tokenSecret
21+
* @param mixed $method
22+
* @param mixed $url
23+
* @return string
24+
*/
25+
public function sign(
26+
array $params,
27+
string $algo,
28+
string $consumerSecret,
29+
?string $tokenSecret = null,
30+
?string $method = null,
31+
?string $url = null
32+
): string {
33+
unset($params['oauth_signature']);
34+
35+
$binaryHash = HMACEncryption::compute(
36+
$this->assembleKey($consumerSecret, $tokenSecret),
37+
$algo,
38+
$this->getBaseSignatureString($params, $method, $url),
39+
HMACEncryption::OUTPUT_BINARY
40+
);
41+
42+
return base64_encode($binaryHash);
43+
}
44+
45+
/**
46+
* Assemble key from consumer and token secrets
47+
*
48+
* @param string $consumerSecret
49+
* @param string|null $tokenSecret
50+
* @return string
51+
*/
52+
private function assembleKey(string $consumerSecret, ?string $tokenSecret): string
53+
{
54+
$parts = [$consumerSecret];
55+
if ($tokenSecret !== null) {
56+
$parts[] = $tokenSecret;
57+
}
58+
foreach ($parts as $key => $secret) {
59+
$parts[$key] = $this->urlEncode($secret);
60+
}
61+
62+
return implode('&', $parts);
63+
}
64+
65+
/**
66+
* Get base signature string
67+
*
68+
* @param array $params
69+
* @param null|string $method
70+
* @param null|string $url
71+
* @return string
72+
*/
73+
private function getBaseSignatureString(array $params, $method = null, $url = null): string
74+
{
75+
$encodedParams = [];
76+
foreach ($params as $key => $value) {
77+
$encodedParams[$this->urlEncode($key)] =
78+
$this->urlEncode($value);
79+
}
80+
$baseStrings = [];
81+
if (isset($method)) {
82+
$baseStrings[] = strtoupper($method);
83+
}
84+
if (isset($url)) {
85+
$baseStrings[] = $this->urlEncode($url);
86+
}
87+
if (isset($encodedParams['oauth_signature'])) {
88+
unset($encodedParams['oauth_signature']);
89+
}
90+
$baseStrings[] = $this->urlEncode(
91+
$this->toByteValueOrderedQueryString($encodedParams)
92+
);
93+
94+
return implode('&', $baseStrings);
95+
}
96+
97+
/**
98+
* Transform an array to a byte value ordered query string
99+
*
100+
* @param array $params
101+
* @return string
102+
*/
103+
private function toByteValueOrderedQueryString(array $params): string
104+
{
105+
$return = [];
106+
uksort($params, 'strnatcmp');
107+
foreach ($params as $key => $value) {
108+
if (is_array($value)) {
109+
natsort($value);
110+
foreach ($value as $keyduplicate) {
111+
$return[] = $key . '=' . $keyduplicate;
112+
}
113+
} else {
114+
$return[] = $key . '=' . $value;
115+
}
116+
}
117+
return implode('&', $return);
118+
}
119+
120+
/**
121+
* URL encode a value
122+
*
123+
* @param string $value
124+
* @return string
125+
*/
126+
private function urlEncode(string $value): string
127+
{
128+
$encoded = rawurlencode($value);
129+
return str_replace('%7E', '~', $encoded);
130+
}
131+
}
Lines changed: 41 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,25 @@
11
<?php
2-
/************************************************************************
3-
*
2+
/**
43
* Copyright 2024 Adobe
54
* All Rights Reserved.
6-
*
7-
* NOTICE: All information contained herein is, and remains
8-
* the property of Adobe and its suppliers, if any. The intellectual
9-
* and technical concepts contained herein are proprietary to Adobe
10-
* and its suppliers and are protected by all applicable intellectual
11-
* property laws, including trade secret and copyright laws.
12-
* Dissemination of this information or reproduction of this material
13-
* is strictly forbidden unless prior written permission is obtained
14-
* from Adobe.
15-
* ************************************************************************
165
*/
176
declare(strict_types=1);
187

198
namespace Magento\Framework\Oauth\Helper;
209

21-
use Laminas\Crypt\Hmac as HMACEncryption;
22-
use Laminas\OAuth\Http\Utility as HTTPUtility;
10+
use Laminas\OAuth\Http\Utility as LaminasUtility;
11+
use Magento\Framework\Oauth\Helper\Signature\Hmac256;
2312

24-
class Utility extends HTTPUtility
13+
class Utility
2514
{
15+
/**
16+
* @param LaminasUtility $httpUtility
17+
* @param Hmac256 $hmac256
18+
*/
19+
public function __construct(private readonly LaminasUtility $httpUtility, private readonly Hmac256 $hmac256)
20+
{
21+
}
22+
2623
/**
2724
* Generate signature string
2825
*
@@ -35,97 +32,55 @@ class Utility extends HTTPUtility
3532
* @return string
3633
*/
3734
public function sign(
38-
array $params,
39-
$signatureMethod,
40-
$consumerSecret,
41-
$tokenSecret = null,
42-
$method = null,
43-
$url = null
35+
array $params,
36+
string $signatureMethod,
37+
string $consumerSecret,
38+
?string $tokenSecret = null,
39+
?string $method = null,
40+
?string $url = null
4441
): string {
45-
unset($params['oauth_signature']);
46-
47-
$binaryHash = HMACEncryption::compute(
48-
$this->assembleKey($consumerSecret, $tokenSecret),
49-
$signatureMethod,
50-
$this->getBaseSignatureString($params, $method, $url),
51-
HMACEncryption::OUTPUT_BINARY
52-
);
53-
54-
return base64_encode($binaryHash);
55-
}
56-
57-
/**
58-
* Assemble key from consumer and token secrets
59-
*
60-
* @param string $consumerSecret
61-
* @param string|null $tokenSecret
62-
* @return string
63-
*/
64-
private function assembleKey(string $consumerSecret, ?string $tokenSecret): string
65-
{
66-
$parts = [$consumerSecret];
67-
if ($tokenSecret !== null) {
68-
$parts[] = $tokenSecret;
42+
if ($this->isHmac256($signatureMethod)) {
43+
return $this->hmac256->sign($params, 'sha256', $consumerSecret, $tokenSecret, $method, $url);
44+
} else {
45+
return $this->httpUtility->sign($params, $signatureMethod, $consumerSecret, $tokenSecret, $method, $url);
6946
}
70-
foreach ($parts as $key => $secret) {
71-
$parts[$key] = self::urlEncode($secret);
72-
}
73-
74-
return implode('&', $parts);
7547
}
7648

7749
/**
78-
* Get base signature string
50+
* Check if signature method is HMAC-SHA256
7951
*
80-
* @param array $params
81-
* @param null|string $method
82-
* @param null|string $url
83-
* @return string
52+
* @param string $signatureMethod
53+
* @return bool
8454
*/
85-
private function getBaseSignatureString(array $params, $method = null, $url = null): string
55+
private function isHmac256(string $signatureMethod): bool
8656
{
87-
$encodedParams = [];
88-
foreach ($params as $key => $value) {
89-
$encodedParams[self::urlEncode($key)] =
90-
self::urlEncode($value);
91-
}
92-
$baseStrings = [];
93-
if (isset($method)) {
94-
$baseStrings[] = strtoupper($method);
57+
if (strtoupper(preg_replace('/[\W]/', '', $signatureMethod)) === 'HMACSHA256') {
58+
return true;
9559
}
96-
if (isset($url)) {
97-
$baseStrings[] = self::urlEncode($url);
98-
}
99-
if (isset($encodedParams['oauth_signature'])) {
100-
unset($encodedParams['oauth_signature']);
101-
}
102-
$baseStrings[] = self::urlEncode(
103-
$this->toByteValueOrderedQueryString($encodedParams)
104-
);
10560

106-
return implode('&', $baseStrings);
61+
return false;
10762
}
10863

10964
/**
110-
* Transform an array to a byte value ordered query string
65+
* Cast to authorization header
11166
*
112-
* @param array $params
67+
* @param array $params
68+
* @param bool $excludeCustomParams
11369
* @return string
11470
*/
115-
private function toByteValueOrderedQueryString(array $params): string
71+
public function toAuthorizationHeader(array $params, bool $excludeCustomParams = true): string
11672
{
117-
$return = [];
118-
uksort($params, 'strnatcmp');
73+
$headerValue = [];
11974
foreach ($params as $key => $value) {
120-
if (is_array($value)) {
121-
natsort($value);
122-
foreach ($value as $keyduplicate) {
123-
$return[] = $key . '=' . $keyduplicate;
75+
if ($excludeCustomParams) {
76+
if (! preg_match("/^oauth_/", $key)) {
77+
continue;
12478
}
125-
} else {
126-
$return[] = $key . '=' . $value;
12779
}
80+
$headerValue[] = $this->httpUtility::urlEncode((string)$key)
81+
. '="'
82+
. $this->httpUtility::urlEncode((string)$value) . '"';
12883
}
129-
return implode('&', $return);
84+
return 'OAuth ' . implode(",", $headerValue);
13085
}
13186
}

lib/internal/Magento/Framework/Oauth/Oauth.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,16 +156,14 @@ public function buildAuthorizationHeader(
156156
$headerParameters = array_merge($headerParameters, $params);
157157
$headerParameters['oauth_signature'] = $this->hmacSignatureHelper->sign(
158158
$params,
159-
'SHA256',
159+
$signatureMethod,
160160
$headerParameters['oauth_consumer_secret'],
161161
$headerParameters['oauth_token_secret'],
162162
$httpMethod,
163163
$requestUrl
164164
);
165-
$authorizationHeader = $this->hmacSignatureHelper->toAuthorizationHeader($headerParameters);
166-
// toAuthorizationHeader adds an optional realm="" which is not required for now.
167-
// http://tools.ietf.org/html/rfc2617#section-1.2
168-
return str_replace('realm="",', '', $authorizationHeader);
165+
166+
return $this->hmacSignatureHelper->toAuthorizationHeader($headerParameters);
169167
}
170168

171169
/**
@@ -192,7 +190,7 @@ protected function _validateSignature($params, $consumerSecret, $httpMethod, $re
192190

193191
$calculatedSign = $this->hmacSignatureHelper->sign(
194192
$params,
195-
'SHA256',
193+
$params['oauth_signature_method'],
196194
$consumerSecret,
197195
$tokenSecret,
198196
$httpMethod,

0 commit comments

Comments
 (0)