. // // // /////////////////////////////////////////////////////////////////////////// // disable moodle specific debug messages and any errors in output define('NO_MOODLE_COOKIES', true); require_once('../config.php'); require_once('lib.php'); /** * This class generate the web service documentation specific to one * web service user * @package webservice * @copyright 2009 Moodle Pty Ltd (http://moodle.com) * @author Jerome Mouneyrac * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class webservice_documentation_generator { /** @property array all external function description*/ protected $functions; /** @property string $username name of local user */ protected $username = null; /** @property string $password password of the local user */ protected $password = null; /** @property string $token token of the local user */ protected $token = null; /** @property object $webserviceuser authenticated web service user */ protected $webserviceuser = null; /** * Contructor */ public function __construct() { $this->functionsdescriptions = array(); $this->functions = array(); } /** * Run the documentation generation * @return void */ public function run() { // init all properties from the request data $this->get_authentication_parameters(); // this sets up $this->webserviceuser try { $this->authenticate_user(); } catch(moodle_exception $e) { $errormessage = $e->debuginfo; $displayloginpage = true; } if (!empty($displayloginpage)){ $this->display_login_page_html($errormessage); } else { // make a descriptions list of all function that user is allowed to excecute $this->generate_documentation(); //finally display the documentation $this->display_documentation_html(); } die; } /////////////////////////// /////// CLASS METHODS ///// /////////////////////////// /** * This method parses the $_REQUEST superglobal and looks for * the following information: * user authentication - username+password * @return void */ protected function get_authentication_parameters() { if (isset($_REQUEST['wsusername'])) { $this->username = $_REQUEST['wsusername']; } if (isset($_REQUEST['wspassword'])) { $this->password = $_REQUEST['wspassword']; } if (isset($_REQUEST['token'])) { $this->token = $_REQUEST['token']; } } /** * Generate the documentation specific to the auhenticated webservice user * @return void */ protected function generate_documentation() { global $DB; /// first of all get a complete list of services user is allowed to access $params = array(); $wscond1 = ''; $wscond2 = ''; // make sure the function is listed in at least one service user is allowed to use // allow access only if: // 1/ entry in the external_services_users table if required // 2/ validuntil not reached // 3/ has capability if specified in service desc // 4/ iprestriction $sql = "SELECT s.*, NULL AS iprestriction FROM {external_services} s JOIN {external_services_functions} sf ON (sf.externalserviceid = s.id AND s.restrictedusers = 0) WHERE s.enabled = 1 $wscond1 UNION SELECT s.*, su.iprestriction FROM {external_services} s JOIN {external_services_functions} sf ON (sf.externalserviceid = s.id AND s.restrictedusers = 1) JOIN {external_services_users} su ON (su.externalserviceid = s.id AND su.userid = :userid) WHERE s.enabled = 1 AND su.validuntil IS NULL OR su.validuntil < :now $wscond2"; $params = array_merge($params, array('userid'=>$this->webserviceuser->id, 'now'=>time())); $serviceids = array(); $rs = $DB->get_recordset_sql($sql, $params); // make sure user may access at least one service $allowed = false; foreach ($rs as $service) { if (isset($serviceids[$service->id])) { continue; } if ($service->requiredcapability and !has_capability($service->requiredcapability, $this->restricted_context)) { continue; // cap required, sorry } $serviceids[$service->id] = $service->id; } $rs->close(); // now get the list of all functions if ($serviceids) { list($serviceids, $params) = $DB->get_in_or_equal($serviceids); $sql = "SELECT f.* FROM {external_functions} f WHERE f.name IN (SELECT sf.functionname FROM {external_services_functions} sf WHERE sf.externalserviceid $serviceids)"; $functions = $DB->get_records_sql($sql, $params); } else { $functions = array(); } foreach ($functions as $function) { $this->functions[$function->name] = external_function_info($function); } } /** * Authenticate user using username+password * This function sets up $this->webserviceuser. * called into the Moodle header * @return void */ protected function authenticate_user() { global $CFG, $DB; if (!NO_MOODLE_COOKIES) { throw new coding_exception('Cookies must be disabled!'); } if (!$this->token) { if (!is_enabled_auth('webservice')) { throw new webservice_access_exception(get_string('wsauthnotenabled', 'webservice')); } if (!$auth = get_auth_plugin('webservice')) { throw new webservice_access_exception(get_string('wsauthmissing', 'webservice')); } if (!$this->username) { throw new webservice_access_exception(get_string('missingusername', 'webservice')); } if (!$this->password) { throw new webservice_access_exception(get_string('missingpassword', 'webservice')); } if (!$auth->user_login_webservice($this->username, $this->password)) { throw new webservice_access_exception(get_string('wrongusernamepassword', 'webservice')); } $this->webserviceuser = $DB->get_record('user', array('username'=>$this->username, 'mnethostid'=>$CFG->mnet_localhost_id, 'deleted'=>0), '*', MUST_EXIST); } else { if (!$token = $DB->get_record('external_tokens', array('token'=>$this->token, 'tokentype'=>EXTERNAL_TOKEN_PERMANENT))) { // log failed login attempts throw new webservice_access_exception(get_string('invalidtoken', 'webservice')); } if ($token->validuntil and $token->validuntil < time()) { throw new webservice_access_exception(get_string('invalidtimedtoken', 'webservice')); } if ($token->iprestriction and !address_in_subnet(getremoteaddr(), $token->iprestriction)) { throw new webservice_access_exception(get_string('invalidiptoken', 'webservice')); } $this->webserviceuser = $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)); } } //////////////////////////////////////////////// ///// DISPLAY METHODS ///// //////////////////////////////////////////////// /** * Generate and display the documentation */ protected function display_documentation_html() { global $PAGE, $OUTPUT, $SITE, $CFG; $PAGE->set_url('/webservice/wsdoc'); $PAGE->set_docs_path(''); $PAGE->set_title($SITE->fullname." ".get_string('wsdocumentation', 'webservice')); $PAGE->set_heading($SITE->fullname." ".get_string('wsdocumentation', 'webservice')); $PAGE->set_pagelayout('popup'); $PAGE->set_pagetype('webservice-doc-generator'); echo $OUTPUT->header(); $activatedprotocol = array(); $activatedprotocol['rest'] = webservice_protocol_is_enabled('rest'); $activatedprotocol['xmlrpc'] = webservice_protocol_is_enabled('xmlrpc'); $renderer = $PAGE->get_renderer('core', 'webservice'); /// Check if we are in printable mode $printableformat = false; if (isset($_REQUEST['print'])) { $printableformat = $_REQUEST['print']; } $authparams = array(); if (empty($this->token)) { $authparams['wsusername'] = $this->username; $authparams['wspassword'] = $this->password; } else { $authparams['wsusername'] = $this->webserviceuser->username; $authparams['token'] = $this->token; } echo $renderer->documentation_html($this->functions, $printableformat, $activatedprotocol, $authparams); /// trigger browser print operation if (!empty($printableformat)) { $PAGE->requires->js_function_call('window.print', array()); } echo $OUTPUT->footer(); } /** * Display login page to the web service documentation * @global object $PAGE * @global object $OUTPUT * @global object $SITE * @global object $CFG * @param string $errormessage error message displayed if wrong login */ protected function display_login_page_html($errormessage) { global $PAGE, $OUTPUT, $SITE, $CFG; $PAGE->set_url('/webservice/wsdoc'); $PAGE->set_docs_path(''); $PAGE->set_title($SITE->fullname." ".get_string('wsdocumentation', 'webservice')); $PAGE->set_heading($SITE->fullname." ".get_string('wsdocumentation', 'webservice')); $PAGE->set_pagelayout('popup'); $PAGE->set_pagetype('webservice-doc-generator-login'); echo $OUTPUT->header(); $renderer = $PAGE->get_renderer('core', 'webservice'); echo $renderer->login_page_html($errormessage); echo $OUTPUT->footer(); } } /////////////////////////// /////// RUN THE SCRIPT //// /////////////////////////// if (empty($CFG->enablewsdocumentation)) { echo get_string('wsdocumentationdisable', 'webservice'); die; } //run the documentation generator $generator = new webservice_documentation_generator(); $generator->run(); die;