summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--framework/Exceptions/TErrorHandler.php17
-rw-r--r--framework/Exceptions/exception-en.html3
-rw-r--r--framework/Exceptions/exception-zh.html3
-rw-r--r--framework/Exceptions/exception.html3
-rw-r--r--framework/Exceptions/messages.txt6
-rw-r--r--framework/Security/TAuthManager.php175
-rw-r--r--framework/Security/TUserManager.php12
7 files changed, 168 insertions, 51 deletions
diff --git a/framework/Exceptions/TErrorHandler.php b/framework/Exceptions/TErrorHandler.php
index 69166561..e9ef1f33 100644
--- a/framework/Exceptions/TErrorHandler.php
+++ b/framework/Exceptions/TErrorHandler.php
@@ -59,6 +59,10 @@ class TErrorHandler extends TComponent implements IModule
* exception template file basename
*/
const EXCEPTION_FILE_NAME='exception';
+ /**
+ * number of lines to be displayed in case of an exception
+ */
+ const SOURCE_LINES=12;
/**
* @var string module ID
@@ -223,6 +227,7 @@ class TErrorHandler extends TComponent implements IModule
}
}
+
/**
* Displays exception information.
* Exceptions are displayed with rich context information, including
@@ -234,19 +239,19 @@ class TErrorHandler extends TComponent implements IModule
{
$lines=file($exception->getFile());
$errorLine=$exception->getLine();
- $beginLine=$errorLine-9>=0?$errorLine-9:0;
- $endLine=$errorLine+8<=count($lines)?$errorLine+8:count($lines);
+ $beginLine=$errorLine-self::SOURCE_LINES>=0?$errorLine-self::SOURCE_LINES:0;
+ $endLine=$errorLine+self::SOURCE_LINES<=count($lines)?$errorLine+self::SOURCE_LINES:count($lines);
$source='';
- for($i=$beginLine;$i<$endLine;++$i)
+ for($i=$beginLine-1;$i<$endLine;++$i)
{
if($i===$errorLine-1)
{
- $line=highlight_string(sprintf("Line %4d: %s",$i+1,$lines[$i]),true);
- $source.="<div style=\"background-color: #ffeeee\">".$line."</div>";
+ $line=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i])));
+ $source.="<div class=\"error\">".$line."</div>";
}
else
- $source.=highlight_string(sprintf("Line %4d: %s",$i+1,$lines[$i]),true);
+ $source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i])));
}
$fields=array(
diff --git a/framework/Exceptions/exception-en.html b/framework/Exceptions/exception-en.html
index 1d76c7f2..67e15dfe 100644
--- a/framework/Exceptions/exception-en.html
+++ b/framework/Exceptions/exception-en.html
@@ -10,6 +10,7 @@ p {font-family:"Verdana";font-weight:normal;color:black;font-size:9pt;margin-top
code,pre {font-family:"Lucida Console";}
td,.version {color: gray;font-size:8pt;border-top:1px solid #aaaaaa;}
.source {font-family:"Lucida Console";font-weight:normal;background-color:#ffffee;}
+.error {background-color: #ffeeee;}
</style>
</head>
@@ -21,7 +22,9 @@ td,.version {color: gray;font-size:8pt;border-top:1px solid #aaaaaa;}
<h3>Source File</h3>
<p>%%SourceFile%%</p>
<div class="source">
+<code><pre>
%%SourceCode%%
+</pre></code>
</div>
<h3>Stack Trace</h3>
<div class="source">
diff --git a/framework/Exceptions/exception-zh.html b/framework/Exceptions/exception-zh.html
index 8f56ec9e..e0897688 100644
--- a/framework/Exceptions/exception-zh.html
+++ b/framework/Exceptions/exception-zh.html
@@ -10,6 +10,7 @@ p {font-family:"Verdana";font-weight:normal;color:black;font-size:9pt;margin-top
code,pre {font-family:"Lucida Console";}
td,.version {color: gray;font-size:8pt;border-top:1px solid #aaaaaa;}
.source {font-family:"Lucida Console";font-weight:normal;background-color:#ffffee;}
+.error {background-color: #ffeeee;}
</style>
</head>
@@ -21,7 +22,9 @@ td,.version {color: gray;font-size:8pt;border-top:1px solid #aaaaaa;}
<h3>错误代码文件</h3>
<p>%%SourceFile%%</p>
<div class="source">
+<code><pre>
%%SourceCode%%
+</pre></code>
</div>
<h3>错误堆栈信息</h3>
<div class="source">
diff --git a/framework/Exceptions/exception.html b/framework/Exceptions/exception.html
index 1d76c7f2..67e15dfe 100644
--- a/framework/Exceptions/exception.html
+++ b/framework/Exceptions/exception.html
@@ -10,6 +10,7 @@ p {font-family:"Verdana";font-weight:normal;color:black;font-size:9pt;margin-top
code,pre {font-family:"Lucida Console";}
td,.version {color: gray;font-size:8pt;border-top:1px solid #aaaaaa;}
.source {font-family:"Lucida Console";font-weight:normal;background-color:#ffffee;}
+.error {background-color: #ffeeee;}
</style>
</head>
@@ -21,7 +22,9 @@ td,.version {color: gray;font-size:8pt;border-top:1px solid #aaaaaa;}
<h3>Source File</h3>
<p>%%SourceFile%%</p>
<div class="source">
+<code><pre>
%%SourceCode%%
+</pre></code>
</div>
<h3>Stack Trace</h3>
<div class="source">
diff --git a/framework/Exceptions/messages.txt b/framework/Exceptions/messages.txt
index 49160370..209c0124 100644
--- a/framework/Exceptions/messages.txt
+++ b/framework/Exceptions/messages.txt
@@ -79,6 +79,12 @@ xmldocument_file_write_failed = TXmlDocument is unable to write file '%s'.
authorizationrule_action_invalid = TAuthorizationRule.Action can only take 'allow' or 'deny' as the value.
authorizationrule_verb_invalid = TAuthorizationRule.Verb can only take 'get' or 'post' as the value.
+authmanager_usermanager_required = TAuthManager.UserManager must be assigned a value.
+authmanager_usermanager_inexistent = TAuthManager.UserManager '%s' does not refer to an ID of application module.
+authmanager_usermanager_invalid = TAuthManager.UserManager '%s' does not refer to a valid TUserManager application module.
+authmanager_usermanager_unchangeable = TAuthManager.UserManager cannot be modified after the module is initialized.
+authmanager_session_required = TAuthManager requires a session application module.
+
body_contents_not_allowed = %s: body contents are not allowed.
control_id_not_unique = Control ID '%s' is not unique for control type '%s'.
control_not_found = Unable to find a control with ID '%s'.
diff --git a/framework/Security/TAuthManager.php b/framework/Security/TAuthManager.php
index 32b68cdd..f24a1bdd 100644
--- a/framework/Security/TAuthManager.php
+++ b/framework/Security/TAuthManager.php
@@ -11,26 +11,54 @@
*/
/**
+ * Using TUserManager class
+ */
+Prado::using('System.Security.TUserManager');
+
+/**
* TAuthManager class
*
* TAuthManager performs user authentication and authorization for a Prado application.
+ * TAuthManager works together with a {@link TUserManager} module that can be
+ * specified via the {@link setUserManager UserManager} property.
+ * If an authorization fails, TAuthManager will try to redirect the client
+ * browser to a login page that is specified via the {@link setLoginPage LoginPage}.
+ * To login or logout a user, call {@link login} or {@link logout}, respectively.
*
+ * To load TAuthManager, configure it in application configuration as follows,
+ * <module id="auth" type="System.Security.TAuthManager" UserManager="users" LoginPage="login" />
+ * <module id="users" type="System.Security.TUserManager" />
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Revision: $ $Date: $
* @package System.Security
* @since 3.0
*/
-
-Prado::using('System.Security.TUserManager');
-
class TAuthManager extends TComponent implements IModule
{
+ /**
+ * GET variable name for return url
+ */
const RETURN_URL_VAR='ReturnUrl';
+ /**
+ * @var boolean if the module has been initialized
+ */
private $_initialized=false;
+ /**
+ * @var TApplication application instance
+ */
private $_application;
- private $_users=null;
+ /**
+ * @var TUserManager user manager instance
+ */
+ private $_userManager=null;
+ /**
+ * @var string login page
+ */
private $_loginPage=null;
+ /**
+ * @var boolean whether authorization should be skipped
+ */
private $_skipAuthorization=false;
/**
@@ -54,9 +82,20 @@ class TAuthManager extends TComponent implements IModule
* This method is required by the IModule interface.
* @param TApplication Prado application, can be null
* @param TXmlElement configuration for this module, can be null
+ * @throws TConfigurationException if user manager does not exist or is not TUserManager
*/
public function init($application,$config)
{
+ if($this->_userManager===null)
+ throw new TConfigurationException('authmanager_usermanager_required');
+ if(is_string($this->_userManager))
+ {
+ if(($users=$application->getModule($this->_userManager))===null)
+ throw new TConfigurationException('authmanager_usermanager_inexistent',$this->_userManager);
+ if(!($users instanceof TUserManager))
+ throw new TConfigurationException('authmanager_usermanager_invalid',$this->_userManager);
+ $this->_userManager=$users;
+ }
$this->_application=$application;
$application->attachEventHandler('Authentication',array($this,'doAuthentication'));
$application->attachEventHandler('EndRequest',array($this,'leave'));
@@ -64,36 +103,53 @@ class TAuthManager extends TComponent implements IModule
$this->_initialized=true;
}
+ /**
+ * @return TUserManager user manager instance
+ */
public function getUserManager()
{
- if($this->_users instanceof TUserManager)
- return $this->_users;
- else
- {
- if(($users=$this->_application->getModule($this->_users))===null)
- throw new TConfigurationException('authenticator_usermanager_inexistent',$this->_users);
- if(!($users instanceof TUserManager))
- throw new TConfigurationException('authenticator_usermanager_invalid',$this->_users);
- $this->_users=$users;
- return $users;
- }
+ return $this->_userManager;
}
+ /**
+ * @param string|TUserManager the user manager module ID or the user mananger object
+ * @throws TInvalidOperationException if the module has been initialized or the user manager object is not TUserManager
+ */
public function setUserManager($provider)
{
- $this->_users=$provider;
+ if($this->_initialized)
+ throw new TInvalidOperationException('authmanager_usermanager_unchangeable');
+ if(!is_string($provider) && !($provider instanceof TUserManager))
+ throw new TConfigurationException('authmanager_usermanager_invalid',$this->_userManager);
+ $this->_userManager=$provider;
}
+ /**
+ * @return string path of login page should login is required
+ */
public function getLoginPage()
{
return $this->_loginPage;
}
+ /**
+ * Sets the login page that the client browser will be redirected to if login is needed.
+ * Login page should be specified in the format of page path.
+ * @param string path of login page should login is required
+ * @see TPageService
+ */
public function setLoginPage($pagePath)
{
$this->_loginPage=$pagePath;
}
+ /**
+ * Performs authentication.
+ * This is the event handler attached to application's Authentication event.
+ * Do not call this method directly.
+ * @param mixed sender of the Authentication event
+ * @param mixed event parameter
+ */
public function doAuthentication($sender,$param)
{
$this->onAuthenticate($param);
@@ -103,6 +159,13 @@ class TAuthManager extends TComponent implements IModule
$this->_skipAuthorization=true;
}
+ /**
+ * Performs authorization.
+ * This is the event handler attached to application's Authorization event.
+ * Do not call this method directly.
+ * @param mixed sender of the Authorization event
+ * @param mixed event parameter
+ */
public function doAuthorization($sender,$param)
{
if(!$this->_skipAuthorization)
@@ -111,6 +174,13 @@ class TAuthManager extends TComponent implements IModule
}
}
+ /**
+ * Performs login redirect if authorization fails.
+ * This is the event handler attached to application's EndRequest event.
+ * Do not call this method directly.
+ * @param mixed sender of the event
+ * @param mixed event parameter
+ */
public function leave($sender,$param)
{
if($this->_application->getResponse()->getStatusCode()===401)
@@ -125,6 +195,14 @@ class TAuthManager extends TComponent implements IModule
}
}
+ /**
+ * Performs the real authentication work.
+ * An Authenticate event will be raised if there is any handler attached to it.
+ * If the application already has a non-null user, it will return without further authentication.
+ * Otherwise, user information will be restored from session data.
+ * @param mixed parameter to be passed to Authenticate event
+ * @throws TConfigurationException if session module does not exist.
+ */
public function onAuthenticate($param)
{
if($this->hasEventHandler('Authenticate'))
@@ -133,18 +211,23 @@ class TAuthManager extends TComponent implements IModule
return;
if(($session=$this->_application->getSession())===null)
- throw new TConfigurationException('authenticator_session_required');
+ throw new TConfigurationException('authmanager_session_required');
$session->open();
- if(($userManager=$this->getUserManager())===null)
- throw new TConfigurationException('authenticator_usermanager_required');
$sessionInfo=$session->getItems()->itemAt($this->generateUserSessionKey());
- $user=$userManager->getUser(null)->loadFromString($sessionInfo);
+ $user=$this->_userManager->getUser(null)->loadFromString($sessionInfo);
$this->_application->setUser($user);
}
+ /**
+ * Performs the real authorization work.
+ * Authorization rules obtained from the application will be used to check
+ * if a user is allowed. If authorization fails, the response status code
+ * will be set as 401 and the application terminates.
+ * @param mixed parameter to be passed to Authenticate event
+ */
public function onAuthorize($param)
{
- if($this->hasEventHandler('Authenticate'))
+ if($this->hasEventHandler('Authorize'))
$this->raiseEvent('Authorize',$this,$this->_application);
if(!$this->_application->getAuthorizationRules()->isUserAllowed($this->_application->getUser(),$this->_application->getRequest()->getRequestType()))
{
@@ -153,49 +236,63 @@ class TAuthManager extends TComponent implements IModule
}
}
+ /**
+ * @return string a key used to store user information in session
+ */
protected function generateUserSessionKey()
{
return md5($this->_application->getUniqueID().'prado:user');
}
+ /**
+ * Updates the user data stored in session.
+ * @param IUser user object
+ * @throws new TConfigurationException if session module is not loaded.
+ */
public function updateSessionUser($user)
{
if(!$user->getIsGuest())
{
if(($session=$this->_application->getSession())===null)
- throw new TConfigurationException('authenticator_session_required');
+ throw new TConfigurationException('authmanager_session_required');
else
$session->getItems()->add($this->generateUserSessionKey(),$user->saveToString());
}
}
+ /**
+ * Logs in a user with username and password.
+ * The username and password will be used to validate if login is successful.
+ * If yes, a user object will be created for the application.
+ * @param string username
+ * @param string password
+ * @return boolean if login is successful
+ */
public function login($username,$password)
{
- if(($userManager=$this->getUserManager())===null)
- throw new TConfigurationException('authenticator_usermanager_required');
- else
+ if($this->_userManager->validateUser($username,$password))
{
- if($userManager->validateUser($username,$password))
- {
- $user=$userManager->getUser($username);
- $this->updateSessionUser($user);
- $this->_application->setUser($user);
- return true;
- }
- else
- return false;
+ $user=$this->_userManager->getUser($username);
+ $this->updateSessionUser($user);
+ $this->_application->setUser($user);
+ return true;
}
+ else
+ return false;
}
+ /**
+ * Logs out a user.
+ * User session will be destroyed after this method is called.
+ * @throws TConfigurationException if session module is not loaded.
+ */
public function logout()
{
- if(($userManager=$this->getUserManager())===null)
- throw new TConfigurationException('authenticator_usermanager_required');
- else if(($session=$this->_application->getSession())===null)
- throw new TConfigurationException('authenticator_session_required');
+ if(($session=$this->_application->getSession())===null)
+ throw new TConfigurationException('authmanager_session_required');
else
{
- $userManager->switchToGuest($this->_application->getUser());
+ $this->_userManager->switchToGuest($this->_application->getUser());
$session->destroy();
}
}
diff --git a/framework/Security/TUserManager.php b/framework/Security/TUserManager.php
index c4bcbacd..9da386f0 100644
--- a/framework/Security/TUserManager.php
+++ b/framework/Security/TUserManager.php
@@ -169,12 +169,12 @@ class TUser extends TComponent implements IUser
*
* TUserManager manages a static list of users {@link TUser}.
* The user information is specified via module configuration using the following XML syntax,
- * <code>
- * <user name="Joe" password="demo" />
- * <user name="John" password="demo" />
- * <role name="Administrator" users="John" />
- * <role name="Writer" users="Joe,John" />
- * </code>
+ * <module id="users" type="System.Security.TUserManager" PasswordMode="Clear">
+ * <user name="Joe" password="demo" />
+ * <user name="John" password="demo" />
+ * <role name="Administrator" users="John" />
+ * <role name="Writer" users="Joe,John" />
+ * </module>
*
* The user passwords may be specified as clear text, SH1 or MD5 hashed by setting
* {@link setPasswordMode PasswordMode} as <b>Clear</b>, <b>SH1</b> or <b>MD5</b>.