Skip to content
This repository has been archived by the owner on Mar 27, 2019. It is now read-only.

Commit

Permalink
Improved validators with fixed number of digits.
Browse files Browse the repository at this point in the history
  • Loading branch information
ezzatron committed Aug 28, 2013
1 parent 064f0ce commit e036893
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 36 deletions.
25 changes: 20 additions & 5 deletions src/Eloquent/Otis/Hotp/HotpValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public function generator()
* @param string $secret The HOTP secret.
* @param integer $currentCounter The current counter value.
* @param integer|null &$newCounter Will be set to the new counter value.
* @param integer|null $digits The number of password digits.
* @param integer|null $window The amount of counter increments to search through for a match.
*
* @return boolean True if the password is valid.
Expand All @@ -56,15 +57,18 @@ public function validate(
$secret,
$currentCounter,
&$newCounter = null,
$digits = null,
$window = null
) {
$newCounter = $currentCounter;

if (null === $digits) {
$digits = 6;
}
if (null === $window) {
$window = 0;
}

$newCounter = $currentCounter;
$length = strlen($password);

for (
$counter = $currentCounter;
$counter <= $currentCounter + $window;
Expand All @@ -73,7 +77,7 @@ public function validate(
$value = $this->generator()->generate($secret, $counter);

try {
$thisPassword = $value->string($length);
$thisPassword = $value->string($digits);
} catch (Exception\InvalidPasswordLengthException $e) {
return false;
}
Expand All @@ -95,6 +99,7 @@ public function validate(
* @param string $secret The HOTP secret.
* @param integer $currentCounter The current counter value.
* @param integer|null &$newCounter Will be set to the new counter value.
* @param integer|null $digits The number of password digits.
* @param integer|null $window The amount of counter increments to search through for a match.
*
* @return boolean True if the password is valid.
Expand All @@ -104,6 +109,7 @@ public function validateSequence(
$secret,
$currentCounter,
&$newCounter = null,
$digits = null,
$window = null
) {
$newCounter = $currentCounter;
Expand All @@ -118,11 +124,20 @@ public function validateSequence(
$secret,
$currentCounter,
$counter,
$digits,
$window
)
) {
foreach ($passwords as $password) {
if (!$this->validate($password, $secret, $counter, $counter)) {
if (
!$this->validate(
$password,
$secret,
$counter,
$counter,
$digits
)
) {
return false;
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/Eloquent/Otis/Hotp/HotpValidatorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ interface HotpValidatorInterface
* @param string $secret The HOTP secret.
* @param integer $currentCounter The current counter value.
* @param integer|null &$newCounter Will be set to the new counter value.
* @param integer|null $digits The number of password digits.
* @param integer|null $window The amount of counter increments to search through for a match.
*
* @return boolean True if the password is valid.
Expand All @@ -32,6 +33,7 @@ public function validate(
$secret,
$currentCounter,
&$newCounter = null,
$digits = null,
$window = null
);

Expand All @@ -42,6 +44,7 @@ public function validate(
* @param string $secret The HOTP secret.
* @param integer $currentCounter The current counter value.
* @param integer|null &$newCounter Will be set to the new counter value.
* @param integer|null $digits The number of password digits.
* @param integer|null $window The amount of counter increments to search through for a match.
*
* @return boolean True if the password is valid.
Expand All @@ -51,6 +54,7 @@ public function validateSequence(
$secret,
$currentCounter,
&$newCounter = null,
$digits = null,
$window = null
);
}
15 changes: 12 additions & 3 deletions src/Eloquent/Otis/Totp/TotpValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public function generator()
*
* @param string $password The password to validate.
* @param string $secret The TOTP secret.
* @param integer|null $digits The number of password digits.
* @param integer|null $window The number of seconds each token is valid for.
* @param integer|null $pastWindows The number of past windows to check.
* @param integer|null $futureWindows The number of future windows to check.
Expand All @@ -62,11 +63,17 @@ public function generator()
public function validate(
$password,
$secret,
$digits = null,
$window = null,
$pastWindows = null,
$futureWindows = null,
&$driftWindows = null
) {
$driftWindows = null;

if (null === $digits) {
$digits = 6;
}
if (null === $window) {
$window = 30;
}
Expand All @@ -77,9 +84,11 @@ public function validate(
$futureWindows = 1;
}

$driftWindows = null;
if (strlen($password) !== $digits) {
return false;
}

$time = $this->isolator()->time();
$length = strlen($password);

for ($i = -$pastWindows; $i <= $futureWindows; ++$i) {
$result = $this->generator()->generate(
Expand All @@ -89,7 +98,7 @@ public function validate(
);

try {
$thisPassword = $result->string($length);
$thisPassword = $result->string($digits);
} catch (InvalidPasswordLengthException $e) {
return false;
}
Expand Down
2 changes: 2 additions & 0 deletions src/Eloquent/Otis/Totp/TotpValidatorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ interface TotpValidatorInterface
*
* @param string $password The password to validate.
* @param string $secret The TOTP secret.
* @param integer|null $digits The number of password digits.
* @param integer|null $window The number of seconds each token is valid for.
* @param integer|null $pastWindows The number of past windows to check.
* @param integer|null $futureWindows The number of future windows to check.
Expand All @@ -31,6 +32,7 @@ interface TotpValidatorInterface
public function validate(
$password,
$secret,
$digits = null,
$window = null,
$pastWindows = null,
$futureWindows = null,
Expand Down
36 changes: 19 additions & 17 deletions test/suite/Eloquent/Otis/Hotp/HotpValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,51 +37,53 @@ public function testConstructorDefaults()

public function validateData()
{
// password secret currentCounter window expected newCounter
// password secret currentCounter digits window expected newCounter
return array(
'No window, valid' => array('969429', '12345678901234567890', 3, null, true, 4),
'With window, valid' => array('520489', '12345678901234567890', 0, 9, true, 10),
'No window, valid' => array('969429', '12345678901234567890', 3, null, null, true, 4),
'With window, valid' => array('520489', '12345678901234567890', 0, null, 9, true, 10),

'No window, invalid' => array('338314', '12345678901234567890', 3, null, false, 3),
'With window, invalid' => array('520489', '12345678901234567890', 0, 8, false, 0),
'Invalid length' => array('12345', '12345678901234567890', 0, 100, false, 0),
'No window, invalid' => array('338314', '12345678901234567890', 3, null, null, false, 3),
'With window, invalid' => array('520489', '12345678901234567890', 0, null, 8, false, 0),
'Length mismatch' => array('969429', '12345678901234567890', 3, 8, null, false, 3),
'Invalid length' => array('12345', '12345678901234567890', 0, 5, 100, false, 0),
);
}

/**
* @dataProvider validateData
*/
public function testValidate($password, $secret, $currentCounter, $window, $expected, $expectedCounter)
public function testValidate($password, $secret, $currentCounter, $digits, $window, $expected, $expectedCounter)
{
$this->assertSame(
$expected,
$this->validator->validate($password, $secret, $currentCounter, $newCounter, $window)
$this->validator->validate($password, $secret, $currentCounter, $newCounter, $digits, $window)
);
$this->assertSame($expectedCounter, $newCounter);
}

public function validateSequenceData()
{
// passwords secret currentCounter window expected newCounter
// passwords secret currentCounter digits window expected newCounter
return array(
'No window, valid' => array(array('969429', '338314'), '12345678901234567890', 3, null, true, 5),
'With window, valid' => array(array('399871', '520489'), '12345678901234567890', 0, 8, true, 10),
'No window, valid' => array(array('969429', '338314'), '12345678901234567890', 3, null, null, true, 5),
'With window, valid' => array(array('399871', '520489'), '12345678901234567890', 0, null, 8, true, 10),

'No window, invalid' => array(array('359152', '969429'), '12345678901234567890', 3, null, false, 3),
'With window, invalid' => array(array('755224', '359152'), '12345678901234567890', 0, 100, false, 0),
'Invalid length' => array(array('755224', '12345'), '12345678901234567890', 0, 100, false, 0),
'No passwords' => array(array(), '12345678901234567890', 0, 100, false, 0),
'No window, invalid' => array(array('359152', '969429'), '12345678901234567890', 3, null, null, false, 3),
'With window, invalid' => array(array('755224', '359152'), '12345678901234567890', 0, null, 100, false, 0),
'Length mismatch' => array(array('969429', '338314'), '12345678901234567890', 3, 8, null, false, 3),
'Invalid length' => array(array('755224', '12345'), '12345678901234567890', 0, null, 100, false, 0),
'No passwords' => array(array(), '12345678901234567890', 0, null, 100, false, 0),
);
}

/**
* @dataProvider validateSequenceData
*/
public function testValidateSequence($passwords, $secret, $currentCounter, $window, $expected, $expectedCounter)
public function testValidateSequence($passwords, $secret, $currentCounter, $digits, $window, $expected, $expectedCounter)
{
$this->assertSame(
$expected,
$this->validator->validateSequence($passwords, $secret, $currentCounter, $newCounter, $window)
$this->validator->validateSequence($passwords, $secret, $currentCounter, $newCounter, $digits, $window)
);
$this->assertSame($expectedCounter, $newCounter);
}
Expand Down
23 changes: 12 additions & 11 deletions test/suite/Eloquent/Otis/Totp/TotpValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,30 +40,31 @@ public function testConstructorDefaults()

public function validateData()
{
// password secret window time pastWindows futureWindows expected drift
// password secret digits window time pastWindows futureWindows expected drift
return array(
'Valid, no drift' => array('14050471', '12345678901234567890', null, 1111111111, null, null, true, 0),
'Valid, 1 past drift' => array('07081804', '12345678901234567890', null, 1111111111, null, null, true, -1),
'Valid, 1 future drift' => array('44266759', '12345678901234567890', null, 1111111111, null, null, true, 1),
'Valid, 10 past drift' => array('13755423', '12345678901234567890', null, 1111111111, 100, 100, true, -10),
'Valid, 10 future drift' => array('78536305', '12345678901234567890', null, 1111111111, 100, 100, true, 10),
'Valid, no drift' => array('14050471', '12345678901234567890', 8, null, 1111111111, null, null, true, 0),
'Valid, 1 past drift' => array('07081804', '12345678901234567890', 8, null, 1111111111, null, null, true, -1),
'Valid, 1 future drift' => array('44266759', '12345678901234567890', 8, null, 1111111111, null, null, true, 1),
'Valid, 10 past drift' => array('13755423', '12345678901234567890', 8, null, 1111111111, 100, 100, true, -10),
'Valid, 10 future drift' => array('78536305', '12345678901234567890', 8, null, 1111111111, 100, 100, true, 10),

'Invalid, too far past' => array('13755423', '12345678901234567890', null, 1111111111, 9, null, false, null),
'Invalid, too far future' => array('78536305', '12345678901234567890', null, 1111111111, null, 9, false, null),
'Invalid length' => array('12345', '12345678901234567890', null, 1111111111, null, null, false, null),
'Invalid, too far past' => array('13755423', '12345678901234567890', 8, null, 1111111111, 9, null, false, null),
'Invalid, too far future' => array('78536305', '12345678901234567890', 8, null, 1111111111, null, 9, false, null),
'Length mismatch' => array('14050471', '12345678901234567890', null, null, 1111111111, null, null, false, null),
'Invalid length' => array('12345', '12345678901234567890', 5, null, 1111111111, null, null, false, null),
);
}

/**
* @dataProvider validateData
*/
public function testValidate($password, $secret, $window, $time, $pastWindows, $futureWindows, $expected, $expectedDrift)
public function testValidate($password, $secret, $digits, $window, $time, $pastWindows, $futureWindows, $expected, $expectedDrift)
{
Phake::when($this->isolator)->time()->thenReturn($time);

$this->assertSame(
$expected,
$this->validator->validate($password, $secret, $window, $pastWindows, $futureWindows, $actualDrift)
$this->validator->validate($password, $secret, $digits, $window, $pastWindows, $futureWindows, $actualDrift)
);
$this->assertSame($expectedDrift, $actualDrift);
}
Expand Down

0 comments on commit e036893

Please sign in to comment.