mirror of
https://github.com/RobThree/TwoFactorAuth.git
synced 2026-08-17 18:03:15 +00:00
📚 doc blocks
This commit is contained in:
@@ -4,8 +4,14 @@ namespace RobThree\Auth\Providers\Qr;
|
||||
|
||||
abstract class BaseHTTPQRCodeProvider implements IQRCodeProvider
|
||||
{
|
||||
/** @var bool */
|
||||
protected $verifyssl;
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
protected function getContent($url)
|
||||
{
|
||||
$curlhandle = curl_init();
|
||||
|
||||
@@ -4,6 +4,21 @@ namespace RobThree\Auth\Providers\Qr;
|
||||
|
||||
interface IQRCodeProvider
|
||||
{
|
||||
/**
|
||||
* Generate and return the QR code to embed in a web page
|
||||
*
|
||||
* @param string $qrtext the value to encode in the QR code
|
||||
* @param int $size the desired size of the QR code
|
||||
*
|
||||
* @return string file contents of the QR code
|
||||
*/
|
||||
public function getQRCodeImage($qrtext, $size);
|
||||
|
||||
/**
|
||||
* Returns the appropriate mime type for the QR code
|
||||
* that will be generated
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getMimeType();
|
||||
}
|
||||
|
||||
@@ -5,9 +5,17 @@ namespace RobThree\Auth\Providers\Qr;
|
||||
// https://image-charts.com
|
||||
class ImageChartsQRCodeProvider extends BaseHTTPQRCodeProvider
|
||||
{
|
||||
/** @var string */
|
||||
public $errorcorrectionlevel;
|
||||
|
||||
/** @var int */
|
||||
public $margin;
|
||||
|
||||
/**
|
||||
* @param bool $verifyssl
|
||||
* @param string $errorcorrectionlevel
|
||||
* @param int $margin
|
||||
*/
|
||||
public function __construct($verifyssl = false, $errorcorrectionlevel = 'L', $margin = 1)
|
||||
{
|
||||
if (!is_bool($verifyssl)) {
|
||||
@@ -20,16 +28,28 @@ class ImageChartsQRCodeProvider extends BaseHTTPQRCodeProvider
|
||||
$this->margin = $margin;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMimeType()
|
||||
{
|
||||
return 'image/png';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQRCodeImage($qrtext, $size)
|
||||
{
|
||||
return $this->getContent($this->getUrl($qrtext, $size));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $qrtext the value to encode in the QR code
|
||||
* @param int $size the desired size of the QR code
|
||||
*
|
||||
* @return string file contents of the QR code
|
||||
*/
|
||||
public function getUrl($qrtext, $size)
|
||||
{
|
||||
return 'https://image-charts.com/chart?cht=qr'
|
||||
|
||||
@@ -5,13 +5,33 @@ namespace RobThree\Auth\Providers\Qr;
|
||||
// http://goqr.me/api/doc/create-qr-code/
|
||||
class QRServerProvider extends BaseHTTPQRCodeProvider
|
||||
{
|
||||
/** @var string */
|
||||
public $errorcorrectionlevel;
|
||||
|
||||
/** @var int */
|
||||
public $margin;
|
||||
|
||||
/** @var int */
|
||||
public $qzone;
|
||||
|
||||
/** @var string */
|
||||
public $bgcolor;
|
||||
|
||||
/** @var string */
|
||||
public $color;
|
||||
|
||||
/** @var string */
|
||||
public $format;
|
||||
|
||||
/**
|
||||
* @param bool $verifyssl
|
||||
* @param string $errorcorrectionlevel
|
||||
* @param int $margin
|
||||
* @param int $qzone
|
||||
* @param string $bgcolor
|
||||
* @param string $color
|
||||
* @param string $format
|
||||
*/
|
||||
public function __construct($verifyssl = false, $errorcorrectionlevel = 'L', $margin = 4, $qzone = 1, $bgcolor = 'ffffff', $color = '000000', $format = 'png')
|
||||
{
|
||||
if (!is_bool($verifyssl)) {
|
||||
@@ -28,6 +48,9 @@ class QRServerProvider extends BaseHTTPQRCodeProvider
|
||||
$this->format = $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMimeType()
|
||||
{
|
||||
switch (strtolower($this->format)) {
|
||||
@@ -46,16 +69,30 @@ class QRServerProvider extends BaseHTTPQRCodeProvider
|
||||
throw new QRException(sprintf('Unknown MIME-type: %s', $this->format));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQRCodeImage($qrtext, $size)
|
||||
{
|
||||
return $this->getContent($this->getUrl($qrtext, $size));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function decodeColor($value)
|
||||
{
|
||||
return vsprintf('%d-%d-%d', sscanf($value, "%02x%02x%02x"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $qrtext the value to encode in the QR code
|
||||
* @param int|string $size the desired size of the QR code
|
||||
*
|
||||
* @return string file contents of the QR code
|
||||
*/
|
||||
public function getUrl($qrtext, $size)
|
||||
{
|
||||
return 'https://api.qrserver.com/v1/create-qr-code/'
|
||||
|
||||
@@ -5,13 +5,24 @@ namespace RobThree\Auth\Providers\Qr;
|
||||
// http://qrickit.com/qrickit_apps/qrickit_api.php
|
||||
class QRicketProvider extends BaseHTTPQRCodeProvider
|
||||
{
|
||||
/** @var string */
|
||||
public $errorcorrectionlevel;
|
||||
public $margin;
|
||||
public $qzone;
|
||||
|
||||
/** @var string */
|
||||
public $bgcolor;
|
||||
|
||||
/** @var string */
|
||||
public $color;
|
||||
|
||||
/** @var string */
|
||||
public $format;
|
||||
|
||||
/**
|
||||
* @param string $errorcorrectionlevel
|
||||
* @param string $bgcolor
|
||||
* @param string $color
|
||||
* @param string $format
|
||||
*/
|
||||
public function __construct($errorcorrectionlevel = 'L', $bgcolor = 'ffffff', $color = '000000', $format = 'p')
|
||||
{
|
||||
$this->verifyssl = false;
|
||||
@@ -22,6 +33,9 @@ class QRicketProvider extends BaseHTTPQRCodeProvider
|
||||
$this->format = $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMimeType()
|
||||
{
|
||||
switch (strtolower($this->format)) {
|
||||
@@ -35,11 +49,20 @@ class QRicketProvider extends BaseHTTPQRCodeProvider
|
||||
throw new QRException(sprintf('Unknown MIME-type: %s', $this->format));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQRCodeImage($qrtext, $size)
|
||||
{
|
||||
return $this->getContent($this->getUrl($qrtext, $size));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $qrtext the value to encode in the QR code
|
||||
* @param int|string $size the desired size of the QR code
|
||||
*
|
||||
* @return string file contents of the QR code
|
||||
*/
|
||||
public function getUrl($qrtext, $size)
|
||||
{
|
||||
return 'http://qrickit.com/api/qr'
|
||||
|
||||
@@ -4,11 +4,17 @@ namespace RobThree\Auth\Providers\Rng;
|
||||
|
||||
class CSRNGProvider implements IRNGProvider
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRandomBytes($bytecount)
|
||||
{
|
||||
return random_bytes($bytecount); // PHP7+
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCryptographicallySecure()
|
||||
{
|
||||
return true;
|
||||
|
||||
@@ -4,8 +4,12 @@ namespace RobThree\Auth\Providers\Rng;
|
||||
|
||||
class HashRNGProvider implements IRNGProvider
|
||||
{
|
||||
/** @var string */
|
||||
private $algorithm;
|
||||
|
||||
/**
|
||||
* @param string $algorithm
|
||||
*/
|
||||
public function __construct($algorithm = 'sha256')
|
||||
{
|
||||
$algos = array_values(hash_algos());
|
||||
@@ -15,6 +19,9 @@ class HashRNGProvider implements IRNGProvider
|
||||
$this->algorithm = $algorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRandomBytes($bytecount)
|
||||
{
|
||||
$result = '';
|
||||
@@ -26,6 +33,9 @@ class HashRNGProvider implements IRNGProvider
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCryptographicallySecure()
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -4,6 +4,15 @@ namespace RobThree\Auth\Providers\Rng;
|
||||
|
||||
interface IRNGProvider
|
||||
{
|
||||
/**
|
||||
* @param int $bytecount the number of bytes of randomness to return
|
||||
*
|
||||
* @return string the random bytes
|
||||
*/
|
||||
public function getRandomBytes($bytecount);
|
||||
|
||||
/**
|
||||
* @return bool whether this provider is cryptographically secure
|
||||
*/
|
||||
public function isCryptographicallySecure();
|
||||
}
|
||||
|
||||
@@ -4,13 +4,20 @@ namespace RobThree\Auth\Providers\Rng;
|
||||
|
||||
class MCryptRNGProvider implements IRNGProvider
|
||||
{
|
||||
/** @var int */
|
||||
private $source;
|
||||
|
||||
/**
|
||||
* @param int $source
|
||||
*/
|
||||
public function __construct($source = MCRYPT_DEV_URANDOM)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRandomBytes($bytecount)
|
||||
{
|
||||
$result = @mcrypt_create_iv($bytecount, $this->source);
|
||||
@@ -20,6 +27,9 @@ class MCryptRNGProvider implements IRNGProvider
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCryptographicallySecure()
|
||||
{
|
||||
return true;
|
||||
|
||||
@@ -4,13 +4,20 @@ namespace RobThree\Auth\Providers\Rng;
|
||||
|
||||
class OpenSSLRNGProvider implements IRNGProvider
|
||||
{
|
||||
/** @var bool */
|
||||
private $requirestrong;
|
||||
|
||||
/**
|
||||
* @param bool $requirestrong
|
||||
*/
|
||||
public function __construct($requirestrong = true)
|
||||
{
|
||||
$this->requirestrong = $requirestrong;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRandomBytes($bytecount)
|
||||
{
|
||||
$result = openssl_random_pseudo_bytes($bytecount, $crypto_strong);
|
||||
@@ -23,6 +30,9 @@ class OpenSSLRNGProvider implements IRNGProvider
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCryptographicallySecure()
|
||||
{
|
||||
return $this->requirestrong;
|
||||
|
||||
@@ -9,17 +9,26 @@ use DateTime;
|
||||
*/
|
||||
class HttpTimeProvider implements ITimeProvider
|
||||
{
|
||||
/** @var string */
|
||||
public $url;
|
||||
public $options;
|
||||
|
||||
/** @var string */
|
||||
public $expectedtimeformat;
|
||||
|
||||
/** @var array */
|
||||
public $options;
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param string $expectedtimeformat
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct($url = 'https://google.com', $expectedtimeformat = 'D, d M Y H:i:s O+', array $options = null)
|
||||
{
|
||||
$this->url = $url;
|
||||
$this->expectedtimeformat = $expectedtimeformat;
|
||||
$this->options = $options;
|
||||
if ($this->options === null) {
|
||||
$this->options = array(
|
||||
if ($options === null) {
|
||||
$options = array(
|
||||
'http' => array(
|
||||
'method' => 'HEAD',
|
||||
'follow_location' => false,
|
||||
@@ -34,8 +43,12 @@ class HttpTimeProvider implements ITimeProvider
|
||||
)
|
||||
);
|
||||
}
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTime()
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -4,5 +4,8 @@ namespace RobThree\Auth\Providers\Time;
|
||||
|
||||
interface ITimeProvider
|
||||
{
|
||||
/**
|
||||
* @return int the current timestamp according to this provider
|
||||
*/
|
||||
public function getTime();
|
||||
}
|
||||
|
||||
@@ -7,10 +7,20 @@ namespace RobThree\Auth\Providers\Time;
|
||||
*/
|
||||
class NTPTimeProvider implements ITimeProvider
|
||||
{
|
||||
/** @var string */
|
||||
public $host;
|
||||
|
||||
/** @var int */
|
||||
public $port;
|
||||
|
||||
/** @var int */
|
||||
public $timeout;
|
||||
|
||||
/**
|
||||
* @param string $host
|
||||
* @param int $port
|
||||
* @param int $timeout
|
||||
*/
|
||||
public function __construct($host = 'time.google.com', $port = 123, $timeout = 1)
|
||||
{
|
||||
$this->host = $host;
|
||||
@@ -26,6 +36,9 @@ class NTPTimeProvider implements ITimeProvider
|
||||
$this->timeout = $timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTime()
|
||||
{
|
||||
try {
|
||||
|
||||
+84
-1
@@ -18,18 +18,48 @@ use RobThree\Auth\Providers\Time\NTPTimeProvider;
|
||||
// Algorithms, digits, period etc. explained: https://github.com/google/google-authenticator/wiki/Key-Uri-Format
|
||||
class TwoFactorAuth
|
||||
{
|
||||
/** @var string */
|
||||
private $algorithm;
|
||||
|
||||
/** @var int */
|
||||
private $period;
|
||||
|
||||
/** @var int */
|
||||
private $digits;
|
||||
|
||||
/** @var string */
|
||||
private $issuer;
|
||||
|
||||
/** @var ?IQRCodeProvider */
|
||||
private $qrcodeprovider = null;
|
||||
|
||||
/** @var ?IRNGProvider */
|
||||
private $rngprovider = null;
|
||||
|
||||
/** @var ?ITimeProvider */
|
||||
private $timeprovider = null;
|
||||
|
||||
/** @var string */
|
||||
private static $_base32dict = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=';
|
||||
|
||||
/** @var array */
|
||||
private static $_base32;
|
||||
|
||||
/** @var array */
|
||||
private static $_base32lookup = array();
|
||||
|
||||
/** @var array */
|
||||
private static $_supportedalgos = array('sha1', 'sha256', 'sha512', 'md5');
|
||||
|
||||
/**
|
||||
* @param ?string $issuer
|
||||
* @param int $digits
|
||||
* @param int $period
|
||||
* @param string $algorithm
|
||||
* @param ?IQRCodeProvider $qrcodeprovider
|
||||
* @param ?IRNGProvider $rngprovider
|
||||
* @param ?ITimeProvider $timeprovider
|
||||
*/
|
||||
public function __construct($issuer = null, $digits = 6, $period = 30, $algorithm = 'sha1', IQRCodeProvider $qrcodeprovider = null, IRNGProvider $rngprovider = null, ITimeProvider $timeprovider = null)
|
||||
{
|
||||
$this->issuer = $issuer;
|
||||
@@ -58,6 +88,11 @@ class TwoFactorAuth
|
||||
|
||||
/**
|
||||
* Create a new secret
|
||||
*
|
||||
* @param int $bits
|
||||
* @param bool $requirecryptosecure
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function createSecret($bits = 80, $requirecryptosecure = true)
|
||||
{
|
||||
@@ -76,6 +111,11 @@ class TwoFactorAuth
|
||||
|
||||
/**
|
||||
* Calculate the code with given secret and point in time
|
||||
*
|
||||
* @param string $secret
|
||||
* @param ?int $time
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCode($secret, $time = null)
|
||||
{
|
||||
@@ -92,6 +132,14 @@ class TwoFactorAuth
|
||||
|
||||
/**
|
||||
* Check if the code is correct. This will accept codes starting from ($discrepancy * $period) sec ago to ($discrepancy * period) sec from now
|
||||
*
|
||||
* @param string $secret
|
||||
* @param string $code
|
||||
* @param int $discrepancy
|
||||
* @param ?int $time
|
||||
* @param int $timeslice
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function verifyCode($secret, $code, $discrepancy = 1, $time = null, &$timeslice = 0)
|
||||
{
|
||||
@@ -114,6 +162,11 @@ class TwoFactorAuth
|
||||
|
||||
/**
|
||||
* Timing-attack safe comparison of 2 codes (see http://blog.ircmaxell.com/2014/11/its-all-about-time.html)
|
||||
*
|
||||
* @param string $safe
|
||||
* @param string $user
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function codeEquals($safe, $user)
|
||||
{
|
||||
@@ -134,6 +187,12 @@ class TwoFactorAuth
|
||||
|
||||
/**
|
||||
* Get data-uri of QRCode
|
||||
*
|
||||
* @param string $label
|
||||
* @param string $secret
|
||||
* @param mixed $size
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getQRCodeImageAsDataUri($label, $secret, $size = 200)
|
||||
{
|
||||
@@ -150,6 +209,10 @@ class TwoFactorAuth
|
||||
|
||||
/**
|
||||
* Compare default timeprovider with specified timeproviders and ensure the time is within the specified number of seconds (leniency)
|
||||
* @param ?array $timeproviders
|
||||
* @param int $leniency
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ensureCorrectTime(array $timeproviders = null, $leniency = 5)
|
||||
{
|
||||
@@ -176,11 +239,22 @@ class TwoFactorAuth
|
||||
}
|
||||
}
|
||||
|
||||
private function getTime($time)
|
||||
/**
|
||||
* @param ?int $time
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function getTime($time = null)
|
||||
{
|
||||
return ($time === null) ? $this->getTimeProvider()->getTime() : $time;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $time
|
||||
* @param int $offset
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function getTimeSlice($time = null, $offset = 0)
|
||||
{
|
||||
return (int)floor($time / $this->period) + ($offset * $this->period);
|
||||
@@ -188,6 +262,11 @@ class TwoFactorAuth
|
||||
|
||||
/**
|
||||
* Builds a string to be encoded in a QR code
|
||||
*
|
||||
* @param string $label
|
||||
* @param string $secret
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getQRText($label, $secret)
|
||||
{
|
||||
@@ -199,6 +278,10 @@ class TwoFactorAuth
|
||||
. '&digits=' . intval($this->digits);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
private function base32Decode($value)
|
||||
{
|
||||
if (strlen($value) == 0) {
|
||||
|
||||
@@ -9,6 +9,8 @@ trait MightNotMakeAssertions
|
||||
*
|
||||
* It has to be named something that doesn't collide with existing
|
||||
* TestCase methods as we can't support PHP return types right now
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function noAssertionsMade()
|
||||
{
|
||||
|
||||
@@ -8,6 +8,11 @@ use RobThree\Auth\TwoFactorAuthException;
|
||||
|
||||
class IQRCodeProviderTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @param string $datauri
|
||||
*
|
||||
* @return null|array
|
||||
*/
|
||||
private function DecodeDataUri($datauri)
|
||||
{
|
||||
if (preg_match('/data:(?P<mimetype>[\w\.\-\/]+);(?P<encoding>\w+),(?P<data>.*)/', $datauri, $m) === 1) {
|
||||
@@ -21,6 +26,9 @@ class IQRCodeProviderTest extends TestCase
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testTotpUriIsCorrect()
|
||||
{
|
||||
$qr = new TestQrProvider();
|
||||
@@ -32,6 +40,9 @@ class IQRCodeProviderTest extends TestCase
|
||||
$this->assertEquals('otpauth://totp/Test%26Label?secret=VMR466AB62ZBOKHE&issuer=Test%26Issuer&period=30&algorithm=SHA1&digits=6@200', $data['data']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testGetQRCodeImageAsDataUriThrowsOnInvalidSize()
|
||||
{
|
||||
$qr = new TestQrProvider();
|
||||
|
||||
@@ -6,11 +6,17 @@ use RobThree\Auth\Providers\Qr\IQRCodeProvider;
|
||||
|
||||
class TestQrProvider implements IQRCodeProvider
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getQRCodeImage($qrtext, $size)
|
||||
{
|
||||
return $qrtext . '@' . $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getMimeType()
|
||||
{
|
||||
return 'test/test';
|
||||
|
||||
@@ -12,6 +12,8 @@ class CSRNGProviderTest extends TestCase
|
||||
|
||||
/**
|
||||
* @requires function random_bytes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testCSRNGProvidersReturnExpectedNumberOfBytes()
|
||||
{
|
||||
|
||||
@@ -9,6 +9,9 @@ class HashRNGProviderTest extends TestCase
|
||||
{
|
||||
use NeedsRngLengths;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testHashRNGProvidersReturnExpectedNumberOfBytes()
|
||||
{
|
||||
$rng = new HashRNGProvider();
|
||||
|
||||
@@ -8,6 +8,9 @@ use RobThree\Auth\TwoFactorAuthException;
|
||||
|
||||
class IRNGProviderTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testCreateSecretThrowsOnInsecureRNGProvider()
|
||||
{
|
||||
$rng = new TestRNGProvider();
|
||||
@@ -18,6 +21,9 @@ class IRNGProviderTest extends TestCase
|
||||
$tfa->createSecret();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testCreateSecretOverrideSecureDoesNotThrowOnInsecureRNG()
|
||||
{
|
||||
$rng = new TestRNGProvider();
|
||||
@@ -26,6 +32,9 @@ class IRNGProviderTest extends TestCase
|
||||
$this->assertEquals('ABCDEFGHIJKLMNOP', $tfa->createSecret(80, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testCreateSecretDoesNotThrowOnSecureRNGProvider()
|
||||
{
|
||||
$rng = new TestRNGProvider(true);
|
||||
@@ -34,6 +43,9 @@ class IRNGProviderTest extends TestCase
|
||||
$this->assertEquals('ABCDEFGHIJKLMNOP', $tfa->createSecret());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testCreateSecretGeneratesDesiredAmountOfEntropy()
|
||||
{
|
||||
$rng = new TestRNGProvider(true);
|
||||
|
||||
@@ -12,6 +12,8 @@ class MCryptRNGProviderTest extends TestCase
|
||||
|
||||
/**
|
||||
* @requires function mcrypt_create_iv
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testMCryptRNGProvidersReturnExpectedNumberOfBytes()
|
||||
{
|
||||
|
||||
@@ -4,5 +4,6 @@ namespace Tests\Providers\Rng;
|
||||
|
||||
trait NeedsRngLengths
|
||||
{
|
||||
/** @var array */
|
||||
protected $rngTestLengths = array(1, 16, 32, 256);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@ class OpenSSLRNGProviderTest extends TestCase
|
||||
{
|
||||
use NeedsRngLengths;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testStrongOpenSSLRNGProvidersReturnExpectedNumberOfBytes()
|
||||
{
|
||||
$rng = new OpenSSLRNGProvider(true);
|
||||
@@ -19,6 +22,9 @@ class OpenSSLRNGProviderTest extends TestCase
|
||||
$this->assertTrue($rng->isCryptographicallySecure());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testNonStrongOpenSSLRNGProvidersReturnExpectedNumberOfBytes()
|
||||
{
|
||||
$rng = new OpenSSLRNGProvider(false);
|
||||
|
||||
@@ -6,13 +6,20 @@ use RobThree\Auth\Providers\Rng\IRNGProvider;
|
||||
|
||||
class TestRNGProvider implements IRNGProvider
|
||||
{
|
||||
/** @var bool */
|
||||
private $isSecure;
|
||||
|
||||
/**
|
||||
* @param bool $isSecure whether this provider is cryptographically secure
|
||||
*/
|
||||
function __construct($isSecure = false)
|
||||
{
|
||||
$this->isSecure = $isSecure;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRandomBytes($bytecount)
|
||||
{
|
||||
$result = '';
|
||||
@@ -24,6 +31,9 @@ class TestRNGProvider implements IRNGProvider
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isCryptographicallySecure()
|
||||
{
|
||||
return $this->isSecure;
|
||||
|
||||
@@ -11,6 +11,9 @@ class ITimeProviderTest extends TestCase
|
||||
{
|
||||
use MightNotMakeAssertions;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testEnsureCorrectTimeDoesNotThrowForCorrectTime()
|
||||
{
|
||||
$tpr1 = new TestTimeProvider(123);
|
||||
@@ -22,6 +25,9 @@ class ITimeProviderTest extends TestCase
|
||||
$this->noAssertionsMade();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testEnsureCorrectTimeThrowsOnIncorrectTime()
|
||||
{
|
||||
$tpr1 = new TestTimeProvider(123);
|
||||
@@ -34,6 +40,9 @@ class ITimeProviderTest extends TestCase
|
||||
$tfa->ensureCorrectTime(array($tpr2), 0); // We force a leniency of 0, 124-123 = 1 so this should throw
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testEnsureDefaultTimeProviderReturnsCorrectTime()
|
||||
{
|
||||
$tfa = new TwoFactorAuth('Test', 6, 30, 'sha1');
|
||||
|
||||
@@ -6,13 +6,20 @@ use RobThree\Auth\Providers\Time\ITimeProvider;
|
||||
|
||||
class TestTimeProvider implements ITimeProvider
|
||||
{
|
||||
/** @var int */
|
||||
private $time;
|
||||
|
||||
/**
|
||||
* @param int $time
|
||||
*/
|
||||
function __construct($time)
|
||||
{
|
||||
$this->time = $time;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTime()
|
||||
{
|
||||
return $this->time;
|
||||
|
||||
@@ -10,6 +10,9 @@ class TwoFactorAuthTest extends TestCase
|
||||
{
|
||||
use MightNotMakeAssertions;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testConstructorThrowsOnInvalidDigits()
|
||||
{
|
||||
$this->expectException(TwoFactorAuthException::class);
|
||||
@@ -17,6 +20,9 @@ class TwoFactorAuthTest extends TestCase
|
||||
new TwoFactorAuth('Test', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testConstructorThrowsOnInvalidPeriod()
|
||||
{
|
||||
$this->expectException(TwoFactorAuthException::class);
|
||||
@@ -24,6 +30,9 @@ class TwoFactorAuthTest extends TestCase
|
||||
new TwoFactorAuth('Test', 6, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testConstructorThrowsOnInvalidAlgorithm()
|
||||
{
|
||||
$this->expectException(TwoFactorAuthException::class);
|
||||
@@ -31,6 +40,9 @@ class TwoFactorAuthTest extends TestCase
|
||||
new TwoFactorAuth('Test', 6, 30, 'xxx');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testGetCodeReturnsCorrectResults()
|
||||
{
|
||||
$tfa = new TwoFactorAuth('Test');
|
||||
@@ -38,6 +50,9 @@ class TwoFactorAuthTest extends TestCase
|
||||
$this->assertEquals('538532', $tfa->getCode('VMR466AB62ZBOKHE', 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testEnsureAllTimeProvidersReturnCorrectTime()
|
||||
{
|
||||
$tfa = new TwoFactorAuth('Test', 6, 30, 'sha1');
|
||||
@@ -51,6 +66,9 @@ class TwoFactorAuthTest extends TestCase
|
||||
$this->noAssertionsMade();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testVerifyCodeWorksCorrectly()
|
||||
{
|
||||
$tfa = new TwoFactorAuth('Test', 6, 30);
|
||||
@@ -70,6 +88,9 @@ class TwoFactorAuthTest extends TestCase
|
||||
$this->assertTrue($tfa->verifyCode('VMR466AB62ZBOKHE', '543160', 2, 1426847205 - 65)); //Test discrepancy
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testVerifyCorrectTimeSliceIsReturned()
|
||||
{
|
||||
$tfa = new TwoFactorAuth('Test', 6, 30);
|
||||
@@ -96,6 +117,9 @@ class TwoFactorAuthTest extends TestCase
|
||||
$this->assertEquals(0, $timeslice8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testGetCodeThrowsOnInvalidBase32String1()
|
||||
{
|
||||
$tfa = new TwoFactorAuth('Test');
|
||||
@@ -105,6 +129,9 @@ class TwoFactorAuthTest extends TestCase
|
||||
$tfa->getCode('FOO1BAR8BAZ9'); //1, 8 & 9 are invalid chars
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testGetCodeThrowsOnInvalidBase32String2()
|
||||
{
|
||||
$tfa = new TwoFactorAuth('Test');
|
||||
@@ -114,6 +141,9 @@ class TwoFactorAuthTest extends TestCase
|
||||
$tfa->getCode('mzxw6==='); //Lowercase
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testKnownBase32DecodeTestVectors()
|
||||
{
|
||||
// We usually don't test internals (e.g. privates) but since we rely heavily on base32 decoding and don't want
|
||||
@@ -142,6 +172,9 @@ class TwoFactorAuthTest extends TestCase
|
||||
$this->assertEquals('foobar', $method->invoke($tfa, 'MZXW6YTBOI======'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testKnownBase32DecodeUnpaddedTestVectors()
|
||||
{
|
||||
// See testKnownBase32DecodeTestVectors() for the rationale behind testing the private base32Decode() method.
|
||||
@@ -163,6 +196,9 @@ class TwoFactorAuthTest extends TestCase
|
||||
$this->assertEquals('foobar', $method->invoke($tfa, 'MZXW6YTBOI'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testKnownTestVectors_sha1()
|
||||
{
|
||||
//Known test vectors for SHA1: https://tools.ietf.org/html/rfc6238#page-15
|
||||
@@ -176,6 +212,9 @@ class TwoFactorAuthTest extends TestCase
|
||||
$this->assertEquals('65353130', $tfa->getCode($secret, 20000000000));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testKnownTestVectors_sha256()
|
||||
{
|
||||
//Known test vectors for SHA256: https://tools.ietf.org/html/rfc6238#page-15
|
||||
@@ -189,6 +228,9 @@ class TwoFactorAuthTest extends TestCase
|
||||
$this->assertEquals('77737706', $tfa->getCode($secret, 20000000000));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function testKnownTestVectors_sha512()
|
||||
{
|
||||
//Known test vectors for SHA512: https://tools.ietf.org/html/rfc6238#page-15
|
||||
|
||||
Reference in New Issue
Block a user