summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxue <>2007-09-26 13:15:56 +0000
committerxue <>2007-09-26 13:15:56 +0000
commitcb62a8b25b67f4c23148efe5d9e93278651d1901 (patch)
tree4dec8d359fe2b42965ab370f590094ffd1bc5c36
parent75293bddc7faea69021f5e29ac9e4df3f04c4f36 (diff)
added support to remember login.
-rw-r--r--HISTORY1
-rw-r--r--UPGRADE7
-rw-r--r--demos/quickstart/protected/pages/Advanced/Auth.page42
-rw-r--r--demos/quickstart/protected/pages/GettingStarted/NewFeatures.page1
-rw-r--r--framework/Security/IUserManager.php13
-rw-r--r--framework/Security/TAuthManager.php79
-rw-r--r--framework/Security/TDbUserManager.php66
-rw-r--r--framework/Security/TUserManager.php37
-rw-r--r--framework/TApplication.php4
-rw-r--r--framework/Web/THttpRequest.php2
10 files changed, 241 insertions, 11 deletions
diff --git a/HISTORY b/HISTORY
index c2dd9b6a..28eace7c 100644
--- a/HISTORY
+++ b/HISTORY
@@ -21,6 +21,7 @@ ENH: Ticket#681 - TUrlMapping can construct custom URLs now (Qiang)
ENH: Ticket#692,700 - Added support to wildcard in pages configuration; added IP filters in auth rules. (Qiang)
ENH: Added THead requirement check (Qiang)
ENH: Added TOutputCache.CacheTime (Qiang)
+ENH: Added "remember login" support to TAuthManager and the related modules/classes (Qiang)
CHG: Ticket#685 - Slashes and backslashes mixup in PradoBase (Qiang)
CHG: Ticket#705 - TImage will not set border style by default (Qiang)
CHG: GeSHi is replaced with Text_Highlighter (Christophe)
diff --git a/UPGRADE b/UPGRADE
index 77b136e8..6b609eea 100644
--- a/UPGRADE
+++ b/UPGRADE
@@ -11,10 +11,15 @@ for both A and B.
Upgrading from v3.1.0
---------------------
-- IFeedContentProvider adds a new method getContentType(). This affects any
+- IFeedContentProvider adds a new method: getContentType(). This affects any
class implementing this interface.
- TUrlMapping now only uses the PATH_INFO part of URL for matching, and the matching
is for the whole PATH_INFO.
+- IUserManager adds two new methods: getUserFromCookie() and saveUserToCookie().
+ This affects classes that implements this interface and does not extend from
+ TUserManager.
+- The order of application lifecycles is changed. The loadState and loadStateComplete
+ are moved to right after onBeginRequest.
Upgrading from v3.1b
--------------------
diff --git a/demos/quickstart/protected/pages/Advanced/Auth.page b/demos/quickstart/protected/pages/Advanced/Auth.page
index 531b8bdf..e0cbcaef 100644
--- a/demos/quickstart/protected/pages/Advanced/Auth.page
+++ b/demos/quickstart/protected/pages/Advanced/Auth.page
@@ -124,5 +124,47 @@ In the above, <tt>UserClass</tt> specifies what class will be used to create use
<p id="720566" class="block-content">
The user class has to implement the two abstract methods in <tt>TDbUser</tt>: <tt>validateUser()</tt> and <tt>createUser()</tt>. Since user account information is stored in a database, the user class may make use of its <tt>DbConnection</tt> property to reach the database.
</p>
+<com:SinceVersion Version="3.1.1" />
+<p id="720567" class="block-content">
+Since 3.1.1, <tt>TAuthManager</tt> provides support to allow remembering login. Accordingly, <tt>TDbUser</tt> adds two methods to facilitate the implementation of this feature. In particular, two new methods are introduced: <tt>createUserFromCookie()</tt> and <tt>saveUserToCookie()</tt>. Developers should implement these two methods if remembering login is needed. Below is a sample implementation:
+</p>
+<com:TTextHighlighter Language="php" CssClass="source block-content" id="code5">
+public function createUserFromCookie($cookie)
+{
+ if(($data=$cookie->Value)!=='')
+ {
+ $application=Prado::getApplication();
+ if(($data=$application->SecurityManager->validateData($data))!==false)
+ {
+ $data=unserialize($data);
+ if(is_array($data) && count($data)===3)
+ {
+ list($username,$address,$token)=$data;
+ $sql='SELECT passcode FROM user WHERE LOWER(username)=:username';
+ $command=$this->DbConnection->createCommand($sql);
+ $command->bindValue(':username',strtolower($username));
+ if($token===$command->queryScalar() && $token!==false && $address=$application->Request->UserHostAddress)
+ return $this->createUser($username);
+ }
+ }
+ }
+ return null;
+}
+
+public function saveUserToCookie($cookie)
+{
+ $application=Prado::getApplication();
+ $username=strtolower($this->Name);
+ $address=$application->Request->UserHostAddress;
+ $sql='SELECT passcode FROM user WHERE LOWER(username)=:username';
+ $command=$this->DbConnection->createCommand($sql);
+ $command->bindValue(':username',strtolower($username));
+ $token=$command->queryScalar();
+ $data=array($username,$address,$token);
+ $data=serialize($data);
+ $data=$application->SecurityManager->hashData($data);
+ $cookie->setValue($data);
+}
+</com:TTextHighlighter>
<div class="last-modified">$Id$</div></com:TContent> \ No newline at end of file
diff --git a/demos/quickstart/protected/pages/GettingStarted/NewFeatures.page b/demos/quickstart/protected/pages/GettingStarted/NewFeatures.page
index adc19fc7..faf3b9b1 100644
--- a/demos/quickstart/protected/pages/GettingStarted/NewFeatures.page
+++ b/demos/quickstart/protected/pages/GettingStarted/NewFeatures.page
@@ -17,6 +17,7 @@ This page summarizes the main new features that are introduced in each PRADO rel
<li>Added support to TDataGrid to allow grouping consecutive cells with the same content.</li>
<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>
<li>Added a new page state persister <tt>TCachePageStatePersister</tt>. It allows page state to be stored using a cache module (e.g. TMemCache, TDbCache, etc.)
+<li>Added support to the <a href="?page=Advanced.Auth">auth framework</a> to allow remembering login.</li>
</ul>
<h2 id="8006">Version 3.1.0</h2>
diff --git a/framework/Security/IUserManager.php b/framework/Security/IUserManager.php
index 649c41b6..d90450a9 100644
--- a/framework/Security/IUserManager.php
+++ b/framework/Security/IUserManager.php
@@ -35,6 +35,19 @@ interface IUserManager
*/
public function getUser($username=null);
/**
+ * Returns a user instance according to auth data stored in a cookie.
+ * @param THttpCookie the cookie storing user authentication information
+ * @return TUser the user instance generated based on the cookie auth data, null if the cookie does not have valid auth data.
+ * @since 3.1.1
+ */
+ public function getUserFromCookie($cookie);
+ /**
+ * Saves user auth data into a cookie.
+ * @param THttpCookie the cookie to receive the user auth data.
+ * @since 3.1.1
+ */
+ public function saveUserToCookie($cookie);
+ /**
* Validates if the username and password are correct.
* @param string user name
* @param string password
diff --git a/framework/Security/TAuthManager.php b/framework/Security/TAuthManager.php
index fcbb64d2..7a6b96a1 100644
--- a/framework/Security/TAuthManager.php
+++ b/framework/Security/TAuthManager.php
@@ -60,6 +60,14 @@ class TAuthManager extends TModule
* @var string the session var name for storing return URL
*/
private $_returnUrlVarName;
+ /**
+ * @var boolean whether to allow auto login (using cookie)
+ */
+ private $_allowAutoLogin=false;
+ /**
+ * @var string variable name used to store user session or cookie
+ */
+ private $_userKey;
/**
* Initializes this module.
@@ -216,6 +224,24 @@ class TAuthManager extends TModule
}
/**
+ * @return boolean whether to allow remembering login so that the user logs on automatically next time. Defaults to false.
+ * @since 3.1.1
+ */
+ public function getAllowAutoLogin()
+ {
+ return $this->_allowAutoLogin;
+ }
+
+ /**
+ * @param boolean whether to allow remembering login so that the user logs on automatically next time. Users have to enable cookie to make use of this feature.
+ * @since 3.1.1
+ */
+ public function setAllowAutoLogin($value)
+ {
+ $this->_allowAutoLogin=TPropertyValue::ensureBoolean($value);
+ }
+
+ /**
* Performs the real authentication work.
* An OnAuthenticate 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.
@@ -227,11 +253,27 @@ class TAuthManager extends TModule
{
$application=$this->getApplication();
+ // restoring user info from session
if(($session=$application->getSession())===null)
throw new TConfigurationException('authmanager_session_required');
$session->open();
- $sessionInfo=$session->itemAt($this->generateUserSessionKey());
+ $sessionInfo=$session->itemAt($this->getUserKey());
$user=$this->_userManager->getUser(null)->loadFromString($sessionInfo);
+
+ // try authenticating through cookie if possible
+ if($this->getAllowAutoLogin() && $user->getIsGuest())
+ {
+ $cookie=$this->getRequest()->getCookies()->itemAt($this->getUserKey());
+ if($cookie instanceof THttpCookie)
+ {
+ if(($user2=$this->_userManager->getUserFromCookie($cookie))!==null)
+ {
+ $user=$user2;
+ $this->updateSessionUser($user);
+ }
+ }
+ }
+
$application->setUser($user);
// event handler gets a chance to do further auth work
@@ -259,9 +301,21 @@ class TAuthManager extends TModule
}
/**
+ * @return string a unique variable name for storing user session/cookie data
+ * @since 3.1.1
+ */
+ public function getUserKey()
+ {
+ if($this->_userKey===null)
+ $this->_userKey=$this->generateUserKey();
+ return $this->_userKey;
+ }
+
+ /**
* @return string a key used to store user information in session
+ * @since 3.1.1
*/
- protected function generateUserSessionKey()
+ protected function generateUserKey()
{
return md5($this->getApplication()->getUniqueID().'prado:user');
}
@@ -278,7 +332,7 @@ class TAuthManager extends TModule
if(($session=$this->getSession())===null)
throw new TConfigurationException('authmanager_session_required');
else
- $session->add($this->generateUserSessionKey(),$user->saveToString());
+ $session->add($this->getUserKey(),$user->saveToString());
}
}
@@ -288,15 +342,24 @@ class TAuthManager extends TModule
* If yes, a user object will be created for the application.
* @param string username
* @param string password
+ * @param integer number of seconds that automatic login will remain effective. If 0, it means user logs out when session ends. This parameter is added since 3.1.1.
* @return boolean if login is successful
*/
- public function login($username,$password)
+ public function login($username,$password,$expire=0)
{
if($this->_userManager->validateUser($username,$password))
{
$user=$this->_userManager->getUser($username);
$this->updateSessionUser($user);
$this->getApplication()->setUser($user);
+
+ if($expire>0)
+ {
+ $cookie=new THttpCookie($this->getUserKey(),'');
+ $cookie->setExpire(time()+$expire);
+ $this->_userManager->saveUserToCookie($cookie);
+ $this->getResponse()->getCookies()->add($cookie);
+ }
return true;
}
else
@@ -312,10 +375,12 @@ class TAuthManager extends TModule
{
if(($session=$this->getSession())===null)
throw new TConfigurationException('authmanager_session_required');
- else
+ $this->getApplication()->getUser()->setIsGuest(true);
+ $session->destroy();
+ if($this->getAllowAutoLogin())
{
- $this->getApplication()->getUser()->setIsGuest(true);
- $session->destroy();
+ $cookie=new THttpCookie($this->getUserKey(),'');
+ $this->getResponse()->getCookies()->add($cookie);
}
}
}
diff --git a/framework/Security/TDbUserManager.php b/framework/Security/TDbUserManager.php
index a2f30642..35cf4fd7 100644
--- a/framework/Security/TDbUserManager.php
+++ b/framework/Security/TDbUserManager.php
@@ -155,7 +155,10 @@ class TDbUserManager extends TModule implements IUserManager
public function getDbConnection()
{
if($this->_conn===null)
+ {
$this->_conn=$this->createDbConnection($this->_connID);
+ $this->_conn->setActive(true);
+ }
return $this->_conn;
}
@@ -178,6 +181,29 @@ class TDbUserManager extends TModule implements IUserManager
else
throw new TConfigurationException('dbusermanager_connectionid_required');
}
+
+ /**
+ * Returns a user instance according to auth data stored in a cookie.
+ * @param THttpCookie the cookie storing user authentication information
+ * @return TDbUser the user instance generated based on the cookie auth data, null if the cookie does not have valid auth data.
+ * @since 3.1.1
+ */
+ public function getUserFromCookie($cookie)
+ {
+ return $this->_userFactory->createUserFromCookie($cookie);
+ }
+
+ /**
+ * Saves user auth data into a cookie.
+ * @param THttpCookie the cookie to receive the user auth data.
+ * @since 3.1.1
+ */
+ public function saveUserToCookie($cookie)
+ {
+ $user=$this->getApplication()->getUser();
+ if($user instanceof TDbUser)
+ $user->saveUserToCookie($cookie);
+ }
}
@@ -250,6 +276,46 @@ abstract class TDbUser extends TUser
* @return TDbUser the newly created and initialized user instance
*/
abstract public function createUser($username);
+
+ /**
+ * Creates a new user instance given the cookie containing auth data.
+ *
+ * This method is invoked when {@link TAuthManager::setAllowAutoLogin AllowAutoLogin} is set true.
+ * The default implementation simply returns null, meaning no user instance can be created
+ * from the given cookie.
+ *
+ * If you want to support automatic login (remember login), you should override this method.
+ * Typically, you obtain the username and a unique token from the cookie's value.
+ * You then verify the token is valid and use the username to create a user instance.
+ *
+ * @param THttpCookie the cookie storing user authentication information
+ * @return TDbUser the user instance generated based on the cookie auth data, null if the cookie does not have valid auth data.
+ * @see saveUserToCookie
+ * @since 3.1.1
+ */
+ public function createUserFromCookie($cookie)
+ {
+ return null;
+ }
+
+ /**
+ * Saves necessary auth data into a cookie.
+ * This method is invoked when {@link TAuthManager::rememberLogin} is invoked.
+ * The default implementation does nothing, meaning auth data is not stored in the cookie
+ * (and thus automatic login is not supported.)
+ *
+ * If you want to support automatic login (remember login), you should override this method.
+ * Typically, you generate a unique token according to the current login information
+ * and save it together with the username in the cookie's value.
+ * You should avoid revealing the password in the generated token.
+ *
+ * @param THttpCookie the cookie to store the user auth information
+ * @see createUserFromCookie
+ * @since 3.1.1
+ */
+ public function saveUserToCookie($cookie)
+ {
+ }
}
?> \ No newline at end of file
diff --git a/framework/Security/TUserManager.php b/framework/Security/TUserManager.php
index 28651de8..f6aee767 100644
--- a/framework/Security/TUserManager.php
+++ b/framework/Security/TUserManager.php
@@ -251,6 +251,43 @@ class TUserManager extends TModule implements IUserManager
}
/**
+ * Returns a user instance according to auth data stored in a cookie.
+ * @param THttpCookie the cookie storing user authentication information
+ * @return TUser the user instance generated based on the cookie auth data, null if the cookie does not have valid auth data.
+ * @since 3.1.1
+ */
+ public function getUserFromCookie($cookie)
+ {
+ if(($data=$cookie->getValue())!=='')
+ {
+ $data=unserialize($data);
+ if(is_array($data) && count($data)===2)
+ {
+ list($username,$token)=$data;
+ if(isset($this->_users[$username]) && $token===md5($username.$this->_users[$username]))
+ return $this->getUser($username);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Saves user auth data into a cookie.
+ * @param THttpCookie the cookie to receive the user auth data.
+ * @since 3.1.1
+ */
+ public function saveUserToCookie($cookie)
+ {
+ $user=$this->getApplication()->getUser();
+ $username=strtolower($user->getName());
+ if(isset($this->_users[$username]))
+ {
+ $data=array($username,md5($username.$this->_users[$username]));
+ $cookie->setValue(serialize($data));
+ }
+ }
+
+ /**
* Sets a user as a guest.
* User name is changed as guest name, and roles are emptied.
* @param TUser the user to be changed to a guest.
diff --git a/framework/TApplication.php b/framework/TApplication.php
index 3aa2cec1..a0239072 100644
--- a/framework/TApplication.php
+++ b/framework/TApplication.php
@@ -150,12 +150,12 @@ class TApplication extends TComponent
*/
private static $_steps=array(
'onBeginRequest',
+ 'onLoadState',
+ 'onLoadStateComplete',
'onAuthentication',
'onAuthenticationComplete',
'onAuthorization',
'onAuthorizationComplete',
- 'onLoadState',
- 'onLoadStateComplete',
'onPreRunService',
'runService',
'onSaveState',
diff --git a/framework/Web/THttpRequest.php b/framework/Web/THttpRequest.php
index a9e5fe68..ca7780cd 100644
--- a/framework/Web/THttpRequest.php
+++ b/framework/Web/THttpRequest.php
@@ -911,7 +911,7 @@ class THttpCookie extends TComponent
/**
* @var string value of the cookie
*/
- private $_value=0;
+ private $_value='';
/**
* @var integer expire of the cookie
*/