diff --git a/lib/private/connector/sabre/auth.php b/lib/private/connector/sabre/auth.php index 5a32a9112ba2a4ee0ed90a705d44c614d32fb8bc..8a6eaab5bf81191f96337f7adcadbd49cb96fdfb 100644 --- a/lib/private/connector/sabre/auth.php +++ b/lib/private/connector/sabre/auth.php @@ -30,7 +30,12 @@ */ namespace OC\Connector\Sabre; -class Auth extends \Sabre\DAV\Auth\Backend\AbstractBasic { +use Exception; +use Sabre\DAV\Auth\Backend\AbstractBasic; +use Sabre\DAV\Exception\NotAuthenticated; +use Sabre\DAV\Exception\ServiceUnavailable; + +class Auth extends AbstractBasic { const DAV_AUTHENTICATED = 'AUTHENTICATED_TO_DAV_BACKEND'; /** @@ -69,7 +74,7 @@ class Auth extends \Sabre\DAV\Auth\Backend\AbstractBasic { } else { \OC_Util::setUpFS(); //login hooks may need early access to the filesystem if(\OC_User::login($username, $password)) { - // make sure we use owncloud's internal username here + // make sure we use ownCloud's internal username here // and not the HTTP auth supplied one, see issue #14048 $ocUser = \OC_User::getUser(); \OC_Util::setUpFS($ocUser); @@ -99,21 +104,30 @@ class Auth extends \Sabre\DAV\Auth\Backend\AbstractBasic { } /** - * Override function here. We want to cache authentication cookies - * in the syncing client to avoid HTTP-401 roundtrips. - * If the sync client supplies the cookies, then OC_User::isLoggedIn() - * will return true and we can see this WebDAV request as already authenticated, - * even if there are no HTTP Basic Auth headers. - * In other case, just fallback to the parent implementation. - * - * @param \Sabre\DAV\Server $server - * @param $realm - * @return bool - */ + * Override function here. We want to cache authentication cookies + * in the syncing client to avoid HTTP-401 roundtrips. + * If the sync client supplies the cookies, then OC_User::isLoggedIn() + * will return true and we can see this WebDAV request as already authenticated, + * even if there are no HTTP Basic Auth headers. + * In other case, just fallback to the parent implementation. + * + * @param \Sabre\DAV\Server $server + * @param string $realm + * @return bool + * @throws ServiceUnavailable + */ public function authenticate(\Sabre\DAV\Server $server, $realm) { - $result = $this->auth($server, $realm); - return $result; + try { + $result = $this->auth($server, $realm); + return $result; + } catch (NotAuthenticated $e) { + throw $e; + } catch (Exception $e) { + $class = get_class($e); + $msg = $e->getMessage(); + throw new ServiceUnavailable("$class: $msg"); + } } /** diff --git a/remote.php b/remote.php index c1077e42672092506eb0f997a118ccd6ac5d0eb3..0b43f949ad48bf9db85d407907162035eedae956 100644 --- a/remote.php +++ b/remote.php @@ -25,22 +25,72 @@ * along with this program. If not, see <http://www.gnu.org/licenses/> * */ + +use OC\Connector\Sabre\ExceptionLoggerPlugin; +use Sabre\DAV\Exception\ServiceUnavailable; +use Sabre\DAV\Server; + +/** + * Class RemoteException + * Dummy exception class to be use locally to identify certain conditions + */ +class RemoteException extends Exception { +} + +/** + * @param Exception $e + */ +function handleException(Exception $e) { + $request = \OC::$server->getRequest(); + // in case the request content type is text/xml - we assume it's a WebDAV request + $isXmlContentType = strpos($request->getHeader('Content-Type'), 'text/xml'); + if ($isXmlContentType === 0) { + // fire up a simple server to properly process the exception + $server = new Server(); + $server->addPlugin(new ExceptionLoggerPlugin('webdav', \OC::$server->getLogger())); + $server->on('beforeMethod', function () use ($e) { + if ($e instanceof RemoteException) { + switch ($e->getCode()) { + case OC_Response::STATUS_SERVICE_UNAVAILABLE: + throw new ServiceUnavailable($e->getMessage()); + case OC_Response::STATUS_NOT_FOUND: + throw new \Sabre\DAV\Exception\NotFound($e->getMessage()); + } + } + $class = get_class($e); + $msg = $e->getMessage(); + throw new ServiceUnavailable("$class: $msg"); + }); + $server->exec(); + } else { + $statusCode = OC_Response::STATUS_INTERNAL_SERVER_ERROR; + if ($e instanceof \OC\ServiceUnavailableException ) { + $statusCode = OC_Response::STATUS_SERVICE_UNAVAILABLE; + } + \OCP\Util::writeLog('remote', $e->getMessage(), \OCP\Util::FATAL); + if ($e instanceof RemoteException) { + OC_Response::setStatus($e->getCode()); + OC_Template::printErrorPage($e->getMessage()); + } else { + OC_Response::setStatus($statusCode); + OC_Template::printExceptionErrorPage($e); + } + } +} + try { require_once 'lib/base.php'; if (\OCP\Util::needUpgrade()) { // since the behavior of apps or remotes are unpredictable during // an upgrade, return a 503 directly - OC_Response::setStatus(OC_Response::STATUS_SERVICE_UNAVAILABLE); - OC_Template::printErrorPage('Service unavailable'); - exit; + throw new RemoteException('Service unavailable', OC_Response::STATUS_SERVICE_UNAVAILABLE); } $request = \OC::$server->getRequest(); $pathInfo = $request->getPathInfo(); if ($pathInfo === false || $pathInfo === '') { - OC_Response::setStatus(OC_Response::STATUS_NOT_FOUND); - exit; + throw new RemoteException('Path not found', OC_Response::STATUS_NOT_FOUND); } if (!$pos = strpos($pathInfo, '/', 1)) { $pos = strlen($pathInfo); @@ -50,8 +100,7 @@ try { $file = \OC::$server->getConfig()->getAppValue('core', 'remote_' . $service); if(is_null($file)) { - OC_Response::setStatus(OC_Response::STATUS_NOT_FOUND); - exit; + throw new RemoteException('Path not found', OC_Response::STATUS_NOT_FOUND); } // force language as given in the http request @@ -82,12 +131,6 @@ try { $baseuri = OC::$WEBROOT . '/remote.php/'.$service.'/'; require_once $file; -} catch (\OC\ServiceUnavailableException $ex) { - OC_Response::setStatus(OC_Response::STATUS_SERVICE_UNAVAILABLE); - \OCP\Util::writeLog('remote', $ex->getMessage(), \OCP\Util::FATAL); - OC_Template::printExceptionErrorPage($ex); } catch (Exception $ex) { - OC_Response::setStatus(OC_Response::STATUS_INTERNAL_SERVER_ERROR); - \OCP\Util::writeLog('remote', $ex->getMessage(), \OCP\Util::FATAL); - OC_Template::printExceptionErrorPage($ex); + handleException($ex); }