Skip to content

Commit

Permalink
Merge pull request #4 from rezzza/obfuscation
Browse files Browse the repository at this point in the history
obfuscation
  • Loading branch information
shouze committed Jul 21, 2014
2 parents 8881e70 + da1f37b commit 6e4bf91
Show file tree
Hide file tree
Showing 17 changed files with 1,806 additions and 3 deletions.
3 changes: 3 additions & 0 deletions .atoum.bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php

require_once __DIR__.'/vendor/autoload.php';
11 changes: 11 additions & 0 deletions .atoum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

use \mageekguy\atoum;

$script->bootstrapFile(__DIR__ . DIRECTORY_SEPARATOR . '.atoum.bootstrap.php');

$cliReport = $script->addDefaultReport();
$cliReport->addField(new atoum\report\fields\runner\result\logo());

$runner->addReport($cliReport);
$runner->addTestsFromDirectory(__DIR__.'/Tests/Units');
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
bin
composer.phar
vendor
18 changes: 18 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
language: php

php:
- 5.3

before_script:
- wget http://getcomposer.org/composer.phar
- php composer.phar install --dev --prefer-source

script:
- bin/atoum

notifications:
email:
recipients:
- [email protected]
on_success: change
on_failure: change
34 changes: 34 additions & 0 deletions Controller/Annotations/ObfuscateRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace Rezzza\SecurityBundle\Controller\Annotations;

/**
* @Annotation()
*
* ObfuscateRequest
*
* @author Stephane PY <[email protected]>
*/
class ObfuscateRequest
{
/**
* @var array<string>
*/
private $obfuscatedPatterns;

/**
* @param array $data data
*/
public function __construct(array $obfuscatedPatterns)
{
$this->obfuscatedPatterns = $obfuscatedPatterns;
}

/**
* @return array<string>
*/
public function getObfuscatedPatterns()
{
return $this->obfuscatedPatterns;
}
}
55 changes: 55 additions & 0 deletions DataCollector/RequestDataCollector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

namespace Rezzza\SecurityBundle\DataCollector;

use Doctrine\Common\Annotations\Reader as AnnotationReader;
use Doctrine\Common\Util\ClassUtils;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\RequestDataCollector as BaseRequestDataCollector;
use Rezzza\SecurityBundle\Controller\Annotations\ObfuscateRequest;
use Rezzza\SecurityBundle\Request\Obfuscator\ObfuscatorInterface;

class RequestDataCollector extends BaseRequestDataCollector
{
/**
* @var AnnotationReader
*/
private $annotationReader;

/**
* @var Obfuscator
*/
private $obfuscator;

/**
* @param AnnotationReader $annotationReader annotationReader
* @param ObfuscatorInterface $obfuscator obfuscator
*/
public function __construct(AnnotationReader $annotationReader, ObfuscatorInterface $obfuscator)
{
$this->annotationReader = $annotationReader;
$this->obfuscator = $obfuscator;

parent::__construct();
}

public function collect(Request $request, Response $response, \Exception $exception = null)
{
parent::collect($request, $response, $exception);

$controller = explode('::', $request->get('_controller'));

if (count($controller) !== 2) {
return;
}

$class = new \ReflectionClass($controller[0]);
$reflectionMethod = $class->getMethod($controller[1]);
$annotation = $this->annotationReader->getMethodAnnotation($reflectionMethod, '\Rezzza\SecurityBundle\Controller\Annotations\ObfuscateRequest');

if ($annotation) {
$this->data = $this->obfuscator->obfuscate($this->data, $annotation->getObfuscatedPatterns());
}
}
}
27 changes: 27 additions & 0 deletions DependencyInjection/Compiler/ObfuscatorCompilerPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

namespace Rezzza\SecurityBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;

class ObfuscatorCompilerPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
// request obfuscator is not enabled.
if (!$container->getParameter('rezzza.security.request_obfuscator.enabled')) {
return;
}

$container->setParameter('data_collector.request.class', 'Rezzza\SecurityBundle\DataCollector\RequestDataCollector');

$container->getDefinition('data_collector.request')
->addArgument(new Reference('annotation_reader'))
->addArgument(new Reference('rezzza.security.request_obfuscator.obfuscator'));
}
}
6 changes: 6 additions & 0 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ public function getConfigTreeBuilder()

$rootNode
->children()
->arrayNode('request_obfuscator')
->addDefaultsIfNotSet()
->children()
->booleanNode('enabled')->defaultFalse()->end()
->end()
->end()
->arrayNode('firewalls')
->useAttributeAsKey('name')
->prototype('array')
Expand Down
7 changes: 7 additions & 0 deletions DependencyInjection/RezzzaSecurityExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,15 @@ public function load(array $configs, ContainerBuilder $container)
$config = $processor->processConfiguration($configuration, $configs);

$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config/services'));

$loader->load('security.xml');

$container->setParameter('rezzza.security.request_obfuscator.enabled', $config['request_obfuscator']['enabled']);

if ($container->getParameter('rezzza.security.request_obfuscator.enabled')) {
$loader->load('request_obfuscator.xml');
}

$firewalls = $config['firewalls'];

