function create_registered_user($profilefields = array()) { global $registration, $SESSION, $USER; require_once get_config('libroot') . 'user.php'; db_begin(); // Move the user record to the usr table from the registration table $registrationid = $registration->id; unset($registration->id); unset($registration->expiry); if ($expirytime = get_config('defaultregistrationexpirylifetime')) { $registration->expiry = db_format_timestamp(time() + $expirytime); } $registration->lastlogin = db_format_timestamp(time()); $authinstance = get_record('auth_instance', 'institution', $registration->institution, 'authname', $registration->authtype ? $registration->authtype : 'internal'); if (false == $authinstance) { throw new ConfigException('No ' . ($registration->authtype ? $registration->authtype : 'internal') . ' auth instance for institution'); } if (!empty($registration->extra)) { // Additional user settings were added during confirmation $extrafields = unserialize($registration->extra); } $user = new User(); $user->active = 1; $user->authinstance = $authinstance->id; $user->firstname = $registration->firstname; $user->lastname = $registration->lastname; $user->email = $registration->email; $user->username = get_new_username($user->firstname . $user->lastname); $user->passwordchange = 1; // Points that indicate the user is a "new user" who should be restricted from spammy activities. // We count these down when they do good things; when they have 0 they're no longer a "new user" if (is_using_probation()) { $user->probation = get_config('probationstartingpoints'); } else { $user->probation = 0; } if ($registration->institution != 'mahara') { if (count_records_select('institution', "name != 'mahara'") == 1 || $registration->pending == 2) { if (get_config_plugin('artefact', 'file', 'institutionaloverride')) { $user->quota = get_field('institution', 'defaultquota', 'name', $registration->institution); } } } create_user($user, $profilefields); // If the institution is 'mahara' then don't do anything if ($registration->institution != 'mahara') { $institutions = get_records_select_array('institution', "name != 'mahara'"); // If there is only one available, join it without requiring approval if (count($institutions) == 1) { $user->join_institution($registration->institution); } else { if ($registration->pending == 2) { if (get_config('requireregistrationconfirm') || get_field('institution', 'registerconfirm', 'name', $registration->institution)) { $user->join_institution($registration->institution); } } else { if ($registration->authtype && $registration->authtype != 'internal') { $auth = AuthFactory::create($authinstance->id); if ($auth->weautocreateusers) { $user->join_institution($registration->institution); } else { $user->add_institution_request($registration->institution); } } else { $user->add_institution_request($registration->institution); } } } if (!empty($extrafields->institutionstaff)) { // If the user isn't a member yet, this does nothing, but that's okay, it'll // only be set after successful confirmation. set_field('usr_institution', 'staff', 1, 'usr', $user->id, 'institution', $registration->institution); } } if (!empty($registration->lang) && $registration->lang != 'default') { set_account_preference($user->id, 'lang', $registration->lang); } // Delete the old registration record delete_records('usr_registration', 'id', $registrationid); db_commit(); // Log the user in and send them to the homepage $USER = new LiveUser(); $USER->reanimate($user->id, $authinstance->id); if (function_exists('local_post_register')) { local_post_register($registration); } $SESSION->add_ok_msg(get_string('registrationcomplete', 'mahara', get_config('sitename'))); $SESSION->set('resetusername', true); redirect(); }
/** * Grab a delegate object for auth stuff */ public function request_user_authorise($token, $remotewwwroot) { global $USER, $SESSION; $this->must_be_ready(); $peer = get_peer($remotewwwroot); if ($peer->deleted != 0 || $this->config['theyssoin'] != 1) { throw new XmlrpcClientException('We don\'t accept SSO connections from ' . institution_display_name($peer->institution)); } $client = new Client(); $client->set_method('auth/mnet/auth.php/user_authorise')->add_param($token)->add_param(sha1($_SERVER['HTTP_USER_AGENT']))->send($remotewwwroot); $remoteuser = (object) $client->response; if (empty($remoteuser) or !property_exists($remoteuser, 'username')) { // Caught by land.php throw new AccessDeniedException(); } $create = false; $update = false; if ('1' == $this->config['updateuserinfoonlogin']) { $update = true; } // Retrieve a $user object. If that fails, create a blank one. try { $user = new User(); if (get_config('usersuniquebyusername')) { // When turned on, this setting means that it doesn't matter // which other application the user SSOs from, they will be // given the same account in Mahara. // // This setting is one that has security implications unless // only turned on by people who know what they're doing. In // particular, every system linked to Mahara should be making // sure that same username == same person. This happens for // example if two Moodles are using the same LDAP server for // authentication. // // If this setting is on, it must NOT be possible to self // register on the site for ANY institution - otherwise users // could simply pick usernames of people's accounts they wished // to steal. if ($institutions = get_column('institution', 'name', 'registerallowed', '1')) { log_warn("usersuniquebyusername is turned on but registration is allowed for an institution. " . "No institution can have registration allowed for it, for security reasons.\n" . "The following institutions have registration enabled:\n " . join("\n ", $institutions)); throw new AccessDeniedException(); } if (!get_config('usersallowedmultipleinstitutions')) { log_warn("usersuniquebyusername is turned on but usersallowedmultipleinstitutions is off. " . "This makes no sense, as users will then change institution every time they log in from " . "somewhere else. Please turn this setting on in Site Options"); throw new AccessDeniedException(); } $user->find_by_username($remoteuser->username); } else { $user->find_by_instanceid_username($this->instanceid, $remoteuser->username, true); } if ($user->get('suspendedcusr')) { die_info(get_string('accountsuspended', 'mahara', strftime(get_string('strftimedaydate'), $user->get('suspendedctime')), $user->get('suspendedreason'))); } } catch (AuthUnknownUserException $e) { if (!empty($this->config['weautocreateusers'])) { $institution = new Institution($this->institution); if ($institution->isFull()) { $institution->send_admin_institution_is_full_message(); throw new XmlrpcClientException('SSO attempt from ' . $institution->displayname . ' failed - institution is full'); } $user = new User(); $create = true; } else { log_debug("User authorisation request from {$remotewwwroot} failed - " . "remote user '{$remoteuser->username}' is unknown to us and auto creation of users is turned off"); return false; } } /*******************************************/ if ($create) { $user->passwordchange = 1; $user->active = 1; $user->deleted = 0; //TODO: import institution's expiry?: //$institution = new Institution($peer->institution); $user->expiry = null; $user->expirymailsent = 0; $user->lastlogin = time(); $user->firstname = $remoteuser->firstname; $user->lastname = $remoteuser->lastname; $user->email = $remoteuser->email; $imported = array('firstname', 'lastname', 'email'); //TODO: import institution's per-user-quota?: //$user->quota = $userrecord->quota; $user->authinstance = empty($this->config['parent']) ? $this->instanceid : $this->parent; db_begin(); $user->username = get_new_username($remoteuser->username); $user->id = create_user($user, array(), $this->institution, $this, $remoteuser->username); $locked = $this->import_user_settings($user, $remoteuser); $locked = array_merge($imported, $locked); /* * We need to convert the object to a stdclass with its own * custom method because it uses overloaders in its implementation * and its properties wouldn't be visible to a simple cast operation * like (array)$user */ $userobj = $user->to_stdclass(); $userarray = (array) $userobj; db_commit(); // Now we have fired the create event, we need to re-get the data // for this user $user = new User(); $user->find_by_id($userobj->id); } elseif ($update) { $imported = array('firstname', 'lastname', 'email'); foreach ($imported as $field) { if ($user->{$field} != $remoteuser->{$field}) { $user->{$field} = $remoteuser->{$field}; set_profile_field($user->id, $field, $user->{$field}); } } if (isset($remoteuser->idnumber)) { if ($user->studentid != $remoteuser->idnumber) { $user->studentid = $remoteuser->idnumber; set_profile_field($user->id, 'studentid', $user->studentid); } $imported[] = 'studentid'; } $locked = $this->import_user_settings($user, $remoteuser); $locked = array_merge($imported, $locked); $user->lastlastlogin = $user->lastlogin; $user->lastlogin = time(); //TODO: import institution's per-user-quota?: //$user->quota = $userrecord->quota; $user->commit(); } if (get_config('usersuniquebyusername')) { // Add them to the institution they have SSOed in by $user->join_institution($peer->institution); } // See if we need to create/update a profile Icon image if ($create || $update) { $client->set_method('auth/mnet/auth.php/fetch_user_image')->add_param($remoteuser->username)->send($remotewwwroot); $imageobject = (object) $client->response; $u = preg_replace('/[^A-Za-z0-9 ]/', '', $user->username); $filename = get_config('dataroot') . 'temp/mpi_' . intval($this->instanceid) . '_' . $u; if (array_key_exists('f1', $client->response)) { $imagecontents = base64_decode($client->response['f1']); if (file_put_contents($filename, $imagecontents)) { $imageexists = false; $icons = false; if ($update) { $newchecksum = sha1_file($filename); $icons = get_records_select_array('artefact', 'artefacttype = \'profileicon\' AND owner = ? ', array($user->id), '', 'id'); if (false != $icons) { foreach ($icons as $icon) { $iconfile = get_config('dataroot') . 'artefact/file/profileicons/originals/' . $icon->id % 256 . '/' . $icon->id; $checksum = sha1_file($iconfile); if ($newchecksum == $checksum) { $imageexists = true; unlink($filename); break; } } } } if (false == $imageexists) { $filesize = filesize($filename); if (!$user->quota_allowed($filesize)) { $error = get_string('profileiconuploadexceedsquota', 'artefact.file', get_config('wwwroot')); } require_once 'file.php'; $imagesize = getimagesize($filename); if (!$imagesize || !is_image_type($imagesize[2])) { $error = get_string('filenotimage'); } $mime = $imagesize['mime']; $width = $imagesize[0]; $height = $imagesize[1]; $imagemaxwidth = get_config('imagemaxwidth'); $imagemaxheight = get_config('imagemaxheight'); if ($width > $imagemaxwidth || $height > $imagemaxheight) { $error = get_string('profileiconimagetoobig', 'artefact.file', $width, $height, $imagemaxwidth, $imagemaxheight); } try { $user->quota_add($filesize); } catch (QuotaException $qe) { $error = get_string('profileiconuploadexceedsquota', 'artefact.file', get_config('wwwroot')); } require_once get_config('docroot') . '/artefact/lib.php'; require_once get_config('docroot') . '/artefact/file/lib.php'; // Entry in artefact table $artefact = new ArtefactTypeProfileIcon(); $artefact->set('owner', $user->id); $artefact->set('parent', ArtefactTypeFolder::get_folder_id(get_string('imagesdir', 'artefact.file'), get_string('imagesdirdesc', 'artefact.file'), null, true, $user->id)); $artefact->set('title', ArtefactTypeFileBase::get_new_file_title(get_string('profileicon', 'artefact.file'), (int) $artefact->get('parent'), $user->id)); // unique title $artefact->set('description', get_string('uploadedprofileicon', 'artefact.file')); $artefact->set('note', get_string('profileicon', 'artefact.file')); $artefact->set('size', $filesize); $artefact->set('filetype', $mime); $artefact->set('width', $width); $artefact->set('height', $height); $artefact->commit(); $id = $artefact->get('id'); // Move the file into the correct place. $directory = get_config('dataroot') . 'artefact/file/profileicons/originals/' . $id % 256 . '/'; check_dir_exists($directory); rename($filename, $directory . $id); if ($create || empty($icons)) { $user->profileicon = $id; } } $user->commit(); } else { log_warn(get_string('cantcreatetempprofileiconfile', 'artefact.file', $filename)); } } if ($update) { $locked[] = 'profileicon'; } } /*******************************************/ // We know who our user is now. Bring her back to life. $USER->reanimate($user->id, $this->instanceid); // Set session variables to let the application know this session was // initiated by MNET. Don't forget that users could initiate their // sessions without MNET sometimes, which is why this data is stored in // the session object. $SESSION->set('mnetuser', $user->id); $SESSION->set('authinstance', $this->instanceid); if (isset($_SERVER['HTTP_REFERER'])) { $SESSION->set('mnetuserfrom', $_SERVER['HTTP_REFERER']); } if ($update && isset($locked)) { $SESSION->set('lockedfields', $locked); } return true; }
/** * Process an authorization request. * * Operations: * - Auto creates users. * - Sets up user object for linked accounts. * * @param string $oidcuniqid The OIDC unique identifier received. * @param array $tokenparams Received token parameters. * @param \auth_oidc\jwt $idtoken Received id token. * @return bool Success/Failure. */ public function request_user_authorise($oidcuniqid, $tokenparams, $idtoken) { global $USER, $SESSION; $this->must_be_ready(); $username = $oidcuniqid; $email = $idtoken->claim('email'); $firstname = $idtoken->claim('given_name'); $lastname = $idtoken->claim('family_name'); // Office 365 uses "upn". $upn = $idtoken->claim('upn'); if (!empty($upn)) { $username = $upn; $email = $upn; } $create = false; try { $user = new \User(); $user->find_by_instanceid_username($this->instanceid, $username, true); if ($user->get('suspendedcusr')) { die_info(get_string('accountsuspended', 'mahara', strftime(get_string('strftimedaydate'), $user->get('suspendedctime')), $user->get('suspendedreason'))); } } catch (\AuthUnknownUserException $e) { if ($this->can_auto_create_users() === true) { $institution = new \Institution($this->institution); if ($institution->isFull()) { throw new \XmlrpcClientException('OpenID Connect login attempt failed because the institution is full.'); } $user = new \User(); $create = true; } else { return false; } } if ($create === true) { $user->passwordchange = 0; $user->active = 1; $user->deleted = 0; $user->expiry = null; $user->expirymailsent = 0; $user->lastlogin = time(); $user->firstname = $firstname; $user->lastname = $lastname; $user->email = $email; $user->authinstance = $this->instanceid; db_begin(); $user->username = get_new_username($username); $user->id = create_user($user, array(), $this->institution, $this, $username); $userobj = $user->to_stdclass(); $userarray = (array) $userobj; db_commit(); $user = new User(); $user->find_by_id($userobj->id); } $user->commit(); $USER->reanimate($user->id, $this->instanceid); $SESSION->set('authinstance', $this->instanceid); return true; }
/** * Grab a delegate object for auth stuff */ public function request_user_authorise($attributes) { global $USER, $SESSION; $this->must_be_ready(); if (empty($attributes) or !array_key_exists($this->config['user_attribute'], $attributes) or !array_key_exists($this->config['institutionattribute'], $attributes)) { throw new AccessDeniedException(); } $remoteuser = $attributes[$this->config['user_attribute']][0]; $firstname = isset($attributes[$this->config['firstnamefield']][0]) ? $attributes[$this->config['firstnamefield']][0] : null; $lastname = isset($attributes[$this->config['surnamefield']][0]) ? $attributes[$this->config['surnamefield']][0] : null; $email = isset($attributes[$this->config['emailfield']][0]) ? $attributes[$this->config['emailfield']][0] : null; $institutionname = $this->institution; $create = false; $update = false; // Retrieve a $user object. If that fails, create a blank one. try { $isremote = $this->config['remoteuser'] ? true : false; $user = new User(); if (get_config('usersuniquebyusername')) { // When turned on, this setting means that it doesn't matter // which other application the user SSOs from, they will be // given the same account in Mahara. // // This setting is one that has security implications unless // only turned on by people who know what they're doing. In // particular, every system linked to Mahara should be making // sure that same username == same person. This happens for // example if two Moodles are using the same LDAP server for // authentication. // // If this setting is on, it must NOT be possible to self // register on the site for ANY institution - otherwise users // could simply pick usernames of people's accounts they wished // to steal. if ($institutions = get_column('institution', 'name', 'registerallowed', '1')) { log_warn("usersuniquebyusername is turned on but registration is allowed for an institution. " . "No institution can have registration allowed for it, for security reasons.\n" . "The following institutions have registration enabled:\n " . join("\n ", $institutions)); throw new AccessDeniedException(); } if (!get_config('usersallowedmultipleinstitutions')) { log_warn("usersuniquebyusername is turned on but usersallowedmultipleinstitutions is off. " . "This makes no sense, as users will then change institution every time they log in from " . "somewhere else. Please turn this setting on in Site Options"); throw new AccessDeniedException(); } } else { if (!$isremote) { log_warn("usersuniquebyusername is turned off but remoteuser has not been set on for this institution: {$institutionname}. " . "This is a security risk as users from different institutions with different IdPs can hijack " . "each others accounts. Fix this in the institution level auth/saml settings."); throw new AccessDeniedException(); } } if ($isremote) { $user->find_by_instanceid_username($this->instanceid, $remoteuser, $isremote); } else { $user->find_by_username($remoteuser); } if ($user->get('suspendedcusr')) { die_info(get_string('accountsuspended', 'mahara', strftime(get_string('strftimedaydate'), $user->get('suspendedctime')), $user->get('suspendedreason'))); } if ('1' == $this->config['updateuserinfoonlogin']) { $update = true; } } catch (AuthUnknownUserException $e) { if (!empty($this->config['weautocreateusers'])) { $institution = new Institution($this->institution); if ($institution->isFull()) { $institution->send_admin_institution_is_full_message(); throw new XmlrpcClientException('SSO attempt from ' . $institution->displayname . ' failed - institution is full'); } $user = new User(); $create = true; } else { log_debug("User authorisation request from SAML failed - " . "remote user '{$remoteuser}' is unknown to us and auto creation of users is turned off"); return false; } } /*******************************************/ if ($create) { $user->passwordchange = 1; $user->active = 1; $user->deleted = 0; $user->expiry = null; $user->expirymailsent = 0; $user->lastlogin = time(); $user->firstname = $firstname; $user->lastname = $lastname; $user->email = $email; // must have these values if (empty($firstname) || empty($lastname) || empty($email)) { throw new AccessDeniedException(get_string('errormissinguserattributes1', 'auth.saml', get_config('sitename'))); } $user->authinstance = empty($this->config['parent']) ? $this->instanceid : $this->parent; db_begin(); $user->username = get_new_username($remoteuser, 40); $user->id = create_user($user, array(), $institutionname, $this, $remoteuser); /* * We need to convert the object to a stdclass with its own * custom method because it uses overloaders in its implementation * and its properties wouldn't be visible to a simple cast operation * like (array)$user */ $userobj = $user->to_stdclass(); $userarray = (array) $userobj; db_commit(); // Now we have fired the create event, we need to re-get the data // for this user $user = new User(); $user->find_by_id($userobj->id); if (get_config('usersuniquebyusername')) { // Add them to the institution they have SSOed in by $user->join_institution($institutionname); } } elseif ($update) { if (!empty($firstname)) { set_profile_field($user->id, 'firstname', $firstname); $user->firstname = $firstname; } if (!empty($lastname)) { set_profile_field($user->id, 'lastname', $lastname); $user->lastname = $lastname; } if (!empty($email)) { set_profile_field($user->id, 'email', $email); $user->email = $email; } $user->lastlastlogin = $user->lastlogin; $user->lastlogin = time(); } $user->commit(); /*******************************************/ // We know who our user is now. Bring em back to life. $result = $USER->reanimate($user->id, $this->instanceid); log_debug("remote user '{$remoteuser}' is now reanimated as '{$USER->username}' "); $SESSION->set('authinstance', $this->instanceid); return true; }
function create_registered_user($profilefields = array()) { global $registration, $SESSION, $USER; require_once get_config('libroot') . 'user.php'; db_begin(); // Move the user record to the usr table from the registration table $registrationid = $registration->id; unset($registration->id); unset($registration->expiry); if ($expirytime = get_config('defaultaccountlifetime')) { $registration->expiry = db_format_timestamp(time() + $expirytime); } $registration->lastlogin = db_format_timestamp(time()); $authinstance = get_record('auth_instance', 'institution', $registration->institution, 'authname', 'internal'); if (false == $authinstance) { throw new ConfigException('No internal auth instance for institution'); } $user = new User(); $user->active = 1; $user->authinstance = $authinstance->id; $user->firstname = $registration->firstname; $user->lastname = $registration->lastname; $user->email = $registration->email; $user->username = get_new_username($user->firstname . $user->lastname); $user->passwordchange = 1; $user->salt = substr(md5(rand(1000000, 9999999)), 2, 8); create_user($user, $profilefields); // If the institution is 'mahara' then don't do anything if ($registration->institution != 'mahara') { $institutions = get_records_select_array('institution', "name != 'mahara'"); // If there is only one available, join it without requiring approval if (count($institutions) == 1) { $user->join_institution($registration->institution); } else { $user->add_institution_request($registration->institution); } } if (!empty($registration->lang) && $registration->lang != 'default') { set_account_preference($user->id, 'lang', $registration->lang); } // Delete the old registration record delete_records('usr_registration', 'id', $registrationid); db_commit(); // Log the user in and send them to the homepage $USER = new LiveUser(); $USER->reanimate($user->id, $authinstance->id); // A special greeting for special people if (in_array($user->username, array('waawaamilk', 'Mjollnir`', 'Ned', 'richardm', 'fmarier', 'naveg'))) { $SESSION->add_ok_msg('MAMA!!! Maharababy happy to see you :D :D!'); } else { if ($user->username == 'htaccess') { $SESSION->add_ok_msg('Welcome B-Quack, htaccess!'); } else { $SESSION->add_ok_msg(get_string('registrationcomplete', 'mahara', get_config('sitename'))); } } $SESSION->set('resetusername', true); redirect(); }