Login   Register  
PHP Classes
elePHPant
Icontem

File: DAP.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Craig Manley  >  Authen_DAP  >  DAP.php  >  Download  
File: DAP.php
Role: Class source
Content type: text/plain
Description: The main class, based on an existing Perl class of mine.
Class: Authen_DAP
Slow down attempts to guess login passwords
Author: By
Last change:
Date: 9 years ago
Size: 9,942 bytes
 

Contents

Class file image Download
<?php
// +----------------------------------------------------------------------+
// | Dictionary Attack Protection class for PHP5.                         |
// | Copyright (C) 2005 Craig Manley                                      |
// +----------------------------------------------------------------------+
// | This library is free software; you can redistribute it and/or modify |
// | it under the terms of the GNU Lesser General Public License as       |
// | published by the Free Software Foundation; either version 2.1 of the |
// | License, or (at your option) any later version.                      |
// |                                                                      |
// | This library is distributed in the hope that it will be useful, but  |
// | WITHOUT ANY WARRANTY; without even the implied warranty of           |
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU     |
// | Lesser General Public License for more details.                      |
// |                                                                      |
// | You should have received a copy of the GNU Lesser General Public     |
// | License along with this library; if not, write to the Free Software  |
// | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  |
// | USA                                                                  |
// |                                                                      |
// | LGPL license URL: http://opensource.org/licenses/lgpl-license.php    |
// +----------------------------------------------------------------------+
// | Author: Craig Manley                                                 |
// +----------------------------------------------------------------------+
//
// $Id: DAP.php,v 1.1 2005/01/09 22:44:19 cmanley Exp $
//



/**
 * @author    Craig Manley
 * @copyright Copyright  2004, Craig Manley. All rights reserved.
 * @package   com.craigmanley.classes.authen.DAP
 * @version   $Revision: 1.1 $
 */




/**
 * Offers protection against dictionary attacks.
 *
 * @package  com.craigmanley.classes.authen.DAP
 */
