Author: Michael J Rubinsky (mrubinsk@horde.org)
Exemplo n.º 1
0
Arquivo: Base.php Projeto: horde/horde
 /**
  * @return [type] [description]
  */
 protected function _testListDevices()
 {
     $devices = self::$state->listDevices();
     $this->assertCount(1, $devices);
     $deviceInfo = new Horde_ActiveSync_Device(self::$state);
     $deviceInfo->rwstatus = 0;
     $deviceInfo->deviceType = 'Test Device';
     $deviceInfo->userAgent = 'Horde Tests';
     $deviceInfo->id = 'dev123';
     $deviceInfo->user = '******';
     $deviceInfo->policykey = 123;
     $deviceInfo->supported = array();
     $deviceInfo->save();
     $devices = self::$state->listDevices();
     $this->assertCount(2, $devices);
 }
Exemplo n.º 2
0
 public function testPoomContactsDate()
 {
     $tz = date_default_timezone_get();
     date_default_timezone_set('America/New_York');
     $state = $this->getMockSkipConstructor('Horde_ActiveSync_State_Base');
     // WindowsPhone.
     $fixture = array('deviceType' => 'windowsphone');
     $device = new Horde_ActiveSync_Device($state, $fixture);
     $date = new Horde_Date('2003-09-24', 'UTC');
     $bday = $device->normalizePoomContactsDates($date);
     $this->assertEquals('2003-09-24 00:00:00', (string) $bday);
     $this->assertEquals('America/New_York', $bday->timezone);
     // Android
     date_default_timezone_set('Pacific/Honolulu');
     $fixture = array('deviceType' => 'android', 'userAgent' => 'Android/4.3.1-EAS-1.3');
     $device = new Horde_ActiveSync_Device($state, $fixture);
     $date = new Horde_Date('2003-09-24 08:00:00', 'UTC');
     $bday = $device->normalizePoomContactsDates($date);
     $this->assertEquals('2003-09-24 00:00:00', (string) $bday);
     $this->assertEquals('Pacific/Honolulu', $bday->timezone);
     date_default_timezone_set($tz);
 }
Exemplo n.º 3
0
 public function testPoomContactsDate()
 {
     $tz = date_default_timezone_get();
     date_default_timezone_set('America/New_York');
     $state = $this->getMockSkipConstructor('Horde_ActiveSync_State_Base');
     // WindowsPhone.
     $fixture = array('deviceType' => 'windowsphone');
     $device = new Horde_ActiveSync_Device($state, $fixture);
     $date = new Horde_Date('2003-09-24', 'UTC');
     $bday = $device->normalizePoomContactsDates($date);
     $this->assertEquals('2003-09-24', $bday->setTimezone('America/New_York')->format('Y-m-d'));
     // iOS (Sends as 00:00:00 localtime converted to UTC).
     $fixture = array('deviceType' => 'iPhone', 'userAgent' => 'Apple-iPhone4C1/1002.329', 'properties' => array(Horde_ActiveSync_Device::OS => 'iOS 6.1.3 10B329'));
     $device = new Horde_ActiveSync_Device($state, $fixture);
     $date = new Horde_Date('1970-03-20');
     $bday = $device->normalizePoomContactsDates($date, true);
     $this->assertEquals('1970-03-20 00:00:00', (string) $bday);
     $date = new Horde_Date('1970-03-20T05:00:00.000Z');
     $bday = $device->normalizePoomContactsDates($date);
     $this->assertEquals('1970-03-20 00:00:00', (string) $bday->setTimezone('America/New_York'));
     // Try a positive UTC offset timezone
     date_default_timezone_set('Europe/Berlin');
     $fixture = array('deviceType' => 'iPhone', 'userAgent' => 'Apple-iPhone4C1/1104.201', 'properties' => array(Horde_ActiveSync_Device::OS => 'iOS 7.1.1 11D201'));
     $device = new Horde_ActiveSync_Device($state, $fixture);
     $date = new Horde_Date('1966-07-22T23:00:00.000Z');
     $bday = $device->normalizePoomContactsDates($date);
     $bday->setTimezone(date_default_timezone_get());
     $this->assertEquals('1966-07-23', $bday->format('Y-m-d'));
     // Android
     date_default_timezone_set('Pacific/Honolulu');
     $fixture = array('deviceType' => 'android', 'userAgent' => 'Android/4.3.1-EAS-1.3');
     $device = new Horde_ActiveSync_Device($state, $fixture);
     $date = new Horde_Date('2003-09-24 08:00:00', 'UTC');
     $bday = $device->normalizePoomContactsDates($date);
     $this->assertEquals('2003-09-24', $bday->setTimezone('Pacific/Honolulu')->format('Y-m-d'));
     // Note 3
     date_default_timezone_set('America/Chicago');
     $fixture = array('deviceType' => 'SAMSUNGSMN900V', 'userAgent' => 'SAMSUNG-SM-N900V/101.403', 'properties' => array(Horde_ActiveSync_Device::OS => 'Android'));
     $device = new Horde_ActiveSync_Device($state, $fixture);
     $date = new Horde_Date('1970-03-20');
     $bday = $device->normalizePoomContactsDates($date, true);
     $this->assertEquals('1970-03-20 00:00:00', (string) $bday);
     $fixture = array('deviceType' => 'Android', 'userAgent' => 'hltevzw/KOT49H', 'properties' => array(Horde_ActiveSync_Device::OS => 'Android 4.4.2.N900VVRUCNC4'));
     $device = new Horde_ActiveSync_Device($state, $fixture);
     $device->id = '6E696E656331393035333833303331';
     $date = new Horde_Date('1970-03-20');
     $bday = $device->normalizePoomContactsDates($date, true);
     $this->assertEquals('1970-03-20 00:00:00', (string) $bday);
     date_default_timezone_set($tz);
 }
