PHP: Autentication and Access Control in a modular web application


This example is about the access control and authentication on a modular web application, developed in Symfony2 using the EventDispatcher, the logic of implementation can be used in different projects, that don’t necessarily use these tools. The basis of this access control is the usage of a main event dispatcher and listener (EventDriven) to detect destination request address and intercept it before it reaches that destination (controller + method ).

I first became aware of the idea of using Events to control access, I believe it was by on his blog a long time ago.

Anyway here I describe the usage of a Symfony2  custom EventListener to listen to a onKernelRequest

This usually happens this way:

Client -[call]-> Webserver -[dispatch event request]-> triggers onKernelRequest witch does validation -[Validates]-> if passes code continues normally inside symfony2  … Get the idea? I hope so.

First I implemented the interface in the AccessControl Class no other code will interact with this that’s the beauty of using a event for access control, you can have the event manage the control access of all modules without having to interact directly with them. The code is commented for easier reading…

Class AccessControl implements EventSubscriberInterface

public function __construct($em, $dispatcher, $security, $router)
$this->em = $em; // the EntityManager not used in this demo
$this->dispatcher = $dispatcher; // The SF2 EventDispatcher
$this->security = $security; // security.context
$this->router = $router; // router to know where the request is going to

And of course I will be listening to onKernelRequest events

