Skip to content

Commit bb30267

Browse files
authored
Merge pull request #39
[change] (UMCS-181) Refactor applepay adapter to set certificates/key separately.
2 parents 64c745b + 74ede46 commit bb30267

File tree

3 files changed

+131
-53
lines changed

3 files changed

+131
-53
lines changed

src/Adapter/ApplepayAdapter.php

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,31 +36,27 @@ class ApplepayAdapter
3636
private $request;
3737

3838
/**
39-
* @param string $merchantValidationURL URL for merchant validation request
40-
* @param ApplepaySession $applePaySession Containing applepay session data.
41-
* @param string $merchantValidationCertificatePath Path to merchant identification certificate
42-
* @param string|null $merchantValidationCertificateKeyChainPath
39+
* @param string $merchantValidationURL URL for merchant validation request
40+
* @param ApplepaySession $applePaySession Containing applepay session data.
4341
*
4442
* @return string|null
4543
*
4644
* @throws ApplepayMerchantValidationException
4745
*/
4846
public function validateApplePayMerchant(
4947
string $merchantValidationURL,
50-
ApplepaySession $applePaySession,
51-
string $merchantValidationCertificatePath,
52-
?string $merchantValidationCertificateKeyChainPath = null
48+
ApplepaySession $applePaySession
5349
): ?string {
5450
if (!$this->validMerchantValidationDomain($merchantValidationURL)) {
55-
throw new ApplepayMerchantValidationException('Invalid URL used for merchantValidation request.');
51+
throw new ApplepayMerchantValidationException("Invalid URL used for merchantValidation request.");
52+
}
53+
if ($this->request === null) {
54+
throw new ApplepayMerchantValidationException('No curl adapter initiated yet. Make sure to cal init() function before.');
5655
}
5756
$payload = $applePaySession->jsonSerialize();
58-
$this->init(
59-
$merchantValidationURL,
60-
$payload,
61-
$merchantValidationCertificatePath,
62-
$merchantValidationCertificateKeyChainPath
63-
);
57+
$this->setOption(CURLOPT_URL, $merchantValidationURL);
58+
$this->setOption(CURLOPT_POSTFIELDS, $payload);
59+
6460
$sessionResponse = $this->execute();
6561
$this->close();
6662
return $sessionResponse;
@@ -71,6 +67,7 @@ public function validateApplePayMerchant(
7167
*
7268
* @param string $merchantValidationURL URL used for merchant validation request.
7369
*
70+
* @return bool
7471
*/
7572
public function validMerchantValidationDomain(string $merchantValidationURL): bool
7673
{
@@ -81,18 +78,20 @@ public function validMerchantValidationDomain(string $merchantValidationURL): bo
8178
}
8279

8380
/**
84-
* {@inheritDoc}
81+
* @param string $sslCert Path to merchant identification certificate.
82+
* @param string|null $sslKey Path to merchant identification key file.
83+
* This is necessary if the ssl cert file doesn't contain key already.
84+
* @param string|null $caCert Path to CA certificate.
8585
*/
86-
public function init($url, $payload, $sslCert, $caCert = null): void
86+
public function init(string $sslCert, string $sslKey = null, string $caCert = null): void
8787
{
8888
$timeout = EnvironmentService::getTimeout();
8989
$curlVerbose = EnvironmentService::isCurlVerbose();
9090

91-
$this->request = curl_init($url);
91+
$this->request = curl_init();
9292
$this->setOption(CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
9393
$this->setOption(CURLOPT_POST, 1);
9494
$this->setOption(CURLOPT_DNS_USE_GLOBAL_CACHE, false);
95-
$this->setOption(CURLOPT_POSTFIELDS, $payload);
9695
$this->setOption(CURLOPT_FAILONERROR, false);
9796
$this->setOption(CURLOPT_TIMEOUT, $timeout);
9897
$this->setOption(CURLOPT_CONNECTTIMEOUT, $timeout);
@@ -104,7 +103,10 @@ public function init($url, $payload, $sslCert, $caCert = null): void
104103
$this->setOption(CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
105104

106105
$this->setOption(CURLOPT_SSLCERT, $sslCert);
107-
if (isset($caCert)) {
106+
if (isset($sslKey) && !empty($sslKey)) {
107+
$this->setOption(CURLOPT_SSLKEY, $sslKey);
108+
}
109+
if (isset($caCert) && !empty($caCert)) {
108110
$this->setOption(CURLOPT_CAINFO, $caCert);
109111
}
110112
}

src/Services/EnvironmentService.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class EnvironmentService
4141
public const ENV_VAR_TEST_PRIVATE_KEY_NON_3DS = 'UNZER_PAPI_TEST_PRIVATE_KEY_NON_3DS';
4242
public const ENV_VAR_TEST_PUBLIC_KEY_NON_3DS = 'UNZER_PAPI_TEST_PUBLIC_KEY_NON_3DS';
4343

44-
public const ENV_VAR_TEST_APPLE_MERCHANT_CERTIFICATE = 'UNZER_APPLE_MERCHANT_CERTIFICATE_PATH';
44+
public const ENV_VAR_TEST_APPLE_MERCHANT_ID_FOLDER = 'UNZER_APPLE_MERCHANT_ID_PATH';
4545
public const ENV_VAR_TEST_APPLE_CA_CERTIFICATE = 'UNZER_APPLE_CA_CERTIFICATE_PATH';
4646

4747
private const ENV_VAR_NAME_TIMEOUT = 'UNZER_PAPI_TIMEOUT';
@@ -142,13 +142,13 @@ public static function getTestPublicKey($non3ds = false): string
142142
}
143143

144144
/**
145-
* Returns the apple merchant certificate path set via environment variable.
145+
* Returns the path to apple merchant ID folder set via environment variable.
146146
*
147147
* @return string
148148
*/
149-
public static function getAppleMerchantCertificatePath(): string
149+
public static function getAppleMerchantIdPath(): string
150150
{
151-
return stripslashes($_SERVER[self::ENV_VAR_TEST_APPLE_MERCHANT_CERTIFICATE] ?? '');
151+
return stripslashes($_SERVER[self::ENV_VAR_TEST_APPLE_MERCHANT_ID_FOLDER] ?? '');
152152
}
153153

154154
/**

test/integration/ApplepayAdapterTest.php

Lines changed: 106 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -34,74 +34,143 @@
3434

3535
class ApplepayAdapterTest extends BaseIntegrationTest
3636
{
37+
/** @var string $appleCaCertificatePath Path to ca Certificate file. */
38+
protected $appleCaCertificatePath;
39+
/** @var string $merchantValidationUrl merchant validation url for testing. */
3740
private $merchantValidationUrl;
38-
private $merchantValidationCertificatePath;
39-
private $appleCaCertificatePath;
40-
41-
public function domainShouldBeValidatedCorrectlyDP()
42-
{
43-
return [
44-
'invalid: example.domain.com' => ['https://example.domain.com', false],
45-
'valid: https://apple-pay-gateway.apple.com/some/path' => ['https://apple-pay-gateway.apple.com/some/path', true],
46-
'valid: https://cn-apple-pay-gateway.apple.com' => ['https://cn-apple-pay-gateway.apple.com', true],
47-
'invalid: apple-pay-gateway-nc-pod1.apple.com' => ['apple-pay-gateway-nc-pod1.apple.com', false],
48-
'invalid: (empty)' => ['', false],
49-
];
50-
}
41+
/** @var string $applepayCombinedCertPath Path to combined certificate file. */
42+
private $applepayCombinedCertPath;
43+
/** @var string $applepayCertPath Path to merchant ID certificate file. */
44+
private $applepayCertPath;
45+
/** @var string $applepayKeyPath Path to merchant ID key file. */
46+
private $applepayKeyPath;
5147

5248
/**
5349
* @inheritDoc
5450
*/
5551
protected function setUp(): void
5652
{
5753
$this->merchantValidationUrl = 'https://apple-pay-gateway-cert.apple.com/paymentservices/startSession';
58-
$this->merchantValidationCertificatePath = EnvironmentService::getAppleMerchantCertificatePath();
54+
55+
$appleMerchantIdPath = EnvironmentService::getAppleMerchantIdPath();
56+
$this->applepayCertPath = $appleMerchantIdPath . 'merchant_id.pem';
57+
$this->applepayKeyPath = $appleMerchantIdPath . 'merchant_id.key';
58+
$this->applepayCombinedCertPath = $appleMerchantIdPath . 'apple-pay-cert.pem';
5959
$this->appleCaCertificatePath = EnvironmentService::getAppleCaCertificatePath();
6060
}
6161

6262
/**
63-
* test merchant validation request.
63+
* Test merchant validation request.
6464
*
6565
* @test
6666
*
67-
* @throws \UnzerSDK\Exceptions\ApplepayMerchantValidationException
67+
* @throws ApplepayMerchantValidationException
6868
*/
6969
public function verifyMerchantValidationRequest(): void
7070
{
7171
$applepaySession = $this->createApplepaySession();
7272
$appleAdapter = new ApplepayAdapter();
73+
$appleAdapter->init($this->applepayCertPath, $this->applepayKeyPath, $this->appleCaCertificatePath);
7374

7475
$validationResponse = $appleAdapter->validateApplePayMerchant(
7576
$this->merchantValidationUrl,
76-
$applepaySession,
77-
$this->merchantValidationCertificatePath,
78-
$this->appleCaCertificatePath
77+
$applepaySession
7978
);
8079

8180
$this->assertNotNull($validationResponse);
8281
}
8382

8483
/**
85-
* test merchant validation request without ca certificate.
84+
* @return ApplepaySession
85+
*/
86+
private function createApplepaySession(): ApplepaySession
87+
{
88+
return new ApplepaySession('merchantIdentifier', 'displayName', 'domainName');
89+
}
90+
91+
/**
92+
* Test merchant validation request without ca certificate.
8693
*
8794
* @test
8895
*
89-
* @throws \UnzerSDK\Exceptions\ApplepayMerchantValidationException
96+
* @throws ApplepayMerchantValidationException
9097
*/
91-
public function merchantValidationWorksWithoutCaCert(): void
98+
public function merchantValidationWorksWithApplepayCertOnly(): void
9299
{
93100
$applepaySession = $this->createApplepaySession();
94101
$appleAdapter = new ApplepayAdapter();
102+
$appleAdapter->init($this->applepayCombinedCertPath);
95103

96104
$validationResponse = $appleAdapter->validateApplePayMerchant(
97105
$this->merchantValidationUrl,
98-
$applepaySession,
99-
$this->merchantValidationCertificatePath
106+
$applepaySession
100107
);
101108

102109
$this->assertNotNull($validationResponse);
103110
}
104111

112+
/**
113+
* Test merchant validation request without ca certificate.
114+
*
115+
* @test
116+
*
117+
* @throws ApplepayMerchantValidationException
118+
*/
119+
public function merchantValidationWorksWithCertAndKey(): void
120+
{
121+
$applepaySession = $this->createApplepaySession();
122+
$appleAdapter = new ApplepayAdapter();
123+
$appleAdapter->init($this->applepayCertPath, $this->applepayKeyPath);
124+
125+
$validationResponse = $appleAdapter->validateApplePayMerchant(
126+
$this->merchantValidationUrl,
127+
$applepaySession
128+
);
129+
130+
$this->assertNotNull($validationResponse);
131+
}
132+
133+
/**
134+
* Test merchant validation request without key and only the merchant id certificate should throw exception.
135+
*
136+
* @test
137+
*
138+
* @throws ApplepayMerchantValidationException
139+
*/
140+
public function missingKeyShouldThrowException(): void
141+
{
142+
$applepaySession = $this->createApplepaySession();
143+
$appleAdapter = new ApplepayAdapter();
144+
$appleAdapter->init($this->applepayCertPath);
145+
146+
$this->expectException(ApplepayMerchantValidationException::class);
147+
$appleAdapter->validateApplePayMerchant(
148+
$this->merchantValidationUrl,
149+
$applepaySession
150+
);
151+
}
152+
153+
/**
154+
* Test merchant validation request without init() call should throw exception.
155+
*
156+
* @test
157+
*
158+
* @throws ApplepayMerchantValidationException
159+
*/
160+
public function missingInitCallThrowsException(): void
161+
{
162+
$applepaySession = $this->createApplepaySession();
163+
$appleAdapter = new ApplepayAdapter();
164+
165+
$this->expectException(ApplepayMerchantValidationException::class);
166+
$this->expectExceptionMessage('No curl adapter initiated yet. Make sure to cal init() function before.');
167+
168+
$appleAdapter->validateApplePayMerchant(
169+
$this->merchantValidationUrl,
170+
$applepaySession
171+
);
172+
}
173+
105174
/**
106175
* Merchant validation call should throw Exception if domain of Validation url is invalid.
107176
*
@@ -112,14 +181,14 @@ public function merchantValidationThrowsErrorForInvalidDomain(): void
112181
{
113182
$applepaySession = $this->createApplepaySession();
114183
$appleAdapter = new ApplepayAdapter();
184+
$appleAdapter->init($this->applepayCombinedCertPath);
115185

116186
$this->expectException(ApplepayMerchantValidationException::class);
117187
$this->expectExceptionMessage('Invalid URL used for merchantValidation request.');
118188

119189
$appleAdapter->validateApplePayMerchant(
120190
'https://invalid.domain.com/some/path',
121-
$applepaySession,
122-
$this->merchantValidationCertificatePath
191+
$applepaySession
123192
);
124193
}
125194

@@ -141,11 +210,18 @@ public function domainShouldBeValidatedCorrectly($validationUrl, $expectedResult
141210
$this->assertEquals($expectedResult, $domainValidation);
142211
}
143212

144-
/**
145-
* @return ApplepaySession
213+
/** Provides different urls to test domain validation.
214+
*
215+
* @return array[]
146216
*/
147-
private function createApplepaySession(): ApplepaySession
217+
public function domainShouldBeValidatedCorrectlyDP(): array
148218
{
149-
return new ApplepaySession('merchantIdentifier', 'displayName', 'domainName');
219+
return [
220+
'invalid: example.domain.com' => ['https://example.domain.com', false],
221+
'valid: https://apple-pay-gateway.apple.com/some/path' => ['https://apple-pay-gateway.apple.com/some/path', true],
222+
'valid: https://cn-apple-pay-gateway.apple.com' => ['https://cn-apple-pay-gateway.apple.com', true],
223+
'invalid: apple-pay-gateway-nc-pod1.apple.com' => ['apple-pay-gateway-nc-pod1.apple.com', false],
224+
'invalid: (empty)' => ['', false],
225+
];
150226
}
151227
}

0 commit comments

Comments
 (0)