Exemplo n.º 4
0
 /**
  * Handle device checks. Takes into account permissions and restrictions
  * via various callback methods.
  *
  * @param  string $devId  The client provided device id.
  *
  * @return boolean  If EAS version is > 12.1 returns false on any type of
  *                  failure in allowing the device to connect. Sets
  *                  appropriate internal variables to indicate the type of
  *                  error to return to the client. Failure on EAS version
  *                  < 12.1 results in throwing exceptions. Otherwise, return
  *                  true.
  * @throws Horde_ActiveSync_Exception, Horde_Exception_AuthenticationFailure
  */
 protected function _handleDevice($devId)
 {
     $get = $this->getGetVars();
     $version = $this->getProtocolVersion();
     // Does device exist AND does the user have an account on the device?
     if (!$this->_state->deviceExists($devId, $this->_driver->getUser())) {
         // Device might exist, but with a new (additional) user account
         if ($this->_state->deviceExists($devId)) {
             self::$_device = $this->_state->loadDeviceInfo($devId);
         } else {
             self::$_device = new Horde_ActiveSync_Device($this->_state);
         }
         self::$_device->policykey = 0;
         self::$_device->userAgent = $this->_request->getHeader('User-Agent');
         self::$_device->deviceType = !empty($get['DeviceType']) ? $get['DeviceType'] : '';
         self::$_device->rwstatus = self::RWSTATUS_NA;
         self::$_device->user = $this->_driver->getUser();
         self::$_device->id = $devId;
         self::$_device->needsVersionUpdate($this->getSupportedVersions());
         self::$_device->version = $version;
         // @TODO: Remove is_callable check for H6.
         //        Combine this with the modifyDevice callback? Allow $device
         //        to be modified here?
         if (is_callable(array($this->_driver, 'createDeviceCallback'))) {
             $callback_ret = $this->_driver->createDeviceCallback(self::$_device);
             if ($callback_ret !== true) {
                 $msg = sprintf('The device %s was disallowed for user %s per policy settings.', self::$_device->id, self::$_device->user);
                 self::$_logger->err($msg);
                 // Always throw exception in place of status code since we
                 // won't have a version number before the device is created.
                 throw new Horde_Exception_AuthenticationFailure($msg, $callback_ret);
             } else {
                 // Give the driver a chance to modify device properties.
                 if (is_callable(array($this->_driver, 'modifyDeviceCallback'))) {
                     self::$_device = $this->_driver->modifyDeviceCallback(self::$_device);
                 }
             }
         }
     } else {
         self::$_device = $this->_state->loadDeviceInfo($devId, $this->_driver->getUser());
         // If the device state was removed from storage, we may lose the
         // device properties, so try to repopulate what we can. userAgent
         // is ALWAYS available, so if it's missing, the state is gone.
         if (empty(self::$_device->userAgent)) {
             self::$_device->userAgent = $this->_request->getHeader('User-Agent');
             self::$_device->deviceType = !empty($get['DeviceType']) ? $get['DeviceType'] : '';
             self::$_device->user = $this->_driver->getUser();
         }
         if (empty(self::$_device->version)) {
             self::$_device->version = $version;
         }
         if (self::$_device->version < $this->_maxVersion && self::$_device->needsVersionUpdate($this->getSupportedVersions())) {
             $this->_needMsRp = true;
         }
         // Give the driver a chance to modify device properties.
         if (is_callable(array($this->_driver, 'modifyDeviceCallback'))) {
             self::$_device = $this->_driver->modifyDeviceCallback(self::$_device);
         }
     }
     // Save the device now that we know it is at least allowed to connect,
     // or it has connected successfully at least once in the past.
     self::$_device->save();
     if (is_callable(array($this->_driver, 'deviceCallback'))) {
         $callback_ret = $this->_driver->deviceCallback(self::$_device);
         if ($callback_ret !== true) {
             $msg = sprintf('The device %s was disallowed for user %s per policy settings.', self::$_device->id, self::$_device->user);
             self::$_logger->err($msg);
             if ($version > self::VERSION_TWELVEONE) {
                 // Use a status code here, since the device has already
                 // connected.
                 $this->_globalError = $callback_ret;
                 return false;
             } else {
                 throw new Horde_Exception_AuthenticationFailure($msg, $callback_ret);
             }
         }
     }
     // Lastly, check if the device has been set to blocked.
     if (self::$_device->blocked) {
         $msg = sprintf('The device %s was blocked.', self::$_device->id);
         self::$_logger->err($msg);
         if ($version > self::VERSION_TWELVEONE) {
             $this->_globalError = Horde_ActiveSync_Status::DEVICE_BLOCKED_FOR_USER;
             return false;
         } else {
             throw new Horde_ActiveSync_Exception($msg);
         }
     }
     return true;
 }
