Welcome Guest, Not a member yet? Register   Sign In
Authentication on a hook
#1

[eluser]mscahill[/eluser]
I'm developing an authenticated intranet application for our University Relations division. It is absolutely essential that the entire application be secure.

I've already created an authentication scheme that checks credentials against the database, but I'm having trouble creating a hook function that forces authentication. My hook so far is as follows:

Code:
<?php
class Auth {

    function check()
    {
        $CI  =& get_instance();
        if (strpos($_SERVER['REQUEST_URI'],'account')===FALSE) {
        switch (get_cookie('user_pass')) {
            case TRUE:
                //Double check that the cookie has the right user name and password
                $username = $CI->encrypt->decode(get_cookie('user_name'));
                $password = $CI->encrypt->decode(get_cookie('user_pass'));
                $query = $CI->db->query("SELECT user_pass FROM ci_users WHERE user_name='$username';");
                
                //Username and password incorrect, so force login
                $row = $query->row();
                if ($query->num_rows()==0) {
                    delete_cookie("user_name","urweb.stetson.edu");
                    delete_cookie("user_pass","urweb.stetson.edu");
                    header("Location: " . site_url('account/login'));
                    }
                if ($password!=$row->user_pass) {
                    delete_cookie("user_name","urweb.stetson.edu");
                    delete_cookie("user_pass","urweb.stetson.edu");
                    header("Location: " . site_url('account/login'));
                    }
                break;
                
            case FALSE:
                
                //No cookies found, so force them to log in
                header("Location: " . site_url('account/login'));
                break;
        }
        }
    }
?>

The problem that I'm having is that if I make it a pre_system hook then I don't have access to the CI instance, and as such cannot use CI helpers and libraries. However, if I make it a post_controller_construct hook, then authentication is not required on cached pages. Some of these pages take up to a minute to load, so caching is necessary. The caching process is done on a nightly basis automatically for pages that have taken longer than 10 seconds to load in the previous week (as logged by another hook function).

Is there any way I can force authentication on cached pages and still use CI helpers?
#2

[eluser]barbazul[/eluser]
I'd go with the presystem since no cache check has been made at this point

To avoid the problem of non-loaded classes use the non-documented function load_class() which is internally used to retrieve unique instances of the core classes. So you can retrieve each of the core classes (and even initialize them if they aren't initialized yet) without need for a controller!

Another approach could be setting a cache_override hook that checks for users credentials before retrieving any cache.

Side note: this is one of the reason i'm not happy with codeigniter's cache system. I believe there is room for improvement on this point
#3

[eluser]mscahill[/eluser]
If I did the check on cache_override, would the function run for a non-cached page?
#4

[eluser]barbazul[/eluser]
This is an extract from system/Codeigniter/Codeigniter.php line 97:

Code:
if ($EXT->_call_hook('cache_override') === FALSE)

{

    if ($OUT->_display_cache($CFG, $RTR) == TRUE)

    {

        exit;

    }

}

simple explanation: before working on cache, it checks if there is any cache_override hook. If there is _call_hook will execute the override and return true, and the _display_cache won't fire.
So the answer would be: Yes, the function would run for cached pages but you'll have to work with the cache yourself (probably calling _display_cache from your hook) and you would still have the problem of not having the controller initialized.
#5

[eluser]mscahill[/eluser]
So in my cache_override trigger, I would put something like this?

Code:
if (isset($authentication_cookie)) {
    if ($OUT->_display_cache($CFG, $RTR) == TRUE)
    {
        exit;
    }
} else {
//Redirect to login page
}
#6

[eluser]mscahill[/eluser]
You know what, it doesn't matter because CI still isn't instantiated. I think that's what you were trying to tell me. I think I'm going to have to do a pre_system hook.

How do I load the helpers I need in my hook?
#7

[eluser]barbazul[/eluser]
As I said, you can load classes with the load_class function.
So you can retrieve an instance of the Loader class even when you don't have a controller.

Code:
$loader =& load_class("Loader");
$loader->helper('url');
echo base_url();

If you're running PHP4 the above code might throw some errors.
I haven't tried it myself but I'm pretty sure it will work unexpectedly on some cases.
#8

[eluser]mscahill[/eluser]
Sweet. I loaded the cookie helper successfully. Now I need access to the encrypt class. Can't I just do something like:

Code:
$encrypt =& load_class("encrypt");

I tried this, and it gave me the error:

Call to undefined function get_instance() in ...\Encrypt.php on line 46
#9

[eluser]mscahill[/eluser]
Ugh! Back to the drawing board anyways. The page cache generates a page per url, so post data is ignored. I can't use the cache system on CI for my page anyways...

I guess I'll make the Authentication system a post_controller_constructor hook then. That'll make things slower but easier...
#10

[eluser]barbazul[/eluser]
Ok, I put some more energy into this (have to admit I wasn't thinking THAT hard) and got to the conclusion that the whole caching system is not entirely compatible with what you're trying to accomplish so that's where you should focus.

I think that in order to not to load the cache when post information is sent, the best solution is to extend the _display_cache method so you can check whether post information has been sent and if so, ignore the whole cache loading

system/application/libraries/MY_Cache.php
Code:
<?php
class MY_Cache extends Cache {
  function _display_cache(&$CFG, &$RTR) {
    if ( ! empty($_POST) ) { // Check if there is POST information
      return FALSE;
    } else {
      return parent::_display_cache($CFG,$RTR);
    }
  }
}
?>

If you do this, you should be able to fire your hook after the controller has been initialized




Theme © iAndrew 2016 - Forum software by © MyBB