moodle-auth_jwt/tests/auth_plugin_test.php

1112 lines
38 KiB
PHP
Raw Normal View History

2016-08-16 04:49:39 +00:00
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace auth_jwt;
2022-08-19 00:56:39 +00:00
use advanced_testcase;
use auth_plugin_jwt;
2022-08-19 00:56:39 +00:00
use stdClass;
use invalid_parameter_exception;
use moodle_exception;
use external_value;
2016-08-16 04:49:39 +00:00
/**
* Tests for auth_plugin_jwt class.
2016-08-16 04:49:39 +00:00
*
* @covers \auth_plugin_jwt
2022-08-19 01:16:11 +00:00
*
* @package auth_jwt
* @copyright 2016 Dmitrii Metelkin (dmitriim@catalyst-au.net), 2024 Kumi Systems e.U.
2016-08-16 04:49:39 +00:00
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
2022-08-19 00:56:39 +00:00
class auth_plugin_test extends advanced_testcase {
2016-08-16 04:49:39 +00:00
/**
* An instance of auth_plugin_jwt class.
* @var auth_plugin_jwt
2016-08-16 04:49:39 +00:00
*/
protected $auth;
2016-08-18 12:57:37 +00:00
/**
* User object.
* @var
*/
protected $user;
2023-12-05 16:50:56 +00:00
/**
* Path used for the redirection.
* @var string
*/
const REDIRECTION_PATH = "/redirection";
2016-08-16 04:49:39 +00:00
/**
* Initial set up.
*/
2022-06-03 06:44:24 +00:00
public function setUp(): void {
2016-08-16 04:49:39 +00:00
global $CFG;
require_once($CFG->libdir . "/externallib.php");
require_once($CFG->dirroot . '/auth/jwt/tests/fake_jwt_manager.php');
require_once($CFG->dirroot . '/auth/jwt/auth.php');
2017-04-03 07:55:18 +00:00
require_once($CFG->dirroot . '/user/lib.php');
2016-08-16 04:49:39 +00:00
parent::setUp();
$this->resetAfterTest();
$CFG->getremoteaddrconf = GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR;
$this->auth = new auth_plugin_jwt();
2016-08-18 12:57:37 +00:00
$this->user = self::getDataGenerator()->create_user();
2020-05-08 07:20:28 +00:00
}
/**
* A helper function to create TestKey.
*
* @param array $record Key record.
*/
protected function create_user_private_key(array $record = []) {
global $DB;
$record = (object)$record;
if (!isset($record->value)) {
$record->value = 'TestKey';
}
if (!isset($record->userid)) {
$record->userid = $this->user->id;
}
if (!isset($record->userid)) {
$record->instance = $this->user->id;
}
if (!isset($record->iprestriction)) {
$record->iprestriction = null;
}
if (!isset($record->validuntil)) {
$record->validuntil = time() + 300;
}
if (!isset($record->timecreated)) {
$record->timecreated = time();
}
2016-08-18 12:57:37 +00:00
$record->script = 'auth/jwt';
2020-05-08 07:20:28 +00:00
$DB->insert_record('user_private_key', $record);
2016-08-16 04:49:39 +00:00
}
/**
* Test that users can't login using login form.
*/
public function test_users_can_not_login_using_login_form() {
$user = new stdClass();
$user->auth = 'jwt';
2016-08-16 04:49:39 +00:00
$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());
}
2016-08-17 07:53:26 +00:00
/**
* 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->jwt = true;
$this->auth = new auth_plugin_jwt();
$this->auth->logoutpage_hook();
$this->assertEquals('', $redirect);
unset($SESSION->jwt);
set_config('redirecturl', 'http://example.com', 'auth_jwt');
$this->auth = new auth_plugin_jwt();
$this->auth->logoutpage_hook();
$this->assertEquals('', $redirect);
$SESSION->jwt = true;
set_config('redirecturl', 'http://example.com', 'auth_jwt');
$this->auth = new auth_plugin_jwt();
$this->auth->logoutpage_hook();
$this->assertEquals('http://example.com', $redirect);
}
2016-08-17 07:53:26 +00:00
/**
* Test that configured mapping field gets returned correctly.
*/
public function test_get_mapping_field() {
set_config('mappingfield', 'username', 'auth_jwt');
$this->auth = new auth_plugin_jwt();
$expected = 'username';
$actual = $this->auth->get_mapping_field();
$this->assertEquals($expected, $actual);
}
/**
2016-08-17 07:53:26 +00:00
* Test that auth plugin throws correct exception if default mapping field is not provided.
*/
2016-08-17 07:53:26 +00:00
public function test_throwing_exception_if_default_mapping_field_is_not_provided() {
$user = array();
2022-08-19 00:08:02 +00:00
$this->expectException(invalid_parameter_exception::class);
$this->expectExceptionMessage('Invalid parameter value detected (Required field "email" is not set or empty.)');
2022-08-19 00:38:16 +00:00
$actual = $this->auth->get_login_url($user);
}
/**
2016-08-17 07:53:26 +00:00
* Test that auth plugin throws correct exception if username mapping field is not provided, but set in configs.
*/
2016-08-17 07:53:26 +00:00
public function test_throwing_exception_if_mapping_field_username_is_not_provided() {
$user = array();
set_config('mappingfield', 'username', 'auth_jwt');
$this->auth = new auth_plugin_jwt();
2022-08-19 00:08:02 +00:00
$this->expectException(invalid_parameter_exception::class);
$this->expectExceptionMessage('Invalid parameter value detected (Required field "username" is not set or empty.)');
2016-08-17 07:53:26 +00:00
$actual = $this->auth->get_login_url($user);
}
2016-08-17 07:53:26 +00:00
/**
* Test that auth plugin throws correct exception if idnumber mapping field is not provided, but set in configs.
*/
public function test_throwing_exception_if_mapping_field_idnumber_is_not_provided() {
$user = array();
set_config('mappingfield', 'idnumber', 'auth_jwt');
$this->auth = new auth_plugin_jwt();
2016-08-17 07:53:26 +00:00
2022-08-19 00:08:02 +00:00
$this->expectException(invalid_parameter_exception::class);
$this->expectExceptionMessage('Invalid parameter value detected (Required field "idnumber" is not set or empty.)');
2016-08-17 07:53:26 +00:00
$actual = $this->auth->get_login_url($user);
}
/**
2016-08-17 07:53:26 +00:00
* Test that auth plugin throws correct exception if we trying to request not existing user.
*/
public function test_throwing_exception_if_user_is_not_exist() {
$user = array();
$user['email'] = 'notexists@test.com';
2022-08-19 00:08:02 +00:00
$this->expectException(invalid_parameter_exception::class);
$this->expectExceptionMessage('Invalid parameter value detected (User is not exist)');
$actual = $this->auth->get_login_url($user);
}
2016-08-19 06:01:08 +00:00
/**
* Test that auth plugin throws correct exception if we trying to request user,
* but ip field is not set and iprestriction is enabled.
*/
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_jwt');
$this->auth = new auth_plugin_jwt();
2016-08-19 06:01:08 +00:00
2022-08-19 00:08:02 +00:00
$this->expectException(invalid_parameter_exception::class);
$this->expectExceptionMessage('Invalid parameter value detected (Required parameter "ip" is not set.)');
2016-08-19 06:01:08 +00:00
$actual = $this->auth->get_login_url($user);
}
/**
2016-08-17 07:53:26 +00:00
* 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);
$jwtmanager = new fake_jwt_manager();
$this->auth->set_jwt_manager($jwtmanager);
$expected = $CFG->wwwroot . '/auth/jwt/login.php?key=FaKeKeyFoRtEsTiNg';
$actual = $this->auth->get_login_url($user);
$this->assertEquals($expected, $actual);
}
/**
2016-08-17 07:53:26 +00:00
* 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);
$jwtmanager = new fake_jwt_manager();
$this->auth->set_jwt_manager($jwtmanager);
$expected = $CFG->wwwroot . '/auth/jwt/login.php?key=FaKeKeyFoRtEsTiNg';
$actual = $this->auth->get_login_url($user);
$this->assertEquals($expected, $actual);
}
2016-08-19 06:01:08 +00:00
/**
* 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);
$jwtmanager = new fake_jwt_manager();
$this->auth->set_jwt_manager($jwtmanager);
2016-08-19 06:01:08 +00:00
$expected = $CFG->wwwroot . '/auth/jwt/login.php?key=FaKeKeyFoRtEsTiNg';
2016-08-19 06:01:08 +00:00
$actual = $this->auth->get_login_url($user);
$this->assertEquals($expected, $actual);
}
2017-03-31 10:41:33 +00:00
/**
* Test that we can request a key for a new user.
*/
public function test_return_correct_login_url_and_create_new_user() {
global $CFG, $DB;
set_config('createuser', true, 'auth_jwt');
$this->auth = new auth_plugin_jwt();
2017-03-31 10:41:33 +00:00
$jwtmanager = new fake_jwt_manager();
$this->auth->set_jwt_manager($jwtmanager);
2017-03-31 10:41:33 +00:00
$user = new stdClass();
$user->username = 'username';
$user->email = 'username@test.com';
$user->firstname = 'user';
$user->lastname = 'name';
$user->ip = '192.168.1.1';
$expected = $CFG->wwwroot . '/auth/jwt/login.php?key=FaKeKeyFoRtEsTiNg';
2017-03-31 10:41:33 +00:00
$actual = $this->auth->get_login_url($user);
$this->assertEquals($expected, $actual);
$userrecord = $DB->get_record('user', ['username' => 'username']);
$this->assertEquals($user->email, $userrecord->email);
$this->assertEquals($user->firstname, $userrecord->firstname);
$this->assertEquals($user->lastname, $userrecord->lastname);
2018-05-02 00:06:36 +00:00
$this->assertEquals(1, $userrecord->confirmed);
$this->assertEquals('jwt', $userrecord->auth);
2017-03-31 10:41:33 +00:00
}
/**
* Test that we can request a key for a new user.
*/
public function test_missing_data_to_create_user() {
global $CFG, $DB;
set_config('createuser', true, 'auth_jwt');
$this->auth = new auth_plugin_jwt();
$jwtmanager = new fake_jwt_manager();
$this->auth->set_jwt_manager($jwtmanager);
$user = new stdClass();
$user->email = 'username@test.com';
$user->ip = '192.168.1.1';
2022-08-19 00:08:02 +00:00
$this->expectException(invalid_parameter_exception::class);
$this->expectExceptionMessage('Unable to create user, missing value(s): username,firstname,lastname');
$this->auth->get_login_url($user);
}
2017-03-31 10:41:33 +00:00
/**
* Test that when we attempt to create a new user duplicate usernames are caught.
*/
public function test_create_refuse_duplicate_username() {
set_config('createuser', true, 'auth_jwt');
$this->auth = new auth_plugin_jwt();
2017-03-31 10:41:33 +00:00
$jwtmanager = new fake_jwt_manager();
$this->auth->set_jwt_manager($jwtmanager);
2017-03-31 10:41:33 +00:00
$originaluser = new stdClass();
$originaluser->username = 'username';
$originaluser->email = 'username@test.com';
$originaluser->firstname = 'user';
$originaluser->lastname = 'name';
$originaluser->city = 'brighton';
$originaluser->ip = '192.168.1.1';
self::getDataGenerator()->create_user($originaluser);
2023-12-05 16:50:56 +00:00
$duplicateuser = clone ($originaluser);
2017-03-31 10:41:33 +00:00
$duplicateuser->email = 'duplicateuser@test.com';
2022-08-19 00:08:02 +00:00
$this->expectException(invalid_parameter_exception::class);
$this->expectExceptionMessage('Username already exists: username');
2017-03-31 10:41:33 +00:00
$this->auth->get_login_url($duplicateuser);
}
/**
* Test that when we attempt to create a new user duplicate emails are caught.
*/
public function test_create_refuse_duplicate_email() {
set_config('createuser', true, 'auth_jwt');
set_config('mappingfield', 'username', 'auth_jwt');
$this->auth = new auth_plugin_jwt();
2017-03-31 10:41:33 +00:00
$jwtmanager = new fake_jwt_manager();
$this->auth->set_jwt_manager($jwtmanager);
2017-03-31 10:41:33 +00:00
$originaluser = new stdClass();
$originaluser->username = 'username';
$originaluser->email = 'username@test.com';
$originaluser->firstname = 'user';
$originaluser->lastname = 'name';
$originaluser->city = 'brighton';
$originaluser->ip = '192.168.1.1';
self::getDataGenerator()->create_user($originaluser);
2023-12-05 16:50:56 +00:00
$duplicateuser = clone ($originaluser);
2017-03-31 10:41:33 +00:00
$duplicateuser->username = 'duplicateuser';
2022-08-19 00:08:02 +00:00
$this->expectException(invalid_parameter_exception::class);
$this->expectExceptionMessage('Email address already exists: username@test.com');
2017-03-31 10:41:33 +00:00
$this->auth->get_login_url($duplicateuser);
}
/**
* Test that we can request a key for an existing user and update their details.
*/
public function test_return_correct_login_url_and_update_user() {
global $CFG, $DB;
set_config('updateuser', true, 'auth_jwt');
$this->auth = new auth_plugin_jwt();
2017-03-31 10:41:33 +00:00
$jwtmanager = new fake_jwt_manager();
$this->auth->set_jwt_manager($jwtmanager);
2017-03-31 10:41:33 +00:00
$originaluser = new stdClass();
$originaluser->username = 'username';
$originaluser->email = 'username@test.com';
$originaluser->firstname = 'user';
$originaluser->lastname = 'name';
$originaluser->city = 'brighton';
$originaluser->ip = '192.168.1.1';
self::getDataGenerator()->create_user($originaluser);
$user = new stdClass();
$user->username = 'usernamechanged';
$user->email = 'username@test.com';
$user->firstname = 'userchanged';
$user->lastname = 'namechanged';
$user->ip = '192.168.1.1';
$expected = $CFG->wwwroot . '/auth/jwt/login.php?key=FaKeKeyFoRtEsTiNg';
2017-03-31 10:41:33 +00:00
$actual = $this->auth->get_login_url($user);
$this->assertEquals($expected, $actual);
$userrecord = $DB->get_record('user', ['email' => $user->email]);
$this->assertEquals($user->username, $userrecord->username);
$this->assertEquals($user->firstname, $userrecord->firstname);
$this->assertEquals($user->lastname, $userrecord->lastname);
$this->assertEquals($originaluser->city, $userrecord->city);
$this->assertEquals('jwt', $userrecord->auth);
2017-03-31 10:41:33 +00:00
}
/**
* Test that when we attempt to update a user duplicate emails are caught.
*/
public function test_update_refuse_duplicate_email() {
set_config('updateuser', true, 'auth_jwt');
set_config('mappingfield', 'username', 'auth_jwt');
$this->auth = new auth_plugin_jwt();
2017-03-31 10:41:33 +00:00
$jwtmanager = new fake_jwt_manager();
$this->auth->set_jwt_manager($jwtmanager);
2017-03-31 10:41:33 +00:00
self::getDataGenerator()->create_user(['email' => 'trytoduplicate@test.com']);
self::getDataGenerator()->create_user(['username' => 'username']);
$originaluser = new stdClass();
$originaluser->username = 'username';
$originaluser->email = 'trytoduplicate@test.com';
$originaluser->firstname = 'user';
$originaluser->lastname = 'name';
$originaluser->city = 'brighton';
$originaluser->ip = '192.168.1.1';
2022-08-19 00:08:02 +00:00
$this->expectException(invalid_parameter_exception::class);
$this->expectExceptionMessage('Email address already exists: trytoduplicate@test.com');
2017-03-31 10:41:33 +00:00
$this->auth->get_login_url($originaluser);
}
/**
* Test that when we attempt to update a user duplicate usernames are caught.
*/
public function test_update_refuse_duplicate_username() {
set_config('updateuser', true, 'auth_jwt');
$this->auth = new auth_plugin_jwt();
2017-03-31 10:41:33 +00:00
$jwtmanager = new fake_jwt_manager();
$this->auth->set_jwt_manager($jwtmanager);
2017-03-31 10:41:33 +00:00
self::getDataGenerator()->create_user(['username' => 'trytoduplicate']);
self::getDataGenerator()->create_user(['email' => 'username@test.com']);
$originaluser = new stdClass();
$originaluser->username = 'trytoduplicate';
$originaluser->email = 'username@test.com';
$originaluser->firstname = 'user';
$originaluser->lastname = 'name';
$originaluser->city = 'brighton';
$originaluser->ip = '192.168.1.1';
2022-08-19 00:08:02 +00:00
$this->expectException(invalid_parameter_exception::class);
$this->expectExceptionMessage('Username already exists: trytoduplicate');
2017-03-31 10:41:33 +00:00
$this->auth->get_login_url($originaluser);
}
2016-08-17 07:53:26 +00:00
/**
* 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/jwt', $user->id);
create_user_key('auth/jwt', $user->id);
create_user_key('auth/jwt', $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/jwt/login.php?key=' . $actualkey->value;
$this->assertEquals($expected, $actual);
}
2016-08-17 07:53:26 +00:00
/**
* Test that we can return correct allowed mapping fields.
*/
public function test_get_allowed_mapping_fields_list() {
$expected = array(
2016-08-18 04:43:57 +00:00
'username' => 'Username',
'email' => 'Email address',
'idnumber' => 'ID number',
);
$actual = $this->auth->get_allowed_mapping_fields();
$this->assertEquals($expected, $actual);
}
2016-08-17 07:53:26 +00:00
/**
* 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_jwt');
$this->auth = new auth_plugin_jwt();
$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_jwt');
$this->auth = new auth_plugin_jwt();
$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_jwt');
$this->auth = new auth_plugin_jwt();
$expected = array();
$actual = $this->auth->get_request_login_url_user_parameters();
$this->assertEquals($expected, $actual);
2016-08-19 06:01:08 +00:00
// Check IP if iprestriction disabled.
set_config('iprestriction', false, 'auth_jwt');
$this->auth = new auth_plugin_jwt();
2016-08-19 06:01:08 +00:00
$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_jwt');
$this->auth = new auth_plugin_jwt();
2016-08-19 06:01:08 +00:00
$expected = array(
'ip' => new external_value(
PARAM_HOST,
'User IP address'
),
);
$actual = $this->auth->get_request_login_url_user_parameters();
$this->assertEquals($expected, $actual);
2017-03-31 10:41:33 +00:00
// Check IP if createuser enabled.
set_config('createuser', true, 'auth_jwt');
$this->auth = new auth_plugin_jwt();
2017-03-31 10:41:33 +00:00
$expected = array(
'ip' => new external_value(PARAM_HOST, 'User IP address'),
2017-04-03 08:32:35 +00:00
'firstname' => new external_value(PARAM_NOTAGS, 'The first name(s) of the user', VALUE_OPTIONAL),
'lastname' => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL),
'email' => new external_value(PARAM_RAW_TRIMMED, 'A valid and unique email address', VALUE_OPTIONAL),
'username' => new external_value(PARAM_USERNAME, 'A valid and unique username', VALUE_OPTIONAL),
2017-03-31 10:41:33 +00:00
);
$actual = $this->auth->get_request_login_url_user_parameters();
$this->assertEquals($expected, $actual);
set_config('createuser', false, 'auth_jwt');
2017-03-31 10:41:33 +00:00
// Check IP if updateuser enabled.
set_config('updateuser', true, 'auth_jwt');
$this->auth = new auth_plugin_jwt();
2017-03-31 10:41:33 +00:00
$expected = array(
'ip' => new external_value(PARAM_HOST, 'User IP address'),
2017-04-03 08:32:35 +00:00
'firstname' => new external_value(PARAM_NOTAGS, 'The first name(s) of the user', VALUE_OPTIONAL),
'lastname' => new external_value(PARAM_NOTAGS, 'The family name of the user', VALUE_OPTIONAL),
'email' => new external_value(PARAM_RAW_TRIMMED, 'A valid and unique email address', VALUE_OPTIONAL),
'username' => new external_value(PARAM_USERNAME, 'A valid and unique username', VALUE_OPTIONAL),
2017-03-31 10:41:33 +00:00
);
$actual = $this->auth->get_request_login_url_user_parameters();
$this->assertEquals($expected, $actual);
set_config('updateuser', false, 'auth_jwt');
}
2016-09-26 00:40:21 +00:00
/**
* Data provider for testing URL validation functions.
*
* @return array First element URL, the second URL is error message. Empty error massage means no errors.
*/
public function url_data_provider() {
return array(
array('', ''),
array('http://google.com/', ''),
array('https://google.com', ''),
array('http://some.very.long.and.silly.domain/with/a/path/', ''),
array('http://0.255.1.1/numericip.php', ''),
array('http://0.255.1.1/numericip.php?test=1&id=2', ''),
array('/just/a/path', 'You should provide valid URL'),
array('random string', 'You should provide valid URL'),
array(123456, 'You should provide valid URL'),
array('php://google.com', 'You should provide valid URL'),
);
}
2016-08-18 12:57:37 +00:00
/**
* Test required parameter exception gets thrown id try to login, but key is not set.
*/
public function test_required_parameter_exception_thrown_if_key_not_set() {
2022-08-19 00:08:02 +00:00
$this->expectException(moodle_exception::class);
$this->expectExceptionMessage('A required parameter (key) was missing');
$this->auth->user_login_jwt();
2016-08-18 12:57:37 +00:00
}
/**
* Test that incorrect key exception gets thrown if a key is incorrect.
*/
public function test_invalid_key_exception_thrown_if_invalid_key() {
2022-08-19 00:08:02 +00:00
$this->expectException(moodle_exception::class);
$this->expectExceptionMessage('Incorrect key');
2016-08-18 12:57:37 +00:00
$_POST['key'] = 'InvalidKey';
$this->auth->user_login_jwt();
2016-08-18 12:57:37 +00:00
}
/**
* Test that expired key exception gets thrown if a key is expired.
*/
public function test_expired_key_exception_thrown_if_expired_key() {
2020-05-08 07:20:28 +00:00
$this->create_user_private_key(['validuntil' => time() - 3000]);
2016-08-18 12:57:37 +00:00
2022-08-19 00:08:02 +00:00
$this->expectException(moodle_exception::class);
$this->expectExceptionMessage('Expired key');
2020-05-08 07:20:28 +00:00
$_POST['key'] = 'TestKey';
$this->auth->user_login_jwt();
2016-08-18 12:57:37 +00:00
}
/**
* Test that IP address mismatch exception gets thrown if incorrect IP.
*/
public function test_ipmismatch_exception_thrown_if_ip_is_incorrect() {
2020-05-08 07:20:28 +00:00
$this->create_user_private_key(['iprestriction' => '192.168.1.1']);
2016-08-18 12:57:37 +00:00
2020-05-08 07:20:28 +00:00
$_POST['key'] = 'TestKey';
2016-08-18 12:57:37 +00:00
$_SERVER['HTTP_CLIENT_IP'] = '192.168.1.2';
2022-08-19 00:08:02 +00:00
$this->expectException(moodle_exception::class);
$this->expectExceptionMessage('Client IP address mismatch');
$this->auth->user_login_jwt();
2016-08-18 12:57:37 +00:00
}
/**
2017-10-03 17:03:02 +00:00
* Test that IP address mismatch exception gets thrown if incorrect IP and outside whitelist.
*/
public function test_ipmismatch_exception_thrown_if_ip_is_outside_whitelist() {
set_config('ipwhitelist', '10.0.0.0/8;172.16.0.0/12;192.168.0.0/16', 'auth_jwt');
2020-05-08 07:20:28 +00:00
$this->create_user_private_key(['iprestriction' => '192.161.1.1']);
2020-05-08 07:20:28 +00:00
$_POST['key'] = 'TestKey';
$_SERVER['HTTP_CLIENT_IP'] = '192.161.1.2';
2022-08-19 00:08:02 +00:00
$this->expectException(moodle_exception::class);
$this->expectExceptionMessage('Client IP address mismatch');
$this->auth->user_login_jwt();
}
2016-08-18 12:57:37 +00:00
/**
2016-08-19 06:01:08 +00:00
* Test that IP address mismatch exception gets thrown if user id is incorrect.
2016-08-18 12:57:37 +00:00
*/
2016-08-19 06:01:08 +00:00
public function test_invalid_user_exception_thrown_if_user_is_invalid() {
2020-05-08 07:20:28 +00:00
$this->create_user_private_key([
'userid' => 777,
'instance' => 777,
'iprestriction' => '192.168.1.1',
]);
2016-08-18 12:57:37 +00:00
2020-05-08 07:20:28 +00:00
$_POST['key'] = 'TestKey';
2016-08-18 12:57:37 +00:00
$_SERVER['HTTP_CLIENT_IP'] = '192.168.1.1';
2022-08-19 00:08:02 +00:00
$this->expectException(moodle_exception::class);
$this->expectExceptionMessage('Invalid user');
$this->auth->user_login_jwt();
2016-08-18 12:57:37 +00:00
}
/**
* Test that key gets removed after a user logged in.
*/
public function test_that_key_gets_removed_after_user_logged_in() {
global $DB;
2020-05-08 07:20:28 +00:00
$this->create_user_private_key([
'value' => 'RemoveKey',
'iprestriction' => '192.168.1.1',
]);
2016-08-18 12:57:37 +00:00
$_POST['key'] = 'RemoveKey';
$_SERVER['HTTP_CLIENT_IP'] = '192.168.1.1';
try {
// Using @ is the only way to test this. Thanks moodle!
@$this->auth->user_login_jwt();
} catch (moodle_exception $e) {
$keyexists = $DB->record_exists('user_private_key', array('value' => 'RemoveKey'));
$this->assertFalse($keyexists);
}
}
/**
* Test that a user logs in and gets redirected correctly.
*/
public function test_that_user_logged_in_and_redirected() {
2020-05-08 07:20:28 +00:00
global $CFG;
2016-08-18 12:57:37 +00:00
2020-05-08 07:20:28 +00:00
$this->create_user_private_key();
$CFG->wwwroot = 'http://www.example.com/moodle';
2020-05-08 07:20:28 +00:00
$_POST['key'] = 'TestKey';
2022-08-19 00:08:02 +00:00
$this->expectException(moodle_exception::class);
$this->expectExceptionMessage('Unsupported redirect to http://www.example.com/moodle detected, execution terminated');
@$this->auth->user_login_jwt();
2016-08-18 12:57:37 +00:00
}
/**
* Test that a user logs in correctly.
2016-08-18 12:57:37 +00:00
*/
public function test_that_user_logged_in_correctly() {
2020-05-08 07:20:28 +00:00
global $USER, $SESSION;
2016-08-18 12:57:37 +00:00
2020-05-08 07:20:28 +00:00
$this->create_user_private_key();
2016-08-18 12:57:37 +00:00
2020-05-08 07:20:28 +00:00
$_POST['key'] = 'TestKey';
2016-08-18 12:57:37 +00:00
try {
// Using @ is the only way to test this. Thanks moodle!
@$this->auth->user_login_jwt();
} catch (moodle_exception $e) {
$this->assertEquals($this->user->id, $USER->id);
$this->assertSame(sesskey(), $USER->sesskey);
$this->assertObjectHasAttribute('jwt', $SESSION);
}
2016-08-18 12:57:37 +00:00
}
/**
* Test that a user gets redirected to internal wantsurl URL successful log in.
2016-08-18 12:57:37 +00:00
*/
public function test_that_user_gets_redirected_to_internal_wantsurl() {
2020-05-08 07:20:28 +00:00
$this->create_user_private_key();
$_POST['key'] = 'TestKey';
2016-08-19 00:37:52 +00:00
$_POST['wantsurl'] = '/course/index.php?id=12&key=134';
2016-08-18 12:57:37 +00:00
2022-08-19 00:08:02 +00:00
$this->expectException(moodle_exception::class);
$this->expectExceptionMessage('Unsupported redirect to /course/index.php?id=12&key=134 detected, execution terminated');
2016-08-18 12:57:37 +00:00
// Using @ is the only way to test this. Thanks moodle!
@$this->auth->user_login_jwt();
2016-08-18 12:57:37 +00:00
}
/**
* Test that a user gets redirected to external wantsurl URL successful log in.
2016-08-18 12:57:37 +00:00
*/
public function test_that_user_gets_redirected_to_external_wantsurl() {
2020-05-08 07:20:28 +00:00
$this->create_user_private_key();
2016-08-18 12:57:37 +00:00
2020-05-08 07:20:28 +00:00
$_POST['key'] = 'TestKey';
2016-08-19 00:37:52 +00:00
$_POST['wantsurl'] = 'http://test.com/course/index.php?id=12&key=134';
2016-08-18 12:57:37 +00:00
2022-08-19 00:08:02 +00:00
$this->expectException(moodle_exception::class);
$this->expectExceptionMessage('Unsupported redirect to http://test.com/course/index.php?id=12&key=134 detected, execution terminated');
2016-08-18 12:57:37 +00:00
// Using @ is the only way to test this. Thanks moodle!
@$this->auth->user_login_jwt();
2016-08-18 12:57:37 +00:00
}
/**
* Test that login hook redirects a user if skipsso not set and ssourl is set.
*/
public function test_loginpage_hook_redirects_if_skipsso_not_set_and_ssourl_set() {
global $SESSION;
$SESSION->enrolkey_skipsso = 0;
set_config('ssourl', 'http://google.com', 'auth_jwt');
$this->auth = new auth_plugin_jwt();
2022-08-19 00:08:02 +00:00
$this->expectException(moodle_exception::class);
$this->expectExceptionMessage('Unsupported redirect to http://google.com detected, execution terminated.');
$this->auth->loginpage_hook();
}
/**
* Test that login hook does not redirect a user if skipsso not set and ssourl is not set.
*/
public function test_loginpage_hook_does_not_redirect_if_skipsso_not_set_and_ssourl_not_set() {
global $SESSION;
$SESSION->enrolkey_skipsso = 0;
set_config('ssourl', '', 'auth_jwt');
$this->auth = new auth_plugin_jwt();
$this->assertTrue($this->auth->loginpage_hook());
}
/**
* Test that login hook does not redirect a user if skipsso is set and ssourl is not set.
*/
public function test_loginpage_hook_does_not_redirect_if_skipsso_set_and_ssourl_not_set() {
global $SESSION;
$SESSION->enrolkey_skipsso = 1;
set_config('ssourl', '', 'auth_jwt');
$this->auth = new auth_plugin_jwt();
$this->assertTrue($this->auth->loginpage_hook());
}
/**
* Test that pre login hook redirects a user if skipsso not set and ssourl is set.
*/
public function test_pre_loginpage_hook_redirects_if_skipsso_not_set_and_ssourl_set() {
global $SESSION;
$SESSION->enrolkey_skipsso = 0;
set_config('ssourl', 'http://google.com', 'auth_jwt');
$this->auth = new auth_plugin_jwt();
2022-08-19 00:08:02 +00:00
$this->expectException(moodle_exception::class);
$this->expectExceptionMessage('Unsupported redirect to http://google.com detected, execution terminated.');
$this->auth->pre_loginpage_hook();
}
/**
* Test that pre login hook does not redirect a user if skipsso is not set and ssourl is not set.
*/
public function test_pre_loginpage_hook_does_not_redirect_if_skipsso_not_set_and_ssourl_not_set() {
global $SESSION;
$SESSION->enrolkey_skipsso = 0;
set_config('ssourl', '', 'auth_jwt');
$this->auth = new auth_plugin_jwt();
$this->assertTrue($this->auth->pre_loginpage_hook());
}
/**
* Test that login page hook does not redirect a user if skipsso is set and ssourl is not set.
*/
public function test_pre_loginpage_hook_does_not_redirect_if_skipsso_set_and_ssourl_not_set() {
global $SESSION;
$SESSION->enrolkey_skipsso = 1;
set_config('ssourl', '', 'auth_jwt');
$this->auth = new auth_plugin_jwt();
$this->assertTrue($this->auth->pre_loginpage_hook());
}
/**
* Test that if one user logged, he will be logged out before a new one is authorised.
*/
public function test_that_different_authorised_user_is_logged_out_and_new_one_logged_in() {
2020-05-08 07:20:28 +00:00
global $USER, $SESSION;
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$this->assertEquals($USER->id, $user->id);
2020-05-08 07:20:28 +00:00
$this->create_user_private_key();
2020-05-08 07:20:28 +00:00
$_POST['key'] = 'TestKey';
try {
// Using @ is the only way to test this. Thanks moodle!
@$this->auth->user_login_jwt();
} catch (moodle_exception $e) {
$this->assertEquals($this->user->id, $USER->id);
$this->assertSame(sesskey(), $USER->sesskey);
$this->assertObjectHasAttribute('jwt', $SESSION);
}
}
2019-11-16 12:59:16 +00:00
/**
* Test that authorised user gets logged out when trying to logged in with invalid key.
*/
public function test_if_invalid_key_authorised_user_gets_logged_out() {
2020-05-08 07:20:28 +00:00
global $USER, $SESSION;
2019-11-16 12:59:16 +00:00
$user = $this->getDataGenerator()->create_user();
$this->setUser($user);
$this->assertEquals($USER->id, $user->id);
2020-05-08 07:20:28 +00:00
$this->create_user_private_key();
2019-11-16 12:59:16 +00:00
$_POST['key'] = 'Incorrect Key';
try {
// Using @ is the only way to test this. Thanks moodle!
@$this->auth->user_login_jwt();
2019-11-16 12:59:16 +00:00
} catch (moodle_exception $e) {
$this->assertEquals('Incorrect key', $e->getMessage());
$this->assertEmpty($USER->id);
$this->assertEquals(new stdClass(), $SESSION);
}
}
2019-11-16 13:19:48 +00:00
/**
* Test if a user is logged in and tries to log in again it stays logged in.
*/
public function test_that_already_logged_in_user_stays_logged_in() {
global $DB, $USER, $SESSION;
$this->setUser($this->user);
$this->assertEquals($USER->id, $this->user->id);
2020-05-08 07:20:28 +00:00
$this->create_user_private_key();
2019-11-16 13:19:48 +00:00
2020-05-08 07:20:28 +00:00
$_POST['key'] = 'TestKey';
2019-11-16 13:19:48 +00:00
try {
// Using @ is the only way to test this. Thanks moodle!
@$this->auth->user_login_jwt();
2019-11-16 13:19:48 +00:00
} catch (moodle_exception $e) {
$this->assertEquals($this->user->id, $USER->id);
$this->assertSame(sesskey(), $USER->sesskey);
$this->assertObjectNotHasAttribute('jwt', $SESSION);
2020-05-08 07:20:28 +00:00
$keyexists = $DB->record_exists('user_private_key', array('value' => 'TestKey'));
2019-11-16 13:42:44 +00:00
$this->assertFalse($keyexists);
2019-11-16 13:19:48 +00:00
}
}
2020-05-08 12:57:13 +00:00
/**
* Test when try to logout, but required return is not set.
*/
public function test_user_logout_jwt_when_required_return_not_set() {
2022-08-19 00:08:02 +00:00
$this->expectException(moodle_exception::class);
$this->expectExceptionMessage('A required parameter (return) was missing');
$this->auth->user_logout_jwt();
2020-05-08 12:57:13 +00:00
}
/**
* Test when try to logout, but user is not logged in.
*/
public function test_user_logout_jwt_when_user_is_not_logged_in() {
2023-12-05 16:50:56 +00:00
$_POST['return'] = self::REDIRECTION_PATH;
2020-05-08 12:57:13 +00:00
2022-08-19 00:08:02 +00:00
$this->expectException(moodle_exception::class);
2023-12-05 16:50:56 +00:00
$this->expectExceptionMessage(
2023-12-06 13:07:24 +00:00
sprintf("Unsupported redirect to %s detected, execution terminated.", self::REDIRECTION_PATH)
2023-12-05 16:50:56 +00:00
);
2022-08-19 00:08:02 +00:00
$this->auth->user_logout_jwt();
2020-05-08 12:57:13 +00:00
}
/**
* Test when try to logout, but user logged in with different auth type.
*/
public function test_user_logout_jwt_when_user_logged_in_with_different_auth() {
2020-05-08 12:57:13 +00:00
global $USER;
2023-12-05 16:50:56 +00:00
$_POST['return'] = self::REDIRECTION_PATH;
2020-05-08 12:57:13 +00:00
$this->setUser($this->user);
try {
$this->auth->user_logout_jwt();
2020-05-08 12:57:13 +00:00
} catch (moodle_exception $e) {
$this->assertTrue(isloggedin());
$this->assertEquals($USER->id, $this->user->id);
$this->assertEquals(
'Incorrect logout request',
$e->getMessage()
);
}
}
/**
* Test when try to logout, but user logged in with different auth type.
*/
public function test_user_logout_jwt_when_user_logged_in_but_return_not_set() {
2020-05-08 12:57:13 +00:00
$this->setUser($this->user);
2022-08-19 00:08:02 +00:00
$this->expectException(moodle_exception::class);
$this->expectExceptionMessage('A required parameter (return) was missing');
$this->auth->user_logout_jwt();
2020-05-08 12:57:13 +00:00
}
/**
* Test successful logout.
*/
public function test_user_logout_jwt_logging_out() {
2020-05-08 12:57:13 +00:00
global $USER;
$this->setUser($this->user);
$USER->auth = 'jwt';
2023-12-05 16:50:56 +00:00
$_POST['return'] = self::REDIRECTION_PATH;
2020-05-08 12:57:13 +00:00
try {
$this->auth->user_logout_jwt();
2020-05-08 12:57:13 +00:00
} catch (moodle_exception $e) {
$this->assertFalse(isloggedin());
2023-12-05 16:50:56 +00:00
$this->assertEquals(
sprintf('Unsupported redirect to %s detected, execution terminated.', self::REDIRECTION_PATH),
$e->getMessage()
);
2020-05-08 12:57:13 +00:00
}
}
2016-08-16 04:49:39 +00:00
}