]> source.dussan.org Git - nextcloud-server.git/commitdiff
Adjust sabre changes in core
authorThomas Müller <thomas.mueller@tmit.eu>
Fri, 20 Nov 2015 12:35:23 +0000 (13:35 +0100)
committerThomas Müller <thomas.mueller@tmit.eu>
Tue, 24 Nov 2015 14:11:54 +0000 (15:11 +0100)
apps/dav/lib/caldav/caldavbackend.php
apps/dav/lib/carddav/addressbook.php
apps/dav/lib/carddav/useraddressbooks.php
apps/dav/lib/connector/sabre/auth.php
apps/dav/lib/connector/sabre/fakelockerplugin.php
apps/dav/lib/connector/sabre/taglist.php
apps/dav/tests/unit/caldav/caldavbackendtest.php
apps/dav/tests/unit/connector/sabre/FakeLockerPluginTest.php
apps/dav/tests/unit/connector/sabre/auth.php
apps/dav/tests/unit/connector/sabre/requesttest/auth.php
lib/private/files/storage/dav.php

index 99338650793cc9cdaef03a9d6c4d825312be819d..d912f209d468a319222e945c47702caee2498517 100644 (file)
@@ -26,8 +26,8 @@ use Sabre\CalDAV\Backend\SchedulingSupport;
 use Sabre\CalDAV\Backend\SubscriptionSupport;
 use Sabre\CalDAV\Backend\SyncSupport;
 use Sabre\CalDAV\Plugin;
-use Sabre\CalDAV\Property\ScheduleCalendarTransp;
-use Sabre\CalDAV\Property\SupportedCalendarComponentSet;
+use Sabre\CalDAV\Xml\Property\ScheduleCalendarTransp;
+use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet;
 use Sabre\DAV;
 use Sabre\DAV\Exception\Forbidden;
 use Sabre\VObject\DateTimeParser;
index e50f6f4adf6f828391b7ba07d32cf566857f1950..eff1ad321e5d4a9bef943d94cc613753020fbaf4 100644 (file)
@@ -3,13 +3,9 @@
 namespace OCA\DAV\CardDAV;
 
 use OCA\DAV\CardDAV\Sharing\IShareableAddressBook;
-use OCP\IUserManager;
 
 class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareableAddressBook {
 
-       /** @var IUserManager */
-       private $userManager;
-
        public function __construct(CardDavBackend $carddavBackend, array $addressBookInfo) {
                parent::__construct($carddavBackend, $addressBookInfo);
        }
@@ -55,4 +51,4 @@ class AddressBook extends \Sabre\CardDAV\AddressBook implements IShareableAddres
                $carddavBackend = $this->carddavBackend;
                $carddavBackend->getShares($this->getName());
        }
-}
\ No newline at end of file
+}
index adbb0292fa7a946d543c09c2895e4dd89445d292..5f618a0ece3f3107e2f24db13ce5410126f0fe5d 100644 (file)
@@ -2,7 +2,7 @@
 
 namespace OCA\DAV\CardDAV;
 