Exemplo n.º 5
0
 /**
  * Ensure the client's policy key is current.
  *
  * @param string $sentKey      The policykey sent to us by the client
  * @param string $requestType  The type of request we are handling. A
  *                             Horde_ActiveSync constant.
  *
  * @return boolean
  */
 public function checkPolicyKey($sentKey, $requestType = null)
 {
     $this->_logger->info(sprintf('[%s] Checking policykey for device: %s user: %s', $this->_procid, $this->_device->id, $this->_driver->getUser()));
     // Use looseprovisioning?
     if (empty($sentKey) && !$this->_device->enforceProvisioning() && $this->_provisioning === Horde_ActiveSync::PROVISIONING_LOOSE) {
         $sentKey = null;
         $this->_logger->info(sprintf('[%s] Allowing %s to connect since PROVISIONING_LOOSE is true and is either non-provisionable or has broken provisioning.', $this->_procid, $this->_device->id));
     } elseif (empty($sentKey) && $this->_device->isNonProvisionable()) {
         // Check for non-provisionable, but allowable, devices.
         $this->_logger->info(sprintf('[%s] Allowing %s to connect since it is non-provisionable.', $this->_procid, $this->_device->id));
         $sentKey = null;
     }
     // Don't attempt if we don't care
     if ($this->_provisioning !== Horde_ActiveSync::PROVISIONING_NONE) {
         // Get the stored key
         $storedKey = $this->_state->getPolicyKey($this->_device->id);
         $this->_logger->info(sprintf('[%s] Stored key: %s', $this->_procid, $storedKey));
         // Did we request a remote wipe?
         if ($this->_state->getDeviceRWStatus($this->_device->id) == Horde_ActiveSync::RWSTATUS_PENDING) {
             $this->_requireProvisionWbxml($requestType, Horde_ActiveSync_Status::REMOTEWIPE_REQUESTED);
             return false;
         }
         // Validate the stored key against the device key, honoring
         // the value of _provisioning.
         if ((empty($storedKey) || $storedKey != $sentKey) && ($this->_provisioning != Horde_ActiveSync::PROVISIONING_LOOSE || $this->_provisioning == Horde_ActiveSync::PROVISIONING_LOOSE && !is_null($sentKey))) {
             // We send the headers AND the WBXML if EAS 12.1+ since some
             // devices report EAS 14.1 but don't accept the WBXML.
             $this->_activeSync->provisioningRequired();
             if ($this->_device->version > Horde_ActiveSync::VERSION_TWELVEONE) {
                 if (empty($sentKey)) {
                     $status = Horde_ActiveSync_Status::DEVICE_NOT_PROVISIONED;
                 } else {
                     $status = Horde_ActiveSync_Status::INVALID_POLICY_KEY;
                 }
                 $this->_requireProvisionWbxml($requestType, Horde_ActiveSync_Status::DEVICE_NOT_PROVISIONED);
             }
             return false;
         }
     }
     // Either successfully validated, or we didn't care enough to check.
     $this->_logger->info(sprintf('[%s] Policykey: %s verified.', $this->_procid, $sentKey));
     return true;
 }
