Changeset 2213

Show
Ignore:
Timestamp:
09/10/2007 09:09:27 PM
Author:
xue
Message:

Fixed #692, #700.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/HISTORY

    r2211 r2213  
    1919ENH: Ticket#678 - Improved DateTimeFormatInfo performance (Stever) 
    2020ENH: Ticket#681 - TUrlMapping can construct custom URLs now (Qiang) 
     21ENH: Ticket#692,700 - Added support to wildcard in pages configuration; added IP filters in auth rules. (Qiang) 
    2122ENH: Added THead requirement check (Qiang) 
    2223ENH: Added TOutputCache.CacheTime (Qiang) 
  • trunk/demos/quickstart/protected/pages/Advanced/Auth.page

    r2012 r2213  
    7575In the above example, anonymous users will be denied from posting to <tt>PageID1</tt> and <tt>PageID2</tt>, while <tt>User1</tt> and <tt>User2</tt> and all users of role <tt>Role1</tt> can access the two pages (in both <tt>get</tt> and <tt>post</tt> methods). 
    7676</p> 
     77<com:SinceVersion Version="3.1.1" /> 
     78<p class="block-content"> 
     79Since version 3.1.1, the <tt>pages</tt> attribute in the authorization rules can take relative page paths with wildcard '*'. For example, <tt>pages="admin.Home"</tt> refers to the <tt>Home</tt> page under the <tt>admin</tt> directory, and <tt>pages="admin.*"</tt> would refer to all pages under the <tt>admin</tt> directory and subdirectories. 
     80</p> 
     81 
     82<p class="block-content"> 
     83Also introduced in version 3.1.1 are IP rules. They are specified by a new attribute <tt>ip</tt> in authorization rules. The IP rules are used to determine if an authorization rule aplies to an end-user according to his IP address. One can list a few IPs together, separated by comma ','. Wildcard '*' can be used in the rules. For example, <tt>ip="192.168.0.2, 192.168.1.*"</tt> means the rule applies to users whose IP address is 192.168.0.2 or 192.168.1.*. The latter matches any host in the subnet 192.168.1. 
     84</p> 
    7785 
    7886<h2 id="5504">Using <tt>TUserManager</tt></h2> 
  • trunk/demos/quickstart/protected/pages/Configurations/PageConfig.page

    r1695 r2213  
    4040</p> 
    4141 
     42<com:SinceVersion Version="3.1.1" /> 
     43<p class="block-content"> 
     44Since version 3.1.1, the <tt>id</tt> attribute in the &lt;page&gt; element can be a relative page path pointing to a page in the subdirectory of the directory containing the page configuration. For example, <tt>id="admin.Home"</tt> refers to the <tt>Home</tt> page under the <tt>admin</tt> directory. This enhancement allows developers to centralize their page configurations (e.g. put all page initializations in the aplication configuration or the root page configuration.) 
     45</p> 
     46 
    4247<div class="last-modified">$Id$</div></com:TContent> 
  • trunk/demos/quickstart/protected/pages/GettingStarted/NewFeatures.page

    r2211 r2213  
    1414<li>Added a new control <a href="?page=Controls.Slider">TSlider</a> that displays a slider which can be used for numeric input.</li> 
    1515<li>Added Oracle DB support to Active Record.</li> 
    16 <li>Added support of TDataGrid to allow grouping consecutive cells with the same content.</li> 
     16<li>Added support to TDataGrid to allow grouping consecutive cells with the same content.</li> 
     17<li>Added support to allow configuring page properties and authorization rules using <a href="?page=Configurations.PageConfig">relative page paths</a> in application and page configurations. Added support to allow <a href="?page=Advanced.Auth">authorization</a> based on remote host address.</li> 
    1718</ul> 
    1819 
  • trunk/framework/Exceptions/TErrorHandler.php

    r2112 r2213  
    301301                // because the 1st stack level is of little use (it's in error handler) 
    302302                if($exception instanceof TPhpErrorException) 
    303                         $result=$trace[1]; 
     303                        $result=isset($trace[0]['file'])?$trace[0]:$trace[1]; 
    304304                else if($exception instanceof TInvalidOperationException) 
    305305                { 
  • trunk/framework/Security/TAuthorizationRule.php

    r2012 r2213  
    1515 * TAuthorizationRule represents a single authorization rule. 
    1616 * A rule is specified by an action (required), a list of users (optional), 
    17  * a list of roles (optional), and a verb (optional). 
     17 * a list of roles (optional), a verb (optional), and a list of IP rules (optional). 
    1818 * Action can be either 'allow' or 'deny'. 
    1919 * Guest (anonymous, unauthenticated) users are represented by question mark '?'. 
     
    2323 * Different users/roles are separated by comma ','. 
    2424 * Verb can be either 'get' or 'post'. If it is absent, it means both. 
     25 * IP rules are separated by comma ',' and can contain wild card in the rules (e.g. '192.132.23.33, 192.122.*.*') 
    2526 * 
    2627 * @author Qiang Xue <qiang.xue@gmail.com> 
     
    4849        private $_verb; 
    4950        /** 
     51         * @var string IP patterns 
     52         */ 
     53        private $_ipRules; 
     54        /** 
    5055         * @var boolean if this rule applies to everyone 
    5156         */ 
     
    6671         * @param string a comma separated role list 
    6772         * @param string verb, can be empty, 'get', or 'post' 
    68          */ 
    69         public function __construct($action,$users,$roles,$verb='') 
     73         * @param string IP rules (separated by comma, can contain wild card *) 
     74         */ 
     75        public function __construct($action,$users,$roles,$verb='',$ipRules='') 
    7076        { 
    7177                $action=strtolower(trim($action)); 
     
    7682                $this->_users=array(); 
    7783                $this->_roles=array(); 
     84                $this->_ipRules=array(); 
    7885                $this->_everyone=false; 
    7986                $this->_guest=false; 
     
    106113                else 
    107114                        throw new TInvalidDataValueException('authorizationrule_verb_invalid',$verb); 
     115                foreach(explode(',',$ipRules) as $ipRule) 
     116                { 
     117                        if(($ipRule=trim($ipRule))!=='') 
     118                                $this->_ipRules[]=$ipRule; 
     119                } 
    108120        } 
    109121 
     
    138150        { 
    139151                return $this->_verb; 
     152        } 
     153 
     154        /** 
     155         * @return array list of IP rules. 
     156         * @since 3.1.1 
     157         */ 
     158        public function getIPRules() 
     159        { 
     160                return $this->_ipRules; 
    140161        } 
    141162 
     
    172193                if($this->_verb==='' || strcasecmp($verb,$this->_verb)===0) 
    173194                { 
     195                        if(!$this->isHostAddressMatched()) 
     196                                return 0; 
    174197                        if($this->_everyone || ($this->_guest && $user->getIsGuest()) || ($this->_authenticated && !$user->getIsGuest())) 
    175198                                return $decision; 
     
    182205                return 0; 
    183206        } 
     207 
     208        private function isHostAddressMatched() 
     209        { 
     210                if(empty($this->_ipRules)) 
     211                        return 1; 
     212                $ip=Prado::getApplication()->getRequest()->getUserHostAddress(); 
     213                foreach($this->_ipRules as $rule) 
     214                { 
     215                        if($rule===$ip) 
     216                                return 1; 
     217                        if(strpos($rule,'*')!==false) 
     218                        { 
     219                                $a=explode('.',$rule); 
     220                                $b=explode('.',$ip); 
     221                                if(isset($a[3]) && isset($b[3])) 
     222                                { 
     223                                        $matched=true; 
     224                                        for($i=0;$i<4;++$i) 
     225                                        { 
     226                                                if($a[$i]!==$b[i] && $a[$i]!=='*') 
     227                                                { 
     228                                                        $matched=false; 
     229                                                        break; 
     230                                                } 
     231                                        } 
     232                                        if($matched) 
     233                                                return 1; 
     234                                } 
     235                        } 
     236                } 
     237                return 0; 
     238        } 
    184239} 
    185240 
  • trunk/framework/Web/Services/TPageService.php

    r2112 r2213  
    138138                Prado::trace("Initializing TPageService",'System.Web.Services.TPageService'); 
    139139 
    140                 $pageConfig=$this->loadPageConfig($this->getRequestedPagePath(),$config); 
     140                $pageConfig=$this->loadPageConfig($config); 
    141141 
    142142                $this->initPageContext($pageConfig); 
     
    170170                $this->_properties=$config->getProperties(); 
    171171                $this->getApplication()->getAuthorizationRules()->mergeWith($config->getRules()); 
     172                $pagePath=$this->getRequestedPagePath(); 
    172173                // external configurations 
    173                 foreach($config->getExternalConfigurations() as $filePath=>$condition) 
    174                 { 
     174                foreach($config->getExternalConfigurations() as $filePath=>$params) 
     175                { 
     176                        list($configPagePath,$condition)=$params; 
    175177                        if($condition!==true) 
    176178                                $condition=$this->evaluateExpression($condition); 
     
    179181                                if(($path=Prado::getPathOfNamespace($filePath,TApplication::CONFIG_FILE_EXT))===null || !is_file($path)) 
    180182                                        throw new TConfigurationException('pageservice_includefile_invalid',$filePath); 
    181                                 $c=new TPageConfiguration
    182                                 $c->loadFromFile($path,null); 
     183                                $c=new TPageConfiguration($pagePath)
     184                                $c->loadFromFile($path,$configPagePath); 
    183185                                $this->applyConfiguration($c); 
    184186                        } 
     
    201203        /** 
    202204         * Collects configuration for a page. 
    203          * @param string page path in the format of Path.To.Page 
    204          * @param TXmlElement additional configuration 
     205         * @param TXmlElement additional configuration specified in the application configuration 
    205206         * @return TPageConfiguration 
    206207         */ 
    207         protected function loadPageConfig($pagePath,$config=null
     208        protected function loadPageConfig($config
    208209        { 
    209210                $application=$this->getApplication(); 
     211                $pagePath=$this->getRequestedPagePath(); 
    210212                if(($cache=$application->getCache())===null) 
    211213                { 
    212                         $pageConfig=new TPageConfiguration
     214                        $pageConfig=new TPageConfiguration($pagePath)
    213215                        if($config!==null) 
    214                                 $pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath()); 
    215                         $pageConfig->loadFromFiles($pagePath,$this->getBasePath()); 
     216                                $pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),''); 
     217                        $pageConfig->loadFromFiles($this->getBasePath()); 
    216218                } 
    217219                else 
     
    259261                        if(!$configCached) 
    260262                        { 
    261                                 $pageConfig=new TPageConfiguration
     263                                $pageConfig=new TPageConfiguration($pagePath)
    262264                                if($config!==null) 
    263                                         $pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath()); 
    264                                 $pageConfig->loadFromFiles($pagePath,$this->getBasePath()); 
     265                                        $pageConfig->loadPageConfigurationFromXml($config,$application->getBasePath(),''); 
     266                                $pageConfig->loadFromFiles($this->getBasePath()); 
    265267                                $cache->set(self::CONFIG_CACHE_PREFIX.$this->getID().$pagePath,array($pageConfig,$currentTimestamp)); 
    266268                        } 
     
    518520         */ 
    519521        private $_includes=array(); 
     522        /** 
     523         * @var string the currently request page in the format of Path.To.PageName 
     524         */ 
     525        private $_pagePath=''; 
     526 
     527        /** 
     528         * Constructor. 
     529         * @param string the currently request page in the format of Path.To.PageName 
     530         */ 
     531        public function __construct($pagePath) 
     532        { 
     533                $this->_pagePath=$pagePath; 
     534        } 
    520535 
    521536        /** 
     
    559574        /** 
    560575         * Loads configuration for a page specified in a path format. 
    561          * @param string path to the page (dot-connected format) 
    562576         * @param string root path for pages 
    563577         */ 
    564         public function loadFromFiles($pagePath,$basePath) 
    565         { 
    566                 $paths=explode('.',$pagePath); 
     578        public function loadFromFiles($basePath) 
     579        { 
     580                $paths=explode('.',$this->_pagePath); 
    567581                $page=array_pop($paths); 
    568582                $path=$basePath; 
     583                $configPagePath=''; 
    569584                foreach($paths as $p) 
    570585                { 
    571                         $this->loadFromFile($path.DIRECTORY_SEPARATOR.TPageService::CONFIG_FILE,null); 
     586                        $this->loadFromFile($path.DIRECTORY_SEPARATOR.TPageService::CONFIG_FILE,$configPagePath); 
    572587                        $path.=DIRECTORY_SEPARATOR.$p; 
    573                 } 
    574                 $this->loadFromFile($path.DIRECTORY_SEPARATOR.TPageService::CONFIG_FILE,$page); 
     588                        if($configPagePath==='') 
     589                                $configPagePath=$p; 
     590                        else 
     591                                $configPagePath.='.'.$p; 
     592                } 
     593                $this->loadFromFile($path.DIRECTORY_SEPARATOR.TPageService::CONFIG_FILE,$configPagePath); 
    575594                $this->_rules=new TAuthorizationRuleCollection($this->_rules); 
    576595        } 
     
    579598         * Loads a specific config file. 
    580599         * @param string config file name 
    581          * @param string page name, null if page is not required 
    582          */ 
    583         public function loadFromFile($fname,$page
    584         { 
    585                 Prado::trace("Loading $page with file $fname",'System.Web.Services.TPageService'); 
     600         * @param string the page path that the config file is associated with. The page path doesn't include the page name. 
     601         */ 
     602        public function loadFromFile($fname,$configPagePath
     603        { 
     604                Prado::trace("Loading page configuration file $fname",'System.Web.Services.TPageService'); 
    586605                if(empty($fname) || !is_file($fname)) 
    587606                        return; 
    588607                $dom=new TXmlDocument; 
    589608                if($dom->loadFromFile($fname)) 
    590                         $this->loadFromXml($dom,dirname($fname),$page); 
     609                        $this->loadFromXml($dom,dirname($fname),$configPagePath); 
    591610                else 
    592611                        throw new TConfigurationException('pageserviceconf_file_invalid',$fname); 
     
    598617         * and page service. 
    599618         * @param TXmlElement config xml element 
    600          * @param string base path corresponding to this xml element 
    601          * @param string page name, null if page is not required 
    602          */ 
    603         public function loadFromXml($dom,$configPath,$page=null
     619         * @param string the directory containing this configuration 
     620         * @param string the page path that the config XML is associated with. The page path doesn't include the page name. 
     621         */ 
     622        public function loadFromXml($dom,$configPath,$configPagePath
    604623        { 
    605624                $this->loadApplicationConfigurationFromXml($dom,$configPath); 
    606                 $this->loadPageConfigurationFromXml($dom,$configPath,$page); 
     625                $this->loadPageConfigurationFromXml($dom,$configPath,$configPagePath); 
    607626        } 
    608627 
     
    623642         * @param TXmlElement config xml element 
    624643         * @param string base path corresponding to this xml element 
    625          * @param string page name, null if page is not required 
    626          */ 
    627         public function loadPageConfigurationFromXml($dom,$configPath,$page=null
     644         * @param string the page path that the config XML is associated with. The page path doesn't include the page name. 
     645         */ 
     646        public function loadPageConfigurationFromXml($dom,$configPath,$configPagePath
    628647        { 
    629648                // authorization 
     
    633652                        foreach($authorizationNode->getElements() as $node) 
    634653                        { 
    635                                 $pages=$node->getAttribute('pages'); 
     654                                $patterns=$node->getAttribute('pages'); 
    636655                                $ruleApplies=false; 
    637                                 if(empty($pages)) 
     656                                if(empty($patterns)) // null or empty string 
    638657                                        $ruleApplies=true; 
    639                                 else if($page!==null) 
     658                                else 
    640659                                { 
    641                                         $ps=explode(',',$pages); 
    642                                         foreach($ps as $p) 
     660                                        foreach(explode(',',$patterns) as $pattern) 
    643661                                        { 
    644                                                 if(strcasecmp($page,trim($p))===0
     662                                                if(($pattern=trim($pattern))!==''
    645663                                                { 
    646                                                         $ruleApplies=true; 
    647                                                         break; 
     664                                                        // we know $configPagePath and $this->_pagePath 
     665                                                        if($configPagePath!=='')  // prepend the pattern with ConfigPagePath 
     666                                                                $pattern=$configPagePath.'.'.$pattern; 
     667                                                        if(strcasecmp($pattern,$this->_pagePath)===0) 
     668                                                        { 
     669                                                                $ruleApplies=true; 
     670                                                                break; 
     671                                                        } 
     672                                                        if($pattern[strlen($pattern)-1]==='*') // try wildcard matching 
     673                                                        { 
     674                                                                $pattern=strtolower(substr($pattern,0,strlen($pattern)-1)); 
     675                                                                if(strpos(strtolower($this->_pagePath),$pattern)===0) 
     676                                                                { 
     677                                                                        $ruleApplies=true; 
     678                                                                        break; 
     679                                                                } 
     680                                                        } 
    648681                                                } 
    649682                                        } 
    650683                                } 
    651684                                if($ruleApplies) 
    652                                         $rules[]=new TAuthorizationRule($node->getTagName(),$node->getAttribute('users'),$node->getAttribute('roles'),$node->getAttribute('verb')); 
     685                                        $rules[]=new TAuthorizationRule($node->getTagName(),$node->getAttribute('users'),$node->getAttribute('roles'),$node->getAttribute('verb'),$node->getAttribute('ip')); 
    653686                        } 
    654687                        $this->_rules=array_merge($rules,$this->_rules); 
     
    659692                { 
    660693                        $this->_properties=array_merge($this->_properties,$pagesNode->getAttributes()->toArray()); 
    661                         if($page!==null)   // at the page folder 
     694                        // at the page folder 
     695                        foreach($pagesNode->getElementsByTagName('page') as $node) 
    662696                        { 
    663                                 foreach($pagesNode->getElementsByTagName('page') as $node) 
    664                                 { 
    665                                         $properties=$node->getAttributes(); 
    666                                         if(($id=$properties->itemAt('id'))===null) 
    667                                                 throw new TConfigurationException('pageserviceconf_page_invalid',$configPath); 
    668                                         if(strcasecmp($id,$page)===0) 
    669                                                 $this->_properties=array_merge($this->_properties,$properties->toArray()); 
    670                                 } 
     697                                $properties=$node->getAttributes(); 
     698                                if(($id=$properties->remove('id'))===null) 
     699                                        throw new TConfigurationException('pageserviceconf_page_invalid',$configPath); 
     700                                if(($configPagePath==='' && strcasecmp($id,$this->_pagePath)===0) || ($configPath!=='' && strcasecmp($configPagePath.'.'.$id,$this->_pagePath)===0)) 
     701                                        $this->_properties=array_merge($this->_properties,$properties->toArray()); 
    671702                        } 
    672703                } 
     
    680711                                throw new TConfigurationException('pageserviceconf_includefile_required'); 
    681712                        if(isset($this->_includes[$filePath])) 
    682                                 $this->_includes[$filePath]='('.$this->_includes[$filePath].') || ('.$when.')'
     713                                $this->_includes[$filePath]=array($configPagePath,'('.$this->_includes[$filePath][1].') || ('.$when.')')
    683714                        else 
    684                                 $this->_includes[$filePath]=$when
     715                                $this->_includes[$filePath]=array($configPagePath,$when)
    685716                } 
    686717        }