foreach ($firewalls as $name => $data) {
Expand Down
57 changes: 55 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
SecurityBundle
==============

[![Build Status](https://travis-ci.com/rezzza/SecurityBundle.png)](https://travis-ci.com/#!/rezzza/SecurityBundle)

# Installation

## With Composer
Expand Down Expand Up @@ -71,8 +73,6 @@ It'll hash all theses criterias with a secret defined on `security.yml`, example
Build the signature:

```php
use \Rezzza\SecurityBundle\Security\Authentication\RequestDataCollector;
$context = new \Rezzza\SecurityBundle\Security\Firewall\Context();
$context->set('request.method', 'GET')
->set('request.host', 'subdomain.domain.tld')
Expand Down Expand Up @@ -112,6 +112,59 @@ $builder = $this->get('rezzza.security.request_signature.builder');
$signature = $builder->build($context);
```

# Obfuscate request

If you have critical data coming on your application, you may not want to expose them into symfony profiler. You can easily define which data will not appear on this one on each routes.

```
rezzza_security:
request_obfuscator:
enabled: 1
```
In your route:
```

use \Rezzza\SecurityBundle\Controller\Annotations\ObfuscateRequest;

/**
* @ObfuscateRequest()
*/
public function indexAction(Request $request)
{
}
```
Will obfuscate all datas on symfony profiler.
```
@obfuscate("content=*") // obfuscate $request->getContent()
@obfuscate("headers={'foobar'}") // obfuscate $request->headers->get('foobar')
@obfuscate("request_request={"customer[password]"}") // obfuscate $request->request->get('customer')['password']
```
Keys to obfuscate are:
- format
- content
- content_type
- status_text
- status_code
- request_query ($_GET)
- request_request ($_POST)
- request_headers ($_HEADER)
- request_server ($_SERVER)
- request_cookies ($_COOKIES)
- request_attributes ($request->attributes)
- response_headers
- session_metadata
- session_attributes
- flashes
- path_info
- controller
- locale
# WishList
- QueryString or HTTP Headers
Expand Down
21 changes: 21 additions & 0 deletions Request/Obfuscator/ObfuscatorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Rezzza\SecurityBundle\Request\Obfuscator;

use Symfony\Component\HttpFoundation\Request;

/**
* ObfuscatorInterface
*
* @author Stephane PY <[email protected]>
*/
interface ObfuscatorInterface
{
/**
* @param array $data data
* @param array $obfuscatedPatterns obfuscatedPatterns
*
* @return array
*/
public function obfuscate(array $data, array $obfuscatedPatterns);
}
70 changes: 70 additions & 0 deletions Request/Obfuscator/RequestObfuscator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

namespace Rezzza\SecurityBundle\Request\Obfuscator;

use Rezzza\SecurityBundle\Exception\ObfuscateBadPatternException;

/**
* RequestObfuscator
*
* @uses ObfuscatorInterface
* @author Stephane PY <[email protected]>
*/
class RequestObfuscator implements ObfuscatorInterface
{
CONST TOKEN_REPLACE = 'X';
CONST TOKEN_ALL = '*';

/**
* {@inheritdoc}
*/
public function obfuscate(array $data, array $obfuscatedPatterns)
{
foreach ($obfuscatedPatterns as $key => $pattern) {
if (isset($data[$key])) {
$data[$key] = $this->obfuscateContentWithPattern($data[$key], $pattern);
}
}

return $data;
}

private function obfuscateContentWithPattern($content, $pattern)
{
if (!is_array($content)) {
return is_scalar($content) ? $this->obfuscateContent($content) : null;
}

if ($pattern === self::TOKEN_ALL) {
return self::TOKEN_REPLACE;
}

$patterns = (array) $pattern;
foreach ($patterns as $pattern) {
$keys = array_map(function($v) {
return str_replace(']', '', $v);
}, explode('[', $pattern));

$pattern = array_shift($keys);

if (array_key_exists($pattern, $content)) {
if (count($keys) === 0) {
$content[$pattern] = $this->obfuscateContent($content[$pattern]);
} else {
$newPattern = array_shift($keys);
foreach ($keys as $key) {
$newPattern .= sprintf('[%s]', $key);
}
$content[$pattern] = $this->obfuscateContentWithPattern($content[$pattern], $newPattern);
}
}
}

return $content;
}

private function obfuscateContent($content)
{
return is_scalar($content) ? str_repeat(self::TOKEN_REPLACE, strlen($content)) : self::TOKEN_REPLACE;
}
}
15 changes: 15 additions & 0 deletions Resources/config/services/request_obfuscator.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>

<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

<parameters>
<parameter key="rezzza.security.request_obfuscator.obfuscator.class">Rezzza\SecurityBundle\Request\Obfuscator\RequestObfuscator</parameter>
</parameters>

<services>
<service id="rezzza.security.request_obfuscator.obfuscator" class="%rezzza.security.request_obfuscator.obfuscator.class%"/>
</services>

</container>
3 changes: 3 additions & 0 deletions RezzzaSecurityBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Rezzza\SecurityBundle;

use Rezzza\SecurityBundle\DependencyInjection\Security\Factory\RequestSignatureFactory;
use Rezzza\SecurityBundle\DependencyInjection\Compiler;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;

Expand All @@ -27,5 +28,7 @@ public function build(ContainerBuilder $container)
if (method_exists('\Symfony\Bundle\SecurityBundle\DependencyInjection\SecurityExtension', 'addSecurityListenerFactory')) {
$extension->addSecurityListenerFactory(new RequestSignatureFactory());
}

$container->addCompilerPass(new Compiler\ObfuscatorCompilerPass());
}
}
Loading

0 comments on commit 6e4bf91

Please sign in to comment.