PHP: Autentication and Access Control in a modular web application

Hello,

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);
$event->setResponse($response);
}
return;
}

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,

Anúncios

Java for PHP Developers

I have been working with Java for android and a Web application purely for entertainment. For long I have seen PHP adopt more and more “ideas” from Java so to make it easy for someone that knows PHP to get into java and vice versa I’ll make some easy generic associations. This is from a HTTP point of view to simplify the relations.

Note: I have some basic background on Java and C# (Mono .NET), also I have an understanding of the design patterns that you will see applied in Java and in PHP frameworks and that helps understand the logic faster between the different languages.

  1. In PHP Controllers are Controllers, in Java they are mostly represented by a Servlet. It’s similar to Symfony 2  and Zend Framework adoption for handling requests. (Also in the Java Servlet can provide routing in the service method but not very used according to the reading I have been doing and the web.xml handles more of those requests).
  2. In PHP Models are provided by Frameworks Zend Framework or Symfony also has them, in Java they are usually called Beans and they also take the role of “Services” witch is something that came up in Zend Framework 2 and Symfony 2 not knew but the concept in the framework has been more noticeable.
  3. Template in PHP is done using some one of the following (known to have more) Smarty, Twig, normal PHP + HTML. In Java it is done via “tags” in Javaserver Pages (JSP) the approach of Javaserver Pages + Tags + Controller (Servlet) looked a lot like the Symfony 2 approach. (or vice versa)
  4. HTTP Server Jetty (there is jetty for android) is a simple to use webserver built in java witch is simple to deploy and run you can print a hello world pretty fast with not much work with it. Apache/Nginx install + PHP + some DB still is faster to me since it actually has more documentation and isn’t so java centered.
  5. Build and dependency management tools Maven is a most simple way to manage and install dependency’s in Java just get some example pom.xml files to get your basics and understand the build process and it looks like composer (yes that thing that many criticize). Maven also can create standard working environments and run tests.
  6. A ORM known in PHP is Doctrine a similar ORM in Java can be Hibernate. Hibernate also supports config by Annotations.
  7. Configuration in PHP can be handled on whatever you want to use, in frameworks like Symfony 2 it’s known has app/config.yml in Zend Framework 1 it’s application.ini in Zend Framework 2 it’s TODO something it’s more of a users choice. Symfony 2 also supports Annotations (via Doctrine Annotations) for route config et all, but in Java the Spring Framework his what I know to have those quirks but the Annotations are built in the language the main configuration for web development is usually a web.xml file in a WEB-INF directory.
  8. Database connetions PDO is for PHP what JDBC is for Java for database connection
  9. Packaging WAR or JAR it’s Java package what was based for Phar files in PHP
  10. Unit testing in PHP can be PHPUnit and in Java it can be jUnit
  11. Routing requests If you are looking in a more annotation style configuration for routing requests look at this text from wikipedia JAX-RS: Java API for RESTful Web Services and Rewrite Engine

This is a somewhat generic way of comparing the two languages but what you can notice is that Java like PHP has some built around solutions built with the language but they are supplied by standard API has .jar files and like PHP it also has a very intense activity around and different solutions ( just to say maybe we shouldn’t criticize having a lot of frameworks as Matthew Weier O’Phinney says:

Second, I also think there’s space for multiple implementations of any given component. Often there are different approaches that different authors will take: one might focus on performance, another on having multiple adapters for providing different capabilities, etc. Sometimes having a different background will present different problem areas you want to resolve. As such, having multiple implementations can be a very good thing; developers can look at what each provides, and determine which solves the particular issues presented in the current project.

(this last quote was placed because of a lot of discussion I see in forums and mailing lists regarding standardization of the way the developer codes and the way the language is built. Nothing new was said but the discussion of the PHP group (fig) is “deja vu”.

Coding in Java…

Well it’s not that simple has in PHP… Small example you do a POST in PHP you could just $_POST[“FormDemo”][“id”] , $_POST[“FormDemo”][“name”] , in Java it follows the standards strictly and you can only handle key value pair posts. You can handle the PHP POST array format but that involves regular expressions for what I’ve seen not simple has in PHP.

In Java you get strings via HTTP and change it to the format you require, in PHP you get Strings or whatever and you rarely care and if you care much you can type cast the variable if it’s int, float or Array.

Integer.ParseInt(string) will be your friend for Integer values for the “what you may want”.

Map<String,String> KeyValue = new Map<String,String>();

http://www.vogella.com/articles/EclipseWTP/article.html

Build setup:

I started by using Eclipse + Eclipse Web development tools and jetty with basic code, then installed Maven and https://code.google.com/p/run-jetty-run/ plugin search for it in eclipse market I wasn’t thinking on hibernate but I wanted something more abstract to handle the database and I am using Doctrine in PHP so just searched for a ORM in Java and went with that one.

 

UPDATE:

PHP is simpler to use my issue with Java it’s not about the Type declaration I actually like that and sometimes wish that was better in PHP. I actually didn’t like the server setup requirements I started with jetty witch is very simple but the deployment using maven and all that… If I was coding pure PHP it would have been faster and simpler. Frameworks in Java allow you the basic to build “normal stuff” in a simpler way like “routes” et all. But in PHP you actually can get something like that in a more simpler way and faster by just coding. JavaEE at the just looks like over complicated for a simple web app solution.

Doctrine ORM, prototype that is to much of a prototype

My experience with Doctrine ORM was actually love at first sight, we had cake sat down for dinner and all, did awesome things and fast during day and night… Until I had more requirements, now I have to go write the SQL query’s on my own because I let the relation grow to fast and didn’t take care of the details.

Yes, I have a new requirement that will make me rewrite all the SQL code of the system when I was using the prebuilt ->findXXX this will be painful but at least we went far and fast in the relationship and that’s also important. 

Symfony2 Move uploaded file and SplFileInfo

I took a while to understand that this $fileObject (in Symfony 2 class “File” extends \SplFileInfo) after a move_uploaded_file a call to $fileObject->getMimeType() no longer works.

I really was hoping that the file details would be kept in memory until the code stopped running because I only moved the file.

So mental note is “keep the information on a temp var”.

// …
$files = $request->files->get(‘uploadedfiles’);
// …
$fileObject = $files[0];

if (is_writable($destination)) {
$pathtmp = $fileObject->getRealPath();
$mimetype = $fileObject->getMimeType();
if (!move_uploaded_file($pathtmp, $destination.”algo.csv” )) {
throw new \Exception(“Failed moving file. [” . $pathtmp . “] “);
}
} else {
throw new \Exception(“Destination is not writable. $destination “);
}