Create an account with a linked login that is already confirmed.

@param array $userinfo as returned from an oauth client.
@param \core\oauth2\issuer $issuer
@return bool
548772
public static function create_new_confirmed_account($userinfo, $issuer) {
        global $CFG, $DB;
        require_once($CFG->dirroot.'/user/profile/lib.php');
        require_once($CFG->dirroot.'/user/lib.php');

        $user = new stdClass();
        $user->username = $userinfo['username'];
        $user->email = $userinfo['email'];
        $user->auth = 'oauth2';
        $user->mnethostid = $CFG->mnet_localhost_id;
        $user->lastname = isset($userinfo['lastname']) ? $userinfo['lastname'] : '';
        $user->firstname = isset($userinfo['firstname']) ? $userinfo['firstname'] : '';
        $user->url = isset($userinfo['url']) ? $userinfo['url'] : '';
        $user->alternatename = isset($userinfo['alternatename']) ? $userinfo['alternatename'] : '';
        $user->secret = random_string(15);

        $user->password = '';
        // This user is confirmed.
        $user->confirmed = 1;

        $user->id = user_create_user($user, false, true);

        // The linked account is pre-confirmed.
        $record = new stdClass();
        $record->issuerid = $issuer->get('id');
        $record->username = $userinfo['username'];
        $record->userid = $user->id;
        $record->email = $userinfo['email'];
        $record->confirmtoken = '';
        $record->confirmtokenexpires = 0;

        $linkedlogin = new linked_login(0, $record);
        $linkedlogin->create();

        return $user;
    }
121854
public static function enable_issuer($id) {
        require_capability('moodle/site:config', context_system::instance());
        $issuer = new issuer($id);

        $issuer->set('enabled', 1);
        return $issuer->update();
    }
297134
public static function has_existing_issuer_match(\core\oauth2\issuer $issuer, $username) {
        global $DB;

        $where = "issuerid = :issuerid
              AND username = :username
              AND (confirmtokenexpires = 0 OR confirmtokenexpires > :maxexpiry)";

        $count = $DB->count_records_select(static::TABLE, $where, [
            'issuerid' => $issuer->get('id'),
            'username' => $username,
            'maxexpiry' => (new \DateTime('NOW'))->getTimestamp(),
        ]);

        return $count > 0;
    }
1248705
protected function notify_admins(\core\oauth2\issuer $issuer) {
        global $CFG;
        $admins = get_admins();

        if (empty($admins)) {
            return;
        }
        foreach ($admins as $admin) {
            $strparams = ['siteurl' => $CFG->wwwroot, 'issuer' => $issuer->get('name')];
            $long = get_string('oauthrefreshtokenexpired', 'core_admin', $strparams);
            $short = get_string('oauthrefreshtokenexpiredshort', 'core_admin', $strparams);
            $message = new \core\message\message();
            $message->courseid          = SITEID;
            $message->component         = 'moodle';
            $message->name              = 'errors';
            $message->userfrom          = core_user::get_noreply_user();
            $message->userto            = $admin;
            $message->subject           = $short;
            $message->fullmessage       = $long;
            $message->fullmessageformat = FORMAT_PLAIN;
            $message->fullmessagehtml   = $long;
            $message->smallmessage      = $short;
            $message->notification      = 1;
            message_send($message);
        }
    }
648832
public function SyncScreen($Authenticator, $UserInfo, $Payload) {
      $this->AddJsFile('entry.js');
      $this->View = 'handshake';
      $this->HandshakeScheme = $Authenticator->GetAuthenticationSchemeAlias();
      $this->Form->SetModel($this->UserModel);
      $this->Form->AddHidden('ClientHour', date('Y-m-d H:00')); // Use the server's current hour as a default
      $this->Form->AddHidden('Target', $this->Target());
      
      $PreservedKeys = array(
         'UserKey', 'Token', 'Consumer', 'Email', 'Name', 'Gender', 'HourOffset'
      );
      $UserID = 0;
      $Target = $this->Target();
   
      if ($this->Form->IsPostBack() === TRUE) {
            
         $FormValues = $this->Form->FormValues();
         if (ArrayValue('StopLinking', $FormValues)) {
            $AuthResponse = Gdn_Authenticator::AUTH_ABORTED;
            
            $UserEventData = array_merge(array(
               'UserID'       => $UserID,
               'Payload'      => $Payload
            ),$UserInfo);
            Gdn::Authenticator()->Trigger($AuthResponse, $UserEventData);
            
            $Authenticator->DeleteCookie();
            Gdn::Request()->WithRoute('DefaultController');
            return Gdn::Dispatcher()->Dispatch();
            
         } elseif (ArrayValue('NewAccount', $FormValues)) {
            $AuthResponse = Gdn_Authenticator::AUTH_CREATED;
         
            // Try and synchronize the user with the new username/email.
            $FormValues['Name'] = $FormValues['NewName'];
            $FormValues['Email'] = $FormValues['NewEmail'];
            $UserID = $this->UserModel->Synchronize($UserInfo['UserKey'], $FormValues);
            $this->Form->SetValidationResults($this->UserModel->ValidationResults());
            
         } else {
            $AuthResponse = Gdn_Authenticator::AUTH_SUCCESS;
   
            // Try and sign the user in.
            $PasswordAuthenticator = Gdn::Authenticator()->AuthenticateWith('password');
            $PasswordAuthenticator->HookDataField('Email', 'SignInEmail');
            $PasswordAuthenticator->HookDataField('Password', 'SignInPassword');
            $PasswordAuthenticator->FetchData($this->Form);
            
            $UserID = $PasswordAuthenticator->Authenticate();
            
            if ($UserID < 0) {
               $this->Form->AddError('ErrorPermission');
            } else if ($UserID == 0) {
               $this->Form->AddError('ErrorCredentials');
            }
            
            if ($UserID > 0) {
               $Data = $FormValues;
               $Data['UserID'] = $UserID;
               $Data['Email'] = ArrayValue('SignInEmail', $FormValues, '');
               $UserID = $this->UserModel->Synchronize($UserInfo['UserKey'], $Data);
            }
         }
         
         if ($UserID > 0) {
            // The user has been created successfully, so sign in now
            
            // Finalize the link between the forum user and the foreign userkey
            $Authenticator->Finalize($UserInfo['UserKey'], $UserID, $UserInfo['ConsumerKey'], $UserInfo['TokenKey'], $Payload);
            
            $UserEventData = array_merge(array(
               'UserID'       => $UserID,
               'Payload'      => $Payload
            ),$UserInfo);
            Gdn::Authenticator()->Trigger($AuthResponse, $UserEventData);
            
            /// ... and redirect them appropriately
            $Route = $this->RedirectTo();
            if ($Route !== FALSE)
               Redirect($Route);
         } else {
            // Add the hidden inputs back into the form.
            foreach($FormValues as $Key => $Value) {
               if (in_array($Key, $PreservedKeys))
                  $this->Form->AddHidden($Key, $Value);
            }
         }
      } else {
         $Id = Gdn::Authenticator()->GetIdentity(TRUE);
         if ($Id > 0) {
            // The user is signed in so we can just go back to the homepage.
            Redirect($Target);
         }
         
         $Name = $UserInfo['UserName'];
         $Email = $UserInfo['UserEmail'];
         
         // Set the defaults for a new user.
         $this->Form->SetFormValue('NewName', $Name);
         $this->Form->SetFormValue('NewEmail', $Email);
         
         // Set the default for the login.
         $this->Form->SetFormValue('SignInEmail', $Email);
         $this->Form->SetFormValue('Handshake', 'NEW');
         
         // Add the handshake data as hidden fields.
         $this->Form->AddHidden('Name',       $Name);
         $this->Form->AddHidden('Email',      $Email);
         $this->Form->AddHidden('UserKey',    $UserInfo['UserKey']);
         $this->Form->AddHidden('Token',      $UserInfo['TokenKey']);
         $this->Form->AddHidden('Consumer',   $UserInfo['ConsumerKey']);
         
/*
         $this->Form->AddHidden('Payload',    serialize($Payload));
         $this->Form->AddHidden('UserInfo',   serialize($UserInfo));
*/
         
      }
      
      $this->SetData('Name', ArrayValue('Name', $this->Form->HiddenInputs));
      $this->SetData('Email', ArrayValue('Email', $this->Form->HiddenInputs));
      
      $this->Render();
   }
