aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoas Schilling <coding@schilljs.com>2022-11-11 09:37:26 +0100
committerJoas Schilling <coding@schilljs.com>2022-12-09 22:40:46 +0100
commit256fbe9d77f5413bed1bd1a39451daccdbe3517b (patch)
tree58ee901120c8051440d4eb3b0935288c9c0bde7e
parent2f7a1fca5f1e2a14bcda169b9e8e8da14e720f2c (diff)
downloadnextcloud-server-256fbe9d77f5413bed1bd1a39451daccdbe3517b.tar.gz
nextcloud-server-256fbe9d77f5413bed1bd1a39451daccdbe3517b.zip
Validate if the user part of a "cloud id" can even be a valid user id
Signed-off-by: Joas Schilling <coding@schilljs.com>
-rw-r--r--lib/private/Federation/CloudIdManager.php3
-rw-r--r--lib/private/User/Manager.php70
-rw-r--r--lib/public/IUserManager.php8
3 files changed, 55 insertions, 26 deletions
diff --git a/lib/private/Federation/CloudIdManager.php b/lib/private/Federation/CloudIdManager.php
index e4e42cb1293..85aae8e5ec5 100644
--- a/lib/private/Federation/CloudIdManager.php
+++ b/lib/private/Federation/CloudIdManager.php
@@ -125,6 +125,9 @@ class CloudIdManager implements ICloudIdManager {
if ($lastValidAtPos !== false) {
$user = substr($id, 0, $lastValidAtPos);
$remote = substr($id, $lastValidAtPos + 1);
+
+ $this->userManager->validateUserId($user);
+
if (!empty($user) && !empty($remote)) {
return new CloudId($id, $user, $remote, $this->getDisplayNameFromContact($id));
}
diff --git a/lib/private/User/Manager.php b/lib/private/User/Manager.php
index dc31eece414..82fc4d818ad 100644
--- a/lib/private/User/Manager.php
+++ b/lib/private/User/Manager.php
@@ -44,6 +44,8 @@ use OCP\IGroup;
use OCP\IUser;
use OCP\IUserBackend;
use OCP\IUserManager;
+use OCP\L10N\IFactory;
+use OCP\Server;
use OCP\Support\Subscription\IAssertion;
use OCP\User\Backend\IGetRealUIDBackend;
use OCP\User\Backend\ISearchKnownUsersBackend;
@@ -427,31 +429,7 @@ class Manager extends PublicEmitter implements IUserManager {
public function createUserFromBackend($uid, $password, UserInterface $backend) {
$l = \OC::$server->getL10N('lib');
- // Check the name for bad characters
- // Allowed are: "a-z", "A-Z", "0-9" and "_.@-'"
- if (preg_match('/[^a-zA-Z0-9 _.@\-\']/', $uid)) {
- throw new \InvalidArgumentException($l->t('Only the following characters are allowed in a username:'
- . ' "a-z", "A-Z", "0-9", and "_.@-\'"'));
- }
-
- // No empty username
- if (trim($uid) === '') {
- throw new \InvalidArgumentException($l->t('A valid username must be provided'));
- }
-
- // No whitespace at the beginning or at the end
- if (trim($uid) !== $uid) {
- throw new \InvalidArgumentException($l->t('Username contains whitespace at the beginning or at the end'));
- }
-
- // Username only consists of 1 or 2 dots (directory traversal)
- if ($uid === '.' || $uid === '..') {
- throw new \InvalidArgumentException($l->t('Username must not consist of dots only'));
- }
-
- if (!$this->verifyUid($uid)) {
- throw new \InvalidArgumentException($l->t('Username is invalid because files already exist for this user'));
- }
+ $this->validateUserId($uid, true);
// No empty password
if (trim($password) === '') {
@@ -726,7 +704,43 @@ class Manager extends PublicEmitter implements IUserManager {
}));
}
- private function verifyUid(string $uid): bool {
+ /**
+ * @param string $uid
+ * @param bool $checkDataDirectory
+ * @throws \InvalidArgumentException Message is an already translated string with a reason why the id is not valid
+ * @since 26.0.0
+ */
+ public function validateUserId(string $uid, bool $checkDataDirectory = false): void {
+ $l = Server::get(IFactory::class)->get('lib');
+
+ // Check the name for bad characters
+ // Allowed are: "a-z", "A-Z", "0-9" and "_.@-'"
+ if (preg_match('/[^a-zA-Z0-9 _.@\-\']/', $uid)) {
+ throw new \InvalidArgumentException($l->t('Only the following characters are allowed in a username:'
+ . ' "a-z", "A-Z", "0-9", and "_.@-\'"'));
+ }
+
+ // No empty username
+ if (trim($uid) === '') {
+ throw new \InvalidArgumentException($l->t('A valid username must be provided'));
+ }
+
+ // No whitespace at the beginning or at the end
+ if (trim($uid) !== $uid) {
+ throw new \InvalidArgumentException($l->t('Username contains whitespace at the beginning or at the end'));
+ }
+
+ // Username only consists of 1 or 2 dots (directory traversal)
+ if ($uid === '.' || $uid === '..') {
+ throw new \InvalidArgumentException($l->t('Username must not consist of dots only'));
+ }
+
+ if (!$this->verifyUid($uid, $checkDataDirectory)) {
+ throw new \InvalidArgumentException($l->t('Username is invalid because files already exist for this user'));
+ }
+ }
+
+ private function verifyUid(string $uid, bool $checkDataDirectory = false): bool {
$appdata = 'appdata_' . $this->config->getSystemValueString('instanceid');
if (\in_array($uid, [
@@ -740,6 +754,10 @@ class Manager extends PublicEmitter implements IUserManager {
return false;
}
+ if (!$checkDataDirectory) {
+ return true;
+ }
+
$dataDirectory = $this->config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data');
return !file_exists(rtrim($dataDirectory, '/') . '/' . $uid);
diff --git a/lib/public/IUserManager.php b/lib/public/IUserManager.php
index af0d5f08809..8caa027468b 100644
--- a/lib/public/IUserManager.php
+++ b/lib/public/IUserManager.php
@@ -212,4 +212,12 @@ interface IUserManager {
* @since 9.1.0
*/
public function getByEmail($email);
+
+ /**
+ * @param string $uid The user ID to validate
+ * @param bool $checkDataDirectory Whether it should be checked if files for the ID exist inside the data directory
+ * @throws \InvalidArgumentException Message is an already translated string with a reason why the ID is not valid
+ * @since 26.0.0
+ */
+ public function validateUserId(string $uid, bool $checkDataDirectory = false): void;
}