Skip to content

Commit ee2a5fa

Browse files
authored
feat: Allow http options to be passed into ParseClient (#513)
1 parent eba6f4b commit ee2a5fa

24 files changed

+651
-1
lines changed

src/Parse/HttpClients/ParseCurlHttpClient.php

+12
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,18 @@ public function setCAFile($caFile)
306306
$this->parseCurl->setOption(CURLOPT_CAINFO, $caFile);
307307
}
308308

309+
/**
310+
* Sets multiple curl options
311+
* https://www.php.net/manual/en/function.curl-setopt.php
312+
*
313+
* @param array $options Array of options to set
314+
* @throws ParseException
315+
*/
316+
public function setHttpOptions($options)
317+
{
318+
$this->parseCurl->setOptionsArray($options);
319+
}
320+
309321
/**
310322
* Gets the error code
311323
*

src/Parse/HttpClients/ParseHttpable.php

+7
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ public function setTimeout($timeout);
6363
*/
6464
public function setCAFile($caFile);
6565

66+
/**
67+
* Sets http options to pass to the http client
68+
*
69+
* @param string $httpOptions Options to set
70+
*/
71+
public function setHttpOptions($httpOptions);
72+
6673
/**
6774
* Gets the error code
6875
*

src/Parse/HttpClients/ParseStreamHttpClient.php

+25
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ class ParseStreamHttpClient implements ParseHttpable
7878
*/
7979
private $caFile;
8080

81+
/**
82+
* Options to pass to the stream context.
83+
*
84+
* @var array
85+
*/
86+
private $httpOptions;
87+
8188
/**
8289
* Optional timeout for this request
8390
*
@@ -195,6 +202,12 @@ public function send($url, $method = 'GET', $data = array())
195202
$this->options['ssl']['cafile'] = $this->caFile;
196203
}
197204

205+
if (isset($this->httpOptions)) {
206+
foreach ($this->httpOptions as $key => $value) {
207+
$this->options[$key] = $value;
208+
}
209+
}
210+
198211
// add additional options for this request
199212
$this->options['http'] = array(
200213
'method' => $method,
@@ -264,6 +277,7 @@ public function send($url, $method = 'GET', $data = array())
264277

265278
// clear options
266279
$this->options = array();
280+
$this->httpOptions = array();
267281

268282
// flush our existing headers
269283
$this->headers = array();
@@ -348,6 +362,17 @@ public function setCAFile($caFile)
348362
$this->caFile = $caFile;
349363
}
350364

365+
/**
366+
* Sets http options to pass to the stream context
367+
* https://www.php.net/manual/en/context.php
368+
*
369+
* @param array $httpOptions options to set
370+
*/
371+
public function setHttpOptions($httpOptions)
372+
{
373+
$this->httpOptions = $httpOptions;
374+
}
375+
351376
/**
352377
* Sets the request timeout
353378
*

src/Parse/ParseClient.php

+25
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,13 @@ final class ParseClient
103103
*/
104104
private static $caFile;
105105