490526
public static function create($userId, string $secret, int $expiration, string $issuer): string
    {
        $builder = self::builder();

        return $builder->setPayloadClaim('user_id', $userId)
            ->setSecret($secret)
            ->setExpiration($expiration)
            ->setIssuer($issuer)
            ->setIssuedAt(time())
            ->build()
            ->getToken();
    }
1033932
public static function create_issuer($data) {
        require_capability('moodle/site:config', context_system::instance());
        $issuer = new issuer(0, $data);

        // Will throw exceptions on validation failures.
        $issuer->create();

        // Perform service discovery.
        self::discover_endpoints($issuer);
        self::guess_image($issuer);
        return $issuer;
    }
136424
protected function loginCheckUser($userName, $password, AccessControlEvent $event, $ignorePassword = false)
    {
        if (!$userEntity = $this->getUserEntity($userName)) {
            $this->dispatcher->dispatch(AccessControlEvents::LOGIN_FAILURE, $event->setReason(AccessControlEvents::FAILURE_INVALID));

            return false;
        }

        $userAuth = $this->getRepositoryUsers()->getUserAuthData($userEntity->getId());
        if ($userAuth->getPassword() === null || $userAuth->getPassword() === '') {
            $this->systemLogger->alert("Attempt to login to an account with empty password field: '$userName'", ['event' => 'security']);
            $this->flashLogger->error(Trans::__('general.phrase.login-account-disabled'));
            $this->dispatcher->dispatch(AccessControlEvents::LOGIN_FAILURE, $event->setReason(AccessControlEvents::FAILURE_DISABLED));

            return $this->loginFailed($userEntity);
        }

        if ((bool) $userEntity->getEnabled() === false) {
            $this->systemLogger->alert("Attempt to login to a disabled account: '$userName'", ['event' => 'security']);
            $this->flashLogger->error(Trans::__('general.phrase.login-account-disabled'));
            $this->dispatcher->dispatch(AccessControlEvents::LOGIN_FAILURE, $event->setReason(AccessControlEvents::FAILURE_DISABLED));

            return $this->loginFailed($userEntity);
        }

        // Passwords can be ignored if you log in via loginAsUser()
        if (!$ignorePassword) {
            $isValid = $this->passwordFactory->verifyHash($password, $userAuth->getPassword());

            if (!$isValid) {
                $this->dispatcher->dispatch(AccessControlEvents::LOGIN_FAILURE, $event->setReason(AccessControlEvents::FAILURE_PASSWORD));

                return $this->loginFailed($userEntity);
            }

            // Rehash password if not using Blowfish algorithm
            if (!Blowfish::detect($userAuth->getPassword())) {
                $userEntity->setPassword($this->passwordFactory->createHash($password, '$2y$'));
                try {
                    $this->getRepositoryUsers()->update($userEntity);
                } catch (NotNullConstraintViolationException $e) {
                    // Database needs updating
                }
            }
        }

        // Ensure we have a CSRF token, to prevent timing issues when the user opens multiple pages at once.
        $this->csrfTokenManager->getToken('content_edit');

        $this->dispatcher->dispatch(AccessControlEvents::LOGIN_SUCCESS, $event->setDispatched());

        return $this->loginFinish($userEntity);
    }
325383
public function getIssuer()
    {
        $issuer = null;
        $issuerNodes = $this->_query('/samlp:LogoutResponse/saml:Issuer');
        if ($issuerNodes->length == 1) {
            $issuer = $issuerNodes->item(0)->textContent;
        }
        return $issuer;
    }
1051221
public function execute() {
        $issuers = \core\oauth2\api::get_all_issuers();
        foreach ($issuers as $issuer) {
            if ($issuer->is_system_account_connected()) {
                try {
                    // Try to get an authenticated client; renew token if necessary.
                    // Returns false or throws a moodle_exception on error.
                    $success = \core\oauth2\api::get_system_oauth_client($issuer);
                } catch (moodle_exception $e) {
                    $success = false;
                }
                if ($success === false) {
                    $this->notify_admins($issuer);
                }
            }
        }
    }
