From c56b1bdb0065b752930f74eabe20f985722268ac Mon Sep 17 00:00:00 2001 From: xue <> Date: Sat, 11 Feb 2006 21:30:59 +0000 Subject: Added TSecurityManager and state encryption method. --- framework/Web/Services/TPageService.php | 26 ------- framework/Web/UI/TPage.php | 81 ++++++++++++++++++--- framework/Web/UI/TPageStatePersister.php | 116 ++++++++++--------------------- 3 files changed, 106 insertions(+), 117 deletions(-) (limited to 'framework/Web') diff --git a/framework/Web/Services/TPageService.php b/framework/Web/Services/TPageService.php index 463f2dec..393194a1 100644 --- a/framework/Web/Services/TPageService.php +++ b/framework/Web/Services/TPageService.php @@ -17,7 +17,6 @@ Prado::using('System.Web.UI.TPage'); Prado::using('System.Web.UI.TTemplateManager'); Prado::using('System.Web.UI.TThemeManager'); Prado::using('System.Web.UI.TAssetManager'); -Prado::using('System.Web.UI.TPageStatePersister'); /** * TPageService class. @@ -134,10 +133,6 @@ class TPageService extends TService * @var TTemplateManager template manager */ private $_templateManager=null; - /** - * @var IStatePersister page state persister - */ - private $_pageStatePersister=null; /** * Initializes the service. @@ -343,27 +338,6 @@ class TPageService extends TService $this->_themeManager=$value; } - /** - * @return IStatePersister page state persister - */ - public function getPageStatePersister() - { - if(!$this->_pageStatePersister) - { - $this->_pageStatePersister=new TPageStatePersister; - $this->_pageStatePersister->init(null); - } - return $this->_pageStatePersister; - } - - /** - * @param IStatePersister page state persister - */ - public function setPageStatePersister(IStatePersister $value) - { - $this->_pageStatePersister=$value; - } - /** * @return string the requested page path */ diff --git a/framework/Web/UI/TPage.php b/framework/Web/UI/TPage.php index 11f89ab5..78d9115e 100644 --- a/framework/Web/UI/TPage.php +++ b/framework/Web/UI/TPage.php @@ -129,6 +129,11 @@ class TPage extends TTemplateControl private $_isCrossPagePostBack=false; private $_previousPagePath=''; + private $_statePersisterClass='System.Web.UI.TPageStatePersister'; + private $_statePersister=null; + private $_enableStateHMAC=true; + private $_enableStateEncryption=false; + /** * Constructor. * Sets the page object to itself. @@ -513,14 +518,6 @@ class TPage extends TTemplateControl return $this->_postData!==null; } - /** - * @return IStatePersister page state persister - */ - protected function getPageStatePersister() - { - return $this->getService()->getPageStatePersister(); - } - /** * This method is invoked when control state is to be saved. * You can override this method to do last step state saving. @@ -548,7 +545,7 @@ class TPage extends TTemplateControl */ protected function loadPageState() { - $state=$this->getPageStatePersister()->load(); + $state=$this->getStatePersister()->load(); $this->loadStateRecursive($state,$this->getEnableViewState()); } @@ -558,7 +555,7 @@ class TPage extends TTemplateControl protected function savePageState() { $state=&$this->saveStateRecursive($this->getEnableViewState()); - $this->getPageStatePersister()->save($state); + $this->getStatePersister()->save($state); } /** @@ -806,6 +803,70 @@ class TPage extends TTemplateControl { $this->setViewState('Title',$value,''); } + + public function getStatePersisterClass() + { + return $this->_statePersisterClass; + } + + public function setStatePersisterClass($value) + { + $this->_statePersisterClass=$value; + } + + public function getStatePersister() + { + if($this->_statePersister===null) + { + $this->_statePersister=Prado::createComponent($this->_statePersisterClass); + if(!($this->_statePersister instanceof IPageStatePersister)) + throw new TInvalidDataTypeException('page_statepersister_invalid'); + $this->_statePersister->setPage($this); + } + return $this->_statePersister; + } + + public function getEnableStateHMAC() + { + return $this->_enableStateHMAC; + } + + public function setEnableStateHMAC($value) + { + $this->_enableStateHMAC=TPropertyValue::ensureBoolean($value); + } + + public function getEnableStateEncryption() + { + return $this->_enableStateEncryption; + } + + public function setEnableStateEncryption($value) + { + $this->_enableStateEncryption=TPropertyValue::ensureBoolean($value); + } +} + +interface IPageStatePersister +{ + /** + * @param TPage the page that this persister works for + */ + public function getPage(); + /** + * @param TPage the page that this persister works for + */ + public function setPage(TPage $page); + /** + * Saves state to persistent storage. + * @param string state to be stored + */ + public function save($state); + /** + * Loads page state from persistent storage + * @return string the restored state + */ + public function load(); } ?> \ No newline at end of file diff --git a/framework/Web/UI/TPageStatePersister.php b/framework/Web/UI/TPageStatePersister.php index 4ece9a09..746d93c8 100644 --- a/framework/Web/UI/TPageStatePersister.php +++ b/framework/Web/UI/TPageStatePersister.php @@ -14,36 +14,38 @@ * TPageStatePersister class * * TPageStatePersister implements a page state persistent method based on - * form hidden fields. It is the default way of storing page state. - * Should you need to access this module, you may get it via - * {@link TPageService::getPageStatePersister}. + * form hidden fields. * - * TPageStatePersister uses a private key to generate a private unique hash - * code to prevent the page state from being tampered. - * By default, the private key is a randomly generated string. - * You may specify it explicitly by setting the {@link setPrivateKey PrivateKey} property. - * This may be useful if your application is running on a server farm. + * Depending on the {@link TPage::getEnableStateHMAC() EnableStateHMAC} + * and {@link TPage::getEnableStateEncryption() EnableStateEncryption}, + * TPageStatePersister may do HMAC validation and encryption to prevent + * the state data from being tampered or viewed. + * The private keys and hashing/encryption methods are determined by + * {@link TApplication::getSecurityManager() SecurityManager}. * * @author Qiang Xue * @version $Revision: $ $Date: $ * @package System.Web.UI * @since 3.0 */ -class TPageStatePersister extends TModule implements IStatePersister +class TPageStatePersister extends TComponent implements IPageStatePersister { + private $_page; + /** - * @var string private key + * @param TPage the page that this persister works for */ - private $_privateKey=null; + public function getPage() + { + return $this->_page; + } /** - * Registers the module with the page service. - * This method is required by IModule interface and is invoked when the module is initialized. - * @param TXmlElement module configuration + * @param TPage the page that this persister works for */ - public function init($config) + public function setPage(TPage $page) { - $this->getService()->setPageStatePersister($this); + $this->_page=$page; } /** @@ -53,13 +55,15 @@ class TPageStatePersister extends TModule implements IStatePersister public function save($state) { Prado::trace("Saving state",'System.Web.UI.TPageStatePersister'); - $data=Prado::serialize($state); - $hmac=$this->computeHMAC($data,$this->getPrivateKey()); - if(extension_loaded('zlib')) - $data=gzcompress($hmac.$data); + if($this->_page->getEnableStateHMAC()) + $data=$this->getApplication()->getSecurityManager()->hashData(Prado::serialize($state)); else - $data=$hmac.$data; - $this->getService()->getRequestedPage()->getClientScript()->registerHiddenField(TPage::FIELD_PAGESTATE,base64_encode($data)); + $data=Prado::serialize($state); + if($this->_page->getEnableStateEncryption()) + $data=$this->getApplication()->getSecurityManager()->encrypt($data); + if(extension_loaded('zlib')) + $data=gzcompress($data); + $this->_page->getClientScript()->registerHiddenField(TPage::FIELD_PAGESTATE,base64_encode($data)); } /** @@ -77,69 +81,19 @@ class TPageStatePersister extends TModule implements IStatePersister $data=gzuncompress($str); else $data=$str; - if($data!==false && strlen($data)>32) + if($data!==false) { - $hmac=substr($data,0,32); - $state=substr($data,32); - if($hmac===$this->computeHMAC($state,$this->getPrivateKey())) - return Prado::unserialize($state); - } - throw new THttpException(400,'pagestatepersister_pagestate_corrupted'); - } - - /** - * Generates a random private key used for hashing the state. - * You may override this method to provide your own way of private key generation. - * @return string the rondomly generated private key - */ - protected function generatePrivateKey() - { - $v1=rand(); - $v2=rand(); - $v3=rand(); - return md5("$v1$v2$v3"); - } - - /** - * @return string private key used for hashing the state. - */ - public function getPrivateKey() - { - if(empty($this->_privateKey)) - { - if(($this->_privateKey=$this->getApplication()->getGlobalState('prado:pagestatepersister:privatekey'))===null) + if($this->_page->getEnableStateEncryption()) + $data=$this->getApplication()->getSecurityManager()->decrypt($data); + if($this->_page->getEnableStateHMAC()) { - $this->_privateKey=$this->generatePrivateKey(); - $this->getApplication()->setGlobalState('prado:pagestatepersister:privatekey',$this->_privateKey,null); + if(($data=$this->getApplication()->getSecurityManager()->validateData($data))!==null) + return Prado::unserialize($data); } + else + return $data; } - return $this->_privateKey; - } - - /** - * @param string private key used for hashing the state. - * @throws TInvalidDataValueException if the length of the private key is shorter than 8. - */ - public function setPrivateKey($value) - { - if(strlen($value)<8) - throw new TInvalidDataValueException('pagestatepersister_privatekey_invalid'); - $this->_privateKey=$value; - } - - /** - * Computes a hashing code based on the input data and the private key. - * @param string input data - * @param string the private key - * @return string the hashing code - */ - private function computeHMAC($data,$key) - { - if (strlen($key) > 64) - $key = pack('H32', md5($key)); - else if (strlen($key) < 64) - $key = str_pad($key, 64, "\0"); - return md5((str_repeat("\x5c", 64) ^ substr($key, 0, 64)) . pack('H32', md5((str_repeat("\x36", 64) ^ substr($key, 0, 64)) . $data))); + throw new THttpException(400,'pagestatepersister_pagestate_corrupted'); } } -- cgit v1.2.3