Welcome Guest, Not a member yet? Register   Sign In
Best practices for implementing a trust filter
#1

[eluser]Unknown[/eluser]
Sorry in advance for the tome of a post, but I am new to Codeigniter and am hoping you gurus out there can tell me a better way to do something.

I've been trying to find a logical and clean way to hook into the framework to allow something called a trust filter. A Filter is a common design pattern in the Java world (which is where I come from) that allows all inbound requests to be examined before the primary method processing occurs. Typically there is a chain of filters that each get called in turn to do some work, and optionally reject the request.

The concept of a filter (also known as a Valve) is the main pattern I am trying to implement; in particular a trust filter that will examine the inbound IP and vet it against valid ranges and IPs.

I've tried the following approaches that worked but were ugly because of the massively repeated code.

Use Hooks
So I created hook that uses post_controller_constructor to call my filter method. In order to ensure the result, a mere boolean called $trusted, is accessible from all downstream methods I had to make it global. The hook worked fine in terms of getting the answer before any methods were dispatched, but unfortunately there is no way to stop further processing without putting something like at the head of every method.:

Code:
if(!$_IS_TRUSTED)
{
  reject_request();
}

Use Subclassing
I rejected the hook approach because I didn't want to pepper my code with the same call. So I decided to sublcass CI_Controller instead, putting the work in the base constructor and assigning the result as a class variable. Seemed clean but then I discovered there was no way to tell the framework to stop further processing. Not sure why I assumed the Controller would have this feature, but it did.

So I ended up getting what I wanted by hacking Codeigniter.php - something I really didn't want to do for obvious reasons. I levereged the Controller sublcass described above and for the pages I wanted seHere is my hack starting around line 355:
Code:
if($CI instanceof SST_Controller && ! $CI->trusted)
{
  $CI->reject_request();
}
else
{
  // Call the requested method.
  // Any URI segments present (besides the class/function) will be passed to the method for convenience
  call_user_func_array(array(&$CI, $method), array_slice($URI->rsegments, 2));  
}

My question is, does anyone know of a better way to do this so I don't have to go into the core classes in the system folder and can modify just stuff in the application folder? This seems to me like a fundamental feature of any framework, and to be honest I was shocked CI didn't have it considering the obvious thought and years of experience that the team has put into it.
#2

[eluser]CroNiX[/eluser]
I think if you just created a simple library, autoloaded it, and had your code in the __construct() method it would work. Just die('We are sorry, your IP is on our blacklist.');

Edit: I'm not sure why your hook method wouldn't work. Just die(), or use CI's show_error() function and it will do no further processing. You shouldn't have to do anything in each of your controllers.

But as far as your last question, it's pretty straight forward and well documented in the user guide. Yes, it is a fundamental feature, and it IS in the framework Smile


#3

[eluser]Unknown[/eluser]
Thanks CroNix. I'll try the show_error() approach. It didn't dawn on me to use die as that seems pretty gnarly as you can't really set any response headers or present the user with a nice page. Or is my PHP newbie-ness cropping up again?

But I think you misunderstood my question when you responded:

[quote author="CroNiX" date="1327523604"]

But as far as your last question, it's pretty straight forward and well documented in the user guide. Yes, it is a fundamental feature, and it IS in the framework Smile

[/quote]

As I mentioned I actually did override the Controller. Your link only explains how to do what I already knew and it doesn't solve my problem nor does it allow for implementing the Filter design pattern. Many modern server frameworks have a means to intercept requests and perform arbitrary work before actually dispatching to method handlers, and of course the key here is that each filter can signal to the dispatcher to stop processing. The key feature missing from CI's hooks design and even overriding core classes in the application, and what I had to hack at in Codeigniter.php was the part about continuing to process.

FWIW, I think it would be fairly easy to add this feature to CI and it would provide a powerful and unique mechanism for hooking CI that neither subclassing core classes nor hooks provide.
#4

[eluser]CroNiX[/eluser]
My point was you don't need to "hack" codeigniter.php. You could create a new one and place it in /application/core and CI will use that one instead. A slightly different approach than extending the controller.

Sure you can present them with a nice message and headers. Just output them and then die() immediately after, or exit(), to stop the rest of the CI code execution cycle (which is essentially what show_error() does).

Yes, this is a nice feature, but I doubt CI would include something like this as it would rarely get used (is my guess, since I haven't been able to find a similar discussion, so not much demand). They don't even have an official CI ACL library, yet. They just like to have the bare essentials to keep bloat down and let the programmer add in what they need. They're not trying to be Zend.
#5

[eluser]CroNiX[/eluser]
This would make an excellent library.

You can have methods to add ips, add restricted controller/method names, check database, check the requested controller (name) or method, whatever....before the controller even gets processed.

One problem with doing this in codeigniter.php is that you don't have access to databases, config, or much of anything yet, so it wouldn't be very dynamic.




Theme © iAndrew 2016 - Forum software by © MyBB