| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- <?php
- use PHPUnit\Framework\Attributes\DataProvider;
- use PHPUnit\Framework\Attributes\Group;
- /**
- * Account forms reject invalid emails, weak/wrong passwords, and injection payloads.
- */
- #[Group('integration')]
- class AccountValidationTest extends BxDolAccountTestCase
- {
- static public function providerForRejectedCreateEmails(): array
- {
- return [
- 'empty' => [''],
- 'no-at' => ['not-an-email'],
- 'double-at' => ['a@b@c.com'],
- 'leading-dot' => ['.user@example.com'],
- 'underscore-domain' => ['user@exam_ple.com'],
- 'sql-or' => ["admin@example.com' OR '1'='1"],
- 'sql-comment' => ["' OR 1=1 --"],
- 'sql-union' => ["x' UNION SELECT password FROM sys_accounts --@example.com"],
- 'sql-drop' => ["'; DROP TABLE sys_accounts; --"],
- 'xss' => ['<script>alert(1)</script>@example.com'],
- ];
- }
- static public function providerForRejectedCreatePasswords(): array
- {
- return [
- 'empty' => [''],
- 'too-short' => ['Ab1'],
- 'no-digit' => ['Password'],
- 'no-upper' => ['password1'],
- 'no-lower' => ['PASSWORD1'],
- 'sql-or' => ["' OR '1'='1"],
- 'sql-comment' => ["' OR 1=1 --"],
- ];
- }
- static public function providerForRejectedCreateNames(): array
- {
- return [
- 'empty' => [''],
- 'at-prefix' => ['@admin'],
- ];
- }
- static public function providerForMaliciousNames(): array
- {
- return [
- 'sql-or' => ["' OR '1'='1"],
- 'sql-drop' => ["'; DROP TABLE sys_accounts; --"],
- 'sql-delete' => ['1; DELETE FROM sys_accounts --'],
- 'xss-script' => ['<script>alert(1)</script>'],
- 'xss-img' => ['<img src=x onerror=alert(1)>'],
- ];
- }
- static public function providerForRejectedPasswordsCurrent(): array
- {
- return [
- 'wrong' => ['not-the-password'],
- 'empty' => [''],
- 'sql-or' => ["' OR '1'='1"],
- 'sql-comment' => ["' OR 1=1 --"],
- 'sql-drop' => ["'; DROP TABLE sys_accounts; --"],
- ];
- }
- #[DataProvider('providerForRejectedCreateEmails')]
- public function testCreateFormRejectsInvalidEmail(string $sEmail): void
- {
- $this->bxBecomeGuest();
- $sName = 'lifecycle-' . bin2hex(random_bytes(4));
- $oForm = $this->bxSubmitCreateForm($sName, $sEmail, 'UnaTest1a');
- $this->bxAssertFormRejected($oForm, 'email');
- $iCreatedId = $this->bxAccountIdByName($sName);
- if ($iCreatedId)
- $this->_iCreatedAccountId = $iCreatedId;
- $this->assertSame(0, $iCreatedId);
- $this->bxAssertAccountsTableIntact();
- }
- #[DataProvider('providerForRejectedCreatePasswords')]
- public function testCreateFormRejectsInvalidPassword(string $sPassword): void
- {
- $this->bxBecomeGuest();
- $sEmail = 'lifecycle-' . bin2hex(random_bytes(4)) . '@example.com';
- $oForm = $this->bxSubmitCreateForm('Lifecycle User', $sEmail, $sPassword);
- $this->bxAssertFormRejected($oForm, 'password');
- $this->assertSame(0, $this->bxAccountIdByEmail($sEmail));
- $this->bxAssertAccountsTableIntact();
- }
- #[DataProvider('providerForRejectedCreateNames')]
- public function testCreateFormRejectsInvalidName(string $sName): void
- {
- $this->bxBecomeGuest();
- $sEmail = 'lifecycle-' . bin2hex(random_bytes(4)) . '@example.com';
- $oForm = $this->bxSubmitCreateForm($sName, $sEmail, 'UnaTest1a');
- $this->bxAssertFormRejected($oForm, 'name');
- $this->assertSame(0, $this->bxAccountIdByEmail($sEmail));
- $this->bxAssertAccountsTableIntact();
- }
- public function testCreateFormRejectsDuplicateEmail(): void
- {
- $this->bxBecomeGuest();
- $sEmail = $this->bxTestEmail('admin');
- $iExistingId = $this->bxAccountIdByEmail($sEmail);
- $this->assertGreaterThan(0, $iExistingId);
- $oForm = $this->bxSubmitCreateForm('Lifecycle User', $sEmail, 'UnaTest1a');
- $this->bxAssertFormRejected($oForm, 'email');
- $this->assertSame($iExistingId, $this->bxAccountIdByEmail($sEmail));
- $this->bxAssertAccountsTableIntact();
- }
- #[DataProvider('providerForMaliciousNames')]
- public function testCreateFormTreatsMaliciousNameAsData(string $sName): void
- {
- $this->bxBecomeGuest();
- $sEmail = 'lifecycle-' . bin2hex(random_bytes(4)) . '@example.com';
- $oForm = $this->bxSubmitCreateForm($sName, $sEmail, 'UnaTest1a');
- if (!$oForm->isSubmittedAndValid()) {
- $this->assertSame(0, $this->bxAccountIdByEmail($sEmail));
- $this->bxAssertAccountsTableIntact();
- return;
- }
- $this->_aCreatedEmails[] = $sEmail;
- $iAccountId = $oForm->insert(['email_confirmed' => 0]);
- $this->assertNotFalse($iAccountId);
- $this->_iCreatedAccountId = (int)$iAccountId;
- (new BxTemplAccountForms())->onAccountCreated($iAccountId, $oForm->isSetPendingApproval());
- $this->assertSame((int)$iAccountId, $this->bxAccountIdByEmail($sEmail));
- $this->bxAssertAccountsTableIntact();
- $oAccount = BxDolAccount::getInstance($iAccountId, true);
- $this->assertInstanceOf(BxDolAccount::class, $oAccount);
- $this->assertSame($sEmail, $oAccount->getEmail());
- $this->assertStringNotContainsString('<script', strtolower($oAccount->getDisplayName()));
- }
- #[DataProvider('providerForRejectedCreateEmails')]
- public function testEmailFormRejectsInvalidEmail(string $sEmail): void
- {
- $aCreated = $this->bxCreateLifecycleAccount();
- $sResult = $this->bxSubmitEmailForm($aCreated['id'], $sEmail, $aCreated['password']);
- $this->assertIsString($sResult);
- $this->assertStringNotContainsString(_t('_sys_account_settings_email_successfully_submitted'), $sResult);
- $oAccount = BxDolAccount::getInstance($aCreated['id'], true);
- $this->assertSame($aCreated['email'], $oAccount->getEmail());
- $this->assertSame($aCreated['id'], $this->bxAccountIdByEmail($aCreated['email']));
- $this->bxAssertAccountsTableIntact();
- }
- #[DataProvider('providerForRejectedPasswordsCurrent')]
- public function testEmailFormRejectsWrongPassword(string $sPassword): void
- {
- $aCreated = $this->bxCreateLifecycleAccount();
- $sEmailNew = 'lifecycle-' . bin2hex(random_bytes(4)) . '-new@example.com';
- $sResult = $this->bxSubmitEmailForm($aCreated['id'], $sEmailNew, $sPassword);
- $this->assertIsString($sResult);
- $this->assertStringNotContainsString(_t('_sys_account_settings_email_successfully_submitted'), $sResult);
- $oAccount = BxDolAccount::getInstance($aCreated['id'], true);
- $this->assertSame($aCreated['email'], $oAccount->getEmail());
- $this->assertSame(0, $this->bxAccountIdByEmail($sEmailNew));
- $this->bxAssertAccountsTableIntact();
- }
- public function testEmailFormRejectsDuplicateEmail(): void
- {
- $aCreated = $this->bxCreateLifecycleAccount();
- $sResult = $this->bxSubmitEmailForm($aCreated['id'], $this->bxTestEmail('admin'), $aCreated['password']);
- $this->assertIsString($sResult);
- $this->assertStringNotContainsString(_t('_sys_account_settings_email_successfully_submitted'), $sResult);
- $oAccount = BxDolAccount::getInstance($aCreated['id'], true);
- $this->assertSame($aCreated['email'], $oAccount->getEmail());
- $this->bxAssertAccountsTableIntact();
- }
- #[DataProvider('providerForRejectedCreateNames')]
- public function testInfoFormRejectsInvalidName(string $sName): void
- {
- $aCreated = $this->bxCreateLifecycleAccount();
- $sResult = $this->bxSubmitInfoForm($aCreated['id'], $sName);
- $this->assertIsString($sResult);
- $this->assertStringNotContainsString(_t('_sys_account_settings_info_successfully_submitted'), $sResult);
- $oAccount = BxDolAccount::getInstance($aCreated['id'], true);
- $this->assertSame($aCreated['name'], $oAccount->getDisplayName());
- $this->bxAssertAccountsTableIntact();
- }
- #[DataProvider('providerForMaliciousNames')]
- public function testInfoFormTreatsMaliciousNameAsData(string $sName): void
- {
- $aCreated = $this->bxCreateLifecycleAccount();
- $sResult = $this->bxSubmitInfoForm($aCreated['id'], $sName);
- $oAccount = BxDolAccount::getInstance($aCreated['id'], true);
- if (!str_contains((string)$sResult, _t('_sys_account_settings_info_successfully_submitted'))) {
- $this->assertSame($aCreated['name'], $oAccount->getDisplayName());
- $this->bxAssertAccountsTableIntact();
- return;
- }
- $this->assertSame($aCreated['email'], $oAccount->getEmail());
- $this->assertStringNotContainsString('<script', strtolower($oAccount->getDisplayName()));
- $this->bxAssertAccountsTableIntact();
- }
- #[DataProvider('providerForRejectedPasswordsCurrent')]
- public function testDeleteFormRejectsWrongPassword(string $sPassword): void
- {
- $aCreated = $this->bxCreateLifecycleAccount();
- $oForm = $this->bxSubmitDeleteForm($aCreated['account'], $sPassword);
- $this->bxAssertFormRejected($oForm, 'password_current');
- $this->assertInstanceOf(BxDolAccount::class, BxDolAccount::getInstance($aCreated['id'], true));
- $this->bxAssertAccountsTableIntact();
- }
- public function testDeleteFormRejectsMissingConfirm(): void
- {
- $aCreated = $this->bxCreateLifecycleAccount();
- $oForm = $this->bxSubmitDeleteForm($aCreated['account'], $aCreated['password'], '');
- $this->bxAssertFormRejected($oForm, 'delete_confirm');
- $this->assertInstanceOf(BxDolAccount::class, BxDolAccount::getInstance($aCreated['id'], true));
- $this->bxAssertAccountsTableIntact();
- }
- }
|