Page MenuHomeIn-Portal Phabricator

INP-1756 - Create "Security*" classes for security-related jobs
ClosedPublic

Authored by alex on Nov 15 2018, 9:33 AM.

Details

Test Plan

Preparations

  1. after applying the patch run composer install command to install new dependencies
  2. create /test.php file with following content:
<?php
$start = microtime(true);

define('FULL_PATH', realpath(dirname(__FILE__)));
include_once(FULL_PATH.'/core/kernel/startup.php');

$application =& kApplication::Instance();
$application->Init();

echo '<h1>Random generator testing</h1>';

echo '<h2>Different resolving ways (numbers).</h2>';
echo '<div style="color: green;">value before/after "..." must match</div>';
$promise = SecurityGenerator::generateNumber(1, 100);
echo $promise->resolve() . ' ... ' . $promise->resolve() . '<br/>';

$promise = SecurityGenerator::generateNumber(1, 100);
echo $promise . ' ... ' . $promise . '<br/>';

$promise = SecurityGenerator::generateNumber(1, 100);
echo $promise->resolve() . ' ... ' . $promise . '<br/>';


echo '<h2>Different resolving ways (strings).</h2>';
echo '<div style="color: green;">value before/after "..." must match</div>';
$promise = SecurityGenerator::generateString(10, 'abcdef');
echo $promise->resolve() . ' ... ' . $promise->resolve() . '<br/>';

$promise = SecurityGenerator::generateString(10, 'abcdef');
echo $promise . ' ... ' . $promise . '<br/>';

$promise = SecurityGenerator::generateString(10, 'abcdef');
echo $promise->resolve() . ' ... ' . $promise . '<br/>';


echo '<h2>Different resolving ways (bytes).</h2>';
echo '<div style="color: green;">value before/after "..." must match</div>';
$promise = SecurityGenerator::generateBytes(10);
echo $promise->resolve() . ' ... ' . $promise->resolve() . '<br/>';

$promise = SecurityGenerator::generateBytes(10);
echo $promise . ' ... ' . $promise . '<br/>';

$promise = SecurityGenerator::generateBytes(10);
echo $promise->resolve() . ' ... ' . $promise . '<br/>';


echo '<h2>Raw byte value is 2x shorter, then non-raw byte value.</h2>';
echo '<div style="color: green;">number before "..." must be 2x smaller, then number after "..."</div>';
$non_raw_promise = SecurityGenerator::generateBytes(10, false);
$raw_promise = SecurityGenerator::generateBytes(10, true);
echo strlen($raw_promise) . ' ... ' . strlen($non_raw_promise) . ' (non-raw value: ' . $non_raw_promise . ')<br/>';


echo '<h2>String generation supports char classes.</h2>';
echo '<div style="color: green;">random string after ":" must consist only from char class symbols listed before ":"</div>';
echo 'CHAR_UPPER: ' . SecurityGenerator::generateString(10, SecurityGenerator::CHAR_UPPER) . '<br/>';
echo 'CHAR_LOWER: ' . SecurityGenerator::generateString(10, SecurityGenerator::CHAR_LOWER) . '<br/>';
echo 'CHAR_ALPHA: ' . SecurityGenerator::generateString(10, SecurityGenerator::CHAR_ALPHA) . '<br/>';
echo 'CHAR_DIGITS: ' . SecurityGenerator::generateString(10, SecurityGenerator::CHAR_DIGITS) . '<br/>';
echo 'CHAR_ALNUM: ' . SecurityGenerator::generateString(10, SecurityGenerator::CHAR_ALNUM) . '<br/>';
echo 'CHAR_UPPER_HEX: ' . SecurityGenerator::generateString(10, SecurityGenerator::CHAR_UPPER_HEX) . '<br/>';
echo 'CHAR_LOWER_HEX: ' . SecurityGenerator::generateString(10, SecurityGenerator::CHAR_LOWER_HEX) . '<br/>';
echo 'CHAR_BASE64: ' . SecurityGenerator::generateString(10, SecurityGenerator::CHAR_BASE64) . '<br/>';
echo 'CHAR_SYMBOLS: ' . SecurityGenerator::generateString(10, SecurityGenerator::CHAR_SYMBOLS) . '<br/>';
echo 'CHAR_BRACKETS: ' . SecurityGenerator::generateString(10, SecurityGenerator::CHAR_BRACKETS) . '<br/>';
echo 'CHAR_PUNCT: ' . SecurityGenerator::generateString(10, SecurityGenerator::CHAR_PUNCT) . '<br/>';
echo 'CHAR_ALNUM+CHAR_SYMBOLS+EASY_TO_READ: ' . SecurityGenerator::generateString(10, SecurityGenerator::CHAR_ALNUM | SecurityGenerator::CHAR_SYMBOLS | SecurityGenerator::EASY_TO_READ) . '<br/>';


