dAuth v0.3 models

By Dieter Plaetinck (Dieter_be)
User, Host, LoginAttempt models for dAuth v0.3

models/user.php


Model Class:

Download code <?php 
/*
 * PHP versions 4 and 5
 *
 * dAuth: A secure authentication system for the cakePHP framework.
 * Copyright (c)    2006, Dieter Plaetinck
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @author            Dieter Plaetinck
 * @copyright        Copyright (c) 2006, Dieter Plaetinck
 * @version            0.3
 * @modifiedby        Dieter@be
 * @lastmodified    $Date: 2006-12-04 16:18:00 +0000 (Mon, 4 Dec 2006) $
 * @license            http://www.opensource.org/licenses/mit-license.php The MIT License
 */
class User extends AppModel
{
    var 
$name 'User';
    var 
$displayField 'username';

    var 
$validate = array(
        
'username'    => '/[a-z0-9\_\-]{3,}$/i',
        
'email'     => VALID_EMAIL,
        
'password'    => VALID_NOT_EMPTY
    
);

    function 
changePassword ($id null$hash null)
    {
        
$success false;
        if (
$id && $hash)
        {
            
$this->id $id;
            
$success $this->saveField('password'$hash);
        }
        return 
$success;
    }
}
?>

models/host.php


Model Class:

Download code <?php 
/*
 * PHP versions 4 and 5
 *
 * dAuth: A secure authentication system for the cakePHP framework.
 * Copyright (c)    2006, Dieter Plaetinck
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @author            Dieter Plaetinck
 * @copyright        Copyright (c) 2006, Dieter Plaetinck
 * @version            0.3
 * @modifiedby        Dieter@be
 * @lastmodified    $Date: 2006-12-04 16:18:00 +0000 (Mon, 4 Dec 2006) $
 * @license            http://www.opensource.org/licenses/mit-license.php The MIT License
 */
class Host extends AppModel
{
    var 
$name 'Host';
    var 
$hasMany = array('LoginAttempt');
    var 
$validate = array (
        
'ip_adress'  => VALID_NOT_EMPTY
    
);
    function 
block ($id null,$time null)
    {
        
$success false;
        if (
$id)
        {
            if(!
$time)
            {
                
$time time();
            }
            
$this->id $id;
            
$success $this->saveField('blocked'$time);
        }
        return 
$success;
    }

    
/*
     *  not really used since hosts are unblocked automatically when the 'blocked' timestamp expires
     */
   
function unBlock ($id null)
   {
           
$success false;
           if (
$id)
           {
               
$this->id $id;
               
$success $this->saveField('blocked''0');
           }
           return 
$success;
       }

   function 
isBlocked($host null,$limit null)
   {
           
$blocked false;

           if(
$host && $limit)
           {
               if(
$host['Host']['blocked'] >= $limit)
               {
                   
$blocked true;
               }
           }
           return 
$blocked;
   }

   function 
isHammering($data null,$rules null)
    {
        
$hammer false;

        if(
$data['Host'] && $rules && is_array($rules))
        {
            
//$datetime = gmdate("Y-m-d H:i:s", $time);
            //strtotime($datetime.' GMT')
            
$time time();
            
$time += 60*60;
            
//FIXME: really ugly hack . time() is gmt while cake is my timezone. making gmdate -> date below, doesn't work
            
$limit $time $rules['seconds'];
            
$attempts $this->LoginAttempt->findCount(array('host_id' => ' = '.$data['Host']['id'],'LoginAttempt.created' => '>= '.gmdate("Y-m-d H:i:s"$limit)));
            if(
$attempts >= $rules['attempts'])
            {
                
$hammer true;
            }
        }
        return 
$hammer;
    }
}
?>

models/login_attempt.php


Model Class:

Download code <?php 
/*
 * PHP versions 4 and 5
 *
 * dAuth: A secure authentication system for the cakePHP framework.
 * Copyright (c)    2006, Dieter Plaetinck
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @author            Dieter Plaetinck
 * @copyright        Copyright (c) 2006, Dieter Plaetinck
 * @version            0.3
 * @modifiedby        Dieter@be
 * @lastmodified    $Date: 2006-12-04 16:18:00 +0000 (Mon, 4 Dec 2006) $
 * @license            http://www.opensource.org/licenses/mit-license.php The MIT License
 */