106+
/**
107+
* Options to pass to the http client.
108+
*
109+
* @var array
110+
*/
111+
private static $httpOptions;
112+
106113
/**
107114
* Constant for version string to include with requests.
108115
*
@@ -301,6 +308,21 @@ public static function setCAFile($caFile)
301308
self::$caFile = $caFile;
302309
}
303310

311+
/**
312+
* Sets http options to pass to the http client
313+
* For curl
314+
* https://www.php.net/manual/en/function.curl-setopt.php
315+
*
316+
* For stream context
317+
* https://www.php.net/manual/en/context.php
318+
*
319+
* @param array $httpOptions options to set
320+
*/
321+
public static function setHttpOptions($httpOptions)
322+
{
323+
self::$httpOptions = $httpOptions;
324+
}
325+
304326
/**
305327
* ParseClient::_encode, internal method for encoding object values.
306328
*
@@ -452,6 +474,9 @@ private static function getPreparedHttpClient()
452474
// set CA file
453475
$httpClient->setCAFile(self::$caFile);
454476
}
477+
if (isset(self::$httpOptions)) {
478+
$httpClient->setHttpOptions(self::$httpOptions);
479+
}
455480

456481
return $httpClient;
457482
}

tests/Parse/Helper.php

+6
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,10 @@ public static function print($text)
105105
{
106106
fwrite(STDOUT, $text . "\n");
107107
}
108+
109+
public static function printArray($array)
110+
{
111+
print_r($array);
112+
ob_end_flush();
113+
}
108114
}

tests/Parse/ParseClientTest.php

+53
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
use PHPUnit\Framework\TestCase;
1818

19+
defined('CURLOPT_PINNEDPUBLICKEY') || define('CURLOPT_PINNEDPUBLICKEY', 10230);
20+
1921
class ParseClientTest extends TestCase
2022
{
2123
public static function setUpBeforeClass() : void
@@ -35,6 +37,9 @@ public function tearDown() : void
3537

3638
// unset CA file
3739
ParseClient::setCAFile(null);
40+
41+
// unset http options
42+
ParseClient::setHttpOptions(null);
3843
}
3944

4045
/**
@@ -667,4 +672,52 @@ public function testCheckBadServer()
667672
$this->assertTrue(isset($health['error_message']));
668673
}
669674
}
675+
676+
/**
677+
* @group test-http-options
678+
*/
679+
public function testCurlHttpOptions()
680+
{
681+
if (function_exists('curl_init')) {
682+
ParseClient::setHttpClient(new ParseCurlHttpClient());
683+
ParseClient::setServerURL('https://localhost:1338', 'parse');
684+
ParseClient::setHttpOptions([
685+
CURLOPT_SSL_VERIFYPEER => false,
686+
CURLOPT_PINNEDPUBLICKEY => 'sha256//Oz+R70/uIv0irdBWc7RNPyCGeZNbN+CBiPLjJxXWigg=',
687+
CURLOPT_SSLCERT => dirname(__DIR__).'/keys/client.crt',
688+
CURLOPT_SSLKEY => dirname(__DIR__).'/keys/client.key',
689+
]);
690+
$health = ParseClient::getServerHealth();
691+
692+
$this->assertNotNull($health);
693+
$this->assertEquals($health['status'], 200);
694+
$this->assertEquals($health['response']['status'], 'ok');
695+
Helper::setServerURL();
696+
}
697+
}
698+
699+
/**
700+
* @group test-http-options
701+
*/
702+
public function testStreamHttpOptions()
703+
{
704+
ParseClient::setHttpClient(new ParseStreamHttpClient());
705+
ParseClient::setServerURL('https://localhost:1338', 'parse');
706+
ParseClient::setHttpOptions([
707+
'ssl' => [
708+
'verify_peer' => false,
709+
'verify_peer_name' => false,
710+
'allow_self_signed' => true,
711+
'local_cert' => dirname(__DIR__).'/keys/client.crt',
712+
'local_pk' => dirname(__DIR__).'/keys/client.key',
713+
'peer_fingerprint' => '29F36676EFA0CA18B5B571C6144580044CB289C2',
714+
]
715+
]);
716+
$health = ParseClient::getServerHealth();
717+
718+
$this->assertNotNull($health);
719+
$this->assertEquals($health['status'], 200);
720+
$this->assertEquals($health['response']['status'], 'ok');
721+
Helper::setServerURL();
722+
}
670723
}

