Skip to content
This repository was archived by the owner on Jan 13, 2022. It is now read-only.

Commit ebcf8c5

Browse files
author
Fosco Marotto
committed
Merge pull request #133 from sarciszewski/csprng2
Implement CSPRNG in a manner consistent with the feedback on #131
2 parents ceb0e69 + e659b60 commit ebcf8c5

File tree

2 files changed

+123
-63
lines changed

2 files changed

+123
-63
lines changed

src/Facebook/FacebookRedirectLoginHelper.php

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public function __construct($redirectUrl, $appId = null, $appSecret = null)
9090
public function getLoginUrl($scope = array(), $version = null)
9191
{
9292
$version = ($version ?: FacebookRequest::GRAPH_API_VERSION);
93-
$this->state = md5(uniqid(mt_rand(), true));
93+
$this->state = $this->random(16);
9494
$this->storeState($this->state);
9595
$params = array(
9696
'client_id' => $this->appId,
@@ -215,6 +215,56 @@ protected function loadState()
215215
}
216216
return null;
217217
}
218+
219+
/**
220+
* Generate a cryptographically secure pseudrandom number
221+
*
222+
* @param integer $bytes - number of bytes to return
223+
*
224+
* @return string
225+
*
226+
* @throws FacebookSDKException
227+
*
228+
* @todo Support Windows platforms
229+
*/
230+
public function random($bytes)
231+
{
232+
if (!is_numeric($bytes)) {
233+
throw new FacebookSDKException(
234+
"random() expects an integer"
235+
);
236+
}
237+
if ($bytes < 1) {
238+
throw new FacebookSDKException(
239+
"random() expects an integer greater than zero"
240+
);
241+
}
242+
$buf = '';
243+
// http://sockpuppet.org/blog/2014/02/25/safely-generate-random-numbers/
244+
if (is_readable('/dev/urandom')) {
245+
$fp = fopen('/dev/urandom', 'rb');
246+
if ($fp !== FALSE) {
247+
$buf = fread($fp, $bytes);
248+
fclose($fp);
249+
if($buf !== FALSE) {
250+
return bin2hex($buf);
251+
}
252+
}
253+
}
254+
255+
if (function_exists('mcrypt_create_iv')) {
256+
$buf = mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM);
257+
if ($buf !== FALSE) {
258+
return bin2hex($buf);
259+
}
260+
}
261+
262+
while (strlen($buf) < $bytes) {
263+
$buf .= md5(uniqid(mt_rand(), true), true);
264+
// We are appending raw binary
265+
}
266+
return bin2hex(substr($buf, 0, $bytes));
267+
}
218268

