/** * create a new share * * @param array $params * @return \OC_OCS_Result */ public function createShare($params) { if (!$this->isS2SEnabled(true)) { return new \OC_OCS_Result(null, 503, 'Server does not support federated cloud sharing'); } $remote = isset($_POST['remote']) ? $_POST['remote'] : null; $token = isset($_POST['token']) ? $_POST['token'] : null; $name = isset($_POST['name']) ? $_POST['name'] : null; $owner = isset($_POST['owner']) ? $_POST['owner'] : null; $shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null; $remoteId = isset($_POST['remoteId']) ? (int) $_POST['remoteId'] : null; if ($remote && $token && $name && $owner && $remoteId && $shareWith) { if (!\OCP\Util::isValidFileName($name)) { return new \OC_OCS_Result(null, 400, 'The mountpoint name contains invalid characters.'); } // FIXME this should be a method in the user management instead \OCP\Util::writeLog('files_sharing', 'shareWith before, ' . $shareWith, \OCP\Util::DEBUG); \OCP\Util::emitHook('\\OCA\\Files_Sharing\\API\\Server2Server', 'preLoginNameUsedAsUserName', array('uid' => &$shareWith)); \OCP\Util::writeLog('files_sharing', 'shareWith after, ' . $shareWith, \OCP\Util::DEBUG); if (!\OCP\User::userExists($shareWith)) { return new \OC_OCS_Result(null, 400, 'User does not exists'); } \OC_Util::setupFS($shareWith); $externalManager = new \OCA\Files_Sharing\External\Manager(\OC::$server->getDatabaseConnection(), \OC\Files\Filesystem::getMountManager(), \OC\Files\Filesystem::getLoader(), \OC::$server->getHTTPHelper(), \OC::$server->getNotificationManager(), $shareWith); try { $externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId); $user = $owner . '@' . $this->cleanupRemote($remote); \OC::$server->getActivityManager()->publishActivity(Activity::FILES_SHARING_APP, Activity::SUBJECT_REMOTE_SHARE_RECEIVED, array($user, trim($name, '/')), '', array(), '', '', $shareWith, Activity::TYPE_REMOTE_SHARE, Activity::PRIORITY_LOW); /** * FIXME $urlGenerator = \OC::$server->getURLGenerator(); $notificationManager = \OC::$server->getNotificationManager(); $notification = $notificationManager->createNotification(); $notification->setApp('files_sharing') ->setUser($shareWith) ->setTimestamp(time()) ->setObject('remote_share', $remoteId) ->setSubject('remote_share', [$user, trim($name, '/')]); $declineAction = $notification->createAction(); $declineAction->setLabel('decline') ->setLink($urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/remote_shares/' . $remoteId), 'DELETE'); $notification->addAction($declineAction); $acceptAction = $notification->createAction(); $acceptAction->setLabel('accept') ->setLink($urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/remote_shares/' . $remoteId), 'POST'); $notification->addAction($acceptAction); $notificationManager->notify($notification); */ return new \OC_OCS_Result(); } catch (\Exception $e) { \OCP\Util::writeLog('files_sharing', 'server can not add remote share, ' . $e->getMessage(), \OCP\Util::ERROR); return new \OC_OCS_Result(null, 500, 'internal server error, was not able to add share from ' . $remote); } } return new \OC_OCS_Result(null, 400, 'server can not add remote share, missing parameter'); }
/** * create a new share * * @param array $params * @return \OC_OCS_Result */ public function createShare($params) { if (!$this->isS2SEnabled(true)) { return new \OC_OCS_Result(null, 503, 'Server does not support federated cloud sharing'); } $remote = isset($_POST['remote']) ? $_POST['remote'] : null; $token = isset($_POST['token']) ? $_POST['token'] : null; $name = isset($_POST['name']) ? $_POST['name'] : null; $owner = isset($_POST['owner']) ? $_POST['owner'] : null; $shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null; $remoteId = isset($_POST['remoteId']) ? (int) $_POST['remoteId'] : null; if ($remote && $token && $name && $owner && $remoteId && $shareWith) { if (!\OCP\Util::isValidFileName($name)) { return new \OC_OCS_Result(null, 400, 'The mountpoint name contains invalid characters.'); } if (!\OCP\User::userExists($shareWith)) { return new \OC_OCS_Result(null, 400, 'User does not exists'); } \OC_Util::setupFS($shareWith); $externalManager = new \OCA\Files_Sharing\External\Manager(\OC::$server->getDatabaseConnection(), \OC\Files\Filesystem::getMountManager(), \OC\Files\Filesystem::getLoader(), \OC::$server->getHTTPHelper(), $shareWith); try { $externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId); $user = $owner . '@' . $this->cleanupRemote($remote); \OC::$server->getActivityManager()->publishActivity('files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_RECEIVED, array($user), '', array(), '', '', $shareWith, \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_LOW); return new \OC_OCS_Result(); } catch (\Exception $e) { \OCP\Util::writeLog('files_sharing', 'server can not add remote share, ' . $e->getMessage(), \OCP\Util::ERROR); return new \OC_OCS_Result(null, 500, 'internal server error, was not able to add share from ' . $remote); } } return new \OC_OCS_Result(null, 400, 'server can not add remote share, missing parameter'); }
/** * check if path is excluded from encryption * * @param string $path relative to data/ * @return boolean */ protected function isExcludedPath($path) { $view = new \OC\Files\View(); $normalizedPath = \OC\Files\Filesystem::normalizePath($path); $parts = explode('/', $normalizedPath); // we only encrypt/decrypt files in the files and files_versions folder if (sizeof($parts) < 3) { /** * Less then 3 parts means, we can't match: * - /{$uid}/files/* nor * - /{$uid}/files_versions/* * So this is not a path we are looking for. */ return true; } if (!($parts[2] === 'files' && \OCP\User::userExists($parts[1])) && !($parts[2] === 'files_versions' && \OCP\User::userExists($parts[1]))) { return true; } if (!$view->file_exists($normalizedPath)) { $normalizedPath = dirname($normalizedPath); } // we don't encrypt server-to-server shares list($storage, ) = \OC\Files\Filesystem::resolvePath($normalizedPath); /** * @var \OCP\Files\Storage $storage */ if ($storage->instanceOfStorage('OCA\\Files_Sharing\\External\\Storage')) { return true; } return false; }
/** * Checks if the user has all required attributes * and, if successfull, returns user's owncloud uid. * * @return false|string false if requirements not met, OC uid otherwise */ public function checkAttributes() { // Shibboleth/SAML uid is always required $shibUid = $this->getShibUid(); if (!$shibUid) { return false; } // TODO: Move email to $backendConfig['required_attrs'] // TODO: Require email for all users (not only newly created) // when all IdP's will provide it for us. Then move getOcUid // call to the end of this method. $ocUid = $this->getOcUid(); if (!$this->getEmail() && !\OCP\User::userExists($ocUid)) { return false; } // Check for additional required attributes $missingAttrs = ''; foreach ($this->backendConfig['required_attrs'] as &$attr) { if (!$this->getAttribute($attr)) { $missingAttrs .= $attr . ' '; } } if ($missingAttrs !== '') { $this->logger->warning(sprintf('User: %s is' . ' missing required attributes: %s', $shibUid, $missingAttrs), $this->logCtx); return false; } return $ocUid; }
/** * get uid of the owners of the file and the path to the file * @param string $path Path of the file to check * @throws \Exception * @note $shareFilePath must be relative to data/UID/files. Files * relative to /Shared are also acceptable * @return array */ public function getUidAndFilename($path) { $pathinfo = pathinfo($path); $partfile = false; $parentFolder = false; if (array_key_exists('extension', $pathinfo) && $pathinfo['extension'] === 'part') { // if the real file exists we check this file $filePath = $this->userFilesDir . '/' . $pathinfo['dirname'] . '/' . $pathinfo['filename']; if ($this->view->file_exists($filePath)) { $pathToCheck = $pathinfo['dirname'] . '/' . $pathinfo['filename']; } else { // otherwise we look for the parent $pathToCheck = $pathinfo['dirname']; $parentFolder = true; } $partfile = true; } else { $pathToCheck = $path; } $view = new \OC\Files\View($this->userFilesDir); $fileOwnerUid = $view->getOwner($pathToCheck); // handle public access if ($this->isPublic) { return array($this->userId, $path); } else { // Check that UID is valid if (!\OCP\User::userExists($fileOwnerUid)) { throw new \Exception('Could not find owner (UID = "' . var_export($fileOwnerUid, 1) . '") of file "' . $path . '"'); } // NOTE: Bah, this dependency should be elsewhere \OC\Files\Filesystem::initMountPoints($fileOwnerUid); // If the file owner is the currently logged in user if ($fileOwnerUid === $this->userId) { // Assume the path supplied is correct $filename = $path; } else { $info = $view->getFileInfo($pathToCheck); $ownerView = new \OC\Files\View('/' . $fileOwnerUid . '/files'); // Fetch real file path from DB $filename = $ownerView->getPath($info['fileid']); if ($parentFolder) { $filename = $filename . '/' . $pathinfo['filename']; } if ($partfile) { $filename = $filename . '.' . $pathinfo['extension']; } } return array($fileOwnerUid, \OC\Files\Filesystem::normalizePath($filename)); } }
/** * creates a unique name for internal ownCloud use for users. Don't call it directly. * @param string $name the display name of the object * @return string with with the name to use in ownCloud or false if unsuccessful * * Instead of using this method directly, call * createAltInternalOwnCloudName($name, true) */ private function _createAltInternalOwnCloudNameForUsers($name) { $attempts = 0; //while loop is just a precaution. If a name is not generated within //20 attempts, something else is very wrong. Avoids infinite loop. while ($attempts < 20) { $altName = $name . '_' . rand(1000, 9999); if (!\OCP\User::userExists($altName)) { return $altName; } $attempts++; } return false; }
public function testUserExistsPublicAPIForNeverExisting() { $access = $this->getAccessMock(); $backend = new UserLDAP($access, $this->getMock('\\OCP\\IConfig')); $this->prepareMockForUserExists($access); \OC_User::useBackend($backend); $access->expects($this->any())->method('readAttribute')->will($this->returnCallback(function ($dn) { if ($dn === 'dnOfRoland,dc=test') { return array(); } return false; })); //test for never-existing user $result = \OCP\User::userExists('mallory'); $this->assertFalse($result); }
public function testUserExistsPublicAPI() { $access = $this->getAccessMock(); $backend = new UserLDAP($access); $this->prepareMockForUserExists($access); \OC_User::useBackend($backend); $access->expects($this->any())->method('readAttribute')->will($this->returnCallback(function ($dn) { if ($dn === 'dnOfRoland') { return array(); } return false; })); //test for existing user $result = \OCP\User::userExists('gunslinger'); $this->assertTrue($result); //test for deleted user $result = \OCP\User::userExists('formerUser'); $this->assertFalse($result); //test for never-existing user $result = \OCP\User::userExists('mallory'); $this->assertFalse($result); }
/** * delete public key from a given user * * @param \OC\Files\View $view * @param string $uid user * @return bool */ public static function deletePublicKey($view, $uid) { $result = false; if (!\OCP\User::userExists($uid)) { $publicKey = self::$public_key_dir . '/' . $uid . '.publicKey'; self::deleteKey($view, $publicKey); } return $result; }
/** * try to get the user from the path if no user is logged in * @param string $path * @return mixed user or false if we couldn't determine a user */ public static function getUser($path) { $user = \OCP\User::getUser(); // if we are logged in, then we return the userid if ($user) { return $user; } // if no user is logged in we try to access a publicly shared files. // In this case we need to try to get the user from the path $trimmed = ltrim($path, '/'); $split = explode('/', $trimmed); // it is not a file relative to data/user/files if (count($split) < 2 || $split[1] !== 'files' && $split[1] !== 'cache') { return false; } $user = $split[0]; if (\OCP\User::userExists($user)) { return $user; } return false; }
/** * Get display names of users matching a pattern * * @param string $search * @param int $limit * @param int $offset * @return array an array of all displayNames (value) and the corresponding uids (key) */ public function getDisplayNames($search = '', $limit = null, $offset = null) { /* If search is an existing ownCloud user uid, * return nothing and rely on Database backend * for providing the DisplayName */ if (\OCP\User::userExists($search)) { return array(); } $displayNames = array(); $identities = $this->identityMapper->findIdentities($search, $limit, $offset); foreach ($identities as $identity) { $ocUid = $identity->getOcUid(); $dn = \OCP\User::getDisplayName($ocUid); $displayNames[$ocUid] = $dn; } return $displayNames; }
private function renameShareKeys($user, $filePath, $filename, $target, $trash) { $oldShareKeyPath = $this->getOldShareKeyPath($user, $filePath, $trash); $dh = $this->view->opendir($oldShareKeyPath); if (is_resource($dh)) { while (($file = readdir($dh)) !== false) { if (!\OC\Files\Filesystem::isIgnoredDir($file)) { if ($this->view->is_dir($oldShareKeyPath . '/' . $file)) { continue; } else { if (substr($file, 0, strlen($filename) + 1) === $filename . '.') { $uid = $this->getUidFromShareKey($file, $filename, $trash); if ($uid === $this->public_share_key_id || $uid === $this->recovery_key_id || \OCP\User::userExists($uid)) { $this->view->copy($oldShareKeyPath . '/' . $file, $target . '/' . $uid . '.shareKey'); } } } } } closedir($dh); } }
/** * @brief returns an internal ownCloud name for the given LDAP DN * @param $dn the dn of the user object * @param $ldapname optional, the display name of the object * @param $isUser optional, wether it is a user object (otherwise group assumed) * @returns string with with the name to use in ownCloud * * returns the internal ownCloud name for the given LDAP DN of the user, false on DN outside of search DN */ public function dn2ocname($dn, $ldapname = null, $isUser = true) { $table = $this->getMapTable($isUser); if ($isUser) { $fncFindMappedName = 'findMappedUser'; $nameAttribute = $this->connection->ldapUserDisplayName; } else { $fncFindMappedName = 'findMappedGroup'; $nameAttribute = $this->connection->ldapGroupDisplayName; } //let's try to retrieve the ownCloud name from the mappings table $ocname = $this->{$fncFindMappedName}($dn); if ($ocname) { return $ocname; } //second try: get the UUID and check if it is known. Then, update the DN and return the name. $uuid = $this->getUUID($dn); if ($uuid) { $query = \OCP\DB::prepare(' SELECT `owncloud_name` FROM `' . $table . '` WHERE `directory_uuid` = ? '); $component = $query->execute(array($uuid))->fetchOne(); if ($component) { $query = \OCP\DB::prepare(' UPDATE `' . $table . '` SET `ldap_dn` = ? WHERE `directory_uuid` = ? '); $query->execute(array($dn, $uuid)); return $component; } } if (is_null($ldapname)) { $ldapname = $this->readAttribute($dn, $nameAttribute); if (!isset($ldapname[0]) && empty($ldapname[0])) { \OCP\Util::writeLog('user_ldap', 'No or empty name for ' . $dn . '.', \OCP\Util::INFO); return false; } $ldapname = $ldapname[0]; } $ldapname = $this->sanitizeUsername($ldapname); //a new user/group! Then let's try to add it. We're shooting into the blue with the user/group name, assuming that in most cases there will not be a conflict. Otherwise an error will occur and we will continue with our second shot. if ($isUser && !\OCP\User::userExists($ldapname) || !$isUser && !\OC_Group::groupExists($ldapname)) { if ($this->mapComponent($dn, $ldapname, $isUser)) { return $ldapname; } } //doh! There is a conflict. We need to distinguish between users/groups. Adding indexes is an idea, but not much of a help for the user. The DN is ugly, but for now the only reasonable way. But we transform it to a readable format and remove the first part to only give the path where this object is located. $oc_name = $this->alternateOwnCloudName($ldapname, $dn); if ($isUser && !\OCP\User::userExists($oc_name) || !$isUser && !\OC_Group::groupExists($oc_name)) { if ($this->mapComponent($dn, $oc_name, $isUser)) { return $oc_name; } } //if everything else did not help.. \OCP\Util::writeLog('user_ldap', 'Could not create unique ownCloud name for ' . $dn . '.', \OCP\Util::INFO); return false; }
private static function ldap2ownCloudNames($ldapObjects, $isUsers) { if ($isUsers) { $knownObjects = self::mappedUsers(); $nameAttribute = self::conf('ldapUserDisplayName'); } else { $knownObjects = self::mappedGroups(); $nameAttribute = self::conf('ldapGroupDisplayName'); } $ownCloudNames = array(); foreach ($ldapObjects as $ldapObject) { $key = self::recursiveArraySearch($knownObjects, $ldapObject['dn']); //everything is fine when we know the group if ($key !== false) { $ownCloudNames[] = $knownObjects[$key]['owncloud_name']; continue; } //we do not take empty usernames if (!isset($ldapObject[$nameAttribute]) || empty($ldapObject[$nameAttribute])) { OCP\Util::writeLog('user_ldap', 'No or empty name for ' . $ldapObject['dn'] . ', skipping.', OCP\Util::INFO); continue; } //a new group! Then let's try to add it. We're shooting into the blue with the group name, assuming that in most cases there will not be a conflict. But first make sure, that the display name contains only allowed characters. $ocname = self::sanitizeUsername($ldapObject[$nameAttribute]); if ($isUsers && !\OCP\User::userExists($ocname) || !$isUsers && !\OC_Group::groupExists($ocname)) { if (self::mapComponent($ldapObject['dn'], $ocname, $isUsers)) { $ownCloudNames[] = $ocname; continue; } } //doh! There is a conflict. We need to distinguish between groups. Adding indexes is an idea, but not much of a help for the user. The DN is ugly, but for now the only reasonable way. But we transform it to a readable format and remove the first part to only give the path where this entry is located. $ocname = self::alternateOwnCloudName($ocname, $ldapObject['dn']); if ($isUsers && !\OCP\User::userExists($ocname) || !$isUsers && !\OC_Group::groupExists($ocname)) { if (self::mapComponent($ldapObject['dn'], $ocname, $isUsers)) { $ownCloudNames[] = $ocname; continue; } } //if everything else did not help.. OCP\Util::writeLog('user_ldap', 'Could not create unique ownCloud name for ' . $ldapObject['dn'] . ', skipping.', OCP\Util::INFO); } return $ownCloudNames; }
/** * @brief get uid of the owners of the file and the path to the file * @param string $path Path of the file to check * @throws \Exception * @note $shareFilePath must be relative to data/UID/files. Files * relative to /Shared are also acceptable * @return array */ public function getUidAndFilename($path) { $view = new \OC\Files\View($this->userFilesDir); $fileOwnerUid = $view->getOwner($path); // handle public access if ($this->isPublic) { $filename = $path; $fileOwnerUid = $GLOBALS['fileOwner']; return array($fileOwnerUid, $filename); } else { // Check that UID is valid if (!\OCP\User::userExists($fileOwnerUid)) { throw new \Exception('Could not find owner (UID = "' . var_export($fileOwnerUid, 1) . '") of file "' . $path . '"'); } // NOTE: Bah, this dependency should be elsewhere \OC\Files\Filesystem::initMountPoints($fileOwnerUid); // If the file owner is the currently logged in user if ($fileOwnerUid === $this->userId) { // Assume the path supplied is correct $filename = $path; } else { $info = $view->getFileInfo($path); $ownerView = new \OC\Files\View('/' . $fileOwnerUid . '/files'); // Fetch real file path from DB $filename = $ownerView->getPath($info['fileid']); // TODO: Check that this returns a path without including the user data dir } return array($fileOwnerUid, \OC_Filesystem::normalizePath($filename)); } }
/** * extract user from path * * @param string $path * @return string user id * @throws Exception\EncryptionException */ public static function getUserFromPath($path) { $split = self::splitPath($path); if (count($split) > 2 && ($split[2] === 'files' || $split[2] === 'files_versions' || $split[2] === 'cache' || $split[2] === 'files_trashbin')) { $user = $split[1]; if (\OCP\User::userExists($user)) { return $user; } } throw new Exception\EncryptionException('Could not determine user', Exception\EncryptionException::GENERIC); }