-class UserAddressBooks extends \Sabre\CardDAV\UserAddressBooks {
+class UserAddressBooks extends \Sabre\CardDAV\AddressBookHome {
 
        /**
         * Returns a list of addressbooks
index 27f6704ba2ce4ac037bcc90435ac18c0c9bc477c..655152a2cc17629ee3351719174f8d41e8464b84 100644 (file)
@@ -35,6 +35,8 @@ use OCP\IUserSession;
 use Sabre\DAV\Auth\Backend\AbstractBasic;
 use Sabre\DAV\Exception\NotAuthenticated;
 use Sabre\DAV\Exception\ServiceUnavailable;
+use Sabre\HTTP\RequestInterface;
+use Sabre\HTTP\ResponseInterface;
 
 class Auth extends AbstractBasic {
        const DAV_AUTHENTICATED = 'AUTHENTICATED_TO_DAV_BACKEND';
@@ -122,22 +124,15 @@ class Auth extends 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 string $realm
-        * @return bool
-        * @throws ServiceUnavailable
+        * @param RequestInterface $request
+        * @param ResponseInterface $response
+        * @return array
         * @throws NotAuthenticated
+        * @throws ServiceUnavailable
         */
-       public function authenticate(\Sabre\DAV\Server $server, $realm) {
+       function check(RequestInterface $request, ResponseInterface $response) {
                try {
-                       $result = $this->auth($server, $realm);
+                       $result = $this->auth($request, $response);
                        return $result;
                } catch (NotAuthenticated $e) {
                        throw $e;
@@ -149,11 +144,11 @@ class Auth extends AbstractBasic {
     }
 
        /**
-        * @param \Sabre\DAV\Server $server
-        * @param string $realm
-        * @return bool
+        * @param RequestInterface $request
+        * @param ResponseInterface $response
+        * @return array
         */
-       private function auth(\Sabre\DAV\Server $server, $realm) {
+       private function auth(RequestInterface $request, ResponseInterface $response) {
                if (\OC_User::handleApacheAuth() ||
                        ($this->userSession->isLoggedIn() && is_null($this->session->get(self::DAV_AUTHENTICATED)))
                ) {
@@ -161,16 +156,16 @@ class Auth extends AbstractBasic {
                        \OC_Util::setupFS($user);
                        $this->currentUser = $user;
                        $this->session->close();
-                       return true;
+                       return [true, $this->principalPrefix . $user];
                }
 
-               if ($server->httpRequest->getHeader('X-Requested-With') === 'XMLHttpRequest') {
+               if ($request->getHeader('X-Requested-With') === 'XMLHttpRequest') {
                        // do not re-authenticate over ajax, use dummy auth name to prevent browser popup
-                       $server->httpResponse->addHeader('WWW-Authenticate','DummyBasic realm="' . $realm . '"');
-                       $server->httpResponse->setStatus(401);
+                       $response->addHeader('WWW-Authenticate','DummyBasic realm="' . $this->realm . '"');
+                       $response->setStatus(401);
                        throw new \Sabre\DAV\Exception\NotAuthenticated('Cannot authenticate over ajax calls');
                }
 
-               return parent::authenticate($server, $realm);
+               return parent::check($request, $response);
        }
 }
index b9d1a30a041c6cb4f2baf2f8f9746fc1adaa6d71..b75e7f137d871e071a55dee6b09587ca47d089a7 100644 (file)
@@ -22,9 +22,9 @@
 namespace OCA\DAV\Connector\Sabre;
 
 use Sabre\DAV\Locks\LockInfo;
-use Sabre\DAV\Property\LockDiscovery;
-use Sabre\DAV\Property\SupportedLock;
 use Sabre\DAV\ServerPlugin;
+use Sabre\DAV\Xml\Property\LockDiscovery;
+use Sabre\DAV\Xml\Property\SupportedLock;
 use Sabre\HTTP\RequestInterface;
 use Sabre\HTTP\ResponseInterface;
 use Sabre\DAV\PropFind;
@@ -122,12 +122,6 @@ class FakeLockerPlugin extends ServerPlugin {
         */
        public function fakeLockProvider(RequestInterface $request,
                                                                         ResponseInterface $response) {
-               $dom = new \DOMDocument('1.0', 'utf-8');
-               $prop = $dom->createElementNS('DAV:', 'd:prop');
-               $dom->appendChild($prop);
-
-               $lockDiscovery = $dom->createElementNS('DAV:', 'd:lockdiscovery');
-               $prop->appendChild($lockDiscovery);
 
                $lockInfo = new LockInfo();
                $lockInfo->token = md5($request->getPath());
@@ -135,10 +129,12 @@ class FakeLockerPlugin extends ServerPlugin {
                $lockInfo->depth = \Sabre\DAV\Server::DEPTH_INFINITY;
                $lockInfo->timeout = 1800;
 
-               $lockObj = new LockDiscovery([$lockInfo]);
-               $lockObj->serialize($this->server, $lockDiscovery);
+               $body = $this->server->xml->write('{DAV:}prop', [
+                               '{DAV:}lockdiscovery' =>
+                                               new LockDiscovery([$lockInfo])
+               ]);
 
-               $response->setBody($dom->saveXML());
+               $response->setBody($body);
 
                return false;
        }
index 177cc23e80513c7d1529a2fddbed4a2fecd65c8c..1b32d4b10473a0ffb0245bd391304122d2c3d82f 100644 (file)
 
 namespace OCA\DAV\Connector\Sabre;
 
-use Sabre\DAV;
+use Sabre\Xml\Element;
+use Sabre\Xml\Reader;
+use Sabre\Xml\Writer;
 
 /**
  * TagList property
  *
  * This property contains multiple "tag" elements, each containing a tag name.
  */
-class TagList extends DAV\Property {
+class TagList implements Element {
        const NS_OWNCLOUD = 'http://owncloud.org/ns';
 
-    /**
-     * tags
-     *
-     * @var array
-     */
-    private $tags;
-
-    /**
-     * @param array $tags
-     */
-    public function __construct(array $tags) {
-        $this->tags = $tags;
-    }
-
-    /**
-     * Returns the tags
-     *
-     * @return array
-     */
-    public function getTags() {
-
-        return $this->tags;
-
-    }
-
-    /**
-     * Serializes this property.
-     *
-     * @param DAV\Server $server
-     * @param \DOMElement $dom
-     * @return void
-     */
-    public function serialize(DAV\Server $server,\DOMElement $dom) {
-
-        $prefix = $server->xmlNamespaces[self::NS_OWNCLOUD];
-
-        foreach($this->tags as $tag) {
-
-            $elem = $dom->ownerDocument->createElement($prefix . ':tag');
-            $elem->appendChild($dom->ownerDocument->createTextNode($tag));
-
-            $dom->appendChild($elem);
-        }
-
-    }
-
-    /**
-     * Unserializes this property from a DOM Element
-     *
-     * This method returns an instance of this class.
-     * It will only decode tag values.
-     *
-     * @param \DOMElement $dom
-        * @param array $propertyMap
-     * @return \OCA\DAV\Connector\Sabre\TagList
-     */
-    static function unserialize(\DOMElement $dom, array $propertyMap) {
-
-        $tags = array();
-        foreach($dom->childNodes as $child) {
-            if (DAV\XMLUtil::toClarkNotation($child)==='{' . self::NS_OWNCLOUD . '}tag') {
-                $tags[] = $child->textContent;
-            }
-        }
-        return new self($tags);
-
-    }
-
+       /**
+        * tags
+        *
+        * @var array
+        */
+       private $tags;
+
+       /**
+        * @param array $tags
+        */
+       public function __construct(array $tags) {
+               $this->tags = $tags;
+       }
+
+       /**
+        * Returns the tags
+        *
+        * @return array
+        */
+       public function getTags() {
+
+               return $this->tags;
+
+       }
+
+       /**
+        * The deserialize method is called during xml parsing.
+        *
+        * This method is called statictly, this is because in theory this method
+        * may be used as a type of constructor, or factory method.
+        *
+        * Often you want to return an instance of the current class, but you are
+        * free to return other data as well.
+        *
+        * You are responsible for advancing the reader to the next element. Not
+        * doing anything will result in a never-ending loop.
+        *
+        * If you just want to skip parsing for this element altogether, you can
+        * just call $reader->next();
+        *
+        * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
+        * the next element.
+        *
+        * @param Reader $reader
+        * @return mixed
+        */
+       static function xmlDeserialize(Reader $reader) {
+               $tags = [];
+
+               foreach ($reader->parseInnerTree() as $elem) {
+                       if ($elem['name'] === '{' . self::NS_OWNCLOUD . '}tag') {
+                               $tags[] = $elem['value'];
+                       }
+               }
+               return new self($tags);
+       }
+
+       /**
+        * The xmlSerialize metod is called during xml writing.
+        *
+        * Use the $writer argument to write its own xml serialization.
+        *
+        * An important note: do _not_ create a parent element. Any element
+        * implementing XmlSerializble should only ever write what's considered
+        * its 'inner xml'.
+        *
+        * The parent of the current element is responsible for writing a
+        * containing element.
+        *
+        * This allows serializers to be re-used for different element names.
+        *
+        * If you are opening new elements, you must also close them again.
+        *
+        * @param Writer $writer
+        * @return void
+        */
+       function xmlSerialize(Writer $writer) {
+
+               foreach ($this->tags as $tag) {
+                       $writer->startElement(self::NS_OWNCLOUD . ':tag');
+                       $writer->writeElement($tag);
+                       $writer->endElement();
+               }
+       }
 }
index 258c5627ad9a624250de4695de7df8171a1ee737..e9483a47a784271f2773ed56a7c421dc1dd2624b 100644 (file)
@@ -23,9 +23,9 @@ namespace Tests\Connector\Sabre;
 use DateTime;
 use DateTimeZone;
 use OCA\DAV\CalDAV\CalDavBackend;
-use Sabre\CalDAV\Property\SupportedCalendarComponentSet;
-use Sabre\DAV\Property\Href;
+use Sabre\CalDAV\Xml\Property\SupportedCalendarComponentSet;
 use Sabre\DAV\PropPatch;
+use Sabre\DAV\Xml\Property\Href;
 use Test\TestCase;
 
 /**
index dfe8cc220a37e99031ae15d7befecbca9a09d11e..8539e9c06eea875885d33ecfb0f1ced7e8f24c21 100644 (file)
@@ -21,6 +21,7 @@
 namespace OCA\DAV\Tests\Unit\Connector\Sabre;
 
 use OCA\DAV\Connector\Sabre\FakeLockerPlugin;
+use Sabre\HTTP\Response;
 use Test\TestCase;
 
 /**
@@ -141,20 +142,19 @@ class FakeLockerPluginTest extends TestCase {
 
        public function testFakeLockProvider() {
                $request = $this->getMock('\Sabre\HTTP\RequestInterface');
-               $response = $this->getMock('\Sabre\HTTP\ResponseInterface');
+               $response = new Response();
                $server = $this->getMock('\Sabre\DAV\Server');
                $this->fakeLockerPlugin->initialize($server);
 
                $request->expects($this->exactly(2))
                        ->method('getPath')
                        ->will($this->returnValue('MyPath'));
-               $response->expects($this->once())
-                       ->method('setBody')
-                       ->with('<?xml version="1.0" encoding="utf-8"?>
-<d:prop xmlns:d="DAV:"><d:lockdiscovery><d:activelock><d:lockscope><d:exclusive/></d:lockscope><d:locktype><d:write/></d:locktype><d:lockroot><d:href>MyPath</d:href></d:lockroot><d:depth>infinity</d:depth><d:timeout>Second-1800</d:timeout><d:locktoken><d:href>opaquelocktoken:fe4f7f2437b151fbcb4e9f5c8118c6b1</d:href></d:locktoken><d:owner/></d:activelock></d:lockdiscovery></d:prop>
-');
 
                $this->assertSame(false, $this->fakeLockerPlugin->fakeLockProvider($request, $response));
+
+               $expectedXml = '<?xml version="1.0" encoding="utf-8"?><d:prop xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns"><d:lockdiscovery><d:activelock><d:lockscope><d:exclusive/></d:lockscope><d:locktype><d:write/></d:locktype><d:lockroot><d:href>MyPath</d:href></d:lockroot><d:depth>infinity</d:depth><d:timeout>Second-1800</d:timeout><d:locktoken><d:href>opaquelocktoken:fe4f7f2437b151fbcb4e9f5c8118c6b1</d:href></d:locktoken><d:owner/></d:activelock></d:lockdiscovery></d:prop>';
+
+               $this->assertXmlStringEqualsXmlString($expectedXml, $response->getBody());
        }
 
        public function testFakeUnlockProvider() {
index 4c060ff04bbf4bc4ed99340bae515c25e93fb28d..595bd441617afcb503767c97458e0ac78e0aff89 100644 (file)
@@ -249,9 +249,12 @@ class Auth extends TestCase {
        }
 
        public function testAuthenticateAlreadyLoggedIn() {
-               $server = $this->getMockBuilder('\Sabre\DAV\Server')
-                       ->disableOriginalConstructor()
-                       ->getMock();
+               $request = $this->getMockBuilder('Sabre\HTTP\RequestInterface')
+                               ->disableOriginalConstructor()
+                               ->getMock();
+               $response = $this->getMockBuilder('Sabre\HTTP\ResponseInterface')
+                               ->disableOriginalConstructor()
+                               ->getMock();
                $this->userSession
                        ->expects($this->once())
                        ->method('isLoggedIn')
@@ -275,13 +278,10 @@ class Auth extends TestCase {
                        ->expects($this->once())
                        ->method('close');
 
-               $this->assertTrue($this->auth->authenticate($server, 'TestRealm'));
+               $response = $this->auth->check($request, $response);
+               $this->assertEquals([true, 'principals/MyWrongDavUser'], $response);
        }
 
-       /**
-        * @expectedException \Sabre\DAV\Exception\NotAuthenticated
-        * @expectedExceptionMessage No basic authentication headers were found
-        */
        public function testAuthenticateNoBasicAuthenticateHeadersProvided() {
                $server = $this->getMockBuilder('\Sabre\DAV\Server')
                        ->disableOriginalConstructor()
@@ -292,7 +292,8 @@ class Auth extends TestCase {
                $server->httpResponse = $this->getMockBuilder('\Sabre\HTTP\ResponseInterface')
                        ->disableOriginalConstructor()
                        ->getMock();
-               $this->auth->authenticate($server, 'TestRealm');
+               $response = $this->auth->check($server->httpRequest, $server->httpResponse);
+               $this->assertEquals([false, 'No \'Authorization: Basic\' header found. Either the client didn\'t send one, or the server is mis-configured'], $response);
        }
 
        /**
@@ -300,21 +301,20 @@ class Auth extends TestCase {
         * @expectedExceptionMessage Cannot authenticate over ajax calls
         */
        public function testAuthenticateNoBasicAuthenticateHeadersProvidedWithAjax() {
-               $server = $this->getMockBuilder('\Sabre\DAV\Server')
+               /** @var \Sabre\HTTP\RequestInterface $httpRequest */
+               $httpRequest = $this->getMockBuilder('\Sabre\HTTP\RequestInterface')
                        ->disableOriginalConstructor()
                        ->getMock();
-               $server->httpRequest = $this->getMockBuilder('\Sabre\HTTP\RequestInterface')
+               /** @var \Sabre\HTTP\ResponseInterface $httpResponse */
+               $httpResponse = $this->getMockBuilder('\Sabre\HTTP\ResponseInterface')
                        ->disableOriginalConstructor()
                        ->getMock();
-               $server->httpResponse = $this->getMockBuilder('\Sabre\HTTP\ResponseInterface')
-                       ->disableOriginalConstructor()
-                       ->getMock();
-               $server->httpRequest
+               $httpRequest
                        ->expects($this->once())
                        ->method('getHeader')
                        ->with('X-Requested-With')
                        ->will($this->returnValue('XMLHttpRequest'));
-               $this->auth->authenticate($server, 'TestRealm');
+               $this->auth->check($httpRequest, $httpResponse);
        }
 
        public function testAuthenticateValidCredentials() {
@@ -352,13 +352,10 @@ class Auth extends TestCase {
                        ->expects($this->exactly(2))
                        ->method('getUser')
                        ->will($this->returnValue($user));
-               $this->assertTrue($this->auth->authenticate($server, 'TestRealm'));
+               $response = $this->auth->check($server->httpRequest, $server->httpResponse);
+               $this->assertEquals([true, 'principals/username'], $response);
        }
 
-       /**
-        * @expectedException \Sabre\DAV\Exception\NotAuthenticated
-        * @expectedExceptionMessage Username or password does not match
-        */
        public function testAuthenticateInvalidCredentials() {
                $server = $this->getMockBuilder('\Sabre\DAV\Server')
                        ->disableOriginalConstructor()
@@ -384,6 +381,7 @@ class Auth extends TestCase {
                        ->method('login')
                        ->with('username', 'password')
                        ->will($this->returnValue(false));
-               $this->auth->authenticate($server, 'TestRealm');
+               $response = $this->auth->check($server->httpRequest, $server->httpResponse);
+               $this->assertEquals([false, 'Username or password was incorrect'], $response);
        }
 }
index 02b64ab070b9cfd784d24948ede9636b846f2849..3caa019af8de8b243d78efa76c0481fcbe0dc213 100644 (file)
@@ -9,6 +9,8 @@
 namespace OCA\DAV\Tests\Unit\Connector\Sabre\RequestTest;
 
 use Sabre\DAV\Auth\Backend\BackendInterface;
+use Sabre\HTTP\RequestInterface;
+use Sabre\HTTP\ResponseInterface;
 
 class Auth implements BackendInterface {
        /**
@@ -32,18 +34,35 @@ class Auth implements BackendInterface {
                $this->password = $password;
        }
 
-
        /**
-        * Authenticates the user based on the current request.
+        * When this method is called, the backend must check if authentication was
+        * successful.
+        *
+        * The returned value must be one of the following
+        *
+        * [true, "principals/username"]
+        * [false, "reason for failure"]
+        *
+        * If authentication was successful, it's expected that the authentication
+        * backend returns a so-called principal url.
+        *
+        * Examples of a principal url:
         *
-        * If authentication is successful, true must be returned.
-        * If authentication fails, an exception must be thrown.
+        * principals/admin
+        * principals/user1
+        * principals/users/joe
+        * principals/uid/123457
         *
-        * @param \Sabre\DAV\Server $server
-        * @param string $realm
-        * @return boolean|null
+        * If you don't use WebDAV ACL (RFC3744) we recommend that you simply
+        * return a string such as:
+        *
+        * principals/users/[username]
+        *
+        * @param RequestInterface $request
+        * @param ResponseInterface $response
+        * @return array
         */
-       function authenticate(\Sabre\DAV\Server $server, $realm) {
+       function check(RequestInterface $request, ResponseInterface $response) {
                $userSession = \OC::$server->getUserSession();
                $result = $userSession->login($this->user, $this->password);
                if ($result) {
@@ -52,18 +71,33 @@ class Auth implements BackendInterface {
                        \OC_Util::setupFS($user);
                        //trigger creation of user home and /files folder
                        \OC::$server->getUserFolder($user);
+                       return [true, "principals/$user"];
                }
-               return $result;
+               return [false, "login failed"];
        }
 
        /**
-        * Returns information about the currently logged in username.
+        * This method is called when a user could not be authenticated, and
+        * authentication was required for the current request.
+        *
+        * This gives you the opportunity to set authentication headers. The 401
+        * status code will already be set.
+        *
+        * In this case of Basic Auth, this would for example mean that the
+        * following header needs to be set:
+        *
+        * $response->addHeader('WWW-Authenticate', 'Basic realm=SabreDAV');
         *
-        * If nobody is currently logged in, this method should return null.
+        * Keep in mind that in the case of multiple authentication backends, other
+        * WWW-Authenticate headers may already have been set, and you'll want to
+        * append your own WWW-Authenticate header instead of overwriting the
+        * existing one.
         *
-        * @return string
+        * @param RequestInterface $request
+        * @param ResponseInterface $response
+        * @return void
         */
-       function getCurrentUser() {
-               return $this->user;
+       function challenge(RequestInterface $request, ResponseInterface $response) {
+               // TODO: Implement challenge() method.
        }
 }
index dcde7b8029b9b2397b53fb7958c550533a328dd2..9147f5724610eec20a56ee0e692f935d42dc36d8 100644 (file)
@@ -47,6 +47,7 @@ use OCP\Files\StorageNotAvailableException;
 use OCP\Util;
 use Sabre\DAV\Client;
 use Sabre\DAV\Exception\NotFound;
+use Sabre\DAV\Xml\Property\ResourceType;
 use Sabre\HTTP\ClientException;
 use Sabre\HTTP\ClientHttpException;
 
@@ -137,7 +138,7 @@ class DAV extends Common {
                $this->client->setThrowExceptions(true);
 
                if ($this->secure === true && $this->certPath) {
-                       $this->client->addTrustedCertificates($this->certPath);
+                       $this->client->addCurlSetting(CURLOPT_CAINFO, $this->certPath);
                }
        }
 
@@ -280,7 +281,8 @@ class DAV extends Common {
                        $response = $this->propfind($path);
                        $responseType = array();
                        if (isset($response["{DAV:}resourcetype"])) {
-                               $responseType = $response["{DAV:}resourcetype"]->resourceType;
+                               /** @var ResourceType[] $response */
+                               $responseType = $response["{DAV:}resourcetype"]->getValue();
                        }
                        return (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
                } catch (ClientHttpException $e) {
@@ -554,7 +556,8 @@ class DAV extends Common {
                        $response = $this->propfind($path);
                        $responseType = array();
                        if (isset($response["{DAV:}resourcetype"])) {
-                               $responseType = $response["{DAV:}resourcetype"]->resourceType;
+                               /** @var ResourceType[] $response */
+                               $responseType = $response["{DAV:}resourcetype"]->getValue();
                        }
                        $type = (count($responseType) > 0 and $responseType[0] == "{DAV:}collection") ? 'dir' : 'file';
                        if ($type == 'dir') {