diff --git a/lib/ext/Syncroton/Server.php b/lib/ext/Syncroton/Server.php --- a/lib/ext/Syncroton/Server.php +++ b/lib/ext/Syncroton/Server.php @@ -52,7 +52,10 @@ $this->_request = $request instanceof Zend_Controller_Request_Http ? $request : new Zend_Controller_Request_Http(); $this->_body = $body !== null ? $body : fopen('php://input', 'r'); - $this->_deviceBackend = Syncroton_Registry::getDeviceBackend(); + // Not available on unauthenticated OPTIONS request + if (!empty($this->_userId)) { + $this->_deviceBackend = Syncroton_Registry::getDeviceBackend(); + } } @@ -62,6 +65,13 @@ $this->_logger->debug(__METHOD__ . '::' . __LINE__ . ' REQUEST METHOD: ' . $this->_request->getMethod()); } + if ($this->_request->getMethod() != "OPTIONS" && empty($this->_userId)) { + $this->_logger->warn(__METHOD__ . '::' . __LINE__ . ' Not authenticated'); + header('WWW-Authenticate: Basic realm="ActiveSync for Kolab"'); + header('HTTP/1.1 401 Unauthorized'); + exit; + } + switch($this->_request->getMethod()) { case 'OPTIONS': $this->_handleOptions(); diff --git a/lib/kolab_sync.php b/lib/kolab_sync.php --- a/lib/kolab_sync.php +++ b/lib/kolab_sync.php @@ -135,12 +135,6 @@ $userid = $this->authenticate($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']); } - if (empty($userid)) { - header('WWW-Authenticate: Basic realm="' . $this->app_name . '"'); - header('HTTP/1.1 401 Unauthorized'); - exit; - } - $this->plugins->exec_hook('ready', ['task' => 'syncroton']); // Set log directory per-user (again, in case the username changed above) @@ -153,12 +147,15 @@ Syncroton_Registry::set(Syncroton_Registry::LOGGERBACKEND, $this->logger); Syncroton_Registry::set(Syncroton_Registry::DATABASE, $this->get_dbh()); Syncroton_Registry::set(Syncroton_Registry::TRANSACTIONMANAGER, kolab_sync_transaction_manager::getInstance()); - Syncroton_Registry::set(Syncroton_Registry::DEVICEBACKEND, new kolab_sync_backend_device()); - Syncroton_Registry::set(Syncroton_Registry::FOLDERBACKEND, new kolab_sync_backend_folder()); - Syncroton_Registry::set(Syncroton_Registry::SYNCSTATEBACKEND, new kolab_sync_backend_state()); - Syncroton_Registry::set(Syncroton_Registry::CONTENTSTATEBACKEND, new kolab_sync_backend_content()); - Syncroton_Registry::set(Syncroton_Registry::POLICYBACKEND, new kolab_sync_backend_policy()); - Syncroton_Registry::set(Syncroton_Registry::SLEEP_CALLBACK, [$this, 'sleep']); + // The unauthenticated OPTIONS request doesn't require these backends and we can't instantiate them without credentials for the underlying storage backend + if (!empty($userid)) { + Syncroton_Registry::set(Syncroton_Registry::DEVICEBACKEND, new kolab_sync_backend_device()); + Syncroton_Registry::set(Syncroton_Registry::FOLDERBACKEND, new kolab_sync_backend_folder()); + Syncroton_Registry::set(Syncroton_Registry::SYNCSTATEBACKEND, new kolab_sync_backend_state()); + Syncroton_Registry::set(Syncroton_Registry::CONTENTSTATEBACKEND, new kolab_sync_backend_content()); + Syncroton_Registry::set(Syncroton_Registry::POLICYBACKEND, new kolab_sync_backend_policy()); + Syncroton_Registry::set(Syncroton_Registry::SLEEP_CALLBACK, [$this, 'sleep']); + } Syncroton_Registry::setContactsDataClass('kolab_sync_data_contacts'); Syncroton_Registry::setCalendarDataClass('kolab_sync_data_calendar'); diff --git a/tests/Sync/OptionsTest.php b/tests/Sync/OptionsTest.php --- a/tests/Sync/OptionsTest.php +++ b/tests/Sync/OptionsTest.php @@ -7,7 +7,7 @@ */ public function testOptions() { - $response = self::$client->request('OPTIONS', ''); + $response = self::$client->request('OPTIONS', '', ['auth' => null]); $this->assertEquals(200, $response->getStatusCode()); $this->assertStringContainsString('14', $response->getHeader('MS-Server-ActiveSync')[0]); $this->assertStringContainsString('14.1', $response->getHeader('MS-ASProtocolVersions')[0]);