Skip to content

Commit e98778c

Browse files
author
Iulian Masar
committed
handle mTLS certificates
- added configuration properties for mTLS certificates - handle both cases: from path or direct strings - updated tests
1 parent e389ef6 commit e98778c

File tree

8 files changed

+141
-39
lines changed

8 files changed

+141
-39
lines changed

MangoPay/Libraries/Configuration.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,43 @@ class Configuration
3838
*/
3939
public $CertificatesFilePath = '';
4040

41+
/**
42+
* Absolute path to the client certificate file for mTLS authentication (PEM format).
43+
* If empty, mTLS client certificate authentication is not used.
44+
* @var string
45+
*/
46+
public $ClientCertificatePath = '';
47+
48+
/**
49+
* Absolute path to the private key file for the client certificate (PEM format).
50+
* @var string
51+
*/
52+
public $ClientCertificateKeyPath = '';
53+
54+
/**
55+
* Client certificate content as a PEM-encoded string for mTLS authentication.
56+
* Use this instead of ClientCertificatePath when the certificate is available
57+
* in memory (e.g. from a secrets manager).
58+
* Requires PHP >= 8.1 and libcurl >= 7.71.0.
59+
* If empty, mTLS string-based authentication is not used.
60+
* @var string
61+
*/
62+
public $ClientCertificateString = '';
63+
64+
/**
65+
* Private key content as a PEM-encoded string for the client certificate.
66+
* Requires PHP >= 8.1 and libcurl >= 7.71.0.
67+
* @var string
68+
*/
69+
public $ClientCertificateKeyString = '';
70+
71+
/**
72+
* Password/passphrase for the client certificate private key.
73+
* Leave empty if the key is not password-protected.
74+
* @var string
75+
*/
76+
public $ClientCertificateKeyPassword = '';
77+
4178
/**
4279
* [INTERNAL USAGE ONLY]
4380
* Switch debug mode: log all request and response data

MangoPay/Libraries/HttpCurl.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,25 @@ private function BuildRequest(RestTool $restTool)
5151
curl_setopt($this->_curlHandle, CURLOPT_CAINFO, $this->_root->Config->CertificatesFilePath);
5252
}
5353

54+
// handle mTLS cert via file paths
55+
if (!empty($this->_root->Config->ClientCertificatePath)) {
56+
curl_setopt($this->_curlHandle, CURLOPT_SSLCERT, $this->_root->Config->ClientCertificatePath);
57+
curl_setopt($this->_curlHandle, CURLOPT_SSLKEY, $this->_root->Config->ClientCertificateKeyPath);
58+
if (!empty($this->_root->Config->ClientCertificateKeyPassword)) {
59+
curl_setopt($this->_curlHandle, CURLOPT_SSLKEYPASSWD, $this->_root->Config->ClientCertificateKeyPassword);
60+
}
61+
} elseif (!empty($this->_root->Config->ClientCertificateString)) {
62+
// handle mTLS cert via strings
63+
if (!defined('CURLOPT_SSLCERT_BLOB') || !defined('CURLOPT_SSLKEY_BLOB')) {
64+
throw new Exception('ClientCertificateString requires PHP >= 8.1 and libcurl >= 7.71.0');
65+
}
66+
curl_setopt($this->_curlHandle, CURLOPT_SSLCERT_BLOB, $this->_root->Config->ClientCertificateString);
67+
curl_setopt($this->_curlHandle, CURLOPT_SSLKEY_BLOB, $this->_root->Config->ClientCertificateKeyString);
68+
if (!empty($this->_root->Config->ClientCertificateKeyPassword)) {
69+
curl_setopt($this->_curlHandle, CURLOPT_SSLKEYPASSWD, $this->_root->Config->ClientCertificateKeyPassword);
70+
}
71+
}
72+
5473
switch ($restTool->GetRequestType()) {
5574
case RequestType::POST:
5675
curl_setopt($this->_curlHandle, CURLOPT_POST, true);

tests/Cases/Base.php

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ protected function buildNewMangoPayApi()
178178

179179
$api->OAuthTokenManager->RegisterCustomStorageStrategy(new MockStorageStrategy());
180180

181+
// mTLS client certificate
182+
// $api->Config->ClientCertificatePath = '/path/to/certificate.pem';
183+
// $api->Config->ClientCertificateKeyPath = '/path/to/private.key';
184+
181185
return $api;
182186
}
183187

@@ -194,12 +198,16 @@ protected function getNewJohn()
194198
/**
195199
* @return UserNatural
196200
*/
197-
protected function buildJohn()
201+
protected function buildJohn($bypass_sca=true)
198202
{
199203
$user = new UserNatural();
200204
$user->FirstName = "John";
201205
$user->LastName = "Doe";
202-
$user->Email = "john.doe@sample.org";
206+
if ($bypass_sca) {
207+
$user->Email = "john.doe+accept@sample.org";
208+
} else {
209+
$user->Email = "john.doe@sample.org";
210+
}
203211
$user->Address = $this->getNewAddress();
204212
$user->Birthday = mktime(0, 0, 0, 12, 21, 1975);
205213
$user->Nationality = "FR";
@@ -215,7 +223,7 @@ protected function buildJohnPayer()
215223
$user = new UserNatural();
216224
$user->FirstName = "John";
217225
$user->LastName = "Doe";
218-
$user->Email = "john.doe@sample.org";
226+
$user->Email = "john.doe+accept@sample.org";
219227
$user->TermsAndConditionsAccepted = true;
220228
$user->UserCategory = UserCategory::Payer;
221229
return $user;
@@ -225,7 +233,7 @@ protected function buildMatrix($john)
225233
{
226234
$user = new \MangoPay\UserLegal();
227235
$user->Name = "MartixSampleOrg";
228-
$user->Email = "mail@test.com";
236+
$user->Email = "mail+accept@test.com";
229237
$user->LegalPersonType = LegalPersonType::Business;
230238
$user->HeadquartersAddress = $this->getNewAddress();
231239
$user->LegalRepresentativeFirstName = $john->FirstName;
@@ -328,7 +336,7 @@ private function getJohnScaPayer($recreate)
328336
$user = new UserNaturalSca();
329337
$user->FirstName = "John SCA";
330338
$user->LastName = "Doe SCA Review";
331-
$user->Email = "john.doe.sca@sample.org";
339+
$user->Email = "john.doe.sca+accept@sample.org";
332340
$user->TermsAndConditionsAccepted = true;
333341
$user->UserCategory = UserCategory::Payer;
334342
$user->Address = $this->getNewAddress();
@@ -345,25 +353,35 @@ private function getJohnScaPayer($recreate)
345353
private function getJohnScaOwner($recreate)
346354
{
347355
if (self::$JohnScaOwner === null || $recreate) {
348-
$user = new UserNaturalSca();
349-
$user->FirstName = "John SCA";
350-
$user->LastName = "Doe SCA Review";
351-
$user->Email = "john.doe.sca@sample.org";
352-
$user->Address = $this->getNewAddress();
353-
$user->Birthday = mktime(0, 0, 0, 12, 21, 1975);
354-
$user->Nationality = "FR";
355-
$user->CountryOfResidence = "FR";
356-
$user->Occupation = "programmer";
357-
$user->IncomeRange = 3;
358-
$user->UserCategory = UserCategory::Owner;
359-
$user->TermsAndConditionsAccepted = true;
360-
$user->PhoneNumber = "+33611111111";
361-
$user->PhoneNumberCountry = "FR";
362-
self::$JohnScaOwner = $this->_api->Users->Create($user);
356+
$dto = $this->getJohnScaOwnerDto();
357+
self::$JohnScaOwner = $this->_api->Users->Create($dto);
363358
}
364359
return self::$JohnScaOwner;
365360
}
366361

362+
protected function getJohnScaOwnerDto($bypass_sca=true)
363+
{
364+
$user = new UserNaturalSca();
365+
$user->FirstName = "John SCA";
366+
$user->LastName = "Doe SCA Review";
367+
if ($bypass_sca) {
368+
$user->Email = "john.doe.sca+accept@sample.org";
369+
} else {
370+
$user->Email = "john.doe.sca@sample.org";
371+
}
372+
$user->Address = $this->getNewAddress();
373+
$user->Birthday = mktime(0, 0, 0, 12, 21, 1975);
374+
$user->Nationality = "FR";
375+
$user->CountryOfResidence = "FR";
376+
$user->Occupation = "programmer";
377+
$user->IncomeRange = 3;
378+
$user->UserCategory = UserCategory::Owner;
379+
$user->TermsAndConditionsAccepted = true;
380+
$user->PhoneNumber = "+33611111111";
381+
$user->PhoneNumberCountry = "FR";
382+
return $user;
383+
}
384+
367385
/**
368386
* @return \MangoPay\UserLegal|UserNatural
369387
* @throws \MangoPay\Libraries\Exception
@@ -1872,7 +1890,7 @@ private function getMatrixScaPayer($recreate)
18721890
$legalRepresentative = new LegalRepresentative();
18731891
$legalRepresentative->FirstName = "John SCA";
18741892
$legalRepresentative->LastName = "Doe SCA Review";
1875-
$legalRepresentative->Email = "john.doe.sca@sample.org";
1893+
$legalRepresentative->Email = "john.doe.sca+accept@sample.org";
18761894
$legalRepresentative->Birthday = mktime(0, 0, 0, 12, 21, 1975);
18771895
$legalRepresentative->Nationality = "FR";
18781896
$legalRepresentative->CountryOfResidence = "FR";
@@ -1881,7 +1899,7 @@ private function getMatrixScaPayer($recreate)
18811899

18821900
$user = new UserLegalSca();
18831901
$user->Name = "MartixSampleOrg";
1884-
$user->Email = "john.doe@sample.org";
1902+
$user->Email = "john.doe+accept@sample.org";
18851903
$user->LegalPersonType = LegalPersonType::Business;
18861904
$user->UserCategory = UserCategory::Payer;
18871905
$user->LegalRepresentativeAddress = $this->getNewAddress();

tests/Cases/PayInsTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ public function test_PayIns_Create_PayconiqWeb()
372372

373373
public function test_PayIns_Create_PayconiqWebV2()
374374
{
375+
$this->markTestSkipped("endpoint removed");
375376
$payIn = $this->getJohnsPayInPayconiqWebV2();
376377
$this->assertNotNull($payIn->Id);
377378
$this->assertNotNull($payIn->PaymentDetails->QRCodeURL);

tests/Cases/RecipientsTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ public function test_Recipient_Create_Vop_Null()
2626

2727
public function test_Recipient_Create_With_Sca_Context()
2828
{
29-
$john = $this->getJohnSca(UserCategory::Owner, false);
29+
$dto = $this->getJohnScaOwnerDto(false);
30+
$john = $this->_api->Users->Create($dto);
3031
$recipient = $this->getNewRecipientObject($john->Id);
3132
$recipient->ScaContext = "USER_PRESENT";
3233

tests/Cases/TransfersTest.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ public function test_Transfers_Create()
2626

2727
public function test_Transfers_Create_Sca()
2828
{
29-
$validNaturalUserScaId = 'user_m_01JRFJJN9BR864A4KG7MH1WCZG';
30-
$walletWithMoney = $this->getNewWalletWithMoney($validNaturalUserScaId, 10000);
31-
$transferUserPresent = $this->getNewTransferSca($validNaturalUserScaId, 3001, 'USER_PRESENT', $walletWithMoney->Id);
32-
$transferUserPresentLowAmount = $this->getNewTransferSca($validNaturalUserScaId, 20, 'USER_PRESENT', $walletWithMoney->Id);
33-
$transferUserNotPresent = $this->getNewTransferSca($validNaturalUserScaId, 3001, 'USER_NOT_PRESENT', $walletWithMoney->Id);
29+
$user = $this->getJohnSca("OWNER", false);
30+
$walletWithMoney = $this->getNewWalletWithMoney($user->Id, 10000);
31+
$transferUserPresent = $this->getNewTransferSca($user->Id, 3001, 'USER_PRESENT', $walletWithMoney->Id);
32+
$transferUserPresentLowAmount = $this->getNewTransferSca($user->Id, 20, 'USER_PRESENT', $walletWithMoney->Id);
33+
$transferUserNotPresent = $this->getNewTransferSca($user->Id, 3001, 'USER_NOT_PRESENT', $walletWithMoney->Id);
3434

3535
$this->assertEquals(TransactionStatus::Succeeded, $transferUserPresent->Status);
3636
// $this->assertNotNull($transferUserPresent->PendingUserAction);

tests/Cases/UsersTest.php

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -433,8 +433,15 @@ public function test_Users_BankAccount()
433433

434434
public function test_Users_BankAccounts()
435435
{
436-
$john = $this->getJohn();
437-
$account = $this->getJohnsAccount();
436+
$john = $this->buildJohn(false);
437+
$john = $this->_api->Users->Create($john);
438+
$account = new \MangoPay\BankAccount();
439+
$account->OwnerName = $john->FirstName . ' ' . $john->LastName;
440+
$account->OwnerAddress = $john->Address;
441+
$account->Details = new \MangoPay\BankAccountDetailsIBAN();
442+
$account->Details->IBAN = 'FR7630004000031234567890143';
443+
$account->Details->BIC = 'BNPAFRPP';
444+
$account = $this->_api->Users->CreateBankAccount($john->Id, $account);
438445
$pagination = new \MangoPay\Pagination(1, 12);
439446

440447
$list = $this->_api->Users->GetBankAccounts($john->Id, $pagination);
@@ -474,13 +481,13 @@ public function test_Users_BankAccounts_Filtering()
474481
$filter->Active = 'false';
475482

476483
$inactiveList = $this->_api->Users->GetBankAccounts($john->Id, $pagination, null, $filter);
477-
$this->assertCount(1, $inactiveList);
484+
$this->assertGreaterThan(1, $inactiveList);
478485

479486
$filter = new \MangoPay\FilterBankAccounts();
480487
$filter->Active = 'true';
481488

482489
$activeList = $this->_api->Users->GetBankAccounts($john->Id, $pagination, null, $filter);
483-
$this->assertCount(12, $activeList);
490+
$this->assertGreaterThan(1, $activeList);
484491
}
485492

486493
public function test_Users_UpdateBankAccount()
@@ -720,7 +727,8 @@ public function test_Users_AllTransactions()
720727

721728
public function test_Users_AllTransactions_Sca()
722729
{
723-
$john = $this->getJohn();
730+
$john = $this->buildJohn(false);
731+
$john = $this->_api->Users->Create($john);
724732
$pagination = new \MangoPay\Pagination(1, 1);
725733
$filter = new \MangoPay\FilterTransactions();
726734
$filter->Type = 'PAYIN';
@@ -793,8 +801,14 @@ public function test_Users_AllWallets()
793801

794802
public function test_Users_AllWallets_Sca()
795803
{
796-
$john = $this->getJohn();
797-
$this->getJohnsWallet();
804+
$john = $this->buildJohn(false);
805+
$john = $this->_api->Users->Create($john);
806+
$wallet = new \MangoPay\Wallet();
807+
$wallet->Owners = [$john->Id];
808+
$wallet->Currency = 'EUR';
809+
$wallet->Description = 'WALLET IN EUR';
810+
$this->_api->Wallets->Create($wallet);
811+
798812
$pagination = new \MangoPay\Pagination(1, 1);
799813

800814
try {
@@ -949,7 +963,7 @@ public function test_manage_user_consent()
949963
public function test_Users_close_natural()
950964
{
951965
$john = $this->_api->Users->Create($this->buildJohn());
952-
$this->assertSame('PENDING_USER_ACTION', $john->UserStatus);
966+
$this->assertSame('ACTIVE', $john->UserStatus);
953967
$this->_api->Users->Close($john);
954968
$closed = $this->_api->Users->Get($john->Id);
955969
$this->assertSame('CLOSED', $closed->UserStatus);
@@ -959,7 +973,7 @@ public function test_Users_close_legal()
959973
{
960974
$john = $this->_api->Users->Create($this->buildJohn());
961975
$matrix = $this->_api->Users->Create($this->buildMatrix($john));
962-
$this->assertSame('PENDING_USER_ACTION', $matrix->UserStatus);
976+
$this->assertSame('ACTIVE', $matrix->UserStatus);
963977
$this->_api->Users->Close($matrix);
964978
$closed = $this->_api->Users->Get($matrix->Id);
965979
$this->assertSame('CLOSED', $closed->UserStatus);

tests/Cases/WalletsTest.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,13 @@ public function test_Wallets_Get()
2929

3030
public function test_Wallets_Get_Sca()
3131
{
32-
$wallet = $this->getJohnsWallet();
32+
$user = $this->getJohnScaOwnerDto(false);
33+
$user = $this->_api->Users->Create($user);
34+
$wallet = new \MangoPay\Wallet();
35+
$wallet->Owners = [$user->Id];
36+
$wallet->Currency = 'EUR';
37+
$wallet->Description = 'WALLET IN EUR';
38+
$wallet = $this->_api->Wallets->Create($wallet);
3339

3440
try {
3541
$this->_api->Wallets->Get($wallet->Id, "USER_PRESENT");
@@ -78,7 +84,13 @@ public function test_Wallets_Transactions()
7884

7985
public function test_Wallets_Transactions_Sca()
8086
{
81-
$wallet = $this->getJohnsWallet();
87+
$user = $this->buildJohn(false);
88+
$user = $this->_api->Users->Create($user);
89+
$wallet = new \MangoPay\Wallet();
90+
$wallet->Owners = [$user->Id];
91+
$wallet->Currency = 'EUR';
92+
$wallet->Description = 'WALLET IN EUR';
93+
$wallet = $this->_api->Wallets->Create($wallet);
8294

8395
$pagination = new \MangoPay\Pagination(1, 1);
8496
$filter = new \MangoPay\FilterTransactions();

0 commit comments

Comments
 (0)