X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModel%2FUser.php;h=029613b17b0b692e19e3301fcd6d2b841d54640e;hb=8bdfdc7d52e149edb711c6d238c1f7593e237e83;hp=4959c8c21607c66f799d9449b457084ce29889d2;hpb=2a431b580f2e8f6a596e84175932e793678cde63;p=friendica.git diff --git a/src/Model/User.php b/src/Model/User.php index 4959c8c216..029613b17b 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -312,8 +312,8 @@ class User */ public static function getIdForURL(string $url) { - // Avoid any database requests when the hostname isn't even part of the url. - if (!strpos($url, DI::baseUrl()->getHostname())) { + // Avoid database queries when the local node hostname isn't even part of the url. + if (!Contact::isLocal($url)) { return 0; } @@ -515,7 +515,27 @@ class User */ public static function getIdFromPasswordAuthentication($user_info, $password, $third_party = false) { - $user = self::getAuthenticationInfo($user_info); + // Addons registered with the "authenticate" hook may create the user on the + // fly. `getAuthenticationInfo` will fail if the user doesn't exist yet. If + // the user doesn't exist, we should give the addons a chance to create the + // user in our database, if applicable, before re-throwing the exception if + // they fail. + try { + $user = self::getAuthenticationInfo($user_info); + } catch (Exception $e) { + $username = (is_string($user_info) ? $user_info : $user_info['nickname'] ?? ''); + + // Addons can create users, and since this 'catch' branch should only + // execute if getAuthenticationInfo can't find an existing user, that's + // exactly what will happen here. Creating a numeric username would create + // abiguity with user IDs, possibly opening up an attack vector. + // So let's be very careful about that. + if (empty($username) || is_numeric($username)) { + throw $e; + } + + return self::getIdFromAuthenticateHooks($username, $password); + } if ($third_party && DI::pConfig()->get($user['uid'], '2fa', 'verified')) { // Third-party apps can't verify two-factor authentication, we use app-specific passwords instead @@ -544,6 +564,41 @@ class User } return $user['uid']; + } else { + return self::getIdFromAuthenticateHooks($user['nickname'], $password); // throws + } + + throw new HTTPException\ForbiddenException(DI::l10n()->t('Login failed')); + } + + /** + * Try to obtain a user ID via "authenticate" hook addons + * + * Returns the user id associated with a successful password authentication + * + * @param string $username + * @param string $password + * @return int User Id if authentication is successful + * @throws HTTPException\ForbiddenException + */ + public static function getIdFromAuthenticateHooks($username, $password) + { + $addon_auth = [ + 'username' => $username, + 'password' => $password, + 'authenticated' => 0, + 'user_record' => null + ]; + + /* + * An addon indicates successful login by setting 'authenticated' to non-zero value and returning a user record + * Addons should never set 'authenticated' except to indicate success - as hooks may be chained + * and later addons should not interfere with an earlier one that succeeded. + */ + Hook::callAll('authenticate', $addon_auth); + + if ($addon_auth['authenticated'] && $addon_auth['user_record']) { + return $addon_auth['user_record']['uid']; } throw new HTTPException\ForbiddenException(DI::l10n()->t('Login failed')); @@ -584,7 +639,7 @@ class User if (is_int($user_info)) { $user = DBA::selectFirst( 'user', - ['uid', 'password', 'legacy_password'], + ['uid', 'nickname', 'password', 'legacy_password'], [ 'uid' => $user_info, 'blocked' => 0, @@ -594,7 +649,7 @@ class User ] ); } else { - $fields = ['uid', 'password', 'legacy_password']; + $fields = ['uid', 'nickname', 'password', 'legacy_password']; $condition = [ "(`email` = ? OR `username` = ? OR `nickname` = ?) AND NOT `blocked` AND NOT `account_expired` AND NOT `account_removed` AND `verified`", @@ -1068,6 +1123,8 @@ class User Photo::update(['profile' => 1], ['resource-id' => $resource_id]); } } + + Contact::updateSelfFromUserID($uid, true); } Hook::callAll('register_account', $uid);