. /** * Tests for auth_plugin_userkey class. * * @package auth_userkey * @copyright 2016 Dmitrii Metelkin (dmitriim@catalyst-au.net) * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die(); /** * Tests for auth_plugin_userkey class. * * @copyright 2016 Dmitrii Metelkin (dmitriim@catalyst-au.net) * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class auth_plugin_userkey_testcase extends advanced_testcase { /** * An instance of auth_plugin_userkey class. * @var auth_plugin_userkey */ protected $auth; /** * User object. * @var */ protected $user; /** * Initial set up. */ public function setUp() { global $CFG; require_once($CFG->libdir . "/externallib.php"); require_once($CFG->dirroot . '/auth/userkey/tests/fake_userkey_manager.php'); require_once($CFG->dirroot . '/auth/userkey/auth.php'); $this->auth = new auth_plugin_userkey(); $this->user = self::getDataGenerator()->create_user(); $this->resetAfterTest(); } /** * Test that users can't login using login form. */ public function test_users_can_not_login_using_login_form() { $user = new stdClass(); $user->auth = 'userkey'; $user->username = 'username'; $user->password = 'correctpassword'; self::getDataGenerator()->create_user($user); $this->assertFalse($this->auth->user_login('username', 'correctpassword')); $this->assertFalse($this->auth->user_login('username', 'incorrectpassword')); } /** * Test that the plugin doesn't allow to store users passwords. */ public function test_auth_plugin_does_not_allow_to_store_passwords() { $this->assertTrue($this->auth->prevent_local_passwords()); } /** * Test that the plugin is external. */ public function test_auth_plugin_is_external() { $this->assertFalse($this->auth->is_internal()); } /** * Test that the plugin doesn't allow users to change the passwords. */ public function test_auth_plugin_does_not_allow_to_change_passwords() { $this->assertFalse($this->auth->can_change_password()); } /** * Test that default mapping field gets returned correctly. */ public function test_get_default_mapping_field() { $expected = 'email'; $actual = $this->auth->get_mapping_field(); $this->assertEquals($expected, $actual); } /** * Test that logout page hook sets global redirect variable correctly. */ public function test_logoutpage_hook_sets_global_redirect_correctly() { global $redirect, $SESSION; $this->auth->logoutpage_hook(); $this->assertEquals('', $redirect); $SESSION->userkey = true; $this->auth = new auth_plugin_userkey(); $this->auth->logoutpage_hook(); $this->assertEquals('', $redirect); unset($SESSION->userkey); set_config('redirecturl', 'http://example.com', 'auth_userkey'); $this->auth = new auth_plugin_userkey(); $this->auth->logoutpage_hook(); $this->assertEquals('', $redirect); $SESSION->userkey = true; set_config('redirecturl', 'http://example.com', 'auth_userkey'); $this->auth = new auth_plugin_userkey(); $this->auth->logoutpage_hook(); $this->assertEquals('http://example.com', $redirect); } /** * Test that configured mapping field gets returned correctly. */ public function test_get_mapping_field() { set_config('mappingfield', 'username', 'auth_userkey'); $this->auth = new auth_plugin_userkey(); $expected = 'username'; $actual = $this->auth->get_mapping_field(); $this->assertEquals($expected, $actual); } /** * Test that auth plugin throws correct exception if default mapping field is not provided. * * @expectedException \invalid_parameter_exception * @expectedExceptionMessage Invalid parameter value detected (Required field "email" is not set or empty.) */ public function test_throwing_exception_if_default_mapping_field_is_not_provided() { $user = array(); $actual = $this->auth->get_login_url($user); } /** * Test that auth plugin throws correct exception if username mapping field is not provided, but set in configs. * * @expectedException \invalid_parameter_exception * @expectedExceptionMessage Invalid parameter value detected (Required field "username" is not set or empty.) */ public function test_throwing_exception_if_mapping_field_username_is_not_provided() { $user = array(); set_config('mappingfield', 'username', 'auth_userkey'); $this->auth = new auth_plugin_userkey(); $actual = $this->auth->get_login_url($user); } /** * Test that auth plugin throws correct exception if idnumber mapping field is not provided, but set in configs. * * @expectedException \invalid_parameter_exception * @expectedExceptionMessage Invalid parameter value detected (Required field "idnumber" is not set or empty.) */ public function test_throwing_exception_if_mapping_field_idnumber_is_not_provided() { $user = array(); set_config('mappingfield', 'idnumber', 'auth_userkey'); $this->auth = new auth_plugin_userkey(); $actual = $this->auth->get_login_url($user); } /** * Test that auth plugin throws correct exception if we trying to request not existing user. * * @expectedException \invalid_parameter_exception * @expectedExceptionMessage Invalid parameter value detected (User is not exist) */ public function test_throwing_exception_if_user_is_not_exist() { $user = array(); $user['email'] = 'notexists@test.com'; $actual = $this->auth->get_login_url($user); } /** * Test that auth plugin throws correct exception if we trying to request user, * but ip field is not set and iprestriction is enabled. * * @expectedException \invalid_parameter_exception * @expectedExceptionMessage Invalid parameter value detected (Required parameter "ip" is not set.) */ public function test_throwing_exception_if_iprestriction_is_enabled_but_ip_is_missing_in_data() { $user = array(); $user['email'] = 'exists@test.com'; set_config('iprestriction', true, 'auth_userkey'); $this->auth = new auth_plugin_userkey(); $actual = $this->auth->get_login_url($user); } /** * Test that we can request a user provided user data as an array. */ public function test_return_correct_login_url_if_user_is_array() { global $CFG; $user = array(); $user['username'] = 'username'; $user['email'] = 'exists@test.com'; self::getDataGenerator()->create_user($user); $userkeymanager = new \auth_userkey\fake_userkey_manager(); $this->auth->set_userkey_manager($userkeymanager); $expected = $CFG->wwwroot . '/auth/userkey/login.php?key=FaKeKeyFoRtEsTiNg'; $actual = $this->auth->get_login_url($user); $this->assertEquals($expected, $actual); } /** * Test that we can request a user provided user data as an object. */ public function test_return_correct_login_url_if_user_is_object() { global $CFG; $user = new stdClass(); $user->username = 'username'; $user->email = 'exists@test.com'; self::getDataGenerator()->create_user($user); $userkeymanager = new \auth_userkey\fake_userkey_manager(); $this->auth->set_userkey_manager($userkeymanager); $expected = $CFG->wwwroot . '/auth/userkey/login.php?key=FaKeKeyFoRtEsTiNg'; $actual = $this->auth->get_login_url($user); $this->assertEquals($expected, $actual); } /** * Test that we can request a user provided user data as an object. */ public function test_return_correct_login_url_if_iprestriction_is_enabled_and_data_is_correct() { global $CFG; $user = new stdClass(); $user->username = 'username'; $user->email = 'exists@test.com'; $user->ip = '192.168.1.1'; self::getDataGenerator()->create_user($user); $userkeymanager = new \auth_userkey\fake_userkey_manager(); $this->auth->set_userkey_manager($userkeymanager); $expected = $CFG->wwwroot . '/auth/userkey/login.php?key=FaKeKeyFoRtEsTiNg'; $actual = $this->auth->get_login_url($user); $this->assertEquals($expected, $actual); } /** * Test that we can get login url if we do not use fake keymanager. */ public function test_return_correct_login_url_if_user_is_object_using_default_keymanager() { global $DB, $CFG; $user = array(); $user['username'] = 'username'; $user['email'] = 'exists@test.com'; $user = self::getDataGenerator()->create_user($user); create_user_key('auth/userkey', $user->id); create_user_key('auth/userkey', $user->id); create_user_key('auth/userkey', $user->id); $keys = $DB->get_records('user_private_key', array('userid' => $user->id)); $this->assertEquals(3, count($keys)); $actual = $this->auth->get_login_url($user); $keys = $DB->get_records('user_private_key', array('userid' => $user->id)); $this->assertEquals(1, count($keys)); $actualkey = $DB->get_record('user_private_key', array('userid' => $user->id)); $expected = $CFG->wwwroot . '/auth/userkey/login.php?key=' . $actualkey->value; $this->assertEquals($expected, $actual); } /** * Test that we can return correct allowed mapping fields. */ public function test_get_allowed_mapping_fields_list() { $expected = array( 'username' => 'Username', 'email' => 'Email address', 'idnumber' => 'ID number', ); $actual = $this->auth->get_allowed_mapping_fields(); $this->assertEquals($expected, $actual); } /** * Test that we can get correct request parameters based on the plugin configuration. */ public function test_get_request_login_url_user_parameters_based_on_plugin_config() { // Check email as it should be set by default. $expected = array( 'email' => new external_value( PARAM_EMAIL, 'A valid email address' ), ); $actual = $this->auth->get_request_login_url_user_parameters(); $this->assertEquals($expected, $actual); // Check username. set_config('mappingfield', 'username', 'auth_userkey'); $this->auth = new auth_plugin_userkey(); $expected = array( 'username' => new external_value( PARAM_USERNAME, 'Username' ), ); $actual = $this->auth->get_request_login_url_user_parameters(); $this->assertEquals($expected, $actual); // Check idnumber. set_config('mappingfield', 'idnumber', 'auth_userkey'); $this->auth = new auth_plugin_userkey(); $expected = array( 'idnumber' => new external_value( PARAM_RAW, 'An arbitrary ID code number perhaps from the institution' ), ); $actual = $this->auth->get_request_login_url_user_parameters(); $this->assertEquals($expected, $actual); // Check some junk field name. set_config('mappingfield', 'junkfield', 'auth_userkey'); $this->auth = new auth_plugin_userkey(); $expected = array(); $actual = $this->auth->get_request_login_url_user_parameters(); $this->assertEquals($expected, $actual); // Check IP if iprestriction disabled. set_config('iprestriction', false, 'auth_userkey'); $this->auth = new auth_plugin_userkey(); $expected = array(); $actual = $this->auth->get_request_login_url_user_parameters(); $this->assertEquals($expected, $actual); // Check IP if iprestriction enabled. set_config('iprestriction', true, 'auth_userkey'); $this->auth = new auth_plugin_userkey(); $expected = array( 'ip' => new external_value( PARAM_HOST, 'User IP address' ), ); $actual = $this->auth->get_request_login_url_user_parameters(); $this->assertEquals($expected, $actual); } /** * Test that we can validate keylifetime for config form correctly. */ public function test_validate_keylifetime_for_config_form() { $form = new stdClass(); $form->redirecturl = ''; $form->keylifetime = ''; $err = array(); $this->auth->validate_form($form, $err); $this->assertEquals('User key life time should be a number', $err['keylifetime']); $form->keylifetime = '0'; $err = array(); $this->auth->validate_form($form, $err); $this->assertEquals('User key life time should be a number', $err['keylifetime']); $form->keylifetime = '1'; $err = array(); $this->auth->validate_form($form, $err); $this->assertFalse(array_key_exists('keylifetime', $err)); $form->keylifetime = 0; $err = array(); $this->auth->validate_form($form, $err); $this->assertEquals('User key life time should be a number', $err['keylifetime']); $form->keylifetime = 1; $err = array(); $this->auth->validate_form($form, $err); $this->assertFalse(array_key_exists('keylifetime', $err)); $form->keylifetime = 'rkjflj'; $err = array(); $this->auth->validate_form($form, $err); $this->assertEquals('User key life time should be a number', $err['keylifetime']); } /** * Test that we can validate redirecturl for config form correctly. */ public function test_validate_redirecturl_for_config_form() { $form = new stdClass(); $form->keylifetime = 10; $form->redirecturl = ''; $err = array(); $this->auth->validate_form($form, $err); $this->assertFalse(array_key_exists('redirecturl', $err)); $form->redirecturl = 'http://google.com/'; $err = array(); $this->auth->validate_form($form, $err); $this->assertFalse(array_key_exists('redirecturl', $err)); $form->redirecturl = 'https://google.com'; $err = array(); $this->auth->validate_form($form, $err); $this->assertFalse(array_key_exists('redirecturl', $err)); $form->redirecturl = 'http://some.very.long.and.silly.domain/with/a/path/'; $err = array(); $this->auth->validate_form($form, $err); $this->assertFalse(array_key_exists('redirecturl', $err)); $form->redirecturl = 'http://0.255.1.1/numericip.php'; $err = array(); $this->auth->validate_form($form, $err); $this->assertFalse(array_key_exists('redirecturl', $err)); $form->redirecturl = '/just/a/path'; $err = array(); $this->auth->validate_form($form, $err); $this->assertEquals('You should provide valid URL', $err['redirecturl']); $form->redirecturl = 'random string'; $err = array(); $this->auth->validate_form($form, $err); $this->assertEquals('You should provide valid URL', $err['redirecturl']); $form->redirecturl = 123456; $err = array(); $this->auth->validate_form($form, $err); $this->assertEquals('You should provide valid URL', $err['redirecturl']); } /** * Test that we can process config form. */ public function test_process_config_form() { $config = get_config('auth_userkey'); $this->assertObjectNotHasAttribute('mappingfield', $config); $this->assertObjectNotHasAttribute('keylifetime', $config); $this->assertObjectNotHasAttribute('iprestriction', $config); $formconfig = new stdClass(); $formconfig->mappingfield = 'email'; $formconfig->keylifetime = 100; $formconfig->iprestriction = 0; $formconfig->redirecturl = 'http://google.com/'; $this->auth->process_config($formconfig); $config = get_config('auth_userkey'); $this->assertObjectHasAttribute('mappingfield', $config); $this->assertObjectHasAttribute('keylifetime', $config); $this->assertObjectHasAttribute('iprestriction', $config); $this->assertEquals('email', $config->mappingfield); $this->assertEquals(100, $config->keylifetime); $this->assertEquals(0, $config->iprestriction); $this->assertEquals('http://google.com/', $config->redirecturl); } /** * Test required parameter exception gets thrown id try to login, but key is not set. * * @expectedException moodle_exception * @expectedExceptionMessage A required parameter (key) was missing */ public function test_required_parameter_exception_thrown_if_key_not_set() { $this->auth->user_login_userkey(); } /** * Test that incorrect key exception gets thrown if a key is incorrect. * * @expectedException moodle_exception * @expectedExceptionMessage Incorrect key */ public function test_invalid_key_exception_thrown_if_invalid_key() { $_POST['key'] = 'InvalidKey'; $this->auth->user_login_userkey(); } /** * Test that expired key exception gets thrown if a key is expired. * * @expectedException moodle_exception * @expectedExceptionMessage Expired key */ public function test_expired_key_exception_thrown_if_expired_key() { global $DB; $key = new stdClass(); $key->value = 'ExpiredKey'; $key->script = 'auth/userkey'; $key->userid = $this->user->id; $key->instance = $this->user->id; $key->iprestriction = null; $key->validuntil = time() - 3000; $key->timecreated = time(); $DB->insert_record('user_private_key', $key); $_POST['key'] = 'ExpiredKey'; $this->auth->user_login_userkey(); } /** * Test that IP address mismatch exception gets thrown if incorrect IP. * * @expectedException moodle_exception * @expectedExceptionMessage Client IP address mismatch */ public function test_ipmismatch_exception_thrown_if_ip_is_incorrect() { global $DB; $key = new stdClass(); $key->value = 'IpmismatchKey'; $key->script = 'auth/userkey'; $key->userid = $this->user->id; $key->instance = $this->user->id; $key->iprestriction = '192.168.1.1'; $key->validuntil = time() + 300; $key->timecreated = time(); $DB->insert_record('user_private_key', $key); $_POST['key'] = 'IpmismatchKey'; $_SERVER['HTTP_CLIENT_IP'] = '192.168.1.2'; $this->auth->user_login_userkey(); } /** * Test that IP address mismatch exception gets thrown if user id is incorrect. * * @expectedException moodle_exception * @expectedExceptionMessage Invalid user id */ public function test_invalid_user_exception_thrown_if_user_is_invalid() { global $DB; $key = new stdClass(); $key->value = 'InvalidUser'; $key->script = 'auth/userkey'; $key->userid = 777; $key->instance = 777; $key->iprestriction = '192.168.1.1'; $key->validuntil = time() + 300; $key->timecreated = time(); $DB->insert_record('user_private_key', $key); $_POST['key'] = 'InvalidUser'; $_SERVER['HTTP_CLIENT_IP'] = '192.168.1.1'; $this->auth->user_login_userkey(); } /** * Test that key gets removed after a user logged in. */ public function test_that_key_gets_removed_after_user_logged_in() { global $DB; $key = new stdClass(); $key->value = 'RemoveKey'; $key->script = 'auth/userkey'; $key->userid = $this->user->id; $key->instance = $this->user->id; $key->iprestriction = '192.168.1.1'; $key->validuntil = time() + 300; $key->timecreated = time(); $DB->insert_record('user_private_key', $key); $_POST['key'] = 'RemoveKey'; $_SERVER['HTTP_CLIENT_IP'] = '192.168.1.1'; // Using @ is the only way to test this. Thanks moodle! @$this->auth->user_login_userkey(); $keyexists = $DB->record_exists('user_private_key', array('value' => 'RemoveKey')); $this->assertFalse($keyexists); } /** * Test that a user loggs in correctly. */ public function test_that_user_logged_in() { global $DB, $USER, $SESSION, $CFG; $key = new stdClass(); $key->value = 'UserLogin'; $key->script = 'auth/userkey'; $key->userid = $this->user->id; $key->instance = $this->user->id; $key->iprestriction = null; $key->validuntil = time() + 300; $key->timecreated = time(); $DB->insert_record('user_private_key', $key); $_POST['key'] = 'UserLogin'; // Using @ is the only way to test this. Thanks moodle! $redirect = @$this->auth->user_login_userkey(); $this->assertEquals($CFG->wwwroot, $redirect); $this->assertEquals($this->user->id, $USER->id); $this->assertSame(sesskey(), $USER->sesskey); $this->assertObjectHasAttribute('userkey', $SESSION); } /** * Test that wantsurl URL gets returned after user logged in if wantsurl's set. */ public function test_that_return_wantsurl() { global $DB; $key = new stdClass(); $key->value = 'WantsUrl'; $key->script = 'auth/userkey'; $key->userid = $this->user->id; $key->instance = $this->user->id; $key->iprestriction = null; $key->validuntil = time() + 300; $key->timecreated = time(); $DB->insert_record('user_private_key', $key); $_POST['key'] = 'WantsUrl'; $_POST['wantsurl'] = '/course/index.php?id=12&key=134'; // Using @ is the only way to test this. Thanks moodle! $redirect = @$this->auth->user_login_userkey(); $this->assertEquals('/course/index.php?id=12&key=134', $redirect); } /** * Test that wantsurl URL gets returned after user logged in if wantsurl's set to external URL. */ public function test_that_return_wantsurl_if_it_is_external_url() { global $DB; $key = new stdClass(); $key->value = 'WantsUrlExternal'; $key->script = 'auth/userkey'; $key->userid = $this->user->id; $key->instance = $this->user->id; $key->iprestriction = null; $key->validuntil = time() + 300; $key->timecreated = time(); $DB->insert_record('user_private_key', $key); $_POST['key'] = 'WantsUrlExternal'; $_POST['wantsurl'] = 'http://test.com/course/index.php?id=12&key=134'; // Using @ is the only way to test this. Thanks moodle! $redirect = @$this->auth->user_login_userkey(); $this->assertEquals('http://test.com/course/index.php?id=12&key=134', $redirect); } }