echo '<h2>By default resolved value is returned.</h2>';
echo '<div style="color: green;">value before/after "..." must match</div>';
$promise = SecurityGenerator::generateNumber(1, 100);
echo $promise->resolve() . ' ... ' . $promise->asValue()->resolve() . '<br/>';
$promise = SecurityGenerator::generateString(10, 'abcdef');
echo $promise->resolve() . ' ... ' . $promise->asValue()->resolve() . '<br/>';
$promise = SecurityGenerator::generateBytes(10);
echo $promise->resolve() . ' ... ' . $promise->asValue()->resolve() . '<br/>';


echo '<h2>Signature of resolved value is returned.</h2>';
echo '<div style="color: green;">signature of generated value should be shown</div>';
$promise = SecurityGenerator::generateNumber(1, 100);
echo 'number: ' . $promise->asSignature()->resolve() . '<br/>';
$promise = SecurityGenerator::generateString(10, 'abcdef');
echo 'string: ' . $promise->asSignature()->resolve() . '<br/>';
$promise = SecurityGenerator::generateBytes(10);
echo 'bytes: ' . $promise->asSignature()->resolve() . '<br/>';


echo '<h2>Raw signature is 2x shorter, than non-raw signature.</h2>';
echo '<div style="color: green;">number before "..." must be 2x smaller, then number after "..."</div>';
$promise = SecurityGenerator::generateNumber(1, 100);
echo 'number: ' . strlen($promise->asSignature(true)->resolve()) . ' ... ' . strlen($promise->asSignature()->resolve()) . '<br/>';
$promise = SecurityGenerator::generateString(10, 'abcdef');
echo 'string: ' . strlen($promise->asSignature(true)->resolve()) . ' ... ' . strlen($promise->asSignature()->resolve()) . '<br/>';
$promise = SecurityGenerator::generateBytes(10);
echo 'bytes: ' . strlen($promise->asSignature(true)->resolve()) . ' ... ' . strlen($promise->asSignature()->resolve()) . '<br/>';


echo '<h2>Signature generation key can be overridden.</h2>';
echo '<div style="color: green;">values before "..." and after "..." must be different</div>';
$promise = SecurityGenerator::generateNumber(1, 100);
echo 'number: ' . $promise->asSignature()->resolve() . ' ... ' . $promise->asSignature(false, 'different key')->resolve() . '<br/>';
$promise = SecurityGenerator::generateString(10, 'abcdef');
echo 'string: ' . $promise->asSignature()->resolve() . ' ... ' . $promise->asSignature(false, 'different key')->resolve() . '<br/>';
$promise = SecurityGenerator::generateBytes(10);
echo 'bytes: ' . $promise->asSignature()->resolve() . ' ... ' . $promise->asSignature(false, 'different key')->resolve() . '<br/>';


echo '<h2>Unique value generation for database.</h2>';
echo '<div style="color: green;">no could be thrown at some times (e.g. when random number hits db column value)</div>';
$promise = SecurityGenerator::generateNumber(1, 10);
echo 'number: ' . $promise->resolveForPersisting('lang', 'LanguageId') . '<br/>';
$promise = SecurityGenerator::generateString(10, 'abcdef');
echo 'string: ' . $promise->resolveForPersisting('phrases', 'Phrase') . '<br/>';
$promise = SecurityGenerator::generateBytes(10);
echo 'bytes: ' . $promise->resolveForPersisting('phrases', 'Phrase') . '<br/>';


