Files
CoreLibs-Composer-All/test/phpunit/ACL/CoreLibsACLLoginTest.php
Clemens Schwaighofer 0f7bf0ab44 Session class rewrite
2024-12-04 14:22:26 +09:00

2148 lines
57 KiB
PHP

<?php
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
/*
Not yet covered tests:
- loginGetLocale
- loginGetHeaderColor
- loginGetPages
- loginGetEuid
*/
/**
* Test class for ACL\Login
* @coversDefaultClass \CoreLibs\ACL\Login
* @testdox \CoreLibs\ACL\Login method tests
*/
final class CoreLibsACLLoginTest extends TestCase
{
private static $db;
private static $log;
/**
* start DB conneciton, setup DB, etc
*
* @return void
*/
public static function setUpBeforeClass(): void
{
if (!extension_loaded('pgsql')) {
self::markTestSkipped(
'The PgSQL extension is not available for ACL\Login test.'
);
}
// database/CoreLibsACLLogin_database_create_data.sql
$load_sql_file = __DIR__
. DIRECTORY_SEPARATOR
. 'database/CoreLibsACLLogin_database_create_data.sql';
if (!is_file($load_sql_file)) {
self::markTestIncomplete(
'Missing ACL\Login database load SQL file'
);
}
// ASSUME that DB is on Port 5432 and use DEFAULT in path postgresql
$db_user = "corelibs_acl_login_test";
$db_password = "corelibs_acl_login_test";
$db_name = "corelibs_acl_login_test";
$db_host = "localhost";
// run the drop restore script before connecting to the database
// check exit, if not null then abort
$command = __DIR__ . DIRECTORY_SEPARATOR
. "CoreLibsACLLogin_database_prepare.sh "
. "$load_sql_file "
. "$db_user "
. "$db_name "
. "$db_host ";
exec($command, $ouput, $result);
if ($result != 0 || !empty($output[0])) {
self::markTestIncomplete(
'Drop/Create ACL\Login database failed with: ' . $result
);
}
// logger is always needed
// define basic connection set valid and one invalid
self::$log = new \CoreLibs\Logging\Logging([
// 'log_folder' => __DIR__ . DIRECTORY_SEPARATOR . 'log',
'log_folder' => DIRECTORY_SEPARATOR . 'tmp',
'log_file_id' => 'CoreLibs-ACL-Login-Test',
]);
// test database we need to connect do, if not possible this test is skipped
self::$db = new \CoreLibs\DB\IO(
[
'db_name' => $db_name,
'db_user' => $db_user,
'db_pass' => $db_password,
'db_host' => $db_host,
'db_port' => 5432,
'db_schema' => 'public',
'db_type' => 'pgsql',
'db_encoding' => '',
'db_ssl' => 'allow', // allow, disable, require, prefer
'db_debug' => true,
],
self::$log
);
// ALWAYS drop DB and RECREATE DB
// dropdb -U corelibs_acl_login_test -h localhost corelibs_acl_login_test
// createdb -U corelibs_acl_login_test -O corelibs_acl_login_test -E utf8 corelibs_acl_login_test;
if (!self::$db->dbGetConnectionStatus()) {
self::markTestSkipped(
'Cannot connect to valid Test DB for ACL\Login test.'
);
}
// check that edit_user table exist, I assume if this one does,
// the rest does too
if (!self::$db->dbShowTableMetaData('edit_user') !== false) {
self::markTestIncomplete(
'Cannot find edit_user table in ACL\Login database for testing'
);
}
// always disable max query calls
self::$db->dbSetMaxQueryCall(-1);
// insert additional content for testing (locked user, etc)
$queries = [
"INSERT INTO edit_access_data "
. "(edit_access_id, name, value, enabled) VALUES "
. "((SELECT edit_access_id FROM edit_access WHERE uid = 'AdminAccess'), "
. "'test', 'value', 1)"
];
foreach ($queries as $query) {
self::$db->dbExec($query);
}
// define mandatory constant
// must set
// TARGET
define('TARGET', 'test');
// LOGIN DB SCHEMA
// define('LOGIN_DB_SCHEMA', '');
// SHOULD SET
// DEFAULT_ACL_LEVEL (d80)
// OPT:
// LOGOUT_TARGET
// PASSWORD_CHANGE
// PASSWORD_FORGOT
// LANG:
// SITE_LOCALE
// DEFAULT_LOCALE
// CONTENT_PATH (domain)
$_SESSION = [];
global $_SESSION;
}
/**
* close db
*
* @return void
*/
public static function tearDownAfterClass(): void
{
if (self::$db->dbGetConnectionStatus()) {
self::$db->dbClose();
}
}
/**
* Undocumented function
*
* @return array
*/
public function loginProvider(): array
{
// 0[mock] : mock settings/override flag settings
// 1[get] : get array IN
// 2[post] : post array IN
// login_login, login_username, login_password, login_logout
// change_password, pw_username, pw_old_password, pw_new_password,
// pw_new_password_confirm
// 3[session]: override session set
// 4[error] : expected error code, 0 for all ok, 100 for login page view
// note that 1000 (no db), 2000 (no session), 3000 (options set error)
// must be tested too
// <1000 info, >=1000 critical error
// 5[return] : expected return array, eg login_error code,
// or other info data to match
$tests = [
'load, no login' => [
// error code, only for exceptions
[
'page_name' => 'edit_users.php',
],
[],
[],
[],
100,
[
'login_error' => 0,
'error_string' => 'Success: <b>No error</b>',
'error_string_text' => 'Success: No error',
],
],
'load, no login, ajax flag' => [
// error code, only for exceptions
[
'page_name' => 'edit_users.php',
// for ajax
'ajax_page' => true,
'ajax_test_type' => 'parameter',
],
[],
[],
[],
100,
[
'login_error' => 0,
'error_string' => 'Success: <b>No error</b>',
'error_string_text' => 'Success: No error',
// for ajax
'action' => 'login',
'ajax_get_count' => 0,
'ajax_post_count' => 5,
'ajax_post_action' => 'login',
],
],
'load, no login, ajax globals' => [
// error code, only for exceptions
[
'page_name' => 'edit_users.php',
// for ajax
'ajax_page' => true,
'ajax_test_type' => 'globals',
],
[],
[],
[],
100,
[
'login_error' => 0,
'error_string' => 'Success: <b>No error</b>',
'error_string_text' => 'Success: No error',
// for ajax
'action' => 'login',
'ajax_get_count' => 0,
'ajax_post_count' => 5,
'ajax_post_action' => 'login',
],
],
'load, session euid set only, php error' => [
[
'page_name' => 'edit_users.php',
],
[],
[],
[
'EUID' => 1,
'ECUID' => 'abc',
'ECUUID' => '1233456-1234-1234-1234-123456789012',
],
2,
[],
],
'load, session euid set, all set' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'edit_access_uid' => 'AdminAccess',
'edit_access_data' => 'test',
'base_access' => 'list',
'page_access' => 'list',
],
[],
[],
[
'EUID' => 1,
'ECUID' => 'abc',
'ECUUID' => '1233456-1234-1234-1234-123456789012',
'USER_NAME' => '',
'GROUP_NAME' => '',
'ADMIN' => 1,
'GROUP_ACL_LEVEL' => -1,
'PAGES_ACL_LEVEL' => [],
'USER_ACL_LEVEL' => -1,
'USER_ADDITIONAL_ACL' => [],
'GROUP_ADDITIONAL_ACL' => [],
'UNIT_UID' => [
'AdminAccess' => 1,
],
'UNIT' => [
1 => [
'acl_level' => 80,
'name' => 'Admin Access',
'uid' => 'AdminAccess',
'level' => -1,
'default' => 0,
'data' => [
'test' => 'value',
],
'additional_acl' => []
],
],
// 'UNIT_DEFAULT' => '',
// 'DEFAULT_ACL_LIST' => [],
],
0,
[
'login_error' => 0,
'admin_flag' => true,
'check_access' => true,
'check_access_id' => 1,
'check_access_data' => 'value',
'base_access' => true,
'page_access' => true,
],
],
// login: all missing
'login: failed: all missing' => [
[
'page_name' => 'edit_users.php',
],
[],
[
'login_login' => 'Login',
'login_username' => '',
'login_password' => '',
],
[],
100,
[
'login_error' => 102,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
. '<b>Login Failed - Please enter username and password</b>',
'error_string_text' => 'Fatal Error: '
. 'Login Failed - Please enter username and password'
]
],
// login: missing username
'login: failed: missing username' => [
[
'page_name' => 'edit_users.php',
],
[],
[
'login_login' => 'Login',
'login_username' => '',
'login_password' => 'abc',
],
[],
100,
[
'login_error' => 102,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
. '<b>Login Failed - Please enter username and password</b>',
'error_string_text' => 'Fatal Error: '
. 'Login Failed - Please enter username and password'
]
],
// login: missing password
'login: failed: missing password' => [
[
'page_name' => 'edit_users.php',
],
[],
[
'login_login' => 'Login',
'login_username' => 'abc',
'login_password' => '',
],
[],
100,
[
'login_error' => 102,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
. '<b>Login Failed - Please enter username and password</b>',
'error_string_text' => 'Fatal Error: '
. 'Login Failed - Please enter username and password'
]
],
// login: user not found
'login: failed: user not found' => [
[
'page_name' => 'edit_users.php',
],
[],
[
'login_login' => 'Login',
'login_username' => 'abc',
'login_password' => 'abc',
],
[],
100,
[
'login_error' => 1010,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
. '<b>Login Failed - Wrong Username or Password</b>',
'error_string_text' => 'Fatal Error: '
. 'Login Failed - Wrong Username or Password'
]
],
// login: invalid password
// 9999: not valid password encoding
// 1013: normal password failed
// 1012: plain password check failed
'login: failed: invalid password' => [
[
'page_name' => 'edit_users.php',
],
[],
[
'login_login' => 'Login',
'login_username' => 'admin',
'login_password' => 'abc',
],
[],
100,
[
// default password is plain text
'login_error' => 1012,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
. '<b>Login Failed - Wrong Username or Password</b>',
'error_string_text' => 'Fatal Error: '
. 'Login Failed - Wrong Username or Password'
]
],
// login: ok (but deleted)
'login: ok -> failed: but deleted' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'base_access' => 'list',
'page_access' => 'list',
'test_deleted' => true
],
[],
[
'login_login' => 'Login',
'login_username' => 'admin',
'login_password' => 'admin',
],
[],
100,
[
'login_error' => 106,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
. '<b>Login Failed - User is deleted</b>',
'error_string_text' => 'Fatal Error: '
. 'Login Failed - User is deleted'
]
],
// login: ok (but not enabled)
'login: ok -> failed: but not enabled' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'base_access' => 'list',
'page_access' => 'list',
'test_enabled' => true
],
[],
[
'login_login' => 'Login',
'login_username' => 'admin',
'login_password' => 'admin',
],
[],
100,
[
'login_error' => 104,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
. '<b>Login Failed - User not enabled</b>',
'error_string_text' => 'Fatal Error: '
. 'Login Failed - User not enabled'
]
],
// login: ok (but locked)
'login: ok -> failed: but locked' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'base_access' => 'list',
'page_access' => 'list',
'test_locked' => true
],
[],
[
'login_login' => 'Login',
'login_username' => 'admin',
'login_password' => 'admin',
],
[],
100,
[
'login_error' => 105,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
. '<b>Login Failed - User is locked</b>',
'error_string_text' => 'Fatal Error: '
. 'Login Failed - User is locked'
]
],
// login: make user get locked strict
'login: ok -> failed: get locked, strict' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'base_access' => 'list',
'page_access' => 'list',
'test_get_locked' => true,
'max_login_error_count' => 2,
'test_locked_strict' => true,
],
[],
[
'login_login' => 'Login',
'login_username' => 'admin',
'login_password' => 'admin',
],
[],
0,
[
'lock_run_login_error' => 1012,
'login_error' => 105,
]
],
// login ok, but in locked period (until)
'login: ok -> failed: but locked period (until:on)' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'base_access' => 'list',
'page_access' => 'list',
'test_locked_period_until' => 'on'
],
[],
[
'login_login' => 'Login',
'login_username' => 'admin',
'login_password' => 'admin',
],
[],
100,
[
'login_error' => 107,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
. '<b>Login Failed - User in locked via date period</b>',
'error_string_text' => 'Fatal Error: '
. 'Login Failed - User in locked via date period'
]
],
// login ok, but in locked period (until)
'login: ok, but locked period (until:off)' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'edit_access_uid' => 'AdminAccess',
'edit_access_data' => 'test',
'base_access' => 'list',
'page_access' => 'list',
'test_locked_period_until' => 'off'
],
[],
[
'login_login' => 'Login',
'login_username' => 'admin',
'login_password' => 'admin',
],
[],
0,
[
'login_error' => 0,
'admin_flag' => true,
'check_access' => true,
'check_access_id' => 1,
'check_access_data' => 'value',
'base_access' => true,
'page_access' => true,
]
],
// login ok, but in locked period (after)
'login: ok -> failed: but locked period (after:on)' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'base_access' => 'list',
'page_access' => 'list',
'test_locked_period_after' => 'on'
],
[],
[
'login_login' => 'Login',
'login_username' => 'admin',
'login_password' => 'admin',
],
[],
100,
[
'login_error' => 107,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
. '<b>Login Failed - User in locked via date period</b>',
'error_string_text' => 'Fatal Error: '
. 'Login Failed - User in locked via date period'
]
],
// login ok, but in locked period (until, after)
'login: ok -> failed:, but locked period (until:on, after:on)' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'base_access' => 'list',
'page_access' => 'list',
'test_locked_period_until' => 'on',
'test_locked_period_after' => 'on'
],
[],
[
'login_login' => 'Login',
'login_username' => 'admin',
'login_password' => 'admin',
],
[],
100,
[
'login_error' => 107,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
. '<b>Login Failed - User in locked via date period</b>',
'error_string_text' => 'Fatal Error: '
. 'Login Failed - User in locked via date period'
]
],
// login ok, but login user id locked
'login: ok -> failed:, but loginUserId locked' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'base_access' => 'list',
'page_access' => 'list',
'test_login_user_id_locked' => true
],
[],
[
'login_login' => 'Login',
'login_username' => 'admin',
'login_password' => 'admin',
],
[],
100,
[
'login_error' => 108,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
. '<b>Login Failed - User is locked via Login User ID</b>',
'error_string_text' => 'Fatal Error: '
. 'Login Failed - User is locked via Login User ID'
]
],
// login: ok
'login: ok' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'edit_access_uid' => 'AdminAccess',
'edit_access_data' => 'test',
'base_access' => 'list',
'page_access' => 'list',
],
[],
[
'login_login' => 'Login',
'login_username' => 'admin',
'login_password' => 'admin',
],
[],
0,
[
'login_error' => 0,
'admin_flag' => true,
'check_access' => true,
'check_access_id' => 1,
'check_access_data' => 'value',
'base_access' => true,
'page_access' => true,
]
],
// login check via _GET loginUserId
'login: ok, _GET loginUserId' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'edit_access_uid' => 'AdminAccess',
'edit_access_data' => 'test',
'base_access' => 'list',
'page_access' => 'list',
'test_login_user_id' => true,
'test_username' => 'admin',
'loginUserId' => '1234567890ABCDEFG',
],
[
'loginUserId' => '1234567890ABCDEFG',
],
[],
[],
0,
[
'login_error' => 0,
'admin_flag' => true,
'check_access' => true,
'check_access_id' => 1,
'check_access_data' => 'value',
'base_access' => true,
'page_access' => true,
]
],
// login check via _POST loginUserId
'login: ok, _POST loginUserId' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'edit_access_uid' => 'AdminAccess',
'edit_access_data' => 'test',
'base_access' => 'list',
'page_access' => 'list',
'test_login_user_id' => true,
'test_username' => 'admin',
'loginUserId' => '1234567890ABCDEFG',
],
[],
[
'loginUserId' => '1234567890ABCDEFG',
],
[],
0,
[
'login_error' => 0,
'admin_flag' => true,
'check_access' => true,
'check_access_id' => 1,
'check_access_data' => 'value',
'base_access' => true,
'page_access' => true,
]
],
// login: wrong GET loginUserId
'login: ok, illegal chars in _GET loginUserId' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'edit_access_uid' => 'AdminAccess',
'edit_access_data' => 'test',
'base_access' => 'list',
'page_access' => 'list',
'test_login_user_id' => true,
'test_username' => 'admin',
'loginUserId' => '1234567890ABCDEFG'
],
[
'loginUserId' => '123$%_/45678¥\-^9~~0$AB&CDEFG',
],
[],
[],
0,
[
'login_error' => 0,
'admin_flag' => true,
'check_access' => true,
'check_access_id' => 1,
'check_access_data' => 'value',
'base_access' => true,
'page_access' => true,
]
],
'login: not matching _GET loginUserId' => [
[
'page_name' => 'edit_users.php',
'test_login_user_id' => true,
'test_username' => 'admin',
'loginUserId' => '1234567890ABCDEFG'
],
[
'loginUserId' => 'ABC'
],
[],
[],
100,
[
'login_error' => 1010,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
. '<b>Login Failed - Wrong Username or Password</b>',
'error_string_text' => 'Fatal Error: '
. 'Login Failed - Wrong Username or Password'
]
],
// login ok with both _GET loginUserId and _POST login username/password
'login: ok, _GET loginUserId AND login post user data' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'edit_access_uid' => 'AdminAccess',
'edit_access_data' => 'test',
'base_access' => 'list',
'page_access' => 'list',
'test_login_user_id' => true,
'test_username' => 'admin',
'loginUserId' => '1234567890ABCDEFG',
],
[
'loginUserId' => '1234567890ABCDEFG',
],
[
'login_login' => 'Login',
'login_username' => 'admin',
'login_password' => 'admin',
],
[],
0,
[
'login_error' => 0,
'admin_flag' => true,
'check_access' => true,
'check_access_id' => 1,
'check_access_data' => 'value',
'base_access' => true,
'page_access' => true,
]
],
// login with invalid loginUserId but valid username/password
'login: ok, bad _GET loginUserId AND good login post user data' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'edit_access_uid' => 'AdminAccess',
'edit_access_data' => 'test',
'base_access' => 'list',
'page_access' => 'list',
'test_login_user_id' => true,
'test_username' => 'admin',
'loginUserId' => '1234567890ABCDEFG',
],
[
'loginUserId' => 'ABCS',
],
[
'login_login' => 'Login',
'login_username' => 'admin',
'login_password' => 'admin',
],
[],
0,
[
'login_error' => 0,
'admin_flag' => true,
'check_access' => true,
'check_access_id' => 1,
'check_access_data' => 'value',
'base_access' => true,
'page_access' => true,
]
],
// loginUserId check with revalidate on/off
'login: ok -> failed:, but revalidate trigger, _GET loginUserId' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'base_access' => 'list',
'page_access' => 'list',
'test_login_user_id_revalidate_after' => 'on',
'test_login_user_id' => true,
'test_username' => 'admin',
'loginUserId' => '1234567890ABCDEFG',
],
[
'loginUserId' => '1234567890ABCDEFG',
],
[],
[],
100,
[
'login_error' => 1101,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
. '<b>Login Failed - Login User ID must be validated</b>',
'error_string_text' => 'Fatal Error: '
. 'Login Failed - Login User ID must be validated'
]
],
// loginUserId check with revalidate on/off
'login: ok, revalidate set (outside), _GET loginUserId' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'edit_access_uid' => 'AdminAccess',
'edit_access_data' => 'test',
'base_access' => 'list',
'page_access' => 'list',
'test_login_user_id_revalidate_after' => 'off',
'test_login_user_id' => true,
'test_username' => 'admin',
'loginUserId' => '1234567890ABCDEFG',
],
[
'loginUserId' => '1234567890ABCDEFG',
],
[],
[],
0,
[
'login_error' => 0,
'admin_flag' => true,
'check_access' => true,
'check_access_id' => 1,
'check_access_data' => 'value',
'base_access' => true,
'page_access' => true,
]
],
// loginUserId check with active time from only
'login: ok -> failed:, _GET loginUserId, but outside valid (from:on) ' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'base_access' => 'list',
'page_access' => 'list',
'test_login_user_id_valid_from' => 'on',
'test_login_user_id' => true,
'test_username' => 'admin',
'loginUserId' => '1234567890ABCDEFG',
],
[
'loginUserId' => '1234567890ABCDEFG',
],
[],
[],
100,
[
'login_error' => 1102,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
. '<b>Login Failed - Login User ID is outside valid date range</b>',
'error_string_text' => 'Fatal Error: '
. 'Login Failed - Login User ID is outside valid date range'
]
],
// loginUserId check with inactive time from only
'login: ok, _GET loginUserId, but outside valid (from:off) ' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'edit_access_uid' => 'AdminAccess',
'edit_access_data' => 'test',
'base_access' => 'list',
'page_access' => 'list',
'test_login_user_id_valid_from' => 'off',
'test_login_user_id' => true,
'test_username' => 'admin',
'loginUserId' => '1234567890ABCDEFG',
],
[
'loginUserId' => '1234567890ABCDEFG',
],
[],
[],
0,
[
'login_error' => 0,
'admin_flag' => true,
'check_access' => true,
'check_access_id' => 1,
'check_access_data' => 'value',
'base_access' => true,
'page_access' => true,
]
],
// loginUserId check with active time until only
'login: ok -> failed:, _GET loginUserId, but outside valid (until:on) ' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'base_access' => 'list',
'page_access' => 'list',
'test_login_user_id_valid_until' => 'on',
'test_login_user_id' => true,
'test_username' => 'admin',
'loginUserId' => '1234567890ABCDEFG',
],
[
'loginUserId' => '1234567890ABCDEFG',
],
[],
[],
100,
[
'login_error' => 1102,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
. '<b>Login Failed - Login User ID is outside valid date range</b>',
'error_string_text' => 'Fatal Error: '
. 'Login Failed - Login User ID is outside valid date range'
]
],
// loginUserId check with active time from/until
'login: ok -> failed:, _GET loginUserId, but outside valid (from:on,until:on) ' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'base_access' => 'list',
'page_access' => 'list',
'test_login_user_id_valid_from' => 'on',
'test_login_user_id_valid_until' => 'on',
'test_login_user_id' => true,
'test_username' => 'admin',
'loginUserId' => '1234567890ABCDEFG',
],
[
'loginUserId' => '1234567890ABCDEFG',
],
[],
[],
100,
[
'login_error' => 1102,
'error_string' => '<span style="color: red;">Fatal Error:</span> '
. '<b>Login Failed - Login User ID is outside valid date range</b>',
'error_string_text' => 'Fatal Error: '
. 'Login Failed - Login User ID is outside valid date range'
]
],
// TODO: Test that if we have n day check with login, that after login we can use parameter login again
'login: ok -> failed -> ok:, _GET loginUserId, but must revalidate, normal login, _GET loginUserId' => [
[
'page_name' => 'edit_users.php',
'edit_access_id' => 1,
'edit_access_uid' => 'AdminAccess',
'edit_access_data' => 'test',
'base_access' => 'list',
'page_access' => 'list',
'test_login_user_id_revalidate_reset' => true,
'test_login_user_id' => true,
'test_username' => 'admin',
'loginUserId' => '1234567890ABCDEFG',
// this error is thrown on first login round
'login_error' => 1101,
// get post as set sub arrays
'get' => [
'loginUserId' => '1234567890ABCDEFG',
],
'post' => [
'login_login' => 'Login',
'login_username' => 'admin',
'login_password' => 'admin',
],
],
// all empty get, post, session
[],
[],
[],
0,
[
'login_error' => 0,
'admin_flag' => true,
'check_access' => true,
'check_access_id' => 1,
'check_access_data' => 'value',
'base_access' => true,
'page_access' => true,
]
]
//
// other:
// login check edit access id of ID not null and not in array
// login OK, but during action user gets disabled/deleted/etc
];
return $tests;
}
/**
* main test for acl login
*
* @dataProvider loginProvider
* @testdox ACL\Login Class tests [$_dataName]
*
* @param array<string,mixed> $mock_settings
* @param array<string,string> $get
* @param array<string,string> $post
* @param array<string,mixed> $session
* @param int $error
* @param array<string,mixed> $expected
* @return void
*/
public function testACLLoginFlow(
array $mock_settings,
array $get,
array $post,
array $session,
int $error,
array $expected
): void {
// reset session
$_SESSION = [];
// reset post & get
$_GET = [];
$_POST = [];
// reset global ajax page call
unset($GLOBALS['AJAX_PAGE']);
// init session (as MOCK)
/** @var \CoreLibs\Create\Session&MockObject */
$session_mock = $this->createPartialMock(
\CoreLibs\Create\Session::class,
['getSessionId', 'checkActiveSession', 'sessionDestroy']
);
$session_mock->method('getSessionId')->willReturn('ACLLOGINTEST12');
$session_mock->method('checkActiveSession')->willReturn(true);
$session_mock->method('sessionDestroy')->will(
$this->returnCallback(function () {
global $_SESSION;
$_SESSION = [];
return true;
})
);
// set _GET data
foreach ($get as $get_var => $get_value) {
$_GET[$get_var] = $get_value;
}
// set _POST data
foreach ($post as $post_var => $post_value) {
$_POST[$post_var] = $post_value;
}
// set _SESSION data
foreach ($session as $session_var => $session_value) {
$_SESSION[$session_var] = $session_value;
}
/** @var \CoreLibs\ACL\Login&MockObject */
$login_mock = $this->getMockBuilder(\CoreLibs\ACL\Login::class)
->setConstructorArgs([
self::$db,
self::$log,
$session_mock,
[
'auto_login' => false,
'default_acl_level' => 80,
'logout_target' => '',
'site_locale' => 'en_US.UTF-8',
'site_domain' => 'admin',
'site_encoding' => 'UTF-8',
'locale_path' => __DIR__ . DIRECTORY_SEPARATOR
. 'includes' . DIRECTORY_SEPARATOR
. 'locale' . DIRECTORY_SEPARATOR,
]
])
->onlyMethods(['loginTerminate', 'loginReadPageName', 'loginPrintLogin'])
->getMock();
$login_mock->expects($this->any())
->method('loginTerminate')
->will(
$this->returnCallback(function ($message, $code) {
throw new \Exception('', $code);
})
);
$login_mock->expects($this->any())
->method('loginReadPageName')
// set from mock settings, or empty if not set at all
->willReturn($mock_settings['page_name'] ?? '');
// do not echo out any string here
$login_mock->expects($this->any())
->method('loginPrintLogin')
->willReturnCallback(function () {
});
// if mock_settings: enabled OFF
// run DB update and set off
if (!empty($mock_settings['test_enabled'])) {
self::$db->dbExec(
"UPDATE edit_user SET enabled = 0 WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($post['login_username'])
);
}
if (!empty($mock_settings['test_deleted'])) {
self::$db->dbExec(
"UPDATE edit_user SET deleted = 1 WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($post['login_username'])
);
}
if (!empty($mock_settings['test_login_user_id_locked'])) {
self::$db->dbExec(
"UPDATE edit_user SET login_user_id_locked = 1 WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($post['login_username'])
);
}
if (
!empty($mock_settings['test_locked_period_until']) ||
!empty($mock_settings['test_locked_period_after'])
) {
$q_sub = '';
if (!empty($mock_settings['test_locked_period_until'])) {
if ($mock_settings['test_locked_period_until'] == 'on') {
$q_sub .= "lock_until = NOW() + '1 day'::interval ";
} elseif ($mock_settings['test_locked_period_until'] == 'off') {
$q_sub .= "lock_until = NOW() - '1 day'::interval ";
}
}
if (!empty($mock_settings['test_locked_period_after'])) {
if (!empty($q_sub)) {
$q_sub .= ", ";
}
if ($mock_settings['test_locked_period_after'] == 'on') {
$q_sub .= "lock_after = NOW() - '1 day'::interval ";
} elseif ($mock_settings['test_locked_period_after'] == 'off') {
$q_sub .= "lock_after = NOW() + '1 day'::interval ";
}
}
self::$db->dbExec(
"UPDATE edit_user SET "
. $q_sub
. "WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($post['login_username'])
);
}
// test locked already
if (!empty($mock_settings['test_locked'])) {
self::$db->dbExec(
"UPDATE edit_user SET locked = 1 WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($post['login_username'])
);
}
// test get locked
if (!empty($mock_settings['test_get_locked'])) {
// enable strict if needed
if (!empty($mock_settings['test_locked_strict'])) {
self::$db->dbExec(
"UPDATE edit_user SET strict = 1 WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($post['login_username'])
);
}
// reset any previous login error counts
self::$db->dbExec(
"UPDATE edit_user "
. "SET login_error_count = 0, login_error_date_last = NULL, "
. "login_error_date_first = NULL "
. "WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($post['login_username'])
);
// check the max login error count and try login until one time before
// on each run, check that lock count is matching
// next run (run test) should then fail with user locked IF strict,
// else fail as normal login
$login_mock->loginSetMaxLoginErrorCount($mock_settings['max_login_error_count']);
// temporary wrong password
$_POST['login_password'] = 'wrong';
for (
$run = 1, $max_run = $login_mock->loginGetMaxLoginErrorCount();
$run <= $max_run;
$run++
) {
try {
$login_mock->loginMainCall();
} catch (\Exception $e) {
// print 'Expected error code: ' . $e->getCode()
// . ', M:' . $e->getMessage()
// . ', L:' . $e->getLine()
// . ', E: ' . $login_mock->loginGetLastErrorCode()
// . "\n";
$this->assertEquals(
$expected['lock_run_login_error'],
$login_mock->loginGetLastErrorCode(),
'Assert login error code, exit on lock run'
);
}
// check user error count
$res = self::$db->dbReturnRow(
"SELECT login_error_count FROM edit_user "
. "WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($post['login_username'])
);
$this->assertEquals(
$res['login_error_count'],
$run,
'Assert equal login error count'
);
}
// set correct password next locked login
$_POST['login_password'] = $post['login_password'];
}
if (!empty($mock_settings['test_login_user_id'])) {
self::$db->dbExec(
"UPDATE edit_user SET "
. "login_user_id = "
. self::$db->dbEscapeLiteral($mock_settings['loginUserId'])
. " "
. "WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($mock_settings['test_username'])
);
}
if (!empty($mock_settings['test_login_user_id_revalidate_after'])) {
$q_sub = '';
if ($mock_settings['test_login_user_id_revalidate_after'] == 'on') {
$q_sub = "login_user_id_last_revalidate = NOW() - '1 day'::interval, "
. "login_user_id_revalidate_after = '1 day'::interval ";
} else {
$q_sub = "login_user_id_last_revalidate = NOW(), "
. "login_user_id_revalidate_after = '6 day'::interval ";
}
self::$db->dbExec(
"UPDATE edit_user SET "
. $q_sub
. "WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($mock_settings['test_username'])
);
}
if (!empty($mock_settings['test_login_user_id_revalidate_reset'])) {
// init dates data for revalidate frame,
// set to last revalidate 3 days ago and set revalidate frame to
// three days
self::$db->dbExec(
"UPDATE edit_user SET "
. "login_user_id_last_revalidate = NOW() - '3 day'::interval, "
. "login_user_id_revalidate_after = '3 day'::interval "
. "WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($mock_settings['test_username'])
);
$_GET = $mock_settings['get'];
// login with loginUserId -> fail
try {
$login_mock->loginMainCall();
} catch (\Exception $e) {
$this->assertEquals(
$mock_settings['login_error'],
$login_mock->loginGetLastErrorCode(),
'loginUserId reset 1: Assert first loginUserId run failes'
);
}
$_GET = [];
// login with username and password -> reset -> ok
// set _POST data
$_POST = $mock_settings['post'];
try {
$login_mock->loginMainCall();
$this->assertEquals(
0,
$login_mock->loginGetLastErrorCode(),
'loginUserId reset 2: Assert username/password login is successful'
);
} catch (\Exception $e) {
// if we end up here we have an issue
$this->assertTrue(
false,
'loginUserId reset 2: FAILED successful login'
);
}
$_POST = [];
// logut and run normal login with loginUserId
$_GET = $mock_settings['get'];
}
if (
!empty($mock_settings['test_login_user_id_valid_from']) ||
!empty($mock_settings['test_login_user_id_valid_until'])
) {
$q_sub = '';
if (!empty($mock_settings['test_login_user_id_valid_from'])) {
if ($mock_settings['test_login_user_id_valid_from'] == 'on') {
$q_sub .= "login_user_id_valid_from = NOW() + '1 day'::interval ";
} elseif ($mock_settings['test_login_user_id_valid_from'] == 'off') {
$q_sub .= "login_user_id_valid_from = NOW() - '1 day'::interval ";
}
}
if (!empty($mock_settings['test_login_user_id_valid_until'])) {
if (!empty($q_sub)) {
$q_sub .= ", ";
}
if ($mock_settings['test_login_user_id_valid_until'] == 'on') {
$q_sub .= "login_user_id_valid_until = NOW() - '1 day'::interval ";
} elseif ($mock_settings['test_login_user_id_valid_until'] == 'off') {
$q_sub .= "login_user_id_valid_until = NOW() + '1 day'::interval ";
}
}
self::$db->dbExec(
"UPDATE edit_user SET "
. $q_sub
. "WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($mock_settings['test_username'])
);
}
// run test
try {
// if ajax call
// check if parameter, or globals (old type)
// else normal call
if (
!empty($mock_settings['ajax_test_type']) &&
$mock_settings['ajax_test_type'] == 'parameter'
) {
$login_mock->loginMainCall($mock_settings['ajax_page']);
} elseif (
!empty($mock_settings['ajax_test_type']) &&
$mock_settings['ajax_test_type'] == 'globals'
) {
$GLOBALS['AJAX_PAGE'] = $mock_settings['ajax_page'];
$login_mock->loginMainCall();
} else {
$login_mock->loginMainCall();
}
// on ok, do post login check based on expected return
// - loginGetLastErrorCode
$this->assertEquals(
$expected['login_error'],
$login_mock->loginGetLastErrorCode(),
'Assert login error code'
);
// - loginGetPageName
$this->assertEquals(
$mock_settings['page_name'],
$login_mock->loginGetPageName(),
'Assert page name'
);
// - loginCheckPermissions [duplicated from loginrun]
$this->assertTrue(
$login_mock->loginCheckPermissions(),
'Assert true for login permission ok'
);
// - loginCheckAccess [use Base, Page below]
$this->assertEquals(
$expected['base_access'],
$login_mock->loginCheckAccess('base', $mock_settings['base_access']),
'Assert base access, via main method'
);
$this->assertEquals(
$expected['base_access'],
$login_mock->loginCheckAccess('page', $mock_settings['base_access']),
'Assert page access, via main method'
);
// - loginCheckAccessBase
$this->assertEquals(
$expected['base_access'],
$login_mock->loginCheckAccessBase($mock_settings['base_access']),
'Assert base access'
);
// - loginCheckAccessPage
$this->assertEquals(
$expected['page_access'],
$login_mock->loginCheckAccessPage($mock_settings['page_access']),
'Assert page access'
);
// - loginCheckEditAccess
$this->assertEquals(
$expected['check_access'],
$login_mock->loginCheckEditAccess($mock_settings['edit_access_id']),
'Assert check access'
);
// - loginCheckEditAccessId
$this->assertEquals(
$expected['check_access_id'],
$login_mock->loginCheckEditAccessId((int)$mock_settings['edit_access_id']),
'Assert check access id valid'
);
// - loginGetEditAccessIdFromUid
$this->assertEquals(
$expected['check_access_id'],
$login_mock->loginGetEditAccessIdFromUid($mock_settings['edit_access_uid']),
'Assert check access uid to id valid'
);
// - loginGetEditAccessData
$this->assertEquals(
$expected['check_access_data'],
$login_mock->loginGetEditAccessData(
$mock_settings['edit_access_id'],
$mock_settings['edit_access_data']
),
'Assert check access id data value valid'
);
// - loginIsAdmin
$this->assertEquals(
$expected['admin_flag'],
$login_mock->loginIsAdmin(),
'Assert admin flag set'
);
// - loginGetAcl
$this->assertIsArray(
$login_mock->loginGetAcl(),
'Assert get acl is array'
);
// if loginUserId in _GET or _POST check that it is set
if (!empty($get['loginUserId']) || !empty($post['loginUserId'])) {
$this->assertNotEmpty(
$login_mock->loginGetLoginUserId(),
'Assert loginUserId is set'
);
}
// TODO: detail match of ACL array (loginGetAcl)
// .. end with: loginLogoutUser
// _POST['login_logout'] = 'lgogout
// $login_mock->loginMainCall();
// - loginCheckPermissions
// - loginGetPermissionOkay
} catch (\Exception $e) {
// print "[E]: " . $e->getCode() . ", ERROR: " . $login_mock->loginGetLastErrorCode() . "/"
// . ($expected['login_error'] ?? 0) . "\n";
// print "AJAX: " . $login_mock->loginGetAjaxFlag() . "\n";
// print "AJAX GLOBAL: " . ($GLOBALS['AJAX_PAGE'] ?? '{f}') . "\n";
// print "Login error expext: " . ($expected['login_error'] ?? '{0}') . "\n";
// if this is 100, then we do further error checks
if (
$e->getCode() == 100 ||
!empty($_POST['login_exit']) && $_POST['login_exit'] == 100
) {
$this->assertEquals(
$expected['login_error'],
$login_mock->loginGetLastErrorCode(),
'Assert login error code, exit'
);
// - loginGetErrorMsg
$this->assertEquals(
$expected['error_string'],
$login_mock->loginGetErrorMsg($login_mock->loginGetLastErrorCode()),
'Assert error string, html'
);
$this->assertEquals(
$expected['error_string_text'],
$login_mock->loginGetErrorMsg($login_mock->loginGetLastErrorCode(), true),
'Assert error string, text'
);
// - loginGetLoginHTML
$this->assertStringContainsString(
'<html lang="',
$login_mock->loginGetLoginHTML(),
'Assert login html string exits'
);
// check that login script has above error message
if (!empty($login_mock->loginGetLastErrorCode())) {
$this->assertStringContainsString(
$login_mock->loginGetErrorMsg($login_mock->loginGetLastErrorCode()),
$login_mock->loginGetLoginHTML(),
'Assert login error string exits'
);
} else {
$this->assertStringNotContainsString(
$login_mock->loginGetErrorMsg($login_mock->loginGetLastErrorCode()),
$login_mock->loginGetLoginHTML(),
'Assert login error string does not exit'
);
}
// for ajax type, test post return values
if ($login_mock->loginGetAjaxFlag()) {
$this->assertCount(
$expected['ajax_get_count'],
$_GET,
'Assert ajax error _GET is valid count'
);
// post has only action, login_exit, login_error,
// login_error_text and login_html
// 5 entries
$this->assertCount(
$expected['ajax_post_count'],
$_POST,
'Assert ajax error _POST is valid count'
);
// test post entries
$this->assertEquals(
$expected['ajax_post_action'],
$_POST['action'],
'Assert ajax _POST action'
);
$this->assertEquals(
$login_mock->loginGetLastErrorCode(),
$_POST['login_error'],
'Assert ajax _POST error'
);
$this->assertEquals(
$login_mock->loginGetErrorMsg($login_mock->loginGetLastErrorCode(), true),
$_POST['login_error_text'],
'Assert ajax _POST error text'
);
// html login basic check only, content is the same as when
// read from loginGetLoginHTML()
$this->assertStringContainsString(
'<html lang="',
$_POST['login_html'],
'Assert ajax _POST html string exits'
);
}
}
// print "EXCEPTION: " . print_r($e, true) . "\n";
$this->assertEquals(
!$login_mock->loginGetAjaxFlag() ?
$e->getCode() :
$_POST['login_exit'] ?? 0,
$error,
'Expected error code: ' . $e->getCode()
. ', ' . $e->getMessage()
. ', ' . $e->getLine()
);
}
// if _POST login set check this is matching
if (!empty($post['login_login'])) {
$this->assertTrue(
$login_mock->loginActionRun(),
'Assert that post login_login was pressed'
);
}
// always check, even on error or not set
if (!$login_mock->loginGetLoginUserIdUnclean()) {
$this->assertEquals(
$_GET['loginUserId'] ?? $_POST['loginUserId'] ?? '',
$login_mock->loginGetLoginUserId(),
'Assert loginUserId matches'
);
} else {
$this->assertTrue(
$login_mock->loginGetLoginUserIdUnclean(),
'Assert loginUserId is unclear'
);
$this->assertNotEquals(
$_GET['loginUserId'] ?? $_POST['loginUserId'] ?? '',
$login_mock->loginGetLoginUserId(),
'Assert loginUserId does not matche _GET/_POST'
);
}
// check get/post login user id
$this->assertEquals(
(!empty($_GET['loginUserId']) ?
'GET' :
(!empty($_POST['loginUserId']) ?
'POST' : '')
),
$login_mock->loginGetLoginUserIdSource(),
'Assert loginUserId source matches'
);
// enable user again if flag set
if (!empty($mock_settings['test_enabled'])) {
self::$db->dbExec(
"UPDATE edit_user SET enabled = 1 "
. "WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($post['login_username'])
);
}
if (!empty($mock_settings['test_deleted'])) {
self::$db->dbExec(
"UPDATE edit_user SET deleted = 0 WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($post['login_username'])
);
}
if (!empty($mock_settings['test_login_user_id_locked'])) {
self::$db->dbExec(
"UPDATE edit_user SET login_user_id_locked = 0 WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($post['login_username'])
);
}
if (
!empty($mock_settings['test_locked_period_until']) ||
!empty($mock_settings['test_locked_period_after'])
) {
self::$db->dbExec(
"UPDATE edit_user SET "
. "lock_until = NULL, "
. "lock_after = NULL "
. "WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($post['login_username'])
);
}
// reset lock flag
if (!empty($mock_settings['test_locked'])) {
self::$db->dbExec(
"UPDATE edit_user SET locked = 0 "
. "WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($post['login_username'])
);
}
// rest the get locked flow
if (!empty($mock_settings['test_get_locked'])) {
self::$db->dbExec(
"UPDATE edit_user "
. "SET login_error_count = 0, login_error_date_last = NULL, "
. "login_error_date_first = NULL, locked = 0, strict = 0 "
. "WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($post['login_username'])
);
}
if (!empty($mock_settings['test_login_user_id'])) {
self::$db->dbExec(
"UPDATE edit_user SET "
. "login_user_id = NULL, "
// below to rows are automatcially reset
. "login_user_id_set_date = NULL, "
. "login_user_id_last_revalidate = NULL "
. "WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($mock_settings['test_username'])
);
}
if (!empty($mock_settings['test_login_user_id_revalidate_after'])) {
self::$db->dbExec(
"UPDATE edit_user SET "
. "login_user_id_last_revalidate = NULL, "
. "login_user_id_revalidate_after = NULL "
. "WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($mock_settings['test_username'])
);
}
if (
!empty($mock_settings['test_login_user_id_valid_from']) ||
!empty($mock_settings['test_login_user_id_valid_until'])
) {
self::$db->dbExec(
"UPDATE edit_user SET "
. "login_user_id_valid_from = NULL, "
. "login_user_id_valid_until = NULL "
. "WHERE LOWER(username) = "
. self::$db->dbEscapeLiteral($mock_settings['test_username'])
);
}
}
// - loginGetAclList (null, invalid,)
public function aclListProvider(): array
{
// 0: level (int|null)
// 2: type (string), null for skip (if 0 = null)
// 1: acl return from level (array)
// 2: level number to return (must match 0)
return [
'null, get full list' => [
null,
null,
[
0 => [
'type' => 'none',
'name' => 'No Access',
],
10 => [
'type' => 'list',
'name' => 'List',
],
20 => [
'type' => 'read',
'name' => 'Read',
],
30 => [
'type' => 'mod_trans',
'name' => 'Translator',
],
40 => [
'type' => 'mod',
'name' => 'Modify',
],
60 => [
'type' => 'write',
'name' => 'Create/Write',
],
80 => [
'type' => 'del',
'name' => 'Delete',
],
90 => [
'type' => 'siteadmin',
'name' => 'Site Admin',
],
100 => [
'type' => 'admin',
'name' => 'Admin',
],
],
null
],
'valid, search' => [
20,
'read',
[
'type' => 'read',
'name' => 'Read'
],
20
],
'invalid search' => [
12,
'foo',
[],
false,
]
];
}
/**
* Undocumented function
*
* @dataProvider aclListProvider()
* @testdox ACL\Login list if $level and $type exepcted level is $expected_level [$_dataName]
*
* @param int|null $level
* @param string|null $type
* @param array $expected_list
* @param int|null|bool $expected_level
* @return void
*/
public function testAclLoginList(
?int $level,
?string $type,
array $expected_list,
$expected_level
): void {
$_SESSION = [];
// init session (as MOCK)
/** @var \CoreLibs\Create\Session&MockObject */
$session_mock = $this->createPartialMock(
\CoreLibs\Create\Session::class,
['getSessionId', 'checkActiveSession', 'sessionDestroy']
);
$session_mock->method('getSessionId')->willReturn('ACLLOGINTEST34');
$session_mock->method('checkActiveSession')->willReturn(true);
$session_mock->method('sessionDestroy')->will(
$this->returnCallback(function () {
global $_SESSION;
$_SESSION = [];
return true;
})
);
/** @var \CoreLibs\ACL\Login&MockObject */
$login_mock = $this->getMockBuilder(\CoreLibs\ACL\Login::class)
->setConstructorArgs([
self::$db,
self::$log,
$session_mock,
[
'auto_login' => false,
'default_acl_level' => 80,
'logout_target' => '',
'site_locale' => 'en_US.UTF-8',
'site_domain' => 'admin',
'site_encoding' => 'UTF-8',
'locale_path' => __DIR__ . DIRECTORY_SEPARATOR
. 'includes' . DIRECTORY_SEPARATOR
. 'locale' . DIRECTORY_SEPARATOR,
]
])
->onlyMethods(['loginTerminate'])
->getMock();
$login_mock->expects($this->any())
->method('loginTerminate')
->will(
$this->returnCallback(function ($message, $code) {
throw new \Exception('', $code);
})
);
$list = $login_mock->loginGetAclList($level);
$this->assertIsArray(
$list,
'assert get acl list is array'
);
$this->assertEquals(
$expected_list,
$list
);
if ($type !== null) {
$this->assertEquals(
$expected_level,
$login_mock->loginGetAclListFromType($type),
'assert type is level'
);
// only back assert if found
if (isset($list['type'])) {
$this->assertEquals(
$list['type'],
$type,
'assert level read type is type'
);
}
}
}
/**
* Undocumented function
*
* @return array
*/
public function minPasswordCheckProvider(): array
{
// 0: set length
// 1: expected return from set
// 2: expected set length
return [
'set new length' => [
12,
true,
12,
],
'set new length, too short' => [
5,
false,
9
],
'set new length, too long' => [
500,
false,
9
]
];
}
/**
* check setting minimum password length
*
* @covers ::loginSetPasswordMinLength
* @covers ::loginGetPasswordLenght
* @dataProvider minPasswordCheckProvider()
* @testdox ACL\Login password min length set $input is $expected_return and matches $expected [$_dataName]
*
* @param int $input
* @param bool $expected_return
* @param int $expected
* @return void
*/
public function testACLLoginPasswordMinLenght(int $input, bool $expected_return, int $expected): void
{
$_SESSION = [];
// init session (as MOCK)
/** @var \CoreLibs\Create\Session&MockObject */
$session_mock = $this->createPartialMock(
\CoreLibs\Create\Session::class,
['getSessionId', 'checkActiveSession', 'sessionDestroy']
);
$session_mock->method('getSessionId')->willReturn('ACLLOGINTEST34');
$session_mock->method('checkActiveSession')->willReturn(true);
$session_mock->method('sessionDestroy')->will(
$this->returnCallback(function () {
global $_SESSION;
$_SESSION = [];
return true;
})
);
/** @var \CoreLibs\ACL\Login&MockObject */
$login_mock = $this->getMockBuilder(\CoreLibs\ACL\Login::class)
->setConstructorArgs([
self::$db,
self::$log,
$session_mock,
[
'auto_login' => false,
'default_acl_level' => 80,
'logout_target' => '',
'site_locale' => 'en_US.UTF-8',
'site_domain' => 'admin',
'site_encoding' => 'UTF-8',
'locale_path' => __DIR__ . DIRECTORY_SEPARATOR
. 'includes' . DIRECTORY_SEPARATOR
. 'locale' . DIRECTORY_SEPARATOR,
]
])
->onlyMethods(['loginTerminate'])
->getMock();
$login_mock->expects($this->any())
->method('loginTerminate')
->will(
$this->returnCallback(function ($message, $code) {
throw new \Exception('', $code);
})
);
// set new min password length
$this->assertEquals(
$expected_return,
$login_mock->loginSetPasswordMinLength($input),
'assert bool set password min length'
);
// check value
$this->assertEquals(
$expected,
$login_mock->loginGetPasswordLenght('min'),
'assert get password min length'
);
}
/**
* Undocumented function
*
* @return array
*/
public function getPasswordLengthProvider(): array
{
return [
'min' => ['min'],
'lower' => ['lower'],
'max' => ['max'],
'upper' => ['upper'],
'minimum_length' => ['minimum_length'],
'min_length' => ['min_length'],
'length' => ['length'],
];
}
/**
* check all possible readable password length params
*
* @covers ::loginGetPasswordLenght
* @dataProvider getPasswordLengthProvider()
* @testdox ACL\Login get password length $input [$_dataName]
*
* @param string $input
* @return void
*/
public function testACLLoginGetPasswordLength(string $input): void
{
$_SESSION = [];
// init session (as MOCK)
/** @var \CoreLibs\Create\Session&MockObject */
$session_mock = $this->createPartialMock(
\CoreLibs\Create\Session::class,
['getSessionId', 'checkActiveSession', 'sessionDestroy']
);
$session_mock->method('getSessionId')->willReturn('ACLLOGINTEST34');
$session_mock->method('checkActiveSession')->willReturn(true);
$session_mock->method('sessionDestroy')->will(
$this->returnCallback(function () {
global $_SESSION;
$_SESSION = [];
return true;
})
);
/** @var \CoreLibs\ACL\Login&MockObject */
$login_mock = $this->getMockBuilder(\CoreLibs\ACL\Login::class)
->setConstructorArgs([
self::$db,
self::$log,
$session_mock,
[
'auto_login' => false,
'default_acl_level' => 80,
'logout_target' => '',
'site_locale' => 'en_US.UTF-8',
'site_domain' => 'admin',
'site_encoding' => 'UTF-8',
'locale_path' => __DIR__ . DIRECTORY_SEPARATOR
. 'includes' . DIRECTORY_SEPARATOR
. 'locale' . DIRECTORY_SEPARATOR,
]
])
->onlyMethods(['loginTerminate'])
->getMock();
$login_mock->expects($this->any())
->method('loginTerminate')
->will(
$this->returnCallback(function ($message, $code) {
throw new \Exception('', $code);
})
);
$this->assertMatchesRegularExpression(
"/^\d+$/",
(string)$login_mock->loginGetPasswordLenght($input)
);
}
/**
* Undocumented function
*
* @return array
*/
public function loginMaxErrorProvider(): array
{
return [
'set valid max failed login' => [
10,
true,
10
],
'set valid unlimted' => [
-1,
true,
-1
],
'set invalid 0' => [
0,
false,
-1
],
'set invalid negative' => [
-5,
false,
-1
],
];
}
/**
* Undocumented function
*
* @covers ::loginSetMaxLoginErrorCount
* @covers ::loginGetMaxLoginErrorCount
* @dataProvider loginMaxErrorProvider()
* @testdox ACL\Login failed login set/get $input is $expected_return and matches $expected [$_dataName]
*
* @param int $input
* @param bool $expected_return
* @param int $expected
* @return void
*/
public function testACLLoginErrorCount(int $input, bool $expected_return, int $expected): void
{
$_SESSION = [];
// init session (as MOCK)
/** @var \CoreLibs\Create\Session&MockObject */
$session_mock = $this->createPartialMock(
\CoreLibs\Create\Session::class,
['getSessionId', 'checkActiveSession', 'sessionDestroy']
);
$session_mock->method('getSessionId')->willReturn('ACLLOGINTEST34');
$session_mock->method('checkActiveSession')->willReturn(true);
$session_mock->method('sessionDestroy')->will(
$this->returnCallback(function () {
global $_SESSION;
$_SESSION = [];
return true;
})
);
/** @var \CoreLibs\ACL\Login&MockObject */
$login_mock = $this->getMockBuilder(\CoreLibs\ACL\Login::class)
->setConstructorArgs([
self::$db,
self::$log,
$session_mock,
[
'auto_login' => false,
'default_acl_level' => 80,
'logout_target' => '',
'site_locale' => 'en_US.UTF-8',
'site_domain' => 'admin',
'site_encoding' => 'UTF-8',
'locale_path' => __DIR__ . DIRECTORY_SEPARATOR
. 'includes' . DIRECTORY_SEPARATOR
. 'locale' . DIRECTORY_SEPARATOR,
]
])
->onlyMethods(['loginTerminate'])
->getMock();
$login_mock->expects($this->any())
->method('loginTerminate')
->will(
$this->returnCallback(function ($message, $code) {
throw new \Exception('', $code);
})
);
// set new min password length
$this->assertEquals(
$expected_return,
$login_mock->loginSetMaxLoginErrorCount($input),
'assert bool set max login errors'
);
// check value
$this->assertEquals(
$expected,
$login_mock->loginGetMaxLoginErrorCount(),
'assert get max login errors'
);
}
}
// __END__