tests/gencerts.sh

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/bin/bash
2+
# https://gist.github.com/ryankurte/bc0d8cff6e73a6bb1950
3+
# https://curl.se/libcurl/c/CURLOPT_PINNEDPUBLICKEY.html
4+
# ./gencerts.sh parseca localhost parsephp keys/
5+
# ./gencerts.sh parseca client parsephp keys/
6+
7+
set -e
8+
9+
if [ "$#" -ne 3 ] && [ "$#" -ne 4 ]; then
10+
echo "Usage: $0 CA NAME ORG"
11+
echo "CA - name of fake CA"
12+
echo "NAME - name of fake client"
13+
echo "ORG - organisation for both"
14+
echo "[DIR] - directory for cert output"
15+
exit
16+
fi
17+
18+
CA=$1
19+
NAME=$2
20+
ORG=$3
21+
22+
if [ -z "$4" ]; then
23+
DIR=./
24+
else
25+
DIR=$4
26+
fi
27+
28+
if [ ! -d "$DIR" ]; then
29+
mkdir -p $DIR
30+
fi
31+
32+
LENGTH=4096
33+
DAYS=1000
34+
35+
SUBJECT=/C=NZ/ST=AKL/L=Auckland/O=$ORG
36+
37+
if [ ! -f "$DIR/$CA.key" ]; then
38+
39+
echo Generating CA
40+
openssl genrsa -out $DIR/$CA.key $LENGTH
41+
42+
echo Signing CA
43+
openssl req -x509 -new -nodes -key $DIR/$CA.key -sha256 -days 1024 -out $DIR/$CA.crt -subj $SUBJECT/CN=$CA
44+
45+
openssl x509 -in $DIR/$CA.crt -out $DIR/$CA.pem -text
46+
openssl x509 -sha1 -noout -in $DIR/$CA.pem -fingerprint | sed 's/SHA1 Fingerprint=//g' >> $DIR/$CA.fp
47+
48+
else
49+
echo Located existing CA
50+
fi
51+
52+
if [ ! -f "$DIR/$NAME.key" ]; then
53+
54+
echo Generating keys
55+
openssl genrsa -out $DIR/$NAME.key $LENGTH
56+
57+
echo Generating CSR
58+
openssl req -new -out $DIR/$NAME.csr -key $DIR/$NAME.key -subj $SUBJECT/CN=$NAME
59+
60+
echo Signing cert
61+
openssl x509 -req -days $DAYS -in $DIR/$NAME.csr -out $DIR/$NAME.crt -CA $DIR/$CA.crt -CAkey $DIR/$CA.key -CAcreateserial
62+
63+
echo Generating PEM
64+
openssl x509 -in $DIR/$NAME.crt -out $DIR/$NAME.pem -text
65+
66+
openssl x509 -sha1 -noout -in $DIR/$NAME.pem -fingerprint | sed 's/SHA1 Fingerprint=//g' > $DIR/$NAME.fp
67+
68+
echo Cleaning Up
69+
rm $DIR/*.csr
70+
71+
else
72+
echo Located existing client certificate
73+
fi
74+
75+
echo Done

tests/keys/client.crt

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIFITCCAwkCCQDEwoQengRnzDANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJO
3+
WjEMMAoGA1UECAwDQUtMMREwDwYDVQQHDAhBdWNrbGFuZDERMA8GA1UECgwIcGFy
4+
c2VwaHAxEDAOBgNVBAMMB3BhcnNlY2EwHhcNMjMwNTEyMjA0MzAzWhcNMjYwMjA1
5+
MjA0MzAzWjBSMQswCQYDVQQGEwJOWjEMMAoGA1UECAwDQUtMMREwDwYDVQQHDAhB
6+
dWNrbGFuZDERMA8GA1UECgwIcGFyc2VwaHAxDzANBgNVBAMMBmNsaWVudDCCAiIw
7+
DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMlKDLogZSNxm5S4h97XM8A1+MsP
8+
RaK15g8ebVEP7OGrwX1bvLVis0U/ixwHs0mqjQ9tbuefMZyiRgdds+8tpRCCuqGo
9+
dwSk8YMmOlrF5xIpBT2cXJLhGvDyY0F0RLFZYBoioTYFth4i91DkzhmBaL6vjyB7
10+
dXduR1JQbzTpQHkhofPziQsNtinf8qBqLbH1dFaqwUUEgtsKJyaPlxJR21TF3Fv+
11+
2K/fmoyzP6Er7eUSCvJRRH1hCwzHxl7GqTKyQeaS1RLdrHYqZmSeiJpxwl8uSdBs
12+
x4y8wG4lhRdantCCANlTwLd7zPiuIu+RBP276o2+02K8my9N2STZUgHXefSoNx4M
13+
alYujKBUV+2qmhR9H2HlUB/C/h5Sb8PSlfWyD/bo3+agyw/1+9rfMUYCmiEtdik7
14+
amoBaahoqAHL8S3K19L0ytWkgFejSMzn+i4VDifnwupXHifDL7CPDX0vevFNDvC7
15+
HMLkBWmkNaTduDL5P3ximtIXE7akhK+ufiNoO3KLItenCENxCzUdNdDHguei2U5E
16+
vhTyaTmIIrkUGxQ+aVDXRF2njAeQNMdTjsCAiiSN1corYX8RXvNo8QZQUEaHG42u
17+
O6Yolsw8EZotbpExo1jbiDlI2pVIuwJdtaDCucPN/X6uZ8odGQ0LUeyTBYda/1OG
18+
VIQzPZnxSHzqPzuZAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAHOLgs6FLIv+Vvpx
19+
fNtwabgOI2JxkFwaAujwWJS10tmczJp9qZilOlVBBhDFRBwBKqAaanHKCYkEfP6u
20+
dgC8RMOOYOb0gk6Tj3+zhvM4Qz+n8Cn2fA2+EtFXTKyMfJHuG/zddTLep2Phh9c9
21+
t5s/8aHAuqM9RGiA66V7mJiR9G5E8cNpyHniCh8Z11kABPMzAy92LyEGUlRwCrWx
22+
fCwItnzY2/7J8IW20rPIpb0EWmYHhxkUUzu7APQgvJpAUTdhmVKb9GLCUyY+oICE
23+
1WrnV9OQiqYVGFQkry9FXyKbsLVM6b6ar8DIXpYTYnd11sqFdiUUo4oItYYrO/1O
24+
0Bt0PX6hWYjR4r7ZT23KWAHZdlU4EFfrLJeZ6HDeYttJF68x9s8RZGgVU9Xlb/7X
25+
KGRVyCWI7aWzvI1lBVAnc7b7B9LrIkdHnYDt/ettmRvI/zZRBh73T7EPOQB7bEzP
26+
M8BXfAr/+qa2ToBWNd9AJrw7rg+OWGD801iXqsREyLr15nRIR12mGdKuyMkfghk1
27+
9J1Sd0fkfB2ci7Rn3afRdKksGuADQ2fvYihw0lALOPzSq/FYRqZBzwv9Qmw43CKd
28+
euEPcCfT7VYY47lmfFfKBcVv8d7NiJZRGkIUYUxS/UAsrLiBCgRkaUACcbLok7sJ
29+
jrdaTDx4EZu93dmJbEozNO6dRiLb
30+
-----END CERTIFICATE-----

tests/keys/client.der

1.29 KB
Binary file not shown.

tests/keys/client.fp

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
D7:10:BE:24:E6:85:A2:F8:79:F8:36:EF:42:A0:EC:B3:EC:93:C2:FB

tests/keys/client.key

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
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
51+
-----END RSA PRIVATE KEY-----

0 commit comments

Comments
 (0)