Permalink
Browse files

MDL-30542 backport recent 2.2 changes about security checks

  • Loading branch information...
mouneyrac committed Dec 8, 2011
1 parent 9283723 commit 1aa648116db3208bda4dd56b7fe93250035fb433
Showing with 148 additions and 43 deletions.
  1. +2 −0 lang/en/webservice.php
  2. +116 −0 webservice/lib.php
  3. +30 −43 webservice/upload.php
View
@@ -96,6 +96,7 @@
$string['externalservices'] = 'External services';
$string['externalserviceusers'] = 'External service users';
$string['failedtolog'] = 'Failed to log';
+$string['filenameexist'] = 'File name already exists: {$a}';
$string['function'] = 'Function';
$string['functions'] = 'Functions';
$string['generalstructure'] = 'General structure';
@@ -166,6 +167,7 @@
$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'] = 'Web service is not available (it is not existing or might be set to disable)';
$string['servicesbuiltin'] = 'Built-in services';
$string['servicescustom'] = 'Custom services';
$string['serviceusers'] = 'Authorised users';
View
@@ -34,6 +34,122 @@
*/
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 the user info from the token
+ $user = $DB->get_record('user', array('id' => $token->userid, 'deleted' => 0), '*', MUST_EXIST);
+
+ // 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'));
+ }
+ }
+
+ //Refuse non-admin authentication in 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
View
@@ -15,7 +15,14 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
- * Accpet uploading files by web service token
+ * Accept uploading files by web service token
+ *
+ * POST params:
+ * token => the web service user token (needed for authentication)
+ * filepath => the private file aera path (where files will be stored)
+ * [_FILES] => for example you can send the files with <input type=file>,
+ * or with curl magic: 'file_1' => '@/path/to/file', or ...
+ *
* @package moodlecore
* @subpackage files
* @copyright 2011 Dongsheng Cai <dongsheng@moodle.com>
@@ -25,48 +32,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();
-// 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);
-
-// log token access
-$DB->set_field('external_tokens', 'lastaccess', time(), array('id'=>$token->id));
+//authenticate the user
+$token = required_param('token', PARAM_ALPHANUM);
+$webservicelib = new webservice();
+$authenticationinfo = $webservicelib->authenticate_user($token);
-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);
@@ -106,9 +82,10 @@
$file = new stdClass();
$file->filename = clean_param($_FILES[$fieldname]['name'], PARAM_FILE);
// check system maxbytes setting
- if (($_FILES[$fieldname]['size'] > $CFG->maxbytes)) {
+ if (($_FILES[$fieldname]['size'] > get_max_upload_file_size($CFG->maxbytes))) {
// oversize file will be ignored, error added to array to notify
// web service client
+ $file->errortype = 'fileoversized';
$file->error = get_string('maxbytes', 'error');
} else {
$file->filepath = $_FILES[$fieldname]['tmp_name'];
@@ -146,9 +123,19 @@
$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;
+
+ //Check if the file already exist
+ $existingfile = $fs->file_exists($file_record->contextid, $file_record->component, $file_record->filearea,
+ $file_record->itemid, $file_record->filepath, $file_record->filename);
+ if ($existingfile) {
+ $file->errortype = 'filenameexist';
+ $file->error = get_string('filenameexist', 'webservice', $file->filename);
+ $results[] = $file;
+ } else {
+ $stored_file = $fs->create_file_from_pathname($file_record, $file->filepath);
+ $results[] = $file_record;
+ }
}
-echo json_encode($results);
+echo json_encode($results);

0 comments on commit 1aa6481

Please sign in to comment.