class Authen_DAP {

  
// Private members
  
private $shm          null// Object implementing IPC_ISharedMem interface.
  
private $max_attempts null;
  private 
$period       null;


  
/**
   * Constructor.
   *
   * @param object  $shm shared memory object that implements the IPC_ISharedMem interface.
   * @param integer $max_attempts maximum failed (login) attempts after which to block the identity, default 3.
   * @param integer $period time in seconds to block an identity for after too many failed access attempts, default 180.
   */
  
public function __construct($shm$max_attempts 3$period 180) {
    if (!(isset(
$shm) && ($shm instanceof IPC_ISharedMem))) {
      throw 
Exception('You must pass a shared memory management object that implements the IPC_ISharedMem interface as the 1st parameter!');
    }
    
$this->shm $shm;
    
$this->max_attempts($max_attempts);
    
$this->period($period);
  }


  
/**
   * Checks if the parameter is a positive integer (representation).
   *
   * @param mixed $value
   * @return boolean
   */
  
protected function _is_pos_int($value) {
    return (
is_int($value) || (is_string($value) && preg_match('/^\+?\d+$/'$value))) && ($value 0);
  }


  
/**
   * Gets or sets the maximum number of failed access attempts after which an identity
   * will be temporarily blocked. The default value is 3.
   *
   * @param value $name Optional new value. Must be an integer >= 1.
   * @return integer
   */
  
public function max_attempts() {
    if (
func_num_args()) {
      
$value func_get_arg(0);
      if (!(isset(
$value) && $this->_is_pos_int($value))) {
        throw 
Exception("Method parameter is not a positive integer!");
      }
      
$this->max_attempts intval($value);;
    }
    return 
$this->max_attempts;
  }


  
/**
   * Gets or sets the period (in seconds) that identities are blocked for after
   * too many failed access attempts. The default value is 180.
   *
   * @param value $name Optional new value. Must be an integer >= 1.
   * @return integer
   */
  
public function period() {
    if (
func_num_args()) {
      
$value func_get_arg(0);
      if (!(isset(
$value) && $this->_is_pos_int($value))) {
        throw 
Exception("Parameter is not a positive integer!");
      }
      
$this->period intval($value);;
    }
    return 
$this->period;
  }


  
/**
   * Checks to see if the identity's access has been blocked using the given record structure.
   * Returns the seconds the identity is (still) blocked for (0 means not blocked).
   *
   * @param scalar $identity Anything used to identify someone such as an IP, alias, etc.
   * @param array $records array of [$identity, $last_attempt] arrays.
   * @return integer
   */
  
private function _blocked($identity, &$records) {
    
$attempts 0;
    
$max_attempts $this->max_attempts();
    
$last_attempt null;
    
// Search for the last $max_attempts records if any.
    
for ($i count($records) - 1$i >= 0$i--) {
      if (
$records[$i][0] == $identity) {
        
$attempts++;
        if (
is_null($last_attempt)) {
          
$last_attempt $records[$i][1];
        }
        if (
$attempts >= $max_attempts) {
          break;
        }
      }
    }
    
$block_for null;
    if (
$attempts >= $max_attempts) {
      
$block_for $last_attempt $this->period() - time();
      if (
$block_for 0) { // could happen in theory if code executes slowly.
        
$block_for 0;
      }
    }
    else {
      
$block_for 0;
    }
    return 
$block_for;
  }


  
/**
   * Deletes expired records from the record structure passed as parameter.
   * Returns the seconds the identity is (still) blocked for (0 means not blocked).
   * Returns the amount of records deleted.
   *
   * @param array $records array of [identity, time] arrays.
   * @return integer
   */
  
private function _delete_expired_records(&$records) {
    
$result 0;
    
$expire_before time() - $this->period();
    while (
count($records)) {
      if (
$records[0][1] <= $expire_before) {
        
$result++;
        
array_shift($records);
      }
      else {
        break;
      }
    }
    return 
$result;
  }


  
/**
   * Loads the recorded failed access events structure from shared memory,
   * cleans out all expired records if any, saves the structure back into
   * shared memory (if changed), and returns the new record structure.
   *
   * @return array
   */
  
private function &_records() {
    
$records null;
    
$shm $this->shm;
    
$shm->transaction_start();
    try {
      
$s $shm->fetch();
      if (isset(
$s) && strlen($s)) {
          
$records unserialize($s);
        if (
$this->_delete_expired_records($records)) {
          
$s serialize($records);
          
$shm->store($s);
        }
      }
      
$shm->transaction_finish();
    }
    catch(
Exception $e) {
      
$shm->transaction_finish();
      throw 
$e;
    }
    if (!isset(
$records)) {
      
$records = array();
    }
    return 
$records;
  }


  
/**
   * Records a failed access attempt and returns the number of seconds the identity
   * has been blocked for (0 meaning not blocked).
   *
   * @param string $identity Anything used to identify somebody such as an IP address, login alias, session key, etc.
   * @return integer
   */
  
public function record_failed_attempt($identity) {
    
$records null;
    
$shm $this->shm;
    
$shm->transaction_start();
    try {
      
$s $shm->fetch();
      if (isset(
$s) && strlen($s)) {
          
$records unserialize($s);
        
$this->_delete_expired_records($records);
      }
      else {
        
$records = array();
      }
      
array_push($records, array($identitytime()));
      
$s serialize($records);
      
$shm->store($s);
      
$shm->transaction_finish();
    }
    catch(
Exception $e) {
      
$shm->transaction_finish();
      throw 
$e;
    }
    return 
$this->_blocked($identity,$records);
  }


  
/**
   * Dumps the records currently stored in shared memory to stdout. Only useful for debugging.
   */
  
public function dump_records() {
    
$records $this->_records();
    
print_r($records);
  }


  
/**
   * Clears all interal records of failed access attempts for the given identity.
   *
   * @param string $identity Anything used to identify somebody such as an IP address, login alias, session key, etc.
  */
  
public function clear($identity) {
    
$shm $this->shm;
    
$shm->transaction_start();
    try {
      
$s $shm->fetch();
      if (isset(
$s) && strlen($s)) {
        
$records unserialize($s);
        
$changed false;
        if (
$this->_delete_expired_records($result)) {
          
$changed true;
        }
        
$i 0;
        while (
count($records) && ($i count($records))) {
          if (
$records[$i][0] == $identity) {
            
array_splice($records,$i,1);
            
$changed true;
          }
          else {
            
$i++;
          }
        }
        if (
$changed) {
          
$s serialize($result);
          
$shm->store($s);
        }
      }
      
$shm->transaction_finish();
    }
    catch(
Exception $e) {
      
$shm->transaction_finish();
      throw 
$e;
    }
  }


  
/**
   * Checks to see if the indentity's access has been blocked.
   * Returns the number of seconds the identity has been blocked for (0 means not blocked).
   *
   * @param string $identity Anything used to identify somebody such as an IP address, login alias, session key, etc.
   * @return integer
   */
  
public function blocked($identity) {
    return 
$this->_blocked($identity$this->_records());
  }

}


?>