echo '<h1>Encrypter testing</h1>';

/** @var SecurityEncrypter $encrypter */
$encrypter = $application->recallObject('SecurityEncrypter');


echo '<h2>Different signature generation ways.</h2>';
echo '<div style="color: green;">all values after ":" must be different</div>';
echo 'signature using default key + non-raw: ' . $encrypter->createSignature('the string') . '<br/>';
echo 'signature using default key + raw: ' . $encrypter->createSignature('the string', true) . '<br/>';
echo 'signature using custom key + non-raw: ' . $encrypter->createSignature('the string', false, 'custom key') . '<br/>';
echo 'signature using custom key + raw: ' . $encrypter->createSignature('the string', true, 'custom key') . '<br/>';

echo '<h2>Encrypt/decrypt testing.</h2>';
echo '<div style="color: green;">see value in parenthesis below to detect if each line passed</div>';

$plaintext = 'the text';
$cyphertext = $encrypter->encrypt($plaintext);
$plaintext_decrypted = $encrypter->decrypt($cyphertext);
echo 'decrypt(encrypt(plain text)) == plain text: ' . ($plaintext === $plaintext_decrypted ? 'yes' : 'no') . ' (yes - passed)<br/>';

$plaintext = 'the text';
$cyphertext = $encrypter->encrypt($plaintext, 'custom password');
$plaintext_decrypted = $encrypter->decrypt($cyphertext);
echo 'decrypt(encrypt(plain text, custom password)) == plain text: ' . ($plaintext === $plaintext_decrypted ? 'yes' : 'no') . ' (no - passed)<br/>';

echo '<h2>Invalid signature on decrypting.</h2>';
echo '<div style="color: green;">there must be an exception</div>';
$plaintext = 'the text';
$cyphertext = $encrypter->encrypt($plaintext);
$plaintext_decrypted = $encrypter->decrypt(base64_decode(base64_decode($cyphertext) . 'e'));


$end = microtime(true);

Part 1

  1. perform an upgrade
  2. confirm, that after upgrade new "SecurityHmacKey" and "SecurityEncryptionKey" settings were added to "/system/config.php" and the have non-empty values

Part 2

  1. perform clean install
  2. confirm, that after install new "SecurityHmacKey" and "SecurityEncryptionKey" settings were added to "/system/config.php" and the have non-empty values

Part 3

  1. run /test.php script in browser
  2. confirm, that for each sub-section text in green is actually matching what is displayed in black after it

Diff Detail

Repository
rINP In-Portal
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.

Event Timeline

alex created this revision.Nov 15 2018, 9:33 AM
alex edited the test plan for this revision. (Show Details)Nov 15 2018, 9:36 AM
alex added a project: Restricted Project.
erik requested changes to this revision.Nov 15 2018, 11:33 AM
  1. Installation is possible only with PHP v.7 because of "random_int" function, used in added code.
  2. After installation with PHP v.7.2 new "SecurityHmacKey" and "SecurityEncryptionKey" settings were added normally, but test.php resulting in exception: -
This revision now requires changes to proceed.Nov 15 2018, 11:33 AM
alex requested review of this revision.Nov 15 2018, 2:05 PM
alex edited edge metadata.
  1. Installation is possible only with PHP v.7 because of "random_int" function, used in added code.

Since composer.json and composer.lock files were changed you should have also executed composer install command. I'll update test plan.

  1. After installation with PHP v.7.2 new "SecurityHmacKey" and "SecurityEncryptionKey" settings were added normally, but test.php resulting in exception: -

That is expected behavior, because if you close the debugger then last test exactly wants that exception to be thrown.

Please re-test.

alex edited the test plan for this revision. (Show Details)Nov 15 2018, 2:06 PM
erik accepted this revision.Nov 16 2018, 4:24 AM
This revision is now accepted and ready to land.Nov 16 2018, 4:24 AM
This revision was landed with ongoing or failed builds.Thu, Mar 18, 9:29 AM
This revision was automatically updated to reflect the committed changes.