219269
/**
220270
* Disables the session_status() check when using $_SESSION
@@ -224,4 +274,4 @@ public function disableSessionStatusCheck()
224274
$this->checkForSessionStatus = false;
225275
}
226276

227-
}
277+
}
Lines changed: 71 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,71 @@
1-
<?php
2-
3-
use Facebook\FacebookRedirectLoginHelper;
4-
use Facebook\FacebookRequest;
5-
6-
class FacebookRedirectLoginHelperTest extends PHPUnit_Framework_TestCase
7-
{
8-
9-
const REDIRECT_URL = 'http://invalid.zzz';
10-
11-
public function testLoginURL()
12-
{
13-
$helper = new FacebookRedirectLoginHelper(
14-
self::REDIRECT_URL,
15-
FacebookTestCredentials::$appId,
16-
FacebookTestCredentials::$appSecret
17-
);
18-
$helper->disableSessionStatusCheck();
19-
$loginUrl = $helper->getLoginUrl();
20-
$state = $_SESSION['FBRLH_state'];
21-
$params = array(
22-
'client_id' => FacebookTestCredentials::$appId,
23-
'redirect_uri' => self::REDIRECT_URL,
24-
'state' => $state,
25-
'sdk' => 'php-sdk-' . FacebookRequest::VERSION,
26-
'scope' => implode(',', array())
27-
);
28-
$expectedUrl = 'https://www.facebook.com/v2.0/dialog/oauth?';
29-
$this->assertTrue(strpos($loginUrl, $expectedUrl) !== false);
30-
foreach ($params as $key => $value) {
31-
$this->assertTrue(
32-
strpos($loginUrl, $key . '=' . urlencode($value)) !== false
33-
);
34-
}
35-
}
36-
37-
public function testLogoutURL()
38-
{
39-
$helper = new FacebookRedirectLoginHelper(
40-
self::REDIRECT_URL,
41-
FacebookTestCredentials::$appId,
42-
FacebookTestCredentials::$appSecret
43-
);
44-
$helper->disableSessionStatusCheck();
45-
$logoutUrl = $helper->getLogoutUrl(
46-
FacebookTestHelper::$testSession, self::REDIRECT_URL
47-
);
48-
$params = array(
49-
'next' => self::REDIRECT_URL,
50-
'access_token' => FacebookTestHelper::$testSession->getToken()
51-
);
52-
$expectedUrl = 'https://www.facebook.com/logout.php?';
53-
$this->assertTrue(strpos($logoutUrl, $expectedUrl) !== false);
54-
foreach ($params as $key => $value) {
55-
$this->assertTrue(
56-
strpos($logoutUrl, $key . '=' . urlencode($value)) !== false
57-
);
58-
}
59-
}
60-
61-
}
1+
<?php
2+
3+
use Facebook\FacebookRedirectLoginHelper;
4+
use Facebook\FacebookRequest;
5+
6+
class FacebookRedirectLoginHelperTest extends PHPUnit_Framework_TestCase
7+
{
8+
9+
const REDIRECT_URL = 'http://invalid.zzz';
10+
11+
public function testLoginURL()
12+
{
13+
$helper = new FacebookRedirectLoginHelper(
14+
self::REDIRECT_URL,
15+
FacebookTestCredentials::$appId,
16+
FacebookTestCredentials::$appSecret
17+
);
18+
$helper->disableSessionStatusCheck();
19+
$loginUrl = $helper->getLoginUrl();
20+
$state = $_SESSION['FBRLH_state'];
21+
$params = array(
22+
'client_id' => FacebookTestCredentials::$appId,
23+
'redirect_uri' => self::REDIRECT_URL,
24+
'state' => $state,
25+
'sdk' => 'php-sdk-' . FacebookRequest::VERSION,
26+
'scope' => implode(',', array())
27+
);
28+
$expectedUrl = 'https://www.facebook.com/v2.0/dialog/oauth?';
29+
$this->assertTrue(strpos($loginUrl, $expectedUrl) !== false);
30+
foreach ($params as $key => $value) {
31+
$this->assertTrue(
32+
strpos($loginUrl, $key . '=' . urlencode($value)) !== false
33+
);
34+
}
35+
}
36+
37+
public function testLogoutURL()
38+
{
39+
$helper = new FacebookRedirectLoginHelper(
40+
self::REDIRECT_URL,
41+
FacebookTestCredentials::$appId,
42+
FacebookTestCredentials::$appSecret
43+
);
44+
$helper->disableSessionStatusCheck();
45+
$logoutUrl = $helper->getLogoutUrl(
46+
FacebookTestHelper::$testSession, self::REDIRECT_URL
47+
);
48+
$params = array(
49+
'next' => self::REDIRECT_URL,
50+
'access_token' => FacebookTestHelper::$testSession->getToken()
51+
);
52+
$expectedUrl = 'https://www.facebook.com/logout.php?';
53+
$this->assertTrue(strpos($logoutUrl, $expectedUrl) !== false);
54+
foreach ($params as $key => $value) {
55+
$this->assertTrue(
56+
strpos($logoutUrl, $key . '=' . urlencode($value)) !== false
57+
);
58+
}
59+
}
60+
61+
public function testCSPRNG()
62+
{
63+
$helper = new FacebookRedirectLoginHelper(
64+
self::REDIRECT_URL,
65+
FacebookTestCredentials::$appId,
66+
FacebookTestCredentials::$appSecret
67+
);
68+
$this->assertTrue(preg_match('/^([0-9a-f]+)$/', $helper->random(32)));
69+
}
70+
71+
}

0 commit comments

Comments
 (0)