Friday, October 07, 2011

Symfony 1.4 and SSL – playing with symfony filters

Building last application i needed SSL protection for some of my modules and actions. What I wanted to achieve was to choose some actions and redirect non-https requests to https (and https to non-https).
I found a plugin: sfSslRequirementPlugin, it's for sf 1.0/1.1 and it does not really meet my needs. Yes, i know that i can fix it to work with sf 1.4 but that's not a point.

Then in the documentation i found simple ssl filter example:

1 <?php
2  
3 class sfSecureFilter extends sfFilter
4 {
5   public function execute($filterChain)
6   {
7     $context $this->getContext();
8     $request $context->getRequest();
9  
10     if (!$request->isSecure())
11     {
12       $secure_url str_replace('http''https'$request->getUri());
13  
14       return $context->getController()->redirect($secure_url);
15       // We don't continue the filter chain
16     }
17     else
18     {
19       // The request is already secure, so we can continue
20       $filterChain->execute();
21     }
22   }
23 }


I really like the idea of describing the authentication and authorization rules in security.yml file (is_secure option) and filters. So i decided to add another option: „is_ssl" for module-action restrictio. It shoud works on the same rules as sfBasicSecurityFilter.


The default application configuration can be overridden for a module by creating a security.yml file in the config/ directory of the module. The main keys are action names without the execute prefix (index for the executeIndex method for instance).

To determine if an action is secure or not, symfony looks for the information in the following order:
* a configuration for the specific action in the module configuration file if it exists;
* a configuration for the whole module in the module configuration file if it exists (under the all key);
* the default application configuration (under the default key).

1 <?php
2  
3 class MySecureFilter extends sfFilter
4 {
5   public function execute($filterChain) {
6  
7     $context $this->getContext();
8     $request $context->getRequest();
9  
10     $moduleName $request->getParameter('module');
11     $actionName $request->getParameter('action');
12  
13     if ($context->getController()->actionExists($moduleName,$actionName)) {
14  
15         $action $context->getController()->getAction(
16             $moduleName,
17             $actionName
18         );
19  
20         if ($action->getSecurityValue('is_ssl', false) && !$request->isSecure()) {
21  
22             $secure_url str_replace('http''https'$request->getUri());
23  
24             return $context->getController()->redirect($secure_url);
25  
26         else if (!$action->getSecurityValue('is_ssl', false) &&$request->isSecure()) {
27  
28             $not_secure_url str_replace('https''http'$request->getUri());
29  
30             return $context->getController()->redirect($not_secure_url);
31         }
32     }
33  
34     $filterChain->execute();
35   }
36 }

This simple filter redirects all actions that has option 'is_ssl' = true to https requests and https requests (with is_ssl = false) to non-https.

To enable this filter for example for our frontend application we need to set this filter in filters.yml – apps/frontend/config/filters.yml:

1 rendering: ~
2 security:  ~
3  
4 secure:
5   class: MySecureFilter
6  
7 cache:     ~
8 execution: ~

Enable ssl for module/action (default module) – apps/frontend/modules/default/config/security.yml:

1 # for the whole module
2 all:
3   is_ssl: true
4  
5 # just one action
6 login:
7   is_ssl: true

No comments: