I’ve seen quite a few posts in the symonfy forum, asking for a password validation that allows to leave the password field blank if a password is already set. But of course the field should be required if no password exists.

There are different ways to solve this. For example you can set the a validator or the ‘required’ option depending on if the object is new or not. In this post I want to present a password validator so that a distinction by the developer is not necessary.

The validator

<?php

/**
 * Description of fkValidatorPasswordclass
 *
 * @author kling
 */
class fkValidatorPassword extends sfValidatorBase
{
  /**
  * Configures the current validator.
  *
  * Available options:
  *
  *  * password: The password that is already set (required)
  *  * pattern: A regex pattern or an array of regex patterns compatible
  *             with PCRE
  *  * password_field: The name of the password field
  *  * password_check_field: The name of the field to conpare the password with
  *
  * Available error codes:
  *
  *  * notequal
  *  * invalid
  *  * required
  *
  * @param array $options   An array of options
  * @param array $messages  An array of error messages
  *
  * @see sfValidatorBase
  */
  public function configure($options = array(), $messages = array())
  {
    $this->addRequiredOption('password', '');
    $this->addOption('pattern',array());
    $this->addOption('password_field', 'password');
    $this->addOption('password_check_field', 'password_check');

    $this->addMessage('notequal', 'Passwords are not euqal.');
  }

  protected function doClean($values)
  {
    $defaultPassword = (string) $this->getOption('password');
    $password = isset($values[$this->getOption('password_field')]) ? $values[$this->getOption('password_field')] : '';
    $password_check = isset($values[$this->getOption('password_check_field')]) ? $values[$this->getOption('password_check_field')] : '';

    $patterns = is_array($this->getOption('pattern')) ? $this->getOption('pattern') : array($this->getOption('pattern'));

    // check if a password is set in the form...
    if(!empty($password))
    {
      if(!empty($patterns))
      {
         foreach($patterns as $pattern)
         {
           if(!preg_match($pattern, $password))
           {
             throw new sfValidatorErrorSchema($this, array($this->getOption('password_field') => new sfValidatorError($this, 'invalid')));
           }
         }
      }
      // verify password
      if($password !== $password_check)
      {
        throw new sfValidatorErrorSchema($this, array($this->getOption('password_check_field') => new sfValidatorError($this, 'notequal')));
      }

    }
    else
    {
      // no password set in the form, check if a password is already set...
      if(empty($defaultPassword))
      {
        throw new sfValidatorErrorSchema($this, array($this->getOption('password_field') => new sfValidatorError($this, 'required')));
      }
      else
      {
         unset($values['password']);
      }
    }
    return $values;
  }
}

The options

This validator takes 4 options:

  • password: This option either takes an existing password or an empty string if no such exists. If an empty string is given, the user has to provide a password.
  • pattern: An array of regular expression. The password provided by the user has to match against these. It is an array so that it is possible to test the password against multiple requirements (although it is also possible to use Lookahead/Lookbehind, but to split it in serveral expression can increase readability).
  • password_field: The name of the password field, default to ‘password’.
  • password_check_field: The name of the field to verify the password. Default to ‘password_check’.

How the valditor works

First the validator checks, if a password is provided by the user:

YES:

  1. Test the password against regular expressions. If a test fails, throw an error for the password field.
  2. Verify the password. If the values of both fields don’t correspond and error for the second password field is thrown.

NO:

Test if a password is already set. If not, a ‘required’ for the password field is thrown. Otherwise the value ist just removed from the value array to not set it again.

Please feel free to use or change this code. I am also happy to hear about improvements!

Advertisements

The symfony framework gives you the possibility to configure nearly anything in your application with YAML files. You can read more about the configuration system in the official symfony guide.

When you have a first look at these configuration files especially on examples for ‘app.yml’, you may think that you can structure the file in any way you want i.e. the amount of levels. Well I noticed, that this is not the case.

To make it short: You can set up any number of levels but only the second and the third level are directly accessible via sfConfig::get().

The longer version:

My configuration file looked like this:

all:
  .settings:
    some_parameter: value

  somePluginSettings:
    parameter: value

dev:
  email:
    addresses:
      address_1: foo@bar.tld
    smtp:
      host: smtp.host.tld
      config:
        username: username
        password: password

I was able to access every parameter via sfConfig::get() except those below the email key. An invocation of sfConfig::get(‘app_email_smtp_host’) delivered NULL.

The solution is rather simple: Symfony parses every key up to level 3 i.e. in this example up to the key ‘smtp’. Everything below level 3 is parsed as an array. So  sfConfig::get(‘app_email_smtp’) delivers an array:

