public function testDefaultXml() { $stream = fopen('php://memory', 'w+'); $encoder = new Horde_ActiveSync_Wbxml_Encoder($stream); $handler = new Horde_ActiveSync_Policies($encoder); $handler->toXml(); rewind($stream); $results = stream_get_contents($stream); fclose($stream); $fixture = file_get_contents(__DIR__ . '/fixtures/default_policies.xml'); $this->assertEquals($fixture, $results); }
/** * Handle the Provision request. This is a 3-phase process. Phase 1 is * actually the enforcement, when the server rejects a request and forces * the client to perform this PROVISION request...so we are handling phase * 2 (download policies) and 3 (acknowledge policies) here. * * @return boolean * @throws Horde_ActiveSync_Exception */ protected function _handle() { // Be optimistic $status = self::STATUS_SUCCESS; $policyStatus = self::STATUS_SUCCESS; if ($error = $this->_activeSync->checkGlobalError()) { $this->_globalError($error); return true; } // Start by assuming we are in stage 2 $phase2 = true; if (!$this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_PROVISION)) { return $this->_globalError(self::STATUS_PROTERROR); } // Handle remote wipe status response for Android devices. if ($this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_REMOTEWIPE)) { if (!$this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_STATUS)) { return $this->_globalError(self::STATUS_PROTERROR); } $status = $this->_decoder->getElementContent(); if (!$this->_decoder->getElementEndTag() || !$this->_decoder->getElementEndTag()) { return $this->_globalError(self::STATUS_PROTERROR); } if ($status == self::STATUS_CLIENT_SUCCESS) { $this->_state->setDeviceRWStatus($this->_devId, Horde_ActiveSync::RWSTATUS_WIPED); } $policytype = Horde_ActiveSync::POLICYTYPE_XML; } else { if ($deviceinfo = $this->_handleSettings()) { $deviceinfo['version'] = $this->_device->version; $this->_device->setDeviceProperties($deviceinfo); $this->_device->save(); } if (!$this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_POLICIES) || !$this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_POLICY)) { return $this->_globalError(self::STATUS_PROTERROR); } // iOS (at least 5.0.1) incorrectly sends a STATUS tag before the // REMOTEWIPE response. if (!$this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_POLICYTYPE)) { if ($this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_STATUS)) { $this->_decoder->getElementContent(); $this->_decoder->getElementEndTag(); // status } } else { $policytype = $this->_decoder->getElementContent(); if ($this->_device->version < Horde_ActiveSync::VERSION_TWELVE && $policytype != Horde_ActiveSync::POLICYTYPE_XML) { $this->_logger->err('EAS version < 12.0 but policy type is not POLICYTYPE_XML'); $policyStatus = self::STATUS_POLICYUNKNOWN; } if ($this->_device->version >= Horde_ActiveSync::VERSION_TWELVE && $policytype != Horde_ActiveSync::POLICYTYPE_WBXML) { $this->_logger->err('EAS version >= 12.0 but policy type is not POLICYTYPE_WBXML'); $policyStatus = self::STATUS_POLICYUNKNOWN; } if (!$this->_decoder->getElementEndTag()) { //policytype return $this->_globalError(self::STATUS_PROTERROR); } } // POLICYKEY is only sent by client in phase 3 if ($this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_POLICYKEY)) { $policykey = $this->_decoder->getElementContent(); $this->_logger->info('[' . $this->_device->id . '] PHASE 3 policykey sent from client: ' . $policykey); if (!$this->_decoder->getElementEndTag() || !$this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_STATUS)) { return $this->_globalError(self::STATUS_PROTERROR); } if ($this->_decoder->getElementContent() != self::STATUS_SUCCESS) { $this->_logger->err('Policy not accepted by device: ' . $this->_device->id); if ($this->_provisioning == Horde_ActiveSync::PROVISIONING_LOOSE) { // Loose provisioning, don't error out, just don't reqiure provision. $this->_sendNoProvisionNeededResponse($status); return true; } $policyStatus = self::STATUS_POLICYCORRUPT; } if (!$this->_decoder->getElementEndTag()) { return $this->_globalError(self::STATUS_PROTERROR); } $phase2 = false; } if (!$this->_decoder->getElementEndTag() || !$this->_decoder->getElementEndTag()) { return $this->_globalError(self::STATUS_PROTERROR); } // Handle remote wipe status for other devices if ($this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_REMOTEWIPE)) { if (!$this->_decoder->getElementStartTag(Horde_ActiveSync::PROVISION_STATUS)) { return $this->_globalError(self::STATUS_PROTERROR); } $status = $this->_decoder->getElementContent(); if (!$this->_decoder->getElementEndTag() || !$this->_decoder->getElementEndTag()) { return $this->_globalError(self::STATUS_PROTERROR); } if ($status == self::STATUS_CLIENT_SUCCESS) { $this->_state->setDeviceRWStatus($this->_device->id, Horde_ActiveSync::RWSTATUS_WIPED); } } } if (!$this->_decoder->getElementEndTag()) { //provision return $this->_globalError(self::STATUS_PROTERROR); } // Check to be sure that we *need* to PROVISION if ($this->_provisioning === false) { $this->_sendNoProvisionNeededResponse($status); return true; } // Start handling request and sending output $this->_encoder->StartWBXML(); // End of Phase 3 - We create the "final" policy key, store it, then // send it to the client. if (!$phase2) { // Verify intermediate key $this->_logger->info(sprintf('Verifying Phase 3 policykey: From Device: %s, Stored: %s', $policykey, $this->_device->policykey)); if ($this->_state->getPolicyKey($this->_device->id) != $policykey) { $policyStatus = self::STATUS_POLKEYMISM; } else { // Set the final key $policykey = $this->_state->generatePolicyKey(); $this->_state->setPolicyKey($this->_device->id, $policykey); $this->_state->setDeviceRWStatus($this->_device->id, Horde_ActiveSync::RWSTATUS_OK); } $this->_cleanUpAfterPairing(); } elseif (empty($policykey)) { // This is phase2 - we need to set the intermediate key $policykey = $this->_state->generatePolicyKey(); $this->_logger->info(sprintf('Generating PHASE2 policy key: %s', $policykey)); $this->_state->setPolicyKey($this->_device->id, $policykey); } // If we are phase2 we need to check this here, before the status is // sent. Prevents devices not supporting the required policies from // being able to connect. if ($phase2 && $status == self::STATUS_SUCCESS && $policyStatus == self::STATUS_SUCCESS && $this->_provisioning == Horde_ActiveSync::PROVISIONING_FORCE) { $policyHandler = new Horde_ActiveSync_Policies($this->_encoder, $this->_device->version, $this->_driver->getCurrentPolicy($deviceinfo)); if (!$policyHandler->validatePolicyVersion()) { $this->_handleVersionMismatch(); return true; } } $this->_encoder->startTag(Horde_ActiveSync::PROVISION_PROVISION); $this->_encoder->startTag(Horde_ActiveSync::PROVISION_STATUS); $this->_encoder->content($status); $this->_encoder->endTag(); $this->_encoder->startTag(Horde_ActiveSync::PROVISION_POLICIES); $this->_encoder->startTag(Horde_ActiveSync::PROVISION_POLICY); $this->_encoder->startTag(Horde_ActiveSync::PROVISION_POLICYTYPE); $this->_encoder->content($policytype); $this->_encoder->endTag(); $this->_encoder->startTag(Horde_ActiveSync::PROVISION_STATUS); $this->_encoder->content($policyStatus); $this->_encoder->endTag(); $this->_encoder->startTag(Horde_ActiveSync::PROVISION_POLICYKEY); $this->_encoder->content($policykey); $this->_encoder->endTag(); // Send security policies. if ($phase2 && $status == self::STATUS_SUCCESS && $policyStatus == self::STATUS_SUCCESS) { $this->_encoder->startTag(Horde_ActiveSync::PROVISION_DATA); if ($policytype == Horde_ActiveSync::POLICYTYPE_XML) { $policyHandler->toXml(); } else { $policyHandler->toWbxml(); } $this->_encoder->endTag(); //data } $this->_encoder->endTag(); //policy $this->_encoder->endTag(); //policies // Remote wipe if requested. $rwstatus = $this->_state->getDeviceRWStatus($this->_device->id); if ($rwstatus == Horde_ActiveSync::RWSTATUS_PENDING || $rwstatus == Horde_ActiveSync::RWSTATUS_WIPED) { $this->_encoder->startTag(Horde_ActiveSync::PROVISION_REMOTEWIPE, false, true); $this->_state->setDeviceRWStatus($this->_device->id, Horde_ActiveSync::RWSTATUS_WIPED); } $this->_encoder->endTag(); //provision return true; }
/** * Return a policy array suitable for transforming into either wbxml or xml * to send to the device in the provision response. * * @param boolean $deviceinfo EAS 14.1 DEVICESETTINGS sent with PROVISION. * * @return array */ protected function _getPolicyFromPerms($deviceinfo = false) { $prefix = 'horde:activesync:provisioning:'; $policy = array(); $perms = $GLOBALS['injector']->getInstance('Horde_Perms'); if (!$perms->exists('horde:activesync:provisioning')) { return $policy; } $policies = new Horde_ActiveSync_Policies(null, $this->_version); $properties = $policies->getAvailablePolicies(); foreach ($properties as $property) { if ($perms->exists($prefix . $property)) { $p = $perms->getPermissions($prefix . $property, $this->_user); $policy[$property] = $this->_getPolicyValue($property, $p); } } return $policy; }