From 055d58bfc3d8168cf1923030cf6d532cc6f288e4 Mon Sep 17 00:00:00 2001
From: Vincent Petry <pvince81@owncloud.com>
Date: Thu, 19 Nov 2015 14:18:27 +0100
Subject: [PATCH] Do not authenticate over ajax

This makes sure that whenever a Webdav call is done through Ajax, if the
session has expired, it will not send back a challenge but a simple 401
response. Without this fix, the default code would send back a challenge
and trigger the browser's basic auth dialog.
---
 apps/dav/lib/connector/sabre/auth.php        |  7 ++++
 apps/dav/tests/unit/connector/sabre/auth.php | 36 ++++++++++++++++++--
 2 files changed, 41 insertions(+), 2 deletions(-)

diff --git a/apps/dav/lib/connector/sabre/auth.php b/apps/dav/lib/connector/sabre/auth.php
index f9a3979904..27f6704ba2 100644
--- a/apps/dav/lib/connector/sabre/auth.php
+++ b/apps/dav/lib/connector/sabre/auth.php
@@ -164,6 +164,13 @@ class Auth extends AbstractBasic {
 			return true;
 		}
 
+		if ($server->httpRequest->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);
+			throw new \Sabre\DAV\Exception\NotAuthenticated('Cannot authenticate over ajax calls');
+		}
+
 		return parent::authenticate($server, $realm);
 	}
 }
diff --git a/apps/dav/tests/unit/connector/sabre/auth.php b/apps/dav/tests/unit/connector/sabre/auth.php
index d18747d732..4c060ff04b 100644
--- a/apps/dav/tests/unit/connector/sabre/auth.php
+++ b/apps/dav/tests/unit/connector/sabre/auth.php
@@ -295,16 +295,43 @@ class Auth extends TestCase {
 		$this->auth->authenticate($server, 'TestRealm');
 	}
 
-	public function testAuthenticateValidCredentials() {
+	/**
+	 * @expectedException \Sabre\DAV\Exception\NotAuthenticated
+	 * @expectedExceptionMessage Cannot authenticate over ajax calls
+	 */
+	public function testAuthenticateNoBasicAuthenticateHeadersProvidedWithAjax() {
 		$server = $this->getMockBuilder('\Sabre\DAV\Server')
 			->disableOriginalConstructor()
 			->getMock();
 		$server->httpRequest = $this->getMockBuilder('\Sabre\HTTP\RequestInterface')
 			->disableOriginalConstructor()
 			->getMock();
+		$server->httpResponse = $this->getMockBuilder('\Sabre\HTTP\ResponseInterface')
+			->disableOriginalConstructor()
+			->getMock();
 		$server->httpRequest
 			->expects($this->once())
 			->method('getHeader')
+			->with('X-Requested-With')
+			->will($this->returnValue('XMLHttpRequest'));
+		$this->auth->authenticate($server, 'TestRealm');
+	}
+
+	public function testAuthenticateValidCredentials() {
+		$server = $this->getMockBuilder('\Sabre\DAV\Server')
+			->disableOriginalConstructor()
+			->getMock();
+		$server->httpRequest = $this->getMockBuilder('\Sabre\HTTP\RequestInterface')
+			->disableOriginalConstructor()
+			->getMock();
+		$server->httpRequest
+			->expects($this->at(0))
+			->method('getHeader')
+			->with('X-Requested-With')
+			->will($this->returnValue(null));
+		$server->httpRequest
+			->expects($this->at(1))
+			->method('getHeader')
 			->with('Authorization')
 			->will($this->returnValue('basic dXNlcm5hbWU6cGFzc3dvcmQ='));
 		$server->httpResponse = $this->getMockBuilder('\Sabre\HTTP\ResponseInterface')
@@ -340,7 +367,12 @@ class Auth extends TestCase {
 			->disableOriginalConstructor()
 			->getMock();
 		$server->httpRequest
-			->expects($this->once())
+			->expects($this->at(0))
+			->method('getHeader')
+			->with('X-Requested-With')
+			->will($this->returnValue(null));
+		$server->httpRequest
+			->expects($this->at(1))
 			->method('getHeader')
 			->with('Authorization')
 			->will($this->returnValue('basic dXNlcm5hbWU6cGFzc3dvcmQ='));
-- 
GitLab