array(2) { ["host"]=> string(19)"smtp.host.tld" ["config"]=> array(2) { ["username"]=> string(19) "username"  ["password"]=> string(9) "password" } }

And it makes no differences if you use a ‘normal’ key like ‘smtp’ or if you use what I would call a ‘hidden’ key like ‘.smtp’ (see the dot).

So for the record: Each default configuration file can consist of up to 3 levels:

  • Level 1: Defines the environment like production, development. This is set by the dispatcher.
  • Level 2: Defines either a group of settings or atomic values like strings and numbers. If it defines a group it can be a ‘normal’ or a ‘hidden’ key.
  • Level 3: Defines an valid value in the YAML syntax. Can be strings, numbers, arrays, etc.

Unfortunately I haven’t found any official description of this but maybe I read the documentation too quickly 😉 If you know an official source, please tell me.

The issue

Well I thought I can just unset the primary key field in a Doctrine object form (for security reasons for example). This field didn’t seem to be necessary  if you want to update an object because the object is retrieved via a Doctrine route and provided to the form (in the generated modules). I have to add that my object has a unique property that the user is allowed to change. The curious thing is that the form is valid if I provide a new value for this property but that I get an error for this field if I don’t change it.

Investigating…

Suppose you have a form that enables the user to change a unique property of an object. To ensure that the value is unique, an ‘sfValidatorDoctrineUnique’ is set for the form field. How does this validator work? It tries to get one object with the provided value as you can see here:

<p>class sfValidatorDoctrineUnique extends sfValidatorSchema
{
  //...
  protected function doClean($values)
  {
    //...
    $table = Doctrine::getTable($this->getOption('model'));
    //...
    $q = Doctrine_Query::create()
    ->from($this->getOption('model') . ' a');
    foreach ($this->getOption('column') as $column)
    {
      $colName = $table->getColumnName($column);
       //...
      $q->addWhere('a.' . $colName . ' = ?', $values[$column]);
    }
    $object = $q->fetchOne();
    // if no object or if we're updating the object, it's ok
    if (!$object || $this->isUpdate($object, $values))
    {
      return $originalValues;
    }
   //...
 }

If no object is returned (!$object) or if the method isUpdate() returns true, the value is valid.
Obviously the field is valid if we provide a new unique value for this column (which results in an empty $object). But what happens if we don’t want to change that value? Lets have a look at the isUpdate() method:

protected function isUpdate(Doctrine_Record $object, $values)
{
  // check each primary key column
  foreach ($this->getPrimaryKeys() as $column)
  {
     if (!isset($values[$column]) || $object->$column != $values[$column])
     {
        return false;
     }
 }
return true;
}

As you can see the method checks for every primary key column if a value is provided for it via a form field. If not, the objects are not considered to be the same.

Conclusion

If you have an edit form for an object that has a unique field and a ‘sfValidatorDoctrineUnique’ object applied to it, don’t unset the primary key fields. They are needed to verify that the objects are the same.

For those who really want to do it

To make it work it would be necessary to provide the the current object (retrieved via a Doctrine route) to the validator (via options) and then compare the primary keys of the provided object with those of the found object. Something like this:

<p>protected function isUpdate(Doctrine_Record $object)
{
  // check each primary key column
  foreach ($this->getPrimaryKeys() as $column)
  {
    if ($object->$column != $this->getOption('object')->$column)
    {
      return false;
    }
  }
  return true;
}

But that would result in a custom validator and you have to set it manually.

For one of my projects I needed to add a custom property to the “generator.yml” file. Something like this:

generator:
# ...
  config:
    actions: ~
    fields: ~
    list:
      my_property: value
    filter: ~
    edit: ~
    new: ~

Unfortunately the site threw an InvalidArgumentException:

Your generator configuration contains some errors for the “list” context. The following configuration cannot be parsed: array( ‘my_property’ => ‘value’,).

After a bit searching I found the solution in this form post in the official symfony forum. Here I would like to give a more detailed description:

Create a custom generator theme

The customization of the generator configuration is only useful if you need to modify the code generation somehow (and that means creating a custom generator theme). For example I changed the database query for listing the objects, but the query should only be changed if a certain flag (in the ‘generator.yml’) is set.

To create a new theme, we do the following:

  1. Create the folder ‘data/generator/sfPropelModule/[your_theme_name]’ or ‘data/generator/sfDoctrineModule/[your_theme_name]’ in case you use Doctrine.
  2. Copy all the files in ‘$sf_symfony_lib_dir/plugins/sfPropelPlugin/data/generator/sfPropelModule/admin‘ (resp. ‘$sf_symfony_lib_dir/plugins/sfDoctrinePlugin/data/generator/sfDoctrineModule/admin‘ to the newly created folder.

Our custom theme can now be activated for a module by changing the theme property in the ‘generator.yml’:

# apps/[application]/modules/[module]/config/generator.yml
generator:
  class: sfPropelGenerator
  param:
    model_class:           ModelClass
    theme:                 your_theme_name
    # ...

Edit your custom theme

We add the following line to the end of the class in “data/generator/sfPropelModule/[theme_name]/parts/configuration.php“:

// data/generator/sfPropelModule/[theme_name]/parts/configuration.php
[?php
class Base<?php echo ucfirst($this->getModuleName()) ?>GeneratorConfiguration extends sfModelGeneratorConfiguration
{
    //...
    // This is the new line
    <?php include dirname(__FILE__).'/customConfiguration.php' ?>
}

The file ‘customConfiguration.php’ will contain our extensions to the generator configuration. This way it is easier to keep an overview of which code is written by us.

Before we go further,  a little explanation of the function names in the ‘*Configuration.php’ files:

As we already can conclude from the exception, every entry directly under the ‘config’ key of the generator.yml is referred to as a context. So the default contexts are: actions, fields, list, filter, edit and new.

Every function is named like

get[Context][Property]

If we want to create a new property under the list context called my_property, we have to create this function:

public function getListMyProperty() {
}

How to process the custom property

The complete function will look like this:

// data/generator/sfPropelModule/[theme_name]/parts/customConfiguration.php

public function getListMyProperty() {
    return <?php echo isset($this->config['list']['my_property']) ? (integer) $this->config['list']['my_property'] : 10 ?>;
<?php unset($this->config['list']['my_property']) ?>
}

Please notice the non-existence of the <?php tag at the beginning of the file. That is because we deal with templates of PHP files here. That means this file is parsed once with PHP to create another PHP file. The instructions between <?php … ?> are instructions for the parser.

Lets have a look at the function in detail:

The whole generator configuration is accessible via the array $this->config and is structured as $this->config[context][property]. So what happens here is that the return value of the function getListMyProperty is specified (remember: it is a PHP template). If my_property exists then its value is taken (and transformed to an integer in this example because my_property is supposed to hold an integer) otherwise the default value 10 is used.

Afterwards the array key my_property is deleted (unset).
Important: This statement must be included, otherwise you will get the mentioned exception nonetheless! Read below if you are interested why.

Keep in mind to always follow this procedure: Check for existence of the property and provide a default value if it does not. Otherwise the generated code may end up in a mess.

The generated code

So what does the generated code look like? Lets have a look at the file ‘cache/[application_name]/dev/modules/[module_name]/lib/Base[Module_name]GeneratorConfiguration.class.php‘:

<?php

class BaseModule_nameGeneratorConfiguration extends sfModelGeneratorConfiguration
{
    // ...

    // If my_property was defined in 'generator.yml':
    public function getListMyProperty() {
        return 20;
    }

    // ...
}
&#91;/sourcecode&#93;

That is the generated code if <em>my_property</em> was defined with the value '20' in 'generator.yml'. Otherwise the function would return the default value:


    public function getListMyProperty() {
        return 10;
    }

How to access the custom property

In the other theme files, at least in the  ‘*Actions.php’ files,  you have now access to the property via $this->configuration->getListMyProperty().

How to return values correctly

In this example the function was supposed to return an integer. But of course any valid value can be returned. Just keep in mind that we deal with templates of PHP files here.

  • To return a string, enclose the commands for the parser in quotation marks, like:
    return ‘<?php echo isset(…) ? … : … ?>’;
  • It is wise to escape the string when it should be printed on the page (like the title property). You can use the method escapeString() for that:
    return ‘<?php echo $this->escapeString(isset(…) ? … : … ) ?>’;
  • Integer and boolean values should be casted:
    (integer) resp. (boolean)
  • If your property contains an array (either associative like the object_actions property or numerical like the display property), you should use the method asPhp():
    return <?php echo $this->asPhp(isset(…) ? … : … ) ?>;

How to add a custom context

Adding a custom context is easy. Actually it is the same like just adding a new property only that the ‘generator.yml’ looks a bit different:

generator:
-- ...
  config:
    actions: ~
    fields: ~
    list: ~
    filter: ~
    edit: ~
    new: ~
    my_context:
      my_property: value

And the function we create looks like this (assuming that my_property holds an integer again):

// data/generator/sfPropelModule/[theme_name]/parts/customConfiguration.php

public function getMycontextMyProperty() {
    return <?php echo isset($this->config['my_context']['my_property']) ? (integer) $this->config['my_context']['my_property'] : 10 ?>;
<?php unset($this->config['my_context']['my_property']) ?>
}

We just have to change the list context to our custom context.

Why to unset the property in the configuration array?

To answer this question we have to investigate where and why the InvalidArgumentException is thrown. Fortunately symfony delivers us the stack trace when something goes wrong and there we see that the exception is thrown in ‘SF_ROOT_DIR/lib/vendor/symfony-1.2.8/lib/generator/sfModelGenerator.class.php’ line 416 (in symfony version 1.2.8).

The interesting part of the enclosing function is the following:

protected function loadConfiguration()
{

    // ...

    // validate configuration

    foreach ($this->config as $context => $value)
    {
       if (!$value)
       {
           continue;
       }
       throw new InvalidArgumentException(sprintf('Your generator configuration contains some errors for the "%s" context. The following configuration cannot be parsed: %s.', $context, $this->asPhp($value)));
    }
    return new $class();

}

As you can see the $this->config is examined in a loop. Each property of each context is tested for existence. It becomes clearer now, why every property has to be unset:

If a property is not unset it means that it is not processed and therefore not understood by the parser. if(!$value) returns false then and the exception is thrown. Thats the whole magic. With this in mind I have to revert something that I have said before: We don’t have to name our function like get[Context][Property]. We have just to make sure the the property is unset. Nevertheless to keep the code consistent and self-explanatory I strongly recommend to name it the same way as the other functions.

Top security Firefox plugins

September 7, 2009

I’m really concerned about security and privacy in the world wide web. So I try to make my “web experience” as save as possible. Fortunately Firefox provides a good plugin system that enables people to extend Firefox’s features. This is a list plugins that should been installed at least (if you are concerned about security as well):

NoScript

Perhaps this the best known security plugin for Firefox. Just a short introduction:

A lot websites use JavaScript (JS) to improve the usability and user experience of their visitors. As a reminder:  JS provides the possibility to alter the document (i.e. website). Normally websites are static pages, just text with markup.   Web developers can use JS to create more dynamical websites that change their content in response to the action of the visitor (especially now with Ajax).
JS itself is not insecure. But as with the most script or programming languages it can be used for bad things.
You probably know about the security option in the common web browser to disable JS. This would make you save but unfortunately some well known sites like Facebook or Google Mail won’t work with JS disabled. NoScript gives you the possibility to enable or disable JS, Java, Flash and other executable content  per site.
Have a look at there website.

RequestPolicy

This plugin is my favorite one. Actually what it does is pretty simple but has a huge impact. It gives you back the control over cross site requests that websites make. That means you can allow or disallow if a website can fetch or access content that is located at another domain. This prevents you from cross site request forgery for example but also protects your privacy.
Have a detailed description on their website.

CookieSafe

There a lot different cookie manager plugins for Firefox out there, but I like this one the most. Why? Because it is simple and easy to handle. The problems with cookies is similar to those with JavaScript regarding the security settings in web browser: Turn it on or off (or ask every time). That is not usable.

As a reminder: Cookies are small files where websites store some data. Every request to the website contains this data. What is it used for? Per the communication to the webservers is stateless. That means a webserver cannot make a connection between to requests, they are independent. But some times requests should not be independent. For example if you log in to a website the websever has to know somehow that every following request is made by you. A lot of those website use cookies for this. After your login a so called “session id” is generated  and stored in a cookie. Every time a webserver receives a request with this session id it knows the request is sent by you (and thats why it is important to protect your cookies from getting stolen, see NoScript).

Anyway, back to topic:
CookieSafe gives you the possibility to enable or disable cookies per website. And as websites sometimes store information in cookies that have to be stored over multiple sessions, CookieSafe provides three options for saving cookies:

  1. Allow cookies: Cookies of a certain website expire as it is set. Useful if certain settings like display options are stored in cookies.
  2. Allow cookies for session: All cookies of a website a kept until the web browser is closed. Most of the time this is a sufficient if it is a website you have to log in.
  3. Allow cookies temporarily: Only allow cookies this time until the browser is closed. Most useful when you visit a site only one time and it doesn’t work properly without cookies.

Otherwise cookies are disabled.

Adblock Plus

This plugin keeps ads away from the website you are visiting. I.e. it filters ads out. What has this to do with security? Well not directly with security but privacy. There are some advertising companies out there that provide advertisement to websites. Often those are images that are loaded from the company’s webserver (not the webserver of the website).
If you visit several websites that use ads of this company it is possible to track which websites you have visited.

In my opinion these plugins are sufficient from a security point of view. The whole point is to give you a back some control, the power to decide how the site you are visiting communicates with the rest of the net and what it is allowed to do on your computer.
And an important usability factor: Each of this plugins (besides adblock) includes a small icon into the right bottom corner of your browser so you can change the settings for a website very easily.