public static function getSubscribedEvents()
return array(
KernelEvents::REQUEST => [‘onKernelRequest’, 0],

Here follows an example on access control without any dynamic database support

This is a basic decision path based on the destination route using the symfony name and the request from the client.

public function onKernelRequest($event)
if ($event->getRequestType() != HttpKernelInterface::MASTER_REQUEST) {
return null; // will only be handled if it’s from a external request else returns null

$user = $this->security->getToken()->getUser();  // get the current user information
$request = $event->getRequest(); // get the current request
$requested_uri = $request->getRequestUri(); // get the requested URI
$internal_route = $request->get(‘_route’); // this what is used to validate access

// $internal_route has the route name used by symfony witch I use to compare since it’s simpler

if ($internal_route == ‘fos_user_registration_register’) {
return true; // by default I allow the call to the registering of a new user

if ($user == ‘anon.’) {
$mainrequest = $event->getRequest();
// Matched route
$_route = $mainrequest->attributes->get(‘_route’);
// Matched controller
$_controller = $mainrequest->attributes->get(‘_controller’);
// All route parameters including the `_controller`
$params = $mainrequest->attributes->get(‘_route_params’);

if ($_route != ‘fos_user_security_login’) {

// if anonymous is not trying to login
// send him to login
$url = $this->router->generate(‘fos_user_security_login’);
$response = new RedirectResponse($url);

if ($user->hasGroup(“Admin”)) {
return true; // if the user has a group admin allow him to everywhere

$request = $event->getRequest();
$requested_uri = $request->getRequestUri();
$internal_route = $request->get(‘_route’); // this is what is used to validate access

if (mb_substr($internal_route, 0, mb_strlen(“lab_”)) == “lab_”) {
if ($user->hasGroup(“Laboratorio”)) {

// allow user to space _lab if he’s from the Group Laboratorio
return true;
} else {
// monolog here
throw new \Exception(“Unauthorized access. $internal_route”);

if (mb_substr($internal_route, 0, mb_strlen(“stock”)) == “stock”) {
if ($user->hasGroup(“Stock”)) {

// allow the user to access stock route names if he his in the stock Group
return true;
} else {
// monolog here
throw new \Exception(“Unauthorized access. $internal_route”);

if (mb_substr($internal_route, 0, mb_strlen(“user”)) == “user”) {
if ($user->hasGroup(“Admin”)) {

  // if the user is admin allow him to manage users
return true;
} else {
// monolog here
throw new \Exception(“Unauthorized access. $internal_route”);


After this, configure the services.xml file in Resources/config/  this will allow for the dependencies to be loaded in the object.

security.context provides information about the user logged (or not), router allow’s to generate a different destination route for the Event

In this gist you can see all the code used.

Best regards,

ZF2 Zend\Mail usage with gmail

Example usage of Zend Mail in ZF2 for sending e-mail by gmail.

require_once './Zend/Loader/StandardAutoloader.php';

$loader = new Zend\Loader\StandardAutoloader( array( 'autoregister_zf' => true));
$loader->register( );

use Zend\Mail;
use Zend\Mail\Transport\Smtp as SmtpTransport;
use Zend\Mail\Transport\SmtpOptions;

$options = new SmtpOptions( array(
"name" => "gmail",
"host" => "",
"port" => 587,
"connection_class" => "plain",
"connection_config" => array( "username" => "",
"password" => "oleaodeSodor","ssl" => "tls" )
) );

$mail = new Mail\Message();
$mail->setBody('Hello there!');
$mail->setFrom('', 'Pat');
$mail->addTo('', 'Andre');
$mail->addCC( '' );

$mail->setSubject('Hello today ' . date( "d-m-Y" ));

$transport = new SmtpTransport();
$transport->setOptions( $options );

Zend Framework Zend Db Profiler

Analyzing database SQL query’s within Zend Framework Front Controllers isn’t difficult here’s an example:

$bootstrap = $this->getFrontController()->getParam(“bootstrap”);

if ($bootstrap->hasPluginResource(“db”)) {
      $dbResource = $bootstrap->getPluginResource(“db”);
      $db = $dbResource->getDbAdapter();

$profiler = $db->getProfiler();

            foreach ($devs->getDevices($cliente->idcliente) as $equip) {

                $equip->findDependentRowset(“DM_Model_Services”, “equipment”);
    $query = $profiler->getLastQueryProfile();

    echo $query->getQuery();      


My database config in application.ini:

resources.db.adapter         = pdo_mysql     =
resources.db.params.username = user
resources.db.params.password = pass
resources.db.params.dbname   = sal_db

This will give an output like:

SELECT `service`.* FROM `service` WHERE (`idequipment` = 70)



Primeira colocação do uso de selenium no meu projecto de trabalho.

16:52:56.775 INFO – Started org.openqa.jetty.jetty.servlet.ServletHandler@7ad81784
16:52:56.775 INFO – Started HttpContext[/wd,/wd]
16:52:56.779 INFO – Started SocketListener on
16:52:56.779 INFO – Started org.openqa.jetty.jetty.Server@6f507fb2
16:54:27.227 INFO – Checking Resource aliases
16:54:27.245 INFO – Command request: getNewBrowserSession[*chrome, http://cableweb/%5D on session null
16:54:27.257 INFO – creating new remote session
16:54:27.430 WARN – Caution: ‘/usr/bin/firefox’: file is a script file, not a real executable.  The browser environment is no longer fully under RC control
16:54:27.432 INFO – Allocated session ad8fbaba3c6a4caba2aaa62f118253b8 for http://cableweb/, launching…
16:54:27.516 INFO – Preparing Firefox profile…
16:54:32.489 INFO – Launching Firefox…
16:54:35.965 INFO – Got result: OK,ad8fbaba3c6a4caba2aaa62f118253b8 on session ad8fbaba3c6a4caba2aaa62f118253b8
16:54:36.028 INFO – Command request: setTimeout[30000, ] on session ad8fbaba3c6a4caba2aaa62f118253b8
16:54:36.052 INFO – Got result: OK on session ad8fbaba3c6a4caba2aaa62f118253b8
16:54:36.104 INFO – Command request: open[/index.php, ] on session ad8fbaba3c6a4caba2aaa62f118253b8
16:54:36.356 INFO – Got result: OK on session ad8fbaba3c6a4caba2aaa62f118253b8
16:54:36.407 INFO – Command request: click[link=Aquisições, ] on session ad8fbaba3c6a4caba2aaa62f118253b8
16:54:36.426 INFO – Got result: ERROR: Element link=Aquisições not found on session ad8fbaba3c6a4caba2aaa62f118253b8
16:54:36.477 INFO – Command request: testComplete[, ] on session ad8fbaba3c6a4caba2aaa62f118253b8
16:54:36.477 INFO – Killing Firefox…
16:54:36.513 INFO – Got result: OK on session ad8fbaba3c6a4caba2aaa62f118253b8
16:55:30.999 INFO – Command request: getNewBrowserSession[*chrome, http://cableweb/%5D on session null
16:55:30.999 INFO – creating new remote session
16:55:31.000 INFO – Allocated session 38cbb4859dcf4cdfb8c33f7f160c56f7 for http://cableweb/, launching…
16:55:31.060 INFO – Preparing Firefox profile…
16:55:33.334 INFO – Launching Firefox…
16:55:35.379 INFO – Got result: OK,38cbb4859dcf4cdfb8c33f7f160c56f7 on session 38cbb4859dcf4cdfb8c33f7f160c56f7
16:55:35.427 INFO – Command request: setTimeout[30000, ] on session 38cbb4859dcf4cdfb8c33f7f160c56f7
16:55:35.438 INFO – Got result: OK on session 38cbb4859dcf4cdfb8c33f7f160c56f7
16:55:35.490 INFO – Command request: open[/index.php, ] on session 38cbb4859dcf4cdfb8c33f7f160c56f7
16:55:35.691 INFO – Got result: OK on session 38cbb4859dcf4cdfb8c33f7f160c56f7
16:55:35.742 INFO – Command request: click[link=Aquisições, ] on session 38cbb4859dcf4cdfb8c33f7f160c56f7
16:55:35.759 INFO – Got result: ERROR: Element link=Aquisições not found on session 38cbb4859dcf4cdfb8c33f7f160c56f7
16:55:35.810 INFO – Command request: testComplete[, ] on session 38cbb4859dcf4cdfb8c33f7f160c56f7
16:55:35.811 INFO – Killing Firefox…

Houston we have a #FAIL

Apesar do fail isto é apenas o principio, os testes ficaram relativamente bem feitos com o selenium IDE, agora em codigo tenho de resolver situações, que não consigo cobrir com o selenium IDE.

É da crise, é da crise

A Natura em Portugal realizou no passado domingo uma reunião com os funcionários comunicando-lhes o seguinte:
Está com dificuldades e pensaram em  despedir os funcionários, mas chegaram à conclusão que será melhor para todos reduzir o número de horas dos trabalhadores (o que implica baixar os salários numa média de 50 euros por trabalhador ).

Então tem de aceitar estas novas regras possivelmente implica a escrita de um novo contrato dado que muitos estão a contrato a termo certo. Caso não aceitem segundo as palavras dos administradores eles vão colocar todos os nomes num saco e vão tirando à sorte para ver quem vão despedir. É caso para dizer que está toda a gente no mesmo saco não é?

Entretanto os empregados assustados foram pressionados a assinar o contrato até ao dia de ontem sem o levarem para ler ou questionar, porque era a lei do “ou assinam todos ou não assina nenhum”.
Resta então saber também se a medida que dizem ser temporária até ao final do ano e “depois vê-se”, se vai ser mesmo apenas temporária, se vai ser usada para vender a empresa a um preço mais alto para facilitar os despedimentos aos novos compradores, se é para facilitar os despedimentos aos donos actuais alegando dificuldades económicas no futuro…



PHP property_exists vs ReflectionClass

Mental note, no php < 5.3 a função property_exists não encontra todas as propriedades…
Vou passar a usar a ReflectionClass.

Posted from WordPress for Android

2 anos depois

Depois de o local onde trabalhava experimentar as garras do corporate world e com o tempo as pessoas com quem trabalhava passarem do estado empregado para desempregado com excepção de alguns. Parece que no meu caso a escolha até agora ficou a meu critério o que é sempre bom. Foram uns bons dois anos e meio de trabalho, complicações e algum stress mas já tinha passado por pior. Aperfeiçoei bastante os meus conhecimentos e consegui aplicar o que aperfeiçoei o que foi bom. Os sistemas proprietários ficaram ainda mais marcados na minha experiência como uma boa forma de controlar desenvolvedores e de os manter num estado de incapacidade face a problemas de gestão de recursos da máquina e liberdade para criar.
Relembro que depois de promessas a tanta gente e beneficios supostamente garantidos a tantos que me acompanharam para este local quantos ficaram ? Uns 10 talvez… Quem estava mais abaixo na hierarquia não demorou a sair e está agora na boca do lobo da crise não recebiam bem e o stress que tinham também não deveria compensar o trabalho a que se sujeitaram só para ficar com o estado de “empregado”. Quem tem contactos vai-se safando arranjando algum trabalho por aí, os outros aguardam uma hipotese de ainda poderem mostrar o que valem.
O país (Portugal) deu uma volta de 180º da expansão e do progresso, desenvolvimento e modernismo passou para uma politica de contenção e como sempre quem sofre são os mais pequenos. As palavras podem parecer comunistas mas a verdade é que são uma expressão da realidade. Depois de tantos anos dizem que ainda se fala de Salazar se calhar é porque ele foi o último governante com alguma inteligência neste país. As pequenas empresas hoje tentam remar contra a maré negativa que se avisinha sempre com recurso à palavra que mais identifica os portugueses… Desenrasque, sem desenrasque não haverá solução pois não podem esperar pela mão do governo.

O país tem boas qualidades e a Europa ajuda bastante a que ele saia da imagem de republica das bananas, até na Tunísia dizem que o país pode vir ser igual a Portugal isto quando a nossa dívida e austeridade aumenta. Mas isto não é tudo na vida.