views:

118

answers:

6

EDIT: After a complaint about assigning myself the answer, I want to update that the answers provided were not satisfactory. No one came out and explicitly said this is your problem, do this and you will have a resolution. Mere suggestions are not sufficient to merit a bounty award. Lastly, the problem was with server settings and after doing some research on server sessions and looking at Stackoverflow/Serverfault I was able to determine how to best resolve this problem. Therefore, I did not feel it was unjust to mark my own answer as the correct one.

I have a php based authentication system which relies on LDAP to verify identity and uses sessions to maintain users authenticated status.

Lately I noticed that it appears to be pushing me back to the login page like my session expired. The problem is that it does not appear to be for any specific reason that I have noticed and I am not sure how to debug/test something like this.

Here is my authentication function which starts the session:

function authenticateUser($user, $password){
    //assuming ldap connection and verification of user login/pass
    //this is what will happen with authenticate user which is called 
    //when user submits login/pass on authentication form. 
    $_SESSION['id'] = $uID;
    $time = time(); 
    $_SESSION['time'] = $time;                                  
    $_SESSION['lastActivity'] = $time; 
    $_SESSION['expiration'] = $time+$cookieExpiration; 
    $_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];  
    $_SESSION['secret'] = md5(rand());                          
    $_SESSION['userHash'] = getSessionHash();  
    $_SESSION['firstLogin'] = isFirstLogin($user); 
    //assign cookie to user and log authentication 
    giveCookie("userHash", $_SESSION['userHash'],0);
    logAuthenticationAttempt($user, $_SERVER['REMOTE_ADDR'], 1);
    return true;
}//end authenticateUser 

Give cookie function:

function giveCookie($name, $value, $expiration=0){
    global $path, $site; 
    setcookie("userHash", $_SESSION['userHash'], $expiration, $path, $site, true, true);    
}//end giveCookie 

Here is my function which is called on each page to verify the user is authenticated before allowing them to proceed with action requiring authenticated status:

function isValidUser(){
    global $links; global $userName; global $userID; global $cookieExpiration; 
    if(isset($_COOKIE['userHash']) and isset($_SESSION['userHash'])){
        if($_COOKIE['userHash'] == $_SESSION['userHash']){

         $userName = $_SESSION['nameN'];
         $userID = $_SESSION['id'];
         //update userHash cookie for additinoal expiration time this way session
         $time = time(); 
         $expiration = $time+$cookieExpiration; 
         $_SESSION['lastActivity'] = $time; 
         giveCookie("userHash", $_SESSION['userHash'],0);
         $_SESSION['expiration'] = $expiration; 
         return true;
         }
    }
    return false;
}//end isvalidUser() 

Any advice or feedback on how to test this would be appreciated. I am looking to figure out why occasionally after performing some action I get pushed back to the login page.

On a page which request authentication what I do at the top is the following:

if(!isValidUser()){changePage($links['login']."?refer=".$links['requestHelp']);}
//note: changePage is just a function for header("location: somepage.php"); 
+2  A: 

You seem to be confusing authentication, authorization and session management. If you want to test all 3 then you'll need some sort of automated test tool capable of scriptable, stateful HTTP session replay (e.g. http::recorder / www::mechaninze with Perl).

OTOH if you want to investigate the session management using your deployed application, then I'd recommend instrumenting the login page to capture information about the current session and how the user got routed there. You should also consider logging the session cookie on the webserver.

symcbean
Can you provide a bit of detail on how to test some of this?
Chris
Which bit of this?
symcbean
A: 

The server is probably overwriting their session cookie, which will change the session hash and then it won't equal the cookie they have clientside. You appear to be overthinking this. You don't need to set a cookie on their system to verify them. The $_SESSION var will handle it all for you.

If they pass the challenge, then they have a $_SESSION var that is set that gives them auth levels.

Don't pass $_SESSION off to other vars like you are. Don't go $username = $_SESSION['username'] because now you have a var that is nonsecure ($username) that could have secured data in it. But it might not.

Whenever you are displaying session info, make sure it came from the horse's mouth.

Geekster
So just rely on $_SESSION['username'] when I need it and do not set this value to a variable for usage later? Although not entirely an answer to my original question, if this is good practice I will implement it.
Chris
You also don't need a userhash check. That is the root of your issue. The userhash cookie is not in sync with the server session variables. When the session times out your code won't allow it to pass.
Geekster
So what did the userhash check have to do with the session timeout? You never did quite explain that one which is why you never received the answer for this question or the bounty. The answer is they don't, by the way.
Chris
You were checking to make sure the cookie var was the same as the session var. If the session is reset, they will not match. If they don't match... well you know what happens. So when you made it so the sessions lasted longer, you saw the bug seemed to disappear but it's still got some issues because you don't need a client side cookie when you can rely on $_SESSION to do its job. You overcomplicated it. :)
Geekster
A: 