Exemplo n.º 6
0
 /**
  * The heart of the server. Dispatch a request to the appropriate request
  * handler.
  *
  * @param string $cmd    The command we are requesting.
  * @param string $devId  The device id making the request. @deprecated
  *
  * @return string|boolean  false if failed, true if succeeded and response
  *                         content is wbxml, otherwise the
  *                         content-type string to send in the response.
  * @throws Horde_ActiveSync_Exception
  * @throws Horde_ActiveSync_Exception_InvalidRequest
  * @throws Horde_ActiveSync_PermissionDenied
  */
 public function handleRequest($cmd, $devId)
 {
     $get = $this->getGetVars();
     if (empty($cmd)) {
         $cmd = $get['Cmd'];
     }
     if (empty($devId)) {
         $devId = !empty($get['DeviceId']) ? Horde_String::upper($get['DeviceId']) : null;
     } else {
         $devId = Horde_String::upper($devId);
     }
     $this->_setLogger($get);
     // @TODO: Remove is_callable check for H6.
     // Callback to give the backend the option to limit EAS version based
     // on user/device/etc...
     if (is_callable(array($this->_driver, 'versionCallback'))) {
         $this->_driver->versionCallback($this);
     }
     // Autodiscovery handles authentication on it's own.
     if ($cmd == 'Autodiscover') {
         $request = new Horde_ActiveSync_Request_Autodiscover($this, new Horde_ActiveSync_Device($this->_state));
         if (!empty(self::$_logger)) {
             $request->setLogger(self::$_logger);
         }
         $result = $request->handle($this->_request);
         $this->_driver->clearAuthentication();
         return $result;
     }
     if (!$this->authenticate(new Horde_ActiveSync_Credentials($this))) {
         $this->activeSyncHeader();
         $this->versionHeader();
         $this->commandsHeader();
         throw new Horde_Exception_AuthenticationFailure();
     }
     self::$_logger->info(sprintf('[%s] %s request received for user %s', $this->_procid, Horde_String::upper($cmd), $this->_driver->getUser()));
     // These are all handled in the same class.
     if ($cmd == 'FolderDelete' || $cmd == 'FolderUpdate') {
         $cmd = 'FolderCreate';
     }
     // Device id is REQUIRED
     if (empty($devId)) {
         if ($cmd == 'Options') {
             $this->_doOptionsRequest();
             $this->_driver->clearAuthentication();
             return true;
         }
         $this->_driver->clearAuthentication();
         throw new Horde_ActiveSync_Exception_InvalidRequest('Device failed to send device id.');
     }
     // EAS Version
     $version = $this->getProtocolVersion();
     // Does device exist AND does the user have an account on the device?
     if (!$this->_state->deviceExists($devId, $this->_driver->getUser())) {
         // Device might exist, but with a new (additional) user account
         if ($this->_state->deviceExists($devId)) {
             self::$_device = $this->_state->loadDeviceInfo($devId);
         } else {
             self::$_device = new Horde_ActiveSync_Device($this->_state);
         }
         self::$_device->policykey = 0;
         self::$_device->userAgent = $this->_request->getHeader('User-Agent');
         self::$_device->deviceType = !empty($get['DeviceType']) ? $get['DeviceType'] : '';
         self::$_device->rwstatus = self::RWSTATUS_NA;
         self::$_device->user = $this->_driver->getUser();
         self::$_device->id = $devId;
         self::$_device->needsVersionUpdate($this->getSupportedVersions());
         self::$_device->version = $version;
         // @TODO: Remove is_callable check for H6.
         //        Combine this with the modifyDevice callback? Allow $device
         //        to be modified here?
         if (is_callable(array($this->_driver, 'createDeviceCallback'))) {
             $callback_ret = $this->_driver->createDeviceCallback(self::$_device);
             if ($callback_ret !== true) {
                 $msg = sprintf('The device %s was disallowed for user %s per policy settings.', self::$_device->id, self::$_device->user);
                 self::$_logger->err($msg);
                 if ($version > self::VERSION_TWELVEONE) {
                     $this->_globalError = $callback_ret;
                 } else {
                     throw new Horde_ActiveSync_Exception($msg);
                 }
             } else {
                 // Give the driver a chance to modify device properties.
                 if (is_callable(array($this->_driver, 'modifyDeviceCallback'))) {
                     self::$_device = $this->_driver->modifyDeviceCallback(self::$_device);
                 }
             }
         }
     } else {
         self::$_device = $this->_state->loadDeviceInfo($devId, $this->_driver->getUser());
         // If the device state was removed from storage, we may lose the
         // device properties, so try to repopulate what we can. userAgent
         // is ALWAYS available, so if it's missing, the state is gone.
         if (empty(self::$_device->userAgent)) {
             self::$_device->userAgent = $this->_request->getHeader('User-Agent');
             self::$_device->deviceType = !empty($get['DeviceType']) ? $get['DeviceType'] : '';
             self::$_device->user = $this->_driver->getUser();
         }
         if (empty(self::$_device->version)) {
             self::$_device->version = $version;
         }
         if (self::$_device->version < $this->_maxVersion && self::$_device->needsVersionUpdate($this->getSupportedVersions())) {
             $needMsRp = true;
         }
         // Give the driver a chance to modify device properties.
         if (is_callable(array($this->_driver, 'modifyDeviceCallback'))) {
             self::$_device = $this->_driver->modifyDeviceCallback(self::$_device);
         }
     }
     self::$_device->save();
     if (is_callable(array($this->_driver, 'deviceCallback'))) {
         $callback_ret = $this->_driver->deviceCallback(self::$_device);
         if ($callback_ret !== true) {
             $msg = sprintf('The device %s was disallowed for user %s per policy settings.', self::$_device->id, self::$_device->user);
             self::$_logger->err($msg);
             if ($version > self::VERSION_TWELVEONE) {
                 $this->_globalError = $callback_ret;
             } else {
                 throw new Horde_ActiveSync_Exception($msg);
             }
         }
     }
     // Lastly, check if the device has been set to blocked.
     if (self::$_device->blocked) {
         $msg = sprintf('The device %s was blocked.', self::$_device->id);
         self::$_logger->err($msg);
         if ($version > self::VERSION_TWELVEONE) {
             $this->_globalError = Horde_ActiveSync_Status::DEVICE_BLOCKED_FOR_USER;
         } else {
             throw new Horde_ActiveSync_Exception($msg);
         }
     }
     // Don't bother with everything else if all we want are Options
     if ($cmd == 'Options') {
         $this->_doOptionsRequest();
         $this->_driver->clearAuthentication();
         return true;
     }
     // Set provisioning support now that we are authenticated.
     $this->setProvisioning($this->_driver->getProvisioning(self::$_device));
     // Read the initial Wbxml header
     $this->_decoder->readWbxmlHeader();
     // Support Multipart response for ITEMOPERATIONS requests?
     $headers = $this->_request->getHeaders();
     if (!empty($headers['ms-asacceptmultipart']) && $headers['ms-asacceptmultipart'] == 'T' || !empty($get['AcceptMultiPart'])) {
         $this->_multipart = true;
         self::$_logger->info(sprintf('[%s] Requesting multipart data.', $this->_procid));
     }
     // Load the request handler to handle the request
     // We must send the eas header here, since some requests may start
     // output and be large enough to flush the buffer (e.g., GetAttachment)
     // See Bug: 12486
     $this->activeSyncHeader();
     if ($cmd != 'GetAttachment') {
         $this->contentTypeHeader();
     }
     // Should we announce a new version is available to the client?
     if (!empty($needMsRp)) {
         self::$_logger->info(sprintf('[%s] Announcing X-MS-RP to client.', $this->_procid));
         header("X-MS-RP: " . $this->getSupportedVersions());
     }
     // @TODO: Look at getting rid of having to set the version in the driver
     //        and get it from the device object for H6.
     $this->_driver->setDevice(self::$_device);
     $class = 'Horde_ActiveSync_Request_' . basename($cmd);
     if (class_exists($class)) {
         $request = new $class($this);
         $request->setLogger(self::$_logger);
         $result = $request->handle();
         self::$_logger->info(sprintf('[%s] Maximum memory usage for ActiveSync request: %d bytes.', $this->_procid, memory_get_peak_usage(true)));
         return $result;
     }
     $this->_driver->clearAuthentication();
     throw new Horde_ActiveSync_Exception_InvalidRequest(basename($cmd) . ' not supported.');
 }