class LoginAttempt extends AppModel
{
    var 
$name 'LoginAttempt';
    var 
$validate = array(
        
'host_id'  => VALID_NUMBER
    
);
    var 
$belongsTo = array('Host');
    function 
cleanUpExpired($date_limit null)
    {
        if(
$date_limit)
        {
            
$this->query('DELETE FROM `login_attempts` WHERE `login_attempts`.`created` <= '.gmdate("Y-m-d H:i:s",$date_limit));
        }
    }
 }
?>

Here is the sql that you should execute


Download code
--
-- Table structure for table `hosts`
--

DROP TABLE IF EXISTS `hosts`;
CREATE TABLE `hosts` (
  `id` int(11) NOT NULL auto_increment,
  `ip_adress` varchar(255) NOT NULL default '',
  `created` datetime NOT NULL default '0000-00-00 00:00:00',
  `modified` datetime NOT NULL default '0000-00-00 00:00:00',
  `blocked` int(11) NOT NULL default '0',
  PRIMARY KEY  (`id`)
);

--
-- Table structure for table `login_attempts`
--

DROP TABLE IF EXISTS `login_attempts`;
CREATE TABLE `login_attempts` (
  `id` bigint(20) unsigned NOT NULL auto_increment,
  `host_id` int(255) NOT NULL default '0',
  `modified` datetime NOT NULL default '0000-00-00 00:00:00',
  `created` datetime NOT NULL default '0000-00-00 00:00:00',
  PRIMARY KEY  (`id`)
);

--
-- Table structure for table `users`
--

DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `username` varchar(255) NOT NULL default '',
  `email` varchar(255) NOT NULL default '',
  `password` varchar(255) NOT NULL default '',
  PRIMARY KEY  (`id`),
  UNIQUE KEY `username` (`username`)
);


more info about dAuth @ http://bakery.cakephp.org/articles/view/147

 

Comments 155

CakePHP Team Comments Author Comments
 

Bug

1 created and modified

You should remove the default 0000-00-00 00:00:00 part from your SQL.

Because of that, created and modified will not be updated, so all entries will be 0000-00-00 ... once i removed the default save() added the proper datetime value to the row.



Posted Dec 31, 1969 by Kjell Bublitz
 

Bug

2 An interesting bug

models/host.php line 79
<code>
$attempts = $this->LoginAttempt->findCount(array('host_id' => ' = '.$data['Host']['id'],'LoginAttempt.created' => '>= '.gmdate("Y-m-d H:i:s", $limit)));
</code>

generates when using the postgres driver

<code>
SELECT COUNT(*) AS count FROM "login_attempts" AS "LoginAttempt" LEFT JOIN "hosts" AS "Host" ON "LoginAttempt"."host_id" = "Host"."id" WHERE ("host_id" = ' = 1') AND ("LoginAttempt"."created" >= '2007-02-18 23:13:12')
</code>
which raises the error
<code>
ERROR: invalid input syntax for integer: " = 1"
</code>

To fix this change line 79 of models/host.php to
<code>
$attempts = $this->LoginAttempt->findCount(array('host_id' => '= '.$data['Host']['id'],'LoginAttempt.created' => '>= '.gmdate("Y-m-d H:i:s", $limit)));

</code>

Posted Dec 31, 1969 by anshul
 

Comment

3 comment on the above bug

Basically, there is an extra space before the equal to that needs to be removed. Also, the original code seems to work with mysql but gives an error on postgres.
Posted Dec 31, 1969 by anshul
 

Bug

4 Bug

Sorry, i didn't test on postgres, i only have mysql :-)
Nice find!
Posted Dec 31, 1969 by Dieter Plaetinck
 

Bug

5 cleanUpExpired misses quotation

in the cleanUpExpired method of login_attempt you should add quotations around the datetime value

$this->query('DELETE FROM `login_attempts` WHERE `login_attempts`.`created` <= \''.gmdate("Y-m-d H:i:s",$date_limit)) . '\'';
Posted May 19, 2007 by Viktor Nagy
 

Comment

6 Minor Typo


s/adress/address/g

(IP Address should really be spelt correctly.)

Also a minor note for others in case they haven't run into this before - PostgreSQL doesn't use auto_increment (that's a MySQL thing). For PostgreSQL, change lines of the form:

  `id` int(11) NOT NULL auto_increment, 

...to lines of the form:

  `id` serial NOT NULL,

This will create an implicit sequence on the 'id' column, and basically do what 'auto_increment' does for MySQL.

Also, for PostgreSQL, use 'character varying' rather than 'varchar' - this is probably the same in other SQL-compliant databases (varchar is a MySQL-only shortcut). And 'integer' rather than 'int' etc.

Very nice Auth model though - thanks for sharing. _b
Posted Jul 31, 2007 by Sam Evans