Permalink
Browse files

Protect request-options queries with a unique api key.

  • Loading branch information...
1 parent ad6a2e8 commit fdfad7636edc8b6da6f2f4e3106132b56d842544 @cdujeu cdujeu committed Aug 26, 2016
@@ -24,6 +24,8 @@
use Pydio\Access\Core\Model\AJXP_Node;
use Pydio\Access\Driver\StreamProvider\FS\FsAccessWrapper;
use Pydio\Core\Controller\HTMLWriter;
+use Pydio\Core\Services\ApiKeysService;
+use Pydio\Core\Services\AuthService;
use Pydio\Core\Services\ConfService;
use Pydio\Core\Utils\ApplicationState;
use Pydio\Core\Utils\FileHelper;
@@ -440,7 +442,8 @@ protected function sendToAccelerator($accelConfiguration, $localPathOrNode, $ser
}
// Pydio Agent acceleration - We make sure that request was really proxied by Agent, by checking a specific header.
- if($accelConfiguration === "pydio" && array_key_exists("HTTP_X_PYDIO_DOWNLOAD_SUPPORTED", $serverParams)) {
+ if($accelConfiguration === "pydio" && array_key_exists("HTTP_X_PYDIO_DOWNLOAD_SUPPORTED", $serverParams)
+ && ApiKeysService::requestHasValidHeadersForAdminTask($serverParams, "go-upload", AuthService::getLoggedUser()->getId())) {
if ($localPathOrNode instanceof AJXP_Node) {
$options = MetaStreamWrapper::getResolvedOptionsForNode($localPathOrNode);
@@ -20,10 +20,13 @@
*/
namespace Pydio\Core\Services;
+use Psr\Http\Message\ServerRequestInterface;
use Pydio\Conf\Sql\SqlConfDriver;
+use Pydio\Core\Exception\AuthRequiredException;
use Pydio\Core\Exception\PydioException;
use Pydio\Core\Utils\Http\UserAgent;
use Pydio\Core\Utils\Vars\StringHelper;
+use Pydio\Log\Core\Logger;
defined('AJXP_EXEC') or die('Access not allowed');
@@ -79,21 +82,21 @@ public static function generatePairForAuthfront($userId, $deviceId = "", $device
/**
* @param $userId
- * @param $deviceId
+ * @param $adminTaskId
* @param string $restrictToIP
* @return array
* @throws PydioException
* @throws \Exception
*/
- public static function generatePairForAdminTasks($userId, $deviceId, $restrictToIP = ""){
+ public static function generatePairForAdminTask($adminTaskId, $userId, $restrictToIP = ""){
$store = self::getStore();
$token = StringHelper::generateRandomString();
$private = StringHelper::generateRandomString();
$data = [
- "USER_ID" => $userId,
- "PRIVATE" => $private,
- "DEVICE_ID" => $deviceId
+ "USER_ID" => $userId,
+ "PRIVATE" => $private,
+ "ADMIN_TASK_ID" => $adminTaskId
];
if(!empty($restrictToIP)){
$data["RESTRICT_TO_IP"] = $restrictToIP;
@@ -104,6 +107,45 @@ public static function generatePairForAdminTasks($userId, $deviceId, $restrictTo
}
/**
+ * @param $adminTaskId
+ * @param $userId
+ * @return array|null
+ * @throws PydioException
+ */
+ public static function findPairForAdminTask($adminTaskId, $userId){
+
+ $keys = self::getStore()->simpleStoreList("keystore", $cursor, "", "serial", '%"ADMIN_TASK_ID";s:' . strlen($adminTaskId) . ':"' . $adminTaskId . '"%');
+ foreach($keys as $kId => $kData){
+ if($kData["USER_ID"] === $userId){
+ return ["t" => $kId, "p" => $kData["PRIVATE"]];
+ }
+ }
+ return null;
+
+ }
+
+ /**
+ * @param $serverData
+ * @param $adminTaskId
+ * @param $userId
+ * @return bool
+ */
+ public static function requestHasValidHeadersForAdminTask($serverData, $adminTaskId, $userId){
+ if(!isSet($serverData['HTTP_X_PYDIO_ADMIN_AUTH'])){
+ Logger::error(__CLASS__, __FUNCTION__,"Invalid tokens for admin task $adminTaskId");
+ return false;
+ }
+ list($t, $p) = explode(":", trim($serverData['HTTP_X_PYDIO_ADMIN_AUTH']));
+ $existingKey = self::findPairForAdminTask("go-upload", $userId);
+ if($existingKey === null || $existingKey['p'] !== $p || $existingKey['t'] !== $t){
+ Logger::error(__CLASS__, __FUNCTION__, "Invalid tokens for admin task $adminTaskId");
+ return false;
+ }
+ Logger::debug(__CLASS__, "Valid tokens for admin task $adminTaskId");
+ return true;
+ }
+
+ /**
* @param $token
* @param string $checkPrivate
* @return bool
@@ -46,12 +46,7 @@
*/
class KeystoreAuthFrontend extends AbstractAuthFrontend
{
-
- /**
- * @var SqlConfDriver $storage
- */
- var $storage;
-
+
/**
* @param $httpVars
* @param $varName
@@ -140,8 +135,6 @@ function authTokenActions(ServerRequestInterface $requestInterface, ResponseInte
if (!$ctx->hasUser()) {
return null;
}
- $this->storage = ConfService::getConfStorageImpl();
- if (!($this->storage instanceof \Pydio\Conf\Sql\SqlConfDriver)) return false;
$u = $ctx->getUser();
$user = $u->getId();
@@ -34,6 +34,7 @@
use Pydio\Core\Model\ContextInterface;
use Pydio\Core\PluginFramework\PluginsService;
use Pydio\Core\Serializer\UserXML;
+use Pydio\Core\Services\ApiKeysService;
use Pydio\Core\Services\AuthService;
use Pydio\Core\Services\ConfService;
use Pydio\Core\Services\RepositoryService;
@@ -536,6 +537,13 @@ public function generateCaddyFile($params) {
$secure = $params["UPLOAD_SECURE"];
$path = "/" . trim($params["UPLOAD_PATH"], "/");
+ // WE SHOULD HAVE A CONTEXT AT THIS POINT, INSTEAD OF CALLING ::getLoggedUser()
+ $adminKey = ApiKeysService::findPairForAdminTask("go-upload", AuthService::getLoggedUser()->getId());
+ if($adminKey === null){
+ $adminKey = ApiKeysService::generatePairForAdminTask("go-upload", AuthService::getLoggedUser()->getId(), $host);
+ }
+ $adminKeyString = $adminKey["t"].":".$adminKey["p"];
+
$key = "http" . ($secure ? "s" : "") . "://" . $host . ":" . $port;
$hosts[$key] = array_merge(
(array)$hosts[$key],
@@ -551,6 +559,7 @@ public function generateCaddyFile($params) {
"pydioauth " . $path => [$tokenURL . "&device=upload"],
"pydiopre " . $path => [$authURL, "{\n" .
"\t\theader X-File-Direct-Upload request-options\n" .
+ "\t\theader X-Pydio-Admin-Auth $adminKeyString\n" .
"\t}"
],
"pydioupload " . $path => [],
@@ -23,7 +23,10 @@
use Pydio\Access\Core\Model\AJXP_Node;
use Pydio\Access\Core\Model\UserSelection;
use Pydio\Core\Controller\Controller;
+use Pydio\Core\Exception\AuthRequiredException;
use Pydio\Core\Exception\PydioException;
+use Pydio\Core\Model\ContextInterface;
+use Pydio\Core\Services\ApiKeysService;
use Pydio\Core\Services\LocaleService;
use Pydio\Core\Utils\Vars\InputFilter;
use Pydio\Core\Http\Message\ExternalUploadedFile;
@@ -126,6 +129,17 @@ public function preProcess(\Psr\Http\Message\ServerRequestInterface &$request, \
throw new PydioException("Unrecognized direct upload status ". $externalUploadStatus);
}
+ if($externalUploadStatus === ExternalUploadedFile::STATUS_REQUEST_OPTIONS){
+
+ /** @var ContextInterface $ctx */
+ $ctx = $request->getAttribute("ctx");
+ $uId = $ctx->getUser()->getId();
+ if(!ApiKeysService::requestHasValidHeadersForAdminTask($request->getServerParams(), "go-upload", $uId)){
+ throw new AuthRequiredException();
+ }
+
+ }
+
$uploadedFile = new ExternalUploadedFile($externalUploadStatus, $fileSizeH, $fileNameH);
} else {

0 comments on commit fdfad76

Please sign in to comment.