Take a deep look at session.configuration

i would (if your not willing to think over your concept) change the isValidUser to log what ever you can get before return false

function isValidUser(){
    global $cookieExpiration; // since $links isn't used and $userName and $userId come from $_SESSION no need for global there
    if( (isset($_COOKIE['userHash']) and isset($_SESSION['userHash'])) 
        and ($_COOKIE['userHash'] == $_SESSION['userHash']) ){

         $userName = $_SESSION['nameN']; // why these lines?
         $userID = $_SESSION['id']; // see above
         //update userHash cookie for additinoal expiration time this way session
         $time = time(); 
         $expiration = $time+$cookieExpiration; 
         $_SESSION['lastActivity'] = $time; 
         giveCookie("userHash", $_SESSION['userHash'],0);
         $_SESSION['expiration'] = $expiration; 
         return true;
    }
    // $logger ist just an example an could be a p.e Zend_Logger Object
    $logger->debug($_SESSION); // serialize if needed
    $logger->debug($_COOKIE); // serialize if needed
    $logger->err(error_get_last());
    return false;
}//end isvalidUser()

And are you sure you called session_start() before isValidUser()

maggie
+1  A: 

Write a functional test. You can use SimpleTest's WebTestCase for stuff like this. See the documentation at: http://www.simpletest.org/en/web_tester_documentation.html

Of course, you could also try to break the code down into smaller bits that can easier be tested individually. Right now, your authentication system is tightly coupled to the server state (eg. the session management). You could decouple the two and thus be able to test the authentication system in a unit test, rather than a functional test.

troelskn
Can you elaborate a bit on how to decouple authentication and server state ? I understand what decouple means but not sure in regards to this situation, how to seperate authentication from server session.
Chris
Basically, by encapsulating everything which changes session/cookie. You can then mock that out while testing the rest of the logic in isolation. You would still have to write a web test case to test the session/cookie code, but you would keep complexity down in each component. Plus you can reuse the session/cookie code for multiple components, each of which could piggyback on the same tests.
troelskn
.. if you took this approach, you would presumably easily have been able to pinpoint that the problem is with the session-management (and thus the server configuration) it self, rather than with your authentication logic. Of course, I'm just second guessing you here - draw your own conclusions ;)
troelskn
+2  A: 

Not sure what testing software you use at the moment, but I'd strongly recommend Selenium. It allows you to run scripted tests through the browser, effectively simulating what an end user would do and see.

Spudley
A: 

It appears that this was a simple misconfiguration of the server itself. Being that this server environment is a shared environment for hundreds of sites, I do not have ability to modify server wide settings in php.ini and the like.

What I was able to do though is...

session_set_cookie_params(time()+$expiration, $path, $domain, true, true); 

This has resolved the issue, it appears before the session expiration was not set properly and this will set it accordingly for this specific application.

Chris
Wait a minute. You should rep me the 100 points because I told you the problem was with your user cookie and the session limit being out of sync which you seem to have fixed by your code. I might add that there still seems to be a problem with your code in that the user's cookie could become out of sync with the session if an old cookie persists if the user closes their browser. So relying on their cookies at all is probably not a good idea. Plus it's kind of bad form to +rep your own answer. Serverside sessions are the way to go.
Geekster
1. I do not get any reputation for assigning the answer to myself. 2. Your answer did not solve the problem. Code was not overwriting the session, and the cookie is set to validate the session because userHash is a hashing of a few variables which provides a way to validate the user is who they say they are. 3. Login clears userHash cookie when user tries to authenticate so if user goes to a page requiring authentication and userHash does not match then they will be forced back to login. 4. If anything maggie's answer was better than your own.
Chris
Lastly, I lose the points I assign the bounty for before I award them so even if I did award the bounty to myself I would not be gaining I would be reacquiring the points originally awarded for the bounty, not earning additional points. A bounty is when you give away points not create additional points.
Chris
@Chris : shady, bro. My answer told you where to look and you looked, then posted an answer to your question. Reported.
Geekster
Geekster no your answer did not suggest where to look. How do you figure this? Where in your answer do you suggest to look elsewhere? YOu have mere suggestions on potential problems with my code, NOT where to look in terms of php server session settings.
Chris
@Chris: I told you that your clientside cookie was out of sync with your server cookie so you changed the expiry of the server cookie. This directly resolved your issue... REP! :D
Geekster
You were discussing my userHash client side cookie which was a hashing of various variables to validiate authenticity during the session. Not the explicit server session id cookie and its expiration time. I have no problem giving you the reputation points either, but they are not justified and that is not what stackoverflow community is about.
Chris