Пример #1
0
 /**
  * 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;
 }
Пример #2
0
 /**
  * Detect the proper auth instance based on received user information.
  *
  * @param \auth_oidc\jwt $idtoken JWT ID Token.
  * @return int|null The auth instance ID if found, or null if none found.
  */
 protected function detect_auth_instance($idtoken)
 {
     // Get auth instance.
     $sql = 'SELECT ai.id as instanceid, i.priority as institutionpriority
               FROM {auth_instance} ai
               JOIN {institution} i ON i.name = ai.institution
              WHERE ai.authname = \'oidc\'
           ORDER BY i.priority DESC, ai.priority ASC';
     $instances = get_records_sql_array($sql);
     $catchalls = array();
     $instanceid = null;
     foreach ($instances as $instance) {
         $reqattr = get_config_plugin_instance('auth', $instance->instanceid, 'institutionattribute');
         $reqval = get_config_plugin_instance('auth', $instance->instanceid, 'institutionvalue');
         if (empty($reqattr) || empty($reqval)) {
             $catchalls[$instance->institutionpriority][] = $instance;
         } else {
             // Check if we received specified attribute.
             $userattrval = $idtoken->claim($reqattr);
             if (!empty($userattrval)) {
                 // Match value.
                 if (preg_match('#' . trim($reqval) . '#', $userattrval)) {
                     $instanceid = $instance->instanceid;
                     break;
                 }
             }
         }
     }
     // If no match on attribute, get the instance id of the first catchall by priority.
     if (empty($instanceid)) {
         foreach ($catchalls as $priority => $instances) {
             foreach ($instances as $instance) {
                 $instanceid = $instance->instanceid;
                 break;
             }
             break;
         }
     }
     return $instanceid;
 }
Пример #3
0
 /**
  * Handle a login event.
  *
  * @param string $oidcuniqid A unique identifier for the user.
  * @param array $authparams Parameters receieved from the auth request.
  * @param array $tokenparams Parameters received from the token request.
  * @param \auth_oidc\jwt $idtoken A JWT object representing the received id_token.
  */
 protected function handlelogin($oidcuniqid, $authparams, $tokenparams, $idtoken)
 {
     global $DB, $CFG;
     $tokenrec = $DB->get_record('auth_oidc_token', ['oidcuniqid' => $oidcuniqid]);
     if (!empty($tokenrec)) {
         $username = $tokenrec->username;
         $this->updatetoken($tokenrec->id, $authparams, $tokenparams);
     } else {
         // Use 'upn' if available for username (Azure-specific), or fall back to lower-case oidcuniqid.
         $username = $idtoken->claim('upn');
         if (empty($username)) {
             $username = strtolower($oidcuniqid);
         }
         $matchedwith = $this->check_for_matched($username);
         if (!empty($matchedwith)) {
             $matchedwith->aadupn = $username;
             throw new \moodle_exception('errorusermatched', 'local_o365', null, $matchedwith);
         }
         $tokenrec = $this->createtoken($oidcuniqid, $username, $authparams, $tokenparams, $idtoken);
     }
     $existinguserparams = ['username' => $username, 'mnethostid' => $CFG->mnet_localhost_id];
     if ($DB->record_exists('user', $existinguserparams) !== true) {
         // User does not exist. Create user if site allows, otherwise fail.
         if (empty($CFG->authpreventaccountcreation)) {
             $user = create_user_record($username, null, 'oidc');
         } else {
             // Trigger login failed event.
             $failurereason = AUTH_LOGIN_NOUSER;
             $eventdata = ['other' => ['username' => $username, 'reason' => $failurereason]];
             $event = \core\event\user_login_failed::create($eventdata);
             $event->trigger();
             throw new \moodle_exception('errorauthloginfailednouser', 'auth_oidc');
         }
     }
     $user = authenticate_user_login($username, null, true);
     if (empty($user)) {
         throw new \moodle_exception('errorauthloginfailednouser', 'auth_oidc');
     }
     complete_user_login($user);
     return true;
 }
Пример #4
0
 /**
  * Create a token for a user, thus linking a Moodle user to an OpenID Connect user.
  *
  * @param string $oidcuniqid A unique identifier for the user.
  * @param array $username The username of the Moodle user to link to.
  * @param array $authparams Parameters receieved from the auth request.
  * @param array $tokenparams Parameters received from the token request.
  * @param \auth_oidc\jwt $idtoken A JWT object representing the received id_token.
  * @return \stdClass The created token database record.
  */
 protected function createtoken($oidcuniqid, $username, $authparams, $tokenparams, \auth_oidc\jwt $idtoken)
 {
     global $DB;
     // Determine remote username. Use 'upn' if available (Azure-specific), or fall back to standard 'sub'.
     $oidcusername = $idtoken->claim('upn');
     if (empty($oidcusername)) {
         $oidcusername = $idtoken->claim('sub');
     }
     // We should not fail here (idtoken was verified earlier to at least contain 'sub', but just in case...).
     if (empty($oidcusername)) {
         throw new \moodle_exception('errorauthinvalididtoken', 'auth_oidc');
     }
     $tokenrec = new \stdClass();
     $tokenrec->oidcuniqid = $oidcuniqid;
     $tokenrec->username = $username;
     $tokenrec->oidcusername = $oidcusername;
     $tokenrec->scope = $tokenparams['scope'];
     $tokenrec->resource = $tokenparams['resource'];
     $tokenrec->authcode = $authparams['code'];
     $tokenrec->token = $tokenparams['access_token'];
     $tokenrec->expiry = $tokenparams['expires_on'];
     $tokenrec->refreshtoken = $tokenparams['refresh_token'];
     $tokenrec->idtoken = $tokenparams['id_token'];
     $tokenrec->id = $DB->insert_record('auth_oidc_token', $tokenrec);
     return $tokenrec;
 }