829022
public static function is_valid_issuer(\core\oauth2\issuer $issuer) {
        $endpointwebdav = false;
        $endpointocs = false;
        $endpointtoken = false;
        $endpointauth = false;
        $endpointuserinfo = false;
        $endpoints = \core\oauth2\api::get_endpoints($issuer);
        foreach ($endpoints as $endpoint) {
            $name = $endpoint->get('name');
            switch ($name) {
                case 'webdav_endpoint':
                    $endpointwebdav = true;
                    break;
                case 'ocs_endpoint':
                    $endpointocs = true;
                    break;
                case 'token_endpoint':
                    $endpointtoken = true;
                    break;
                case 'authorization_endpoint':
                    $endpointauth = true;
                    break;
                case 'userinfo_endpoint':
                    $endpointuserinfo = true;
                    break;
            }
        }
        return $endpointwebdav && $endpointocs && $endpointtoken && $endpointauth && $endpointuserinfo;
    }
828529
public function setIssuer(\Core\Entity\People $issuer = null) {
        $this->issuer = $issuer;

        return $this;
    }
1163736
public function createTotp($identifier, $issuer = null)
    {
        $totp = $this->factory->createTotp($identifier, $issuer);

        return $totp;
    }
494146
static function tryLogin(\Db\Connection $db, OAuth2Providers $provider) {
    $user = UserOAuth2::auth($provider->getProvider());
    if (!$user) {
      throw new UserAuthenticationException("Could not login user with OAuth2.");
    }

    $uid = $user->uid;
    if (!$uid) {
      throw new UserAuthenticationException("No UID found.");
    }

    // find the user with the uid
    $q = $db->prepare("SELECT users.* FROM users
        JOIN user_oauth2_identities ON users.id=user_oauth2_identities.user_id
        WHERE uid=? AND provider=? LIMIT 1");
    $q->execute(array($uid, $provider->getKey()));

    if ($user_instance = $q->fetch()) {
      $result = new User($user_instance);
      $result->setIdentity($provider->getKey() . ":" . $uid);
      return $result;
    } else {
      // issue #266: If we are using Google, we might have an OpenID account that hasn't been connected yet,
      // in which case we can find it here and connect it
      if (isset($provider->getProvider()->id_token) && isset($provider->getProvider()->id_token['openid_id'])) {
        $id_token = $provider->getProvider()->id_token;

        $q = $db->prepare("SELECT * FROM user_openid_identities WHERE identity=?");
        $q->execute(array($id_token['openid_id']));

        if ($openid_identity = $q->fetch()) {
          // create a new identity
          $q = $db->prepare("INSERT INTO user_oauth2_identities SET user_id=?, provider=?, uid=?");
          $q->execute(array($openid_identity['user_id'], $provider->getKey(), $uid));

          return User::findUser($db, $openid_identity['user_id']);
        }
      }

      throw new UserAuthenticationMissingAccountException("No such '" . $provider->getKey() . "' user found.");
    }
  }
80572
public function isValid($authUser, $authPass)
    {
        if (!\array_key_exists($authUser, $this->userPass)) {
            return false;
        }

        if (!password_verify($authPass, $this->userPass[$authUser])) {
            return false;
        }

        return new UserInfo($authUser, []);
    }
909725
public function getUri(string $label, string $issuer, int $hotpCounter = null):string{

		$values = [
			'secret'    => $this->getSecret(),
			'issuer'    => $issuer,
			'digits'    => $this->options->digits,
			'algorithm' => $this->options->algorithm,
		];

		if($this->options->mode === 'totp'){
			$values['period'] = $this->options->period;
		}

		if($this->options->mode === 'hotp' && $hotpCounter !== null){
			$values['counter'] = $hotpCounter;
		}

		return 'otpauth://'.$this->options->mode.'/'.rawurlencode($label).'?'.http_build_query($values, '', '&', PHP_QUERY_RFC3986);
	}
1330437
public static function create(
        Amount $amountRequested,
        string $issuer,
        int $monetaryAccountId = null,
        array $customHeaders = []
    ): BunqResponseInt {
        $apiClient = new ApiClient(static::getApiContext());
        $responseRaw = $apiClient->post(
            vsprintf(
                self::ENDPOINT_URL_CREATE,
                [static::determineUserId(), static::determineMonetaryAccountId($monetaryAccountId)]
            ),
            [
                self::FIELD_AMOUNT_REQUESTED => $amountRequested,
                self::FIELD_ISSUER => $issuer,
            ],
            $customHeaders
        );

        return BunqResponseInt::castFromBunqResponse(
            static::processForId($responseRaw)
        );
    }