Magento & Protection proxy in a nutshell

Magento & Protection proxy in a nutshell

You’ve just got into the B2B model. The e-commerce platform that you work on must be able to provide information based on various particularities that each contracted business has. Sometimes you may need to restrict access to the website and the information on it for security, technical or business-related reasons.

Well, surprise! Magento Enterprise Edition comes with a WebsiteRestriction module which “gives you the ability to either shut down access to a storefront completely while performing maintenance, or restrict access to private sale or B2B sites by requiring customers to log in”.

When I first dealt with this, it was not what I expected. The WebsiteRestriction’s infrastructure was not sufficient for our particular needs so, after a quick technical analysis over what Magento has to offer, I decided to try an alternative approach.

In this article we will focus on the basics of writing a simple proxy mechanism into the main layers of Magento 1. The mechanism will enable control access to elements that are about to be disclosed while rendering or routing as an end-user is requesting for certain resources. The exposed interface is designed through the Enterprise Edition, but, with a little refinement, it should be compatible with a Community Edition as well.

For the sake of extensibility and maintainability, before the actual mechanism, I decided to apply a little strategy over the “restriction modes” which Magento offers. You can check out this particularity a little later in this article.

Website Restriction

Insights over the legacy package

One of the particularities of this module is the Restriction Mode, which can be found in action at

\Enterprise_WebsiteRestriction_Model_Observer +restrictWebsite($observer)

or exhibited via the administrative panel at System\Configuration\[Default Config Context]\General\General\[Tab Context]\Website Restrictions.

The routine is a touching switch case pile. Surprisingly, or not, it’s not compatible with the very own built-in Enterprise feature, the Full Page Cache.

The not compatible

+restrictWebsite($observer) is dispatched via the controller_action_predispatch event. Based on a debugging callstack, \Mage_Core_Model_App +run($params) enlists the following conditional expression

if ($this->_cache->processRequest()) {
	$this->getResponse()->sendResponse();
} else {
	$this->_initModules(); ...
	$this->getFrontController()->dispatch();
}

Guess what happens after the first request on a given route.

The switch case pile

About a bunch of modes?, represented as integers, handled into a huge pile of switch case, abusing the static interfaces of the app. You can check the full code at \Enterprise_WebsiteRestriction_Model_Observer.

The strategy

Given the representation, I've introduced a little pattern-ish to the \Enterprise_WebsiteRestriction_Model_Observer class, thus:

Each +factoryRestrictionModeObject($restrictionMode) will deliver an instance of \Evozon_WebsiteRestriction_Model_Interface_Restriction. For example:

And voilà! Each case has been transformed into an independent class, represented by itself. Having those in place, we can create new restriction modes based on the needs of the project, with ease and rather fast.

Solving the not compatible

In our case, the restriction mode has to ban the full page caching. Not an elegant solution, but enough for a minimum viable product.

//public function evaluate(\Mage_Core_Controller_Front_Action $controller, \Mage_Core_Controller_Response_Http $response);
Mage::app()->getCacheInstance()->banUse('full_page');

Layer Restriction

Brief description: a WebsiteRestriction wannabe but on steroids

While the upgraded WebsiteRestriction allows you to shut down a storefront, the Layer Restriction would allow you to do much more by providing a basic middleware between a consumer (e.g. the potential customer) and the system itself (e.g. the e-commerce platform).

Middleware

Here, a proxy protection system hooked onto the main layers of Magento offers the possibility of custom layout rendering implementation and custom routing based on various validations.

The system will give different access rights to an object, having built-in the capacity of resolving the resources to defined preferences based on some implemented rules, part of the architectural design.

rules flow description

rules maintainability

It’s about jogging with a websiterestriction.xml file on a per module basis.



    
        
            
            
            
            
            
        
        
            
            
            
            
            
        
    

Each defined rule has the +process interface at root, which is triggered at runtime as listed in the middleware implementation section. The +process interface calls for +passable, which must be implemented based on the rule’s purpose (e.g. validate customer session).

Middleware Implementation

This can be done easily by extending the layout subsystem (for UI elements manipulation) and the action predispatch (for the routes manipulation).

layout subsystem

I've decided to override the #_getBlockInstance routine, like so:

$block = new $block($attributes);
$block = $this->getProxyProtectionBlock()->execute($block);

...

//public function process(\Varien_Object $blockInstance)
$reflectionClass = $this->reflection($blockInstance);
$configuration = $this->fetchConfigurationElement();
$configuration->setName($reflectionClass->getName());
$item = $this->getProxyConfiguration()->getRule($configuration);
if ($item !== null) {
     $blockInstance = $item->process($blockInstance);
}

return $blockInstance;

For each block instantiation, the extended layout will look into the proxy block subsystem via the +execute interface. If any matches are found, the subsystem will provision the request with a preference (as listed above in the rules examples), giving a crafted version of it instead of the intended block.

controller and action predispatch

This is easily resolved through the controller_action_predispatch event and

//public function process(\Varien_Object $instance)
$item = $this->getProxyConfiguration()->getRule($configuration);
if ($item !== null) {
     $preference = $item->process($controllerAction);
     if ($preference !== true) {
         $controllerAction->getResponse()->setRedirect($preference);
         $controllerAction->setFlag('', Mage_Core_Controller_Varien_Action::FLAG_NO_DISPATCH, true);
     }
}

For each request, the routing will look into the proxy route subsystem for matching resources. If any are found, the subsystem will, again, provision the request based on the defined preference.

Complexity

The rule is extracted on a _O(1)_ complexity.

Also, in order to get a good performance blueprint, the entire mechanism's configuration can be held in memory via a core config cache object.

In Short...

Was it worth it? Hell, yeah! Easily got a layer restriction mechanism and enjoyed ourselves a little bit outside of the Magento's sphere.


NO COMMENTS

Tell us what you think

Fields marked with " * " are mandatory.

We use cookies to offer you the best experience on our website. Learn more

Got it