Code snippets for symfony 1.x


Refine Tags

Snippets tagged "sfguard"

sfGuard Logging with Brute Force Login Prevention

For those of us who just need a bit more security out of this already awesome authentication plugin. This has been tested to work on symfony 1.2 using sfGuardPlugin version 3.1.3 stable.

The default behavior of this snippet is a log that tracks each login attempt, the IP, the username entered, and whether it was successful or not. The brute force protection's default settings will check to see if more than 5 attempts for the same username in the past 2 minutes were failed attempts. It also includes a cooldown period of 15 minutes from the last failed login attempt. All of these variables can be changed in the arguments for checkBruteForce().

The first thing we need to do is create a log for sfGuard. Your schema should now contain the following:


    _attributes:    { phpName: sfGuardLog }
    ip:             varchar(30)
    username:       varchar(20)
    valid_login:    boolean

Once the changes to your schema have been made, rebuild your models, forms, and filters. Next, we need to extend the peer class for this new sfGuardLog model to handle brute force protection.


    Auther: Christopher Lewis (
    Check for brute force login attempts
    Case I
     1. Get all logins for this username in the past N minutes
     2. If P or more of them are fails, this is likely a brute force attempt, return true
    Case II
     1. Get last P logins
     2. Are they all fails? AND Are they all within the same window of N minutes? AND Was the last attempt within the past Q minutes?
        If all are true, return true
     N = $attempt_window
     P = $allowed_fail_count
     Q = $cooldown_window
  public static function checkBruteForce($username, $attempt_window = 2, $cooldown_window = 15, $allowed_fail_count = 5)
    //Case I...
    $N_minutes_ago_timestamp = strtotime("$attempt_window minutes ago");
    $N_minutes_ago_sqltime = date('Y-m-d H:i:s', $N_minutes_ago_timestamp);
    $c = new Criteria();
    $c->add(sfGuardLogPeer::USERNAME, $username);
    $c->add(sfGuardLogPeer::CREATED_AT, $N_minutes_ago_sqltime, Criteria::GREATER_THAN);
    $entries = sfGuardLogPeer::doSelect($c);
    $failed_count = 0;
    foreach($entries as $log) { if($log->getValidLogin() == false) { $failed_count++; } }
    if($failed_count >= $allowed_fail_count) { return true; }
    //Case II...
    $all_fails = false; $all_in_window = false; $last_attempt_recent = false;
    //Are they all fails?
    $c = new Criteria();
    $c->add(sfGuardLogPeer::USERNAME, $username);
    $failed_count = 0; $timestamps = array();
    $entries = sfGuardLogPeer::doSelect($c);
    foreach($entries as $pos => $log)
      if($log->getValidLogin() == false) { $failed_count++; }
      array_push($timestamps, strtotime($log->getCreatedAt()));
    if($failed_count >= $allowed_fail_count) { $all_fails = true; }
    else { return false; }
    //Are they all within the same window of N minutes?
    $time_a = $timestamps[0];
    $time_b = $timestamps[(count($timestamps) - 1)];
    $window_in_secs = $time_b - $time_a;
    $window_in_mins = $window_in_secs / 60;
    if($window_in_mins <= $attempt_window) { $all_in_window = true; }
    else { return false; }
    //Was the last attempt less than Q minutes ago?
    $Q_minutes_ago_timestamp = strtotime("$allowed_fail_count minutes ago");
    $last_attempt_timestamp = strtotime($entries[0]->getCreatedAt());
    if($Q_minutes_ago_timestamp <= $last_attempt_timestamp) { $last_attempt_recent = true; }
    else { return false; }
    //If all are true, return true
    if($all_fails == true && $all_in_window == true && $last_attempt_recent == true) { return true; }
    return false;  

Last, we'll need to overload the executeSignin action in the sfGuardAuth module to include our new logging and security features:


public function executeSignin($request)
    $user = $this->getUser();
      return $this->redirect('@homepage');
    $class = sfConfig::get('app_sf_guard_plugin_signin_form', 'sfGuardFormSignin');
    $this->form = new $class();
      $values = $this->form->getValues();
      //Log attempts
      $log = new sfGuardLog();
      //Check for brute force attempt
      $is_brute_force = sfGuardLogPeer::checkBruteForce($request->getParameter('signin[username]'));
      if($this->form->isValid() && !($is_brute_force))
        $this->getUser()->signin($values['user'], array_key_exists('remember', $values) ? $values['remember'] : false);
        // always redirect to a URL set in app.yml
        // or to the referer
        // or to the homepage
        $signinUrl = sfConfig::get('app_sf_guard_plugin_success_signin_url', $user->getReferer('@homepage'));
        return $this->redirect($signinUrl);
by Christopher Lewis on 2009-06-03, tagged authentication  brute  login  plugins  security  sfguard 


or apply transformation on sfGuard tables into your main schema


When you generate a schema with sf_guard tables from your main database with the following command, the schema contains all the tables included the sf_guard tables (it's normal).

symfony propel-build-schema xml

Then after, when you build the model classes, the sfGuardPlugin classes have a wrong name and are in a wrong place (lib/). There is a post on this problem, how to correctly use propel-build-schema after sfGuardPlugin installation?

symfony propel-build-model


To correct the schema, apply the transformation on the XML schema after the schema generation :

symfony transform-schema-sfguard xml

The script add in the schema for all sf_guard_* tables, the package and the phpName with the camelcase used by the plugin.

Also you have to switch off the schema in the plugin to don't have twice declaration :

mv ./plugins/sfGuardPlugin/config/schema.yml ./plugins/sfGuardPlugin/config/

The script: myPakeTransformSchemaSfguard.php

pake_desc( 'apply transformation on sfGuard tables into your main schema' );
pake_task( 'transform-schema-sfguard', 'project_exists' );
function run_transform_schema_sfguard($task, $args) 
  // Check params
  // -- missing params ?
  if ( !count($args) > 1 ) {
    throw new Exception("You must provide a transformation to apply.\nsymfony transform-schema-sfguard\nsymfony transform-schema-sfguard xml");
  // -- schema exists ?
  if ($args[0] == 'xml')
    $schema_filename = sprintf( '%s/schema.xml', sfConfig::get('sf_config_dir') );
    if ( !file_exists($schema_filename) ) {
        throw new Exception( "Missing schema.xml" );
    $schema_filename = sprintf( '%s/schema.yml', sfConfig::get('sf_config_dir') );
    if ( !file_exists($schema_filename) ) {
        throw new Exception( "Missing schema.yml (not yet implemented)" );
    } else {
        throw new Exception( "schema.yml not yet implemented" );
  // Backup schema
  //pake_copy( $schema_filename, $schema_filename . '.previous', array('override' => true) );
  if ($args[0] == 'xml')
    $handle = fopen($schema_filename, "r");
    // get the entire file in $contents
    $contents = '';
    while (!feof($handle))
      $contents.= fread($handle, 8192);
    $num = preg_match_all('/<table(.*)>/i', $contents, $matches);
    // each table definition found
    foreach ($matches[0] as $val)
      if (!preg_match('/package|phpName/i', $val) && preg_match('/name="(sf_guard_.+?)"/i', $val, $val_matches)) {
        $table_name = $val_matches[1];
        //$php_name   = sfInflector::camelize($val_matches[1]);
        $php_name = sfToolkit::pregtr($val_matches[1], array('#/(.?)#e'   => "'::'.strtoupper('\\1')",
                                                             '/(_)(.)/e'  => "strtoupper('\\2')",
                                                             '/(^)(.)/e'  => "strtolower('\\2')"));
        $pattern    = '/(<table.*)(name="'.$table_name.'")(.*>)/i';
        $replace    = '$1$2 package="plugins.sfGuardPlugin.lib.model" phpName="'.$php_name.'" $3';
        $contents   = preg_replace($pattern, $replace, $contents, 1, $count);
    // write the result
    $handle = fopen($schema_filename, "w+");
    fwrite($handle, $contents);


Put the myPakeTransformSchemaSfguard.php script into data/tasks directory


mv ./plugins/sfGuardPlugin/config/schema.yml ./plugins/sfGuardPlugin/config/
symfony propel-build-schema xml
symfony transform-schema-sfguard xml
symfony propel-build-model
by Olivier LOYNET on 2008-04-09, tagged cli  pake  propel  schema  sfguard 

Using HTTP authentification with sfGuardPlugin

Here is how I did this... Create a sfGuardAuth module in your application and edit the actions.class.php file as follow.

The trick is to not try to overwrite the sfGuardAuth/signin action, as it use validation. As well it allow you to use the "normal" signin way (form and etc).

class sfGuardAuthActions extends BasesfGuardAuthActions
  public function executeHTTPSignin()
    // get somme interesting stuff!
    $request = $this->getRequest();
    $response = $this->getResponse();
    $user = $this->getUser();
    // An HTTP authenticated user cannot logout (browser always send authentification datas)
    // So we must be sure that the user has seen the HTTP authentification box before
    if ( $user->getAttribute('request_authentification') )
      // If authentification datas has been sent
      if ( isset( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'] ) )
        // If correct username given
        $guarduser = sfGuardUserPeer::retrieveByUserName( $_SERVER['PHP_AUTH_USER'] );
        if ( $guarduser instanceof sfGuardUser )
          // If correct Password given
          if ( ($guarduser instanceof sfGuardUser) and ($guarduser->checkpassword( $_SERVER['PHP_AUTH_PW'] )) )
            // we can signin the user and redirect it
            $user->signin( $guarduser );
            $this->redirect( sfConfig::get('app_sf_guard_plugin_success_signin_url','@homepage') );
            throw new sfStopException;
    // else, popup the authentification box
    $response->setHttpHeader( 'WWW-Authenticate', 'Basic realm="Identification"' );
    $response->setHttpHeader( 'HTTP/1.0', '401 Unauthorized' );
    // This will be displayed if the user cancel the authentification process
    $this->forward( 'sfGuardAuth', 'password' );
    throw new sfStopException;
  public function executePasswowd()
    # Implement this action as usual...

Enjoy... (I hope)

by jugjug on 2008-03-03, tagged authenticate  http  sfguard 

PG4sfGuard(1): Partial for sfGuardUserProfile and sfGuardUser

If you want add a column to sfGuardUserProfile's list view for show a link to sfGuardUser's edit view:

Create a partial :

And put this:

<?php echo link_to($sf_guard_user_profile->getSfGuardUser()->getUsername(), 'sfGuardUser/edit?id='.$sf_guard_user_profile->getSfGuardUser()->getId()) ?>

PD(It's not very much, but it is my first snippet)

by Roberto G Puentes Diaz on 2008-01-22, tagged generator  partial  sfguard 

Create profile after adding a new user, the simple way.

Sometimes if you use sfGuardUser and sfGuardUserProfile you need to create an empty profile just after adding the new user (automating is such a great thing). This snippet will help out.

UPDATE: Will Killian pointed me to the solution of using this without touching the plugin files, this way it will still work after upgrading the plugin. Thanks!

Edit apps/backend/modules/sfGuardUser/actions/actions.class.php

(create directories and files as needed, just for the record I use this with admin generator on "backend" app)

Mine looks like this.

class sfGuardUserActions extends BasesfGuardUserActions
  protected function savesfGuardUser($sf_guard_user)
    $user_id = $sf_guard_user->getId();
    $c = new Criteria();
    $profile = sfGuardUserProfilePeer::doSelectOne($c);
    if(!$profile) {
      $profile = new sfGuardUserProfile();
by Roberto Carvajal on 2007-10-30, tagged profile  sfguard  user