<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>HirdWeb &#187; authentication</title>
	<atom:link href="http://www.hirdweb.com/tag/authentication/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.hirdweb.com</link>
	<description>Another Blog clogging up the already crowded internet</description>
	<lastBuildDate>Wed, 28 Jul 2010 16:05:05 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>CakePHP Auth error message</title>
		<link>http://www.hirdweb.com/2008/09/01/cakephp-auth-error-message/</link>
		<comments>http://www.hirdweb.com/2008/09/01/cakephp-auth-error-message/#comments</comments>
		<pubDate>Mon, 01 Sep 2008 17:48:54 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[authentication]]></category>
		<category><![CDATA[cakePHP]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=79</guid>
		<description><![CDATA[Today is just going to be a quick post. It is Labor Day here in the States and that means a whole heap of people are not going to be working, including me. So I am just messing around with some stuff in CakePHP as I am doing a side project for a local church [...]]]></description>
			<content:encoded><![CDATA[<p>Today is just going to be a quick post. It is Labor Day here in the States and that means a whole heap of people are not going to be working, including me. So I am just messing around with some stuff in CakePHP as I am doing a side project for a local church to put up a calendar. Most of it is complete, but there was one thing that I wanted to change. </p>
<p>I am using the Auth component in my User model. I have allowed register, resetpass, and index. So when I go to view a user&#8217;s detailed profile, there is that message: &#8220;You are not authorized to access that location.&#8221; Which is a fine message and all, but I want it to be site specific, and also controller specific. So the Users controller will have a separate Auth error message than the Calendars controller. So here is what I did. </p>
<p>In the Users controller, I built a beforeFilter function. I set my authorized actions, set redirect to false. I also set a session level variable with the Auth, then I set the error message. There are a couple of messages you can set for the Users controller. You can set the loginError and the authError. The loginError will be the error when the user logs in and is unable to for whatever reason. The authError is what the user will see when they try to perform an action that is not allowed by them, whether it is because they are not logged in (as in my case) or you are using Auth to &#8220;authorize&#8221; an action. </p>
<p>So here is what it would look like:</p>
<pre>
function beforeFilter() {
	parent::beforeFilter();

	$this->Auth->allow('register', 'index', 'resetpass');
	$this->Auth->autoRedirect = false;
	$this->Auth->authorize = 'controller';
	$this->set('my_id', $this->Auth->user('user_id'));
	$this->Auth->authError = "Please log in first in order to preform that action.";
}
</pre>
<p>So when you want to change the standard Auth error message, just remember to set the &#8220;authError&#8221; to whatever message you would like. Happy Labor Day!</p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2008/09/01/cakephp-auth-error-message/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Access Control Lists (ACLs)</title>
		<link>http://www.hirdweb.com/2008/08/25/access-control-lists-acls/</link>
		<comments>http://www.hirdweb.com/2008/08/25/access-control-lists-acls/#comments</comments>
		<pubDate>Tue, 26 Aug 2008 01:20:49 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[Applications]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[ACL]]></category>
		<category><![CDATA[authentication]]></category>
		<category><![CDATA[cakePHP]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=42</guid>
		<description><![CDATA[Access Control Lists, or ACLs, provide a good level of access control on any site. Code bases and platforms may use a different method of instituting ACLs and I am going to go through how CakePHP 1.2.x is handling them. First is to understand what an ACL really is. The Cookbook has a good page [...]]]></description>
			<content:encoded><![CDATA[<p>Access Control Lists, or ACLs, provide a good level of access control on any site. Code bases and platforms may use a different method of instituting ACLs and I am going to go through how CakePHP 1.2.x is handling them. </p>
<p>First is to understand what an ACL really is. The <a href="http://book.cakephp.org/view/171/access-control-lists" target="_new">Cookbook has a good page explaining this type of concept</a>. I highly recommend reading through this page. The whole concept behind this ACL can be divided in three parts:</p>
<ul>
<li>ACO &#8211; Access Control Object, object that is being requested</li>
<li>ARO &#8211; Access Request Object, object that is putting in the request</li>
<li>ACL &#8211; Access Control List, determines if an ARO can access an ACO.</li>
</ul>
<p><em>In the Cookbook, they have a very good call out about the ACL, it is not authentication. No matter what code base, or platform you are on, never mistake this. The ACL verification only happens after the person logs in. They can be very powerful together, but authentication must happen first. </em></p>
<p>The next thing to understand is the way an ACL would look in a matrix. Again, the Cookbook provides a great example of this. The one thing that I would rather prefer, but understand why they do this, is the use of the example. Sure, we all like movies, and the Lord of the Rings is a great way to really explain different things, but it may be hard to switch that over to the real world of coding. So for this entry, I am going to use as an example, and Event Calendar. </p>
<p><span id="more-42"></span><br />
In this Event Calendar, here is the breakdown: there are events, there are groups, there are users. Each user is going to be a member of a group. A group will have a &#8220;leader&#8221; who can add, edit or delete group events. A group will also have an &#8220;editor&#8221; who will be able to add or edit group events. And the default group membership is one who can only view group events. </p>
<ul>
<li><strong>Groups</strong></li>
<li> &#8211; <em>Leader</em></li>
<li> &#8211; - Add, edit, delete group events</li>
<li> &#8211; - View all group events</li>
<li> &#8211; <em>Editor</em></li>
<li> &#8211; - Add, or edit group events</li>
<li> &#8211; - View all group events</li>
<li> &#8211; <em>Member</em></li>
<li> &#8211; - View all group events</li>
</ul>
<p>Users will be anyone who creates a login to the application. Of course there will be a &#8220;site admin&#8221; who can add, edit, delete to any user account except their own. They can assign a user to a group, or remove memberships. The group leader can add or remove memberships to their own group only. They can not add, edit or delete user accounts. The default user can edit their own account, and request for the account to be deleted (they can not delete their own account). </p>
<ul>
<li><strong>Users</strong></li>
<li> &#8211; <em>Site Admin</em></li>
<li> &#8211; - Add, edit, delete all user accounts (except the site admin account)</li>
<li> &#8211; - Add, or remove users from any group</li>
<li> &#8211; <em>Leader</em></li>
<li> &#8211; - Add or remove users from their own group only</li>
<li> &#8211; <em>Users</em></li>
<li> &#8211; Sign up for an account, edit only their profile</li>
<li> &#8211; request to be a member of a group</li>
</ul>
<p>Events can be either a group event, or an individual event. Group members can see group events, and an individual event is only available to be viewed by the user who entered the event. </p>
<ul>
<li><strong>Events</strong></li>
<li> &#8211; <em>Group Events</em></li>
<li> &#8211; - Viewable by members of the group</li>
<li> &#8211; <em>Individual Events</em></li>
<li> &#8211; - Viewable only by the user who entered the event</li>
</ul>
<p>To put this in a &#8220;use case&#8221; scenario, here are four examples:</p>
<p>Case 1: Username &#8220;MotoCrash&#8221; is a registered user of the site. He is also a group leader of the &#8220;ProFootball&#8221; group. He is able to update membership of the group, and is able to edit the different events for the group calendar. There are some events he has had to delete. He often updates his own account with a new avatar image. He can view all of the group events to determine if any of them need to be edited.<br />
ARO = &#8220;MotoCrash&#8221;<br />
ACOs = Groups, Events, Users</p>
<p>Case 2: Username &#8220;FootballNut&#8221; is a registered user of the site. He is a member of two (2) groups. He is a regular member of the group named &#8220;ProFootball&#8221; and a group leader of &#8220;PopWarnerBall&#8221;. He is able to see events in both groups, but is only able to add, edit, or delete events in the &#8220;PopWarnerBall&#8221; group. He adds his own events for personal uses that only he is able to see.<br />
ARO = &#8220;FootballNut&#8221;<br />
ACOs = Groups (2 checks), Events</p>
<p>Case 3: Username &#8220;Angel&#8221; is a regular member. She is not part of a group as of yet, but posts events to her own personal calendar. She is able to edit her account, adding a new signature line every month. She is able to view her own events. She is an avid football fan, but is unable to see events for the ProFootball group.<br />
ARO = &#8220;Angel&#8221;<br />
ACOs = Groups, Users, Events</p>
<p>Case 4: Username &#8220;Admin&#8221; is a the site admin. They are able to do all actions in any group, and able to update any memberships, or add, edit or delete accounts. They are not able to delete their own account.<br />
ARO = &#8220;Admin&#8221;<br />
ACOs = Groups, Events, Users, Administation</p>
<table width='90%' cellpadding='2' cellspacing='2' border='1'>
<tr>
<td>&nbsp;</td>
<td colspan='4'>Users</td>
</tr>
<tr>
<td>Area</td>
<td>MotoCrash</td>
<td>FootballNut</td>
<td>Angel</td>
<td>Admin</td>
</tr>
<tr>
<td><b>Group ACO</b>: ProFootball</td>
<td colspan='4'>&nbsp;</td>
</tr>
<tr>
<td><i>Add Members</i></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><i>Remove Members</i></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><b>Group ACO</b>: PopWarnerBall</td>
<td colspan='4'>&nbsp;</td>
</tr>
<tr>
<td><i>Add Members</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><i>Remove Members</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><b>Event ACO</b>: ProFootball</td>
<td colspan='4'>&nbsp;</td>
</tr>
<tr>
<td><i>View Events</i></td>
<td align='center'><b>X</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><i>Add, Edit or Delete Events</i></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><b>Event ACO</b>: PopWarnerBall</td>
<td colspan='4'>&nbsp;</td>
</tr>
<tr>
<td><i>View Events</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><i>Add, Edit or Delete Events</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><b>Individual Event ACO</b>: MotoCrash</td>
<td colspan='4'>&nbsp;</td>
</tr>
<tr>
<td><i>View, Add, Edit, Delete  Events</i></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><b>Individual Event ACO</b>: FootballNut</td>
<td colspan='4'>&nbsp;</td>
</tr>
<tr>
<td><i>View, Add, Edit, Delete  Events</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><b>Individual Event ACO</b>: Angel</td>
<td colspan='4'>&nbsp;</td>
</tr>
<tr>
<td><i>View, Add, Edit, Delete  Events</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><b>User ACO</b></td>
<td colspan='4'>&nbsp;</td>
</tr>
<tr>
<td><i>Update Own Account</i></td>
<td align='center'><b>X</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>X</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><i>Update Other Account</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
<tr>
<td><i>Delete Own Account</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
</tr>
<tr>
<td><i>Delete Other Account</i></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>-</b></td>
<td align='center'><b>X</b></td>
</tr>
</table>
<p>I hope this has been helping to better understand ACLs. In order to really delve into this topic, and separate the different areas, I am finishing this post here. I am going to post another one that gets into the code of setting up the tables (acos, aros, aros_acos), and then the coding portion of the ACLs, like when a new user is created, group membership changes, or how to validate on the ACL based on the logged in user. </p>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2008/08/25/access-control-lists-acls/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>CakePHP Authentication</title>
		<link>http://www.hirdweb.com/2008/07/14/cakephp-authentication/</link>
		<comments>http://www.hirdweb.com/2008/07/14/cakephp-authentication/#comments</comments>
		<pubDate>Mon, 14 Jul 2008 14:53:00 +0000</pubDate>
		<dc:creator>stephen</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[authentication]]></category>
		<category><![CDATA[cakePHP]]></category>

		<guid isPermaLink="false">http://www.hirdweb.com/?p=7</guid>
		<description><![CDATA[After last weeks Auth component, it is now time to go into the full Authentication of a user. In order to use the full power of the Auth component, the table should be named &#8220;users&#8221;. In the table I created, there were a few different things put in, but for the sake of this, I [...]]]></description>
			<content:encoded><![CDATA[<p>After last weeks Auth component, it is now time to go into the full Authentication of a user. In order to use the full power of the Auth component, the table should be named &#8220;users&#8221;. In the table I created, there were a few different things put in, but for the sake of this, I will limit those.</p>
<pre>CREATE TABLE IF NOT EXISTS `users` (
	`user_id` int(11) NOT NULL auto_increment,
	`username` varchar(25) NOT NULL,
	`password` varchar(250) NOT NULL,
	`full_name` varchar(250) NOT NULL,
	`email` varchar(250) NOT NULL,
	`remote_address` varchar(16) NOT NULL,
	`last_login` datetime default NULL,
	`last_login_ip` varchar(16) default NULL,
	`created` datetime NOT NULL,
	`modified` datetime default NULL,
	PRIMARY KEY  (`user_id`),
	UNIQUE KEY `username` (`username`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;</pre>
<p>In this table, there is a lot you really do not need, but here is the breakdown: &#8216;user_id&#8217; is needed for my purposes, &#8216;username&#8217; and &#8216;password&#8217; are named as such to be able to use the Auth component methods. The other fields are for personalization (full_name and email). The next three are just for simplistic CYA that should always be good practice, grap the registered IP address, date the user last logged in and the IP they logged in from. Is this a foolproof way of CYA? No. But it starts you out on the right track. The last two I always put in all of my tables, as CakePHP updates those automatically, so this also helps to track when created and when changed.</p>
<p>Now that the table is done, we need to provide some quick validation for registration and such. In the model, the code should look similar to this:</p>
<pre>var $name = 'User';
var $primaryKey = 'user_id';
var $validate = array(
	'username' =&gt; array(
		'alphaNumeric' =&gt; array(
			'rule'		=&gt; 'alphaNumeric',
			'required'	=&gt; true,
			'on'		=&gt; 'create',
			'message'	=&gt; 'Username must be only letters and numbers, no special characters'
		),
		'between' =&gt; array(
			'rule' 		=&gt; array('between', 5, 20),
			'on'		=&gt; 'create',
			'message'	=&gt; 'Username must be between 5 and 20 characters',
		),
		'isUnique' =&gt; array(
			'rule'		=&gt; 'isUnique',
			'on'		=&gt; 'create',
			'message'	=&gt; 'This username is already taken. Please choose a different one.'
		)
	),
	'email' =&gt; array(
		'rule'		=&gt; array('email', true),
		'required'	=&gt; true,
		'message'	=&gt; 'Please provide a valid email address'
	),
);</pre>
<p><span id="more-7"></span><br />
The data validation is a topic for another post, and the <a title="Cookbook Data Validation" href="http://book.cakephp.org/view/125/data-validation" target="_blank">Cookbook has a good entry for this as well</a>. In this example, there is multiple validations for the username, and one for the email. We want the username to be only alphanumeric, between 5 and 20 characters in length, and it needs to be unique. The email just needs to be a valid email address. Each validation rule has its own error message. But we have provided simple validation for the model.</p>
<p>Now it is time to create/update the controller. If you have Baked the controller, then you have 5 actions, index, add, edit, delete, view. I am not particularly fond of having a &#8220;register&#8221; action named &#8220;add&#8221;, so I changed this around. Remember that if you are using the Auth component to allow this in the beforeFilter() function.</p>
<pre>$this-&gt;Auth-&gt;allow('register');</pre>
<p>Now in my &#8220;register&#8221; function, I started off with checking if the data set is empty. And if you Baked the controller, most of this should be in there already. The register function will have two main parts, if the form is filled out and if it is not/has errors. With using the Auth component, it is important to remember a basic part of the Auth with passwords, it hashes the passwords for you and includes the SALT string in the config file. So I will point this out right now. YOU MUST RESET THE PASSWORD FIELD IF YOU DO NOT WANT EMPTY STRINGS FOR PASSWORDS. This includes if you are using data validation for this field. Auth automatically appends whatever is in the password field and appends the SALT. So if someone leaves it blank, Auth will still append the SALT and it will never be blank. The best way to check this is with AJAX/javascript for the field on the form level, not the processing level. On the processing level, if the form is blank, or contains errors, clear the password field.</p>
<pre>function register() {
	if (!empty($this-&gt;data)) {
		// code to be put here
	}

	$this-&gt;data['User']['password'] = ''; // reset the password field
}</pre>
<p>This now checks for the form being filled out, and if not, resets that password field. (As a note, it is always best to have the password verified by entering this twice, but for right now, we are skipping this). If the form is empty, we reset data, and have the user fill out the form again. If not, we start to look to see what data we have to work with. I always suggest to use the <a href="http://book.cakephp.org/view/153/data-sanitization" target="_blank">Data Sanitizer component</a> to help clean up the fields. This helps ensure the data will not empty your tables or other problems occur (not all web surfers are harmless). With the sanitation, set the data to the model so the validation rules can help out.</p>
<pre>function register() {
	if (!empty($this-&gt;data)) {
		$clean = new Sanitize();
		$clean-&gt;clean($this-&gt;data);
		$this-&gt;User-&gt;set($this-&gt;data);
		// Sanitize the data using this only as an example, but all fields that require the user to type should be included
		$this-&gt;data['User']['username'] = $clean-&gt;paranoid($this-&gt;data['User']['username']);
	}

	$this-&gt;data['User']['password'] = ''; // reset the password field
}</pre>
<p>Now we need to check those validation rules, and CakePHP has a perfect function to help do this. By using the $this-&gt;MODEL-&gt;validates() function, it will check any validation rules that have been specified for the model. If there is errors, then it kicks the user back to the form with those error messages. If it does validate, then then we can proceed to create the account.</p>
<pre>function register() {
	if (!empty($this-&gt;data)) {
		$clean = new Sanitize();
		$clean-&gt;clean($this-&gt;data);
		$this-&gt;User-&gt;set($this-&gt;data);

		// Sanitize the data using this only as an example, but all fields that require the user to type should be included
		$this-&gt;data['User']['username'] = $clean-&gt;paranoid($this-&gt;data['User']['username']);

		// Check for validation rules
		if ($this-&gt;User-&gt;validates()) {
			// All validation rules have been satisfied, so we need to check this in to the table
                        $this-&gt;User-&gt;create();

			if ($this-&gt;User-&gt;save($this-&gt;data)) {
				$this-&gt;Session-&gt;setFlash(__('The User has been saved. Please Login using the new identification.', true));
				$this-&gt;redirect(array('action'=&gt;'login'));
			} else {
				$this-&gt;Session-&gt;setFlash(__('The User could not be saved. Please, try again.', true));
			}
		}
	}

	$this-&gt;data['User']['password'] = ''; // reset the password field
}</pre>
<p>First we check to see if the form has been filled out, and sent. If it has, we sanitize the data, then validate it. If it validates, we create the record. If the record can not be created, for whatever reason, it kicks them back. If the data can be saved, and the record is created, it then redirects them back to the &#8220;login&#8221; page. This is just a simplistic registration form. We can extend this to use a full blown profile table, add more sanitation, and more validation. But for right now, this is good. We now need to allow them to login. And the Auth component makes it easy.</p>
<p>We can make it as easy as we need, or as hard as we need. With using the Auth component, all we would really need to do is</p>
<pre>function login() {
}</pre>
<p>You would still need to create the view for it, having the username and password fields there, but if you would like more info in the Session, then there is just a little more to do. The first is to check to see if the login form has been filled out, then check for it to be blank, sanitize the data, and now we get to some meat here. With the Auth, we can grab other fields and set them to be used in the Session</p>
<pre>function login() {
	if ($this-&gt;Auth-&gt;user()) {
		if (!empty($this-&gt;data)) {
			$san = new Sanitize();
			// Sanitize the input of items we do not know what the end user put in.
			$this-&gt;data['User']['username'] = $san-&gt;paranoid($this-&gt;data['User']['username']);

			// Grab the data from the User table and set them to the cookie array
			$cookie = array();
			$cookie['user_id'] = $this-&gt;Auth-&gt;user('user_id');
			$cookie['full_name'] = $this-&gt;Auth-&gt;user('full_name');
			$cookie['ast_login'] = $this-&gt;Auth-&gt;user('last_login');
			$cookie['last_login_ip'] = $this-&gt;Auth-&gt;user('last_login_ip');

			$this-&gt;Session-&gt;write('Auth.User', $cookie);
		}
	}
}</pre>
<p>The Session-&gt;write() method will write these to the Session with the cols/vals in a foreach loop. So name the elements in the array with something useful if you intend to use them later so that you can recall them. The CakePHP API documentation provides great information on the write() function, but real quick, it is the name, then value. The next part I added to this was to update the User table with the info:</p>
<pre>$update['User']['user_id'] = $userid;
$update['User']['last_login'] = $this-&gt;data['User']['last_login'];
$update['User']['last_login_ip'] = $this-&gt;data['User']['last_login_ip'];
$this-&gt;User-&gt;save($update, false, array('user_id', 'last_login', 'last_login_ip'));</pre>
<p>After successful login, we can redirect using the Auth redirect, which is handy to redirect users back to pages where authentication was needed to get in.</p>
<pre>$this-&gt;redirect($this-&gt;Auth-&gt;redirect());</pre>
<p>One other thing I added in, just because I can not stand forms and logins that allow you to log in even if you are already logged in, is to check to see if they are logged in. If they are logged in, and try to log in again, I send them back to the home page, with a message reminding them of their current status. I also clear out the Auth message in case anything is lingering in there.</p>
<pre>if (empty($this-&gt;data)) {
	// Check to see if they are logged in
	if (isset($_SESSION['Auth']['User']['username'])){
		$this-&gt;Session-&gt;setFlash(__('You are already logged in. ', true));
		$this-&gt;redirect(array('action' =&gt; 'index'));
	}

	// Perform other checks on the empty data and set up the form.
	$cookie = $this-&gt;Session-&gt;read('Auth.User');
	if (!is_null($cookie)) {
		if ($this-&gt;Auth-&gt;login($cookie)) {
			//  Clear auth message, just in case we use it.
			$this-&gt;Session-&gt;del('Message.auth');
			$this-&gt;redirect($this-&gt;Auth-&gt;redirect());
		}
	}
}</pre>
<p>Seems like too much? Well, with my long-winded explanations, yes, but it is quite simple and quick when you get to coding it, and one more time, the entire login function</p>
<pre>function login() {
	if ($this-&gt;Auth-&gt;user()) {
		if (!empty($this-&gt;data)) {
			$san = new Sanitize();
			// Sanitize the input of items we do not know what the end user put in.
			$this-&gt;data['User']['username'] = $san-&gt;paranoid($this-&gt;data['User']['username']);

			// Grab the data from the User table and set them to the cookie array
			$cookie = array();
			$cookie['user_id'] = $this-&gt;Auth-&gt;user('user_id');
			$cookie['full_name'] = $this-&gt;Auth-&gt;user('full_name');
			$cookie['ast_login'] = $this-&gt;Auth-&gt;user('last_login');
			$cookie['last_login_ip'] = $this-&gt;Auth-&gt;user('last_login_ip');

			$this-&gt;Session-&gt;write('Auth.User', $cookie); 

			$update['User']['user_id'] = $userid;
			$update['User']['last_login'] = $this-&gt;data['User']['last_login'];
			$update['User']['last_login_ip'] = $this-&gt;data['User']['last_login_ip'];
			$this-&gt;User-&gt;save($update, false, array('user_id', 'last_login', 'last_login_ip'));

			$this-&gt;redirect($this-&gt;Auth-&gt;redirect());
		}
	}

	if (empty($this-&gt;data)) {
		// Check to see if they are logged in
		if (isset($_SESSION['Auth']['User']['username'])){
			$this-&gt;Session-&gt;setFlash(__('You are already logged in. ', true));
			$this-&gt;redirect(array('action' =&gt; 'index'));
		}

		// Perform other checks on the empty data and set up the form.
		$cookie = $this-&gt;Session-&gt;read('Auth.User');
		if (!is_null($cookie)) {
			if ($this-&gt;Auth-&gt;login($cookie)) {
				//  Clear auth message, just in case we use it.
				$this-&gt;Session-&gt;del('Message.auth');
				$this-&gt;redirect($this-&gt;Auth-&gt;redirect());
			}
		}
	}

}</pre>

<!-- Wordpress Connect Modules v1.05 -->]]></content:encoded>
			<wfw:commentRss>http://www.hirdweb.com/2008/07/14/cakephp-authentication/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
