mirror of
https://github.com/moodle/moodle.git
synced 2025-01-17 21:49:15 +01:00
MDL-28646 add missing authentication web service checks. Merge download/upload script checks in the same lib functions. Make the download scrit return json error message. Add missing webservice lang. Minor unit test doc improvement.
This commit is contained in:
parent
ec0d6ea2a9
commit
07cc3d11e2
@ -162,6 +162,7 @@ $string['selectspecificuserdescription'] = 'Add the web services user as an auth
|
||||
$string['service'] = 'Service';
|
||||
$string['servicehelpexplanation'] = 'A service is a set of functions. A service can be accessed by all users or just specified users.';
|
||||
$string['servicename'] = 'Service name';
|
||||
$string['servicenotavailable'] = 'the web service is not available (it does not exist or it is disabled)';
|
||||
$string['servicesbuiltin'] = 'Built-in services';
|
||||
$string['servicescustom'] = 'Custom services';
|
||||
$string['serviceusers'] = 'Authorised users';
|
||||
|
@ -34,6 +34,124 @@ define('WEBSERVICE_AUTHMETHOD_SESSION_TOKEN', 2);
|
||||
*/
|
||||
class webservice {
|
||||
|
||||
/**
|
||||
* Authenticate user (used by download/upload file scripts)
|
||||
* @param string $token
|
||||
* @return array - contains the authenticated user, token and service objects
|
||||
*/
|
||||
public function authenticate_user($token) {
|
||||
global $DB, $CFG;
|
||||
|
||||
// web service must be enabled to use this script
|
||||
if (!$CFG->enablewebservices) {
|
||||
throw new webservice_access_exception(get_string('enablewsdescription', 'webservice'));
|
||||
}
|
||||
|
||||
// Obtain token record
|
||||
if (!$token = $DB->get_record('external_tokens', array('token' => $token))) {
|
||||
throw new webservice_access_exception(get_string('invalidtoken', 'webservice'));
|
||||
}
|
||||
|
||||
// Validate token date
|
||||
if ($token->validuntil and $token->validuntil < time()) {
|
||||
add_to_log(SITEID, 'webservice', get_string('tokenauthlog', 'webservice'), '', get_string('invalidtimedtoken', 'webservice'), 0);
|
||||
$DB->delete_records('external_tokens', array('token' => $token->token));
|
||||
throw new webservice_access_exception(get_string('invalidtimedtoken', 'webservice'));
|
||||
}
|
||||
|
||||
// Check ip
|
||||
if ($token->iprestriction and !address_in_subnet(getremoteaddr(), $token->iprestriction)) {
|
||||
add_to_log(SITEID, 'webservice', get_string('tokenauthlog', 'webservice'), '', get_string('failedtolog', 'webservice') . ": " . getremoteaddr(), 0);
|
||||
throw new webservice_access_exception(get_string('invalidiptoken', 'webservice'));
|
||||
}
|
||||
|
||||
//retrieve user link to the token
|
||||
$user = $DB->get_record('user', array('id' => $token->userid, 'deleted' => 0), '*', MUST_EXIST);
|
||||
|
||||
// let enrol plugins deal with new enrolments if necessary
|
||||
enrol_check_plugins($user);
|
||||
|
||||
// setup user session to check capability
|
||||
session_set_user($user);
|
||||
|
||||
//assumes that if sid is set then there must be a valid associated session no matter the token type
|
||||
if ($token->sid) {
|
||||
$session = session_get_instance();
|
||||
if (!$session->session_exists($token->sid)) {
|
||||
$DB->delete_records('external_tokens', array('sid' => $token->sid));
|
||||
throw new webservice_access_exception(get_string('invalidtokensession', 'webservice'));
|
||||
}
|
||||
}
|
||||
|
||||
//Non admin can not authenticate if maintenance mode
|
||||
$hassiteconfig = has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM), $user);
|
||||
if (!empty($CFG->maintenance_enabled) and !$hassiteconfig) {
|
||||
throw new webservice_access_exception(get_string('sitemaintenance', 'admin'));
|
||||
}
|
||||
|
||||
//retrieve web service record
|
||||
$service = $DB->get_record('external_services', array('id' => $token->externalserviceid, 'enabled' => 1));
|
||||
if (empty($service)) {
|
||||
// will throw exception if no token found
|
||||
throw new webservice_access_exception(get_string('servicenotavailable', 'webservice'));
|
||||
}
|
||||
|
||||
//check if there is any required system capability
|
||||
if ($service->requiredcapability and !has_capability($service->requiredcapability, get_context_instance(CONTEXT_SYSTEM), $user)) {
|
||||
throw new webservice_access_exception(get_string('missingrequiredcapability', 'webservice', $service->requiredcapability));
|
||||
}
|
||||
|
||||
//specific checks related to user restricted service
|
||||
if ($service->restrictedusers) {
|
||||
$authoriseduser = $DB->get_record('external_services_users', array('externalserviceid' => $service->id, 'userid' => $user->id));
|
||||
|
||||
if (empty($authoriseduser)) {
|
||||
throw new webservice_access_exception(get_string('usernotallowed', 'webservice', $service->name));
|
||||
}
|
||||
|
||||
if (!empty($authoriseduser->validuntil) and $authoriseduser->validuntil < time()) {
|
||||
throw new webservice_access_exception(get_string('invalidtimedtoken', 'webservice'));
|
||||
}
|
||||
|
||||
if (!empty($authoriseduser->iprestriction) and !address_in_subnet(getremoteaddr(), $authoriseduser->iprestriction)) {
|
||||
throw new webservice_access_exception(get_string('invalidiptoken', 'webservice'));
|
||||
}
|
||||
}
|
||||
|
||||
//only confirmed user should be able to call web service
|
||||
if (empty($user->confirmed)) {
|
||||
add_to_log(SITEID, 'webservice', 'user unconfirmed', '', $user->username);
|
||||
throw new webservice_access_exception(get_string('usernotconfirmed', 'moodle', $user->username));
|
||||
}
|
||||
|
||||
//check the user is suspended
|
||||
if (!empty($user->suspended)) {
|
||||
add_to_log(SITEID, 'webservice', 'user suspended', '', $user->username);
|
||||
throw new webservice_access_exception(get_string('usersuspended', 'webservice'));
|
||||
}
|
||||
|
||||
//check if the auth method is nologin (in this case refuse connection)
|
||||
if ($user->auth == 'nologin') {
|
||||
add_to_log(SITEID, 'webservice', 'nologin auth attempt with web service', '', $user->username);
|
||||
throw new webservice_access_exception(get_string('nologinauth', 'webservice'));
|
||||
}
|
||||
|
||||
//Check if the user password is expired
|
||||
$auth = get_auth_plugin($user->auth);
|
||||
if (!empty($auth->config->expiration) and $auth->config->expiration == 1) {
|
||||
$days2expire = $auth->password_expire($user->username);
|
||||
if (intval($days2expire) < 0) {
|
||||
add_to_log(SITEID, 'webservice', 'expired password', '', $user->username);
|
||||
throw new webservice_access_exception(get_string('passwordisexpired', 'webservice'));
|
||||
}
|
||||
}
|
||||
|
||||
// log token access
|
||||
$DB->set_field('external_tokens', 'lastaccess', time(), array('id' => $token->id));
|
||||
|
||||
return array('user' => $user, 'token' => $token, 'service' => $service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a user to the list of authorised user of a given service
|
||||
* @param object $user
|
||||
|
@ -24,96 +24,23 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
define('AJAX_SCRIPT', true);
|
||||
define('NO_MOODLE_COOKIES', true);
|
||||
require_once(dirname(dirname(__FILE__)) . '/config.php');
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
require_once($CFG->dirroot . '/webservice/lib.php');
|
||||
|
||||
$relativepath = get_file_argument();
|
||||
//authenticate the user
|
||||
$token = required_param('token', PARAM_ALPHANUM);
|
||||
$webservicelib = new webservice();
|
||||
$authenticationinfo = $webservicelib->authenticate_user($token);
|
||||
|
||||
// web service must be enabled to use this script
|
||||
if (!$CFG->enablewebservices) {
|
||||
print_error('enablewsdescription', 'webservice');
|
||||
}
|
||||
|
||||
// Obtain token record
|
||||
if (!$token = $DB->get_record('external_tokens', array('token'=>$token))) {
|
||||
print_error('invalidtoken', 'webservice');
|
||||
}
|
||||
|
||||
//retrieve web service record
|
||||
$servicesql = 'SELECT s.*
|
||||
FROM {external_services} s, {external_tokens} t
|
||||
WHERE t.externalserviceid = s.id
|
||||
AND t.token = ? AND t.userid = ? AND s.enabled = 1';
|
||||
$service = $DB->get_record_sql($servicesql, array($token->token, $token->userid), MUST_EXIST);
|
||||
|
||||
$enabledfiledownload = (int)$service->downloadfiles;
|
||||
|
||||
//check the service allows file download
|
||||
$enabledfiledownload = (int) ($authenticationinfo['service']->downloadfiles);
|
||||
if (empty($enabledfiledownload)) {
|
||||
print_error('enabledirectdownload', 'webservice');
|
||||
throw new webservice_access_exception(get_string('enabledirectdownload', 'webservice'));
|
||||
}
|
||||
|
||||
$user = $DB->get_record('user', array('id'=>$token->userid, 'deleted'=>0), '*', MUST_EXIST);
|
||||
|
||||
//Non admin can not authenticate if maintenance mode
|
||||
$hassiteconfig = has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM), $user);
|
||||
if (!empty($CFG->maintenance_enabled) and !$hassiteconfig) {
|
||||
print_error('sitemaintenance', 'admin');
|
||||
}
|
||||
|
||||
// Validate token date
|
||||
if ($token->validuntil and $token->validuntil < time()) {
|
||||
add_to_log(SITEID, 'webservice', get_string('tokenauthlog', 'webservice'), '' , get_string('invalidtimedtoken', 'webservice'), 0);
|
||||
$DB->delete_records('external_tokens', array('token'=>$token->token));
|
||||
print_error('invalidtimedtoken', 'webservice');
|
||||
}
|
||||
|
||||
//assumes that if sid is set then there must be a valid associated session no matter the token type
|
||||
if ($token->sid) {
|
||||
$session = session_get_instance();
|
||||
if (!$session->session_exists($token->sid)) {
|
||||
$DB->delete_records('external_tokens', array('sid'=>$token->sid));
|
||||
print_error('invalidtokensession', 'webservice');
|
||||
}
|
||||
}
|
||||
|
||||
// Check ip
|
||||
if ($token->iprestriction and !address_in_subnet(getremoteaddr(), $token->iprestriction)) {
|
||||
add_to_log(SITEID, 'webservice', get_string('tokenauthlog', 'webservice'), '' , get_string('failedtolog', 'webservice').": ".getremoteaddr(), 0);
|
||||
print_error('invalidiptoken', 'webservice');
|
||||
}
|
||||
|
||||
//only confirmed user should be able to call web service
|
||||
if (empty($user->confirmed)) {
|
||||
add_to_log(SITEID, 'webservice', 'user unconfirmed', '', $user->username);
|
||||
print_error('usernotconfirmed', 'moodle', '', $user->username);
|
||||
}
|
||||
|
||||
//check the user is suspended
|
||||
if (!empty($user->suspended)) {
|
||||
add_to_log(SITEID, 'webservice', 'user suspended', '', $user->username);
|
||||
print_error('usersuspended', 'webservice');
|
||||
}
|
||||
|
||||
//check if the auth method is nologin (in this case refuse connection)
|
||||
if ($user->auth == 'nologin') {
|
||||
add_to_log(SITEID, 'webservice', 'nologin auth attempt with web service', '', $user->username);
|
||||
print_error('nologinauth', 'webservice');
|
||||
}
|
||||
|
||||
$auth = get_auth_plugin($user->auth);
|
||||
|
||||
if (!empty($auth->config->expiration) and $auth->config->expiration == 1) {
|
||||
$days2expire = $auth->password_expire($user->username);
|
||||
if (intval($days2expire) < 0 ) {
|
||||
add_to_log(SITEID, 'webservice', 'expired password', '', $user->username);
|
||||
print_error('passwordisexpired', 'webservice');
|
||||
}
|
||||
}
|
||||
|
||||
// log token access
|
||||
$DB->set_field('external_tokens', 'lastaccess', time(), array('id'=>$token->id));
|
||||
session_set_user($user);
|
||||
|
||||
//finally we can serve the file :)
|
||||
$relativepath = get_file_argument();
|
||||
file_pluginfile($relativepath, 0);
|
||||
|
@ -262,12 +262,9 @@ class webservice_test extends UnitTestCase {
|
||||
$coursecontents = $client->call($function, $params);
|
||||
}
|
||||
|
||||
//TODO: some unit tests to check that generated course content data test match what
|
||||
// the web service function is returning.
|
||||
|
||||
//Realistic TODO: display the content of $coursecontents in your php log and check if you obtain
|
||||
//Display the content of $coursecontents in your php log and check if you obtain
|
||||
//what you are expecting
|
||||
//varlog($coursecontents);
|
||||
//error_log(print_r($coursecontents, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,85 +25,17 @@
|
||||
define('AJAX_SCRIPT', true);
|
||||
define('NO_MOODLE_COOKIES', true);
|
||||
require_once(dirname(dirname(__FILE__)) . '/config.php');
|
||||
$token = required_param('token', PARAM_ALPHANUM);
|
||||
require_once($CFG->dirroot . '/webservice/lib.php');
|
||||
$filepath = optional_param('filepath', '/', PARAM_PATH);
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
//Non admin can not authenticate if maintenance mode
|
||||
$hassiteconfig = has_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM), $user);
|
||||
if (!empty($CFG->maintenance_enabled) and !$hassiteconfig) {
|
||||
throw new moodle_exception('sitemaintenance', 'admin');
|
||||
}
|
||||
//authenticate the user
|
||||
$token = required_param('token', PARAM_ALPHANUM);
|
||||
$webservicelib = new webservice();
|
||||
$authenticationinfo = $webservicelib->authenticate_user($token);
|
||||
|
||||
// web service must be enabled to use this script
|
||||
if (!$CFG->enablewebservices) {
|
||||
throw new moodle_exception('enablewsdescription', 'webservice');
|
||||
}
|
||||
// Obtain token record
|
||||
if (!$token = $DB->get_record('external_tokens', array('token'=>$token))) {
|
||||
throw new webservice_access_exception(get_string('invalidtoken', 'webservice'));
|
||||
}
|
||||
|
||||
// Validate token date
|
||||
if ($token->validuntil and $token->validuntil < time()) {
|
||||
add_to_log(SITEID, 'webservice', get_string('tokenauthlog', 'webservice'), '' , get_string('invalidtimedtoken', 'webservice'), 0);
|
||||
$DB->delete_records('external_tokens', array('token'=>$token->token));
|
||||
throw new webservice_access_exception(get_string('invalidtimedtoken', 'webservice'));
|
||||
}
|
||||
|
||||
//assumes that if sid is set then there must be a valid associated session no matter the token type
|
||||
if ($token->sid) {
|
||||
$session = session_get_instance();
|
||||
if (!$session->session_exists($token->sid)) {
|
||||
$DB->delete_records('external_tokens', array('sid'=>$token->sid));
|
||||
throw new webservice_access_exception(get_string('invalidtokensession', 'webservice'));
|
||||
}
|
||||
}
|
||||
|
||||
// Check ip
|
||||
if ($token->iprestriction and !address_in_subnet(getremoteaddr(), $token->iprestriction)) {
|
||||
add_to_log(SITEID, 'webservice', get_string('tokenauthlog', 'webservice'), '' , get_string('failedtolog', 'webservice').": ".getremoteaddr(), 0);
|
||||
throw new webservice_access_exception(get_string('invalidiptoken', 'webservice'));
|
||||
}
|
||||
|
||||
$user = $DB->get_record('user', array('id'=>$token->userid, 'deleted'=>0), '*', MUST_EXIST);
|
||||
|
||||
//check if the auth method is nologin (in this case refuse connection)
|
||||
if ($auth=='nologin') {
|
||||
add_to_log(SITEID, 'webservice', 'nologin auth attempt with web service', '', $user->username);
|
||||
throw new webservice_access_exception(get_string('nologinauth', 'webservice'));
|
||||
}
|
||||
|
||||
//only confirmed user should be able to call web service
|
||||
if (empty($user->confirmed)) {
|
||||
add_to_log(SITEID, 'webservice', 'user unconfirmed', '', $user->username);
|
||||
throw new webservice_access_exception(get_string('usernotconfirmed', 'moodle', $user->username));
|
||||
}
|
||||
|
||||
//check the user is suspended
|
||||
if (!empty($user->suspended)) {
|
||||
add_to_log(SITEID, 'webservice', 'user suspended', '', $user->username);
|
||||
throw new webservice_access_exception(get_string('usersuspended', 'webservice'));
|
||||
}
|
||||
|
||||
// check if credentials have expired
|
||||
$auth = get_auth_plugin($user->auth);
|
||||
|
||||
if (!empty($auth->config->expiration) and $auth->config->expiration == 1) {
|
||||
$days2expire = $auth->password_expire($user->username);
|
||||
if (intval($days2expire) < 0 ) {
|
||||
add_to_log(SITEID, 'webservice', 'expired password', '', $user->username);
|
||||
throw new webservice_access_exception(get_string('passwordisexpired', 'webservice'));
|
||||
}
|
||||
}
|
||||
|
||||
// log token access
|
||||
$DB->set_field('external_tokens', 'lastaccess', time(), array('id'=>$token->id));
|
||||
|
||||
// let enrol plugins deal with new enrolments if necessary
|
||||
enrol_check_plugins($user);
|
||||
session_set_user($user);
|
||||
//check the user can manage his own files (can upload)
|
||||
$context = get_context_instance(CONTEXT_USER, $USER->id);
|
||||
require_capability('moodle/user:manageownfiles', $context);
|
||||
|
||||
@ -183,7 +115,7 @@ foreach ($files as $file) {
|
||||
$file_record->filepath = $filepath;
|
||||
$file_record->itemid = 0;
|
||||
$file_record->license = $CFG->sitedefaultlicense;
|
||||
$file_record->author = fullname($user);;
|
||||
$file_record->author = fullname($authenticationinfo['user']);;
|
||||
$file_record->source = '';
|
||||
$stored_file = $fs->create_file_from_pathname($file_record, $file->filepath);
|
||||
$results[] = $file_record;
|
||||
|
Loading…
x
Reference in New Issue
Block a user