/** * @param object $submitteddata * */ function vmoodle_bind_to_network($submitteddata, &$newmnet_host) { global $USER, $CFG, $DB, $OUTPUT; // debug_trace("step 4.4 : binding to subnetwork"); // Getting services schemes to apply // debug_trace("step 4.4.1 : getting services"); vmoodle_get_service_strategy($submitteddata, $services, $peerservices, 'peer'); // debug_trace("step 4.4.2 : getting possible peers"); $idnewblock = $DB->get_field('local_vmoodle', 'id', array('vhostname' => $submitteddata->vhostname)); // last mnet has been raised by one at step 3 so we add to network if less if ($submitteddata->mnet < vmoodle_get_last_subnetwork_number()) { // Retrieves the subnetwork member(s). $subnetwork_hosts = array(); $select = 'id != ? AND mnet = ? AND enabled = 1'; $subnetwork_members = $DB->get_records_select('local_vmoodle', $select, array($idnewblock, $submitteddata->mnet)); if (!empty($subnetwork_members)) { // debug_trace("step 4.4.3 : preparing peers"); foreach ($subnetwork_members as $subnetwork_member) { $temp_host = new stdClass(); $temp_host->wwwroot = $subnetwork_member->vhostname; $temp_host->name = utf8_decode($subnetwork_member->name); $subnetwork_hosts[] = $temp_host; } } // Member(s) of the subnetwork add the new host. if (!empty($subnetwork_hosts)) { // debug_trace("step 4.4.4 : bind peers"); $rpc_client = new \local_vmoodle\XmlRpc_Client(); $rpc_client->reset_method(); $rpc_client->set_method('local/vmoodle/rpclib.php/mnetadmin_rpc_bind_peer'); // Authentication params. $rpc_client->add_param($USER->username, 'string'); $userhostroot = $DB->get_field('mnet_host', 'wwwroot', array('id' => $USER->mnethostid)); $rpc_client->add_param($userhostroot, 'string'); $rpc_client->add_param($CFG->wwwroot, 'string'); // Peer to bind to. $rpc_client->add_param((array) $newmnet_host, 'array'); $rpc_client->add_param($peerservices, 'array'); foreach ($subnetwork_hosts as $subnetwork_host) { // debug_trace("step 4.4.4.1 : bind to -> $subnetwork_host->wwwroot"); $temp_member = new \local_vmoodle\Mnet_Peer(); $temp_member->set_wwwroot($subnetwork_host->wwwroot); if (!$rpc_client->send($temp_member)) { echo $OUTPUT->notification(implode('<br />', $rpc_client->getErrors($temp_member))); if (debugging()) { echo '<pre>'; // var_dump($rpc_client); echo '</pre>'; } } // debug_trace("step 4.4.4.1 : bind from <- $subnetwork_host->wwwroot"); $rpc_client_2 = new \local_vmoodle\XmlRpc_Client(); $rpc_client_2->reset_method(); $rpc_client_2->set_method('local/vmoodle/rpclib.php/mnetadmin_rpc_bind_peer'); // Authentication params. $rpc_client_2->add_param($USER->username, 'string'); $userhostroot = $DB->get_field('mnet_host', 'wwwroot', array('id' => $USER->mnethostid)); $rpc_client_2->add_param($userhostroot, 'string'); $rpc_client_2->add_param($CFG->wwwroot, 'string'); // Peer to bind to. $rpc_client_2->add_param((array) $temp_member, 'array'); $rpc_client_2->add_param($services, 'array'); if (!$rpc_client_2->send($newmnet_host)) { echo $OUTPUT->notification(implode('<br />', $rpc_client_2->getErrors($newmnet_host))); if (debugging()) { echo '<pre>'; // var_dump($rpc_client_2); echo '</pre>'; } } unset($rpc_client_2); // free some resource } } } // Getting services schemes to apply to main // debug_trace("step 4.4.5 : getting services"); vmoodle_get_service_strategy($submitteddata, $services, $peerservices, 'main'); // debug_trace("step 4.4.5.1 : bind to -> $CFG->wwwroot"); $mainhost = new \local_vmoodle\Mnet_Peer(); // this is us $mainhost->set_wwwroot($CFG->wwwroot); // debug_trace('step 4.4.5.2 : Binding our main service strategy to remote'); // bind the local service strategy to new host if (!empty($peerservices)) { $DB->delete_records('mnet_host2service', array('hostid' => $newmnet_host->id)); // eventually deletes something on the way foreach ($peerservices as $servicename => $servicestate) { $service = $DB->get_record('mnet_service', array('name' => $servicename)); $host2service = new stdclass(); $host2service->hostid = $newmnet_host->id; $host2service->serviceid = $service->id; $host2service->publish = 0 + @$servicestate->publish; $host2service->subscribe = 0 + @$servicestate->subscribe; $DB->insert_record('mnet_host2service', $host2service); // debug_trace("step 4.4.5.2 : adding ".serialize($host2service)); } } // debug_trace('step 4.4.5.4 : Binding remote service strategy to main'); $rpc_client = new \local_vmoodle\XmlRpc_Client(); $rpc_client->reset_method(); $rpc_client->set_method('local/vmoodle/rpclib.php/mnetadmin_rpc_bind_peer'); $rpc_client->add_param($USER->username, 'string'); $userhostroot = $DB->get_field('mnet_host', 'wwwroot', array('id' => $USER->mnethostid)); $rpc_client->add_param($userhostroot, 'string'); $rpc_client->add_param($CFG->wwwroot, 'string'); // Peer to bind to : this is us. $rpc_client->add_param((array) $mainhost, 'array'); $rpc_client->add_param($services, 'array'); // debug_trace('step 4.4.5.4 : Sending'); if (!$rpc_client->send($newmnet_host)) { // echo $OUTPUT->notification(implode('<br />', $rpc_client->getErrors($newmnet_host))); if (debugging()) { echo '<pre>'; // var_dump($rpc_client); echo '</pre>'; } } }
/** * force user account creation. * @param object $callinguser The calling user. * @param string $targetuser The username of the user to be created. * @param array $userparams an array containing all data for user. * @param string $userhostname the user's origin account. * @param array $bounceto an array of or a string containing hostnames to propagate users to. * @param boolean $onlybounce if true, do not try to create the user locally, just bounce. * * if userhostname is empty, the user is created with an account bound to the localhost mnethost id (local account) and * reset to manual auth if the auth is 'mnet' (note the auth will remain unchanged if other than mnet, so it is possible to preset * an SAML or LDAP bound account. * If userhostname is not empty, the call forces auth being mnet, whatever the auth field was set to, and the hostname is searched * for a local matching host in mnet_hosts. * * If bounceto is not empty, the account will be propagated to matching mnet_hosts in the MNET proximity. * The onlybounce feature is provided for using this rpc function using a local direct call to propagate a user programatically * a user to some bounce locations */ function mnetadmin_rpc_create_user($callinguser, $targetuser, $userparams, $userhostname = '', $bounceto = null, $onlybounce = false, $json_response = true, $overridecapability = false) { global $CFG, $USER, $DB; $response = new StdClass(); $response->status = RPC_SUCCESS; $response->errors = array(); $response->error = ''; $userparamsarr = (array) $userparams; $capability = ''; if (!$overridecapability) { $capability = 'local/vmoodle:execute'; } if ($auth_response = invoke_local_user((array) $callinguser, $capability)) { if ($json_response) { return $auth_response; } else { return json_decode($auth_response); } } // be sure of our structure type. $callinguser = (object) $callinguser; if (!$onlybounce) { if (function_exists('debug_trace')) { debug_trace("Up to create {$targetuser} "); } if (!($user = $DB->get_record('user', array('username' => $targetuser)))) { // Collect eventual profilefields and cleanup user record from them. foreach ($userparamsarr as $key => $value) { if (preg_match('/^profile_field_/', $key)) { $profilefields[$key] = $value; unset($userparams[$key]); } } if (function_exists('debug_trace')) { debug_trace("Making new user record"); } $newuser = (object) $userparams; $newuser->username = $targetuser; // Remap local mnethostid and auth method if needed. if (!empty($userhostname)) { if (!($originuserhost = $DB->get_record('mnet_host', array('wwwroot' => $userhostname)))) { // If we fail to find real origin host for the user, take request host as failover. if (function_exists('debug_trace')) { debug_trace("REMOTE CALL ERROR : Bad origin host. Trying {$callinguser->remotehostroot} as failover"); } if (!($originuserhost = $DB->get_record('mnet_host', array('wwwroot' => $callinguser->remotehostroot)))) { if (function_exists('debug_trace')) { debug_trace("REMOTE CALL ERROR : Bad origin host " . json_encode($userhostname)); } $response = new StdClass(); $response->status = 510; $response->errors[] = "Bad origin host " . json_encode($userhostname) . ", or origin host of the user is not known by this host."; $response->error = "Bad origin host " . json_encode($userhostname) . ", or origin host of the user is not known by this host."; if ($json_response) { return json_encode($response); } else { return $response; } } } $newuser->mnethostid = $originuserhost->id; if ($originuserhost->id != $CFG->mnet_localhost_id && (empty($newuser->auth) || $newuser->auth == 'manual')) { $newuser->auth = 'mnet'; } else { if (empty($newuser->auth) || $newuser->auth == 'mnet') { $newuser->auth = 'manual'; } } } else { $newuser->mnethostid = $CFG->mnet_localhost_id; if (empty($newuser->auth) || $newuser->auth == 'mnet') { $newuser->auth = 'manual'; } } $newuser->confirmed = 1; $newuser->timemodified = time(); if (function_exists('debug_trace')) { debug_trace("REMOTE CALL : recording user"); } if (!($userid = $DB->insert_record('user', $newuser))) { if (function_exists('debug_trace')) { debug_trace("REMOTE CALL ERROR : User creation failure"); } $response->status = RPC_FAILURE_RECORD; $response->errors[] = "Could not create the user."; $response->error = "Could not create the user."; if ($json_response) { return json_encode($response); } else { return $response; } } $response->userid = $userid; // add profilefields if (function_exists('debug_trace')) { debug_trace("REMOTE CALL : Adding profile fields"); } if (!empty($profilefields)) { foreach ($profilefields as $key => $value) { $key = str_replace('profile_field_', '', $key); // extract real shortname if ($field = $DB->get_record('user_info_field', array('shortname' => $key))) { // Do insert only if known field. Ignore others. $valuerec->userid = $userid; $valuerec->fieldid = $field->id; $valuerec->data = $value; $DB->insert_record('user_info_data', $valuerec); } } } } else { if (function_exists('debug_trace')) { debug_trace("REMOTE CALL : Reviving user"); } if ($user->deleted == 1) { $user->deleted = 0; foreach ($userparams as $key => $value) { $user->{$key} = $value; } $user->username = $targetuser; if (!($userid = $DB->update_record('user', $user))) { if (function_exists('debug_trace')) { debug_trace("REMOTE CALL ERROR : User revival failure"); } $response->status = RPC_FAILURE_RECORD; $response->errors[] = "Create user REMOTE CALL : Could not revive the user."; $response->error = "Create user REMOTE CALL : Could not revive the user."; if ($json_response) { return json_encode($response); } else { return $response; } } $response->userid = $userid; } else { if (function_exists('debug_trace')) { debug_trace("Create user REMOTE CALL : User exists"); } /* // usually create user matching user should be happy with that $response->status = RPC_SUCCESS; $response->errors[] = "User already exists."; $response->error = "User already exists."; if ($json_response) { return json_encode($response); } else { return $response; } */ } } } else { if (!($userparams = $DB->get_record('user', array('username' => $targetuser)))) { $response->status = RPC_FAILURE_RECORD; $response->errors[] = "Create user REMOTE CALL : No such user to propagate."; $response->error = "Create user REMOTE CALL : No such user to propagate."; if ($json_response) { return json_encode($response); } else { return $response; } } if (function_exists('debug_trace')) { debug_trace('Create user REMOTE CALL : got user data as ' . json_encode($userparams)); } } // Now proceed to bounces if any. if (!empty($bounceto)) { if (is_string($bounceto)) { $bounceto = explode(';', $bounceto); } foreach ($bounceto as $bouncehost) { // Check if known as mnet_hosts and possible to send admin requests. $sql = "\n SELECT\n COUNT(*)\n FROM \n {mnet_host} as mh,\n {mnet_service} as ms,\n {mnet_host2service} as h2s\n WHERE\n mh.wwwroot = '{$bouncehost}' AND\n mh.id = h2s.hostid AND\n mh.deleted = 0 AND\n h2s.serviceid = ms.id AND\n ms.name = 'mnetadmin' AND\n h2s.subscribe = 1\n "; $ok = $DB->count_records_sql($sql); if ($ok) { // We can do it. $userhostroot = $DB->get_field('mnet_host', 'wwwroot', array('id' => $USER->mnethostid)); $rpc_client = new \local_vmoodle\XmlRpc_Client(); $rpc_client->reset_method(); $rpc_client->set_method('local/vmoodle/plugins/roles/rpclib.php/mnetadmin_rpc_create_user'); $caller = new StdClass(); $caller->username = $USER->username; $caller->remoteuserhostroot = $userhostroot; $caller->remotehostroot = $CFG->wwwroot; $rpc_client->add_param($caller, 'struct'); // username $rpc_client->add_param($targetuser, 'string'); $rpc_client->add_param($userparams, 'struct'); if ($userhostname == '') { $rpc_client->add_param($CFG->wwwroot, 'string'); } else { $rpc_client->add_param($userhostname, 'string'); } if (function_exists('debug_trace')) { debug_trace("REMOTE CALL : Bouncing to {$bouncehost} "); } $mnet_host = new mnet_peer(); if ($mnet_host->set_wwwroot($bouncehost)) { $result = $rpc_client->send($mnet_host); if (empty($result)) { // if (preg_match('/dev/', $CFG->wwwroot)) print_object($rpc_client); $response->errors[] = 'Create user : bounce failed rpc transaction to ' . $bouncehost; $response->errors[] = $rpc_client->getErrors(); $response->error = 'Create user : bounce failed rpc transaction to ' . $bouncehost; } else { // whatever we have, aggregate eventual remote errors to error stack. $res = json_decode($rpc_client->response); if (!empty($res->errors)) { foreach ($res->errors as $remoteerror) { $response->errors[] = 'REMOTE: ' . implode(' ', (array) $remoteerror); $response->error = 'REMOTE : bounce failed rpc some of transactions to ' . $bouncehost; } } } } else { // silently ignore unless debugging if (function_exists('debug_trace')) { debug_trace("Bounce ignored : No service capability for {$bouncehost} "); } $response->errors[] = 'Create user : ignoring bounce to ' . $bouncehost . ' because host communication failed.'; $response->error = 'Create user : (last error) ignoring bounce to ' . $bouncehost . ' because host communication failed.'; } } else { $response->errors[] = 'Create user : ignoring bounce to ' . $bouncehost . ' because host unregistered.'; $response->error = 'Create user : (last error) ignoring bounce to ' . $bouncehost . ' because host unregistered.'; } } } if ($json_response) { return json_encode($response); } else { return $response; } }