(file) Return to SessionHandler.class.php CVS log (file) (dir) Up to [Development] / advokit-installer

File: [Development] / advokit-installer / SessionHandler.class.php (download) / (as text)
Revision: 1.6, Wed Aug 25 03:13:03 2004 UTC (6 years ago) by travislow
Branch: MAIN
CVS Tags: r1-x-dev, r0-9-9, r0-9-8, footag0, HEAD
Changes since 1.5: +74 -69 lines
- Fixed minor security issues relating to uninitialized variables.
- Enhanced bug reporting.  If a DB error occurs, a form is displayed.
  The user can choose to use it, or not.
- Change app maintainers to ak@voter2voter.org

<?
# ======================================================================
# AdvoKit -- a campaign managment tool
# Copyright (C) 2004  OrchidSuites, Inc. (info@orchidsuites.net)
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the AFFERO GENERAL PUBLIC LICENSE
# as published by Affero, Inc.; either version 1
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# AFFERO GENERAL PUBLIC LICENSE for more details.
# 
# You should have received a copy of the AFFERO GENERAL PUBLIC LICENSE
# along with this program; if not, write to Affero, Inc. at
# 510 Third Street - Suite 225, San Francisco, CA 94107, USA
# or visit <http://www.affero.org>.
# ======================================================================

# ======================================================================
# Checks to see if there is a user with a valid login session.
# If a session exists, create a user object for that user.
# ======================================================================

# SessionHandler wraps the fetch/set of persistent SessionCookies.
require_once "$t_root".DIRSEP."SessionCookie.class.php";

class SessionHandler
{
    var $config;
    var $logger;
    var $db;
    var $request;
    var $te;
    var $ustate;

    var $sessiontype;
    var $sessionname;
    var $sessioncookie;
    var $encryption_key;
    var $user;

    #------------------------------------------------------------
    # Instance functions
    #------------------------------------------------------------

    #.................................................. SessionHandler
    #
    # Create and authenticate users based on submitted
    # information.  (not the same as logging them in)
    #
    function SessionHandler( &$config, &$logger, &$db, &$request, &$te, &$ustate )
    {
        $this->config =& $config;
        $this->logger =& $logger;
        $this->db =& $db;
        $this->request =& $request;
        $this->te =& $te;
        $this->ustate =& $ustate;

        $this->sessionname = $config->get( "login_cookie_name" );
        if( !$this->sessionname )
        {
            $logger->error( __FILE__, "No session name specified!  You need to set 'login_cookie_name' in your ini file." );
            return;
        }
        $this->sessiontype = $config->get( "login_session_type" );
        if( $config->get( "use_http_auth" ) || $this->sessiontype == "http_auth" )
        {
            global $t_root;
            require_once "$t_root".DIRSEP."auth-utils.inc.php";
            if ( !isset($_SERVER['HTTP_AUTHORIZATION']) && function_exists('apache_request_headers') )
            {
                // work around odd bug when php is not invoked as a CGI.
                $headers = apache_request_headers();
                $_SERVER['HTTP_AUTHORIZATION'] = $headers['Authorization'];
            }
            $clrsess = ($request->get( "action" ) == "clearsession" );
            $authused= ( $_SERVER['REMOTE_USER'] || $_SERVER['PHP_AUTH_USER'] || $_SERVER['HTTP_AUTHORIZATION'] );
            if ($clrsess)
            {
                if (!$authused)
                {
                    // make sure we generate the WWW-Authenticate header
                    // so that the browser sends us the login credentials
                    makeAuthenticateHeader( $config, $request->get( "timestamp" ));
                    // unfriendly messaage; should rarely be seen!
?>

<h1>Login Error</h1>
<p>You're probably using a non-secure connection
from a browser that doesn't support http digest
authentication.
</p>

<?
                    exit;
                }
                else
                {
                    // helper for login/logout; remove 'username:password@'
                    // from url shown in browser.
                    $protocol = ( strtolower($_SERVER['HTTPS']) == "on" ) ? 'https' : 'http';
                    $query=implode ('&', preg_grep('/^(action|timestamp)=/', explode('&',$_SERVER['QUERY_STRING']), PREG_GREP_INVERT));
                    if ($query != "")
                    {
                        $query="?$query";
                    }
                    session_write_close();
                    header("Location: $protocol://".$_SERVER['HTTP_HOST']. $_SERVER['PHP_SELF'].$query);
                    exit;
                }
            }
            if ($authused)
            {
                $this->sessiontype = "http_auth";
            }
        }
        $this->sessioncookie = $this->initSessionCookie();
        $logger->debug( __FILE__, "SessionHandler created:" );
        $logger->debug( __FILE__, " - session type is '".$this->sessiontype."'" );
        $logger->debug( __FILE__, " - session name is '".$this->sessionname."'" );
        $logger->debug( __FILE__, " - session id is '".$this->sessioncookie->toString($config)."'" );
    }

    #.................................................. getSessionType
    #
    # Return the session type.
    #
    function getSessionType()
    {
        return $this->sessiontype;
    }

    #.................................................. getSessionName
    #
    # Return the session name.
    #
    function getSessionName()
    {
        return $this->sessionname;
    }

    #.................................................. initSessionCookie
    #
    # Initialize the sessioncookie associated with the session name.
    # This function should only be used to initialize $this->sessioncookie
    #
    function initSessionCookie()
    {
        switch( $this->getSessionType() )
        {
            case "cookie":
            {
                return SessionCookie::fromString
            ( $this->config, $_COOKIE[ $this->getSessionName() ] );
            }
            case "request":
            {
                return SessionCookie::fromString
            ( $this->config, $this->request->get( $this->getSessionName() ) );
            }
            case "phpsession":
            {
                //----------------------------------------------------------
                // Explicitly start a session.  This is necessary
                // because we use $_SESSION[], rather than
                // session_register(), to manipulate session variables.
                //------------------------------------------------------------
                session_start();
                return SessionCookie::fromString ( $this->config, $_SESSION[ $this->getSessionName() ] );
            }
            case "http_auth":
            {
                return SessionCookie::fromHeaders( $this->config );
            }
            default:
            {
                $this->logger->error( __FILE__, "Invalid session type specified: '".$this->getSessionType()."'" );
            }
        }
    }

    #.................................................. refreshSession
    #
    # Refresh login session information.
    #
    function refreshSession()
    {
        $this->logger->debug( __FILE__, "Refreshing session: " );
        $this->logger->debug( __FILE__, " - session type is '".$this->getSessionType()."'" );
        $this->logger->debug( __FILE__, " - session name is '".$this->getSessionName()."'" );
        $this->logger->debug( __FILE__, " - session id is '".$this->sessioncookie->toString($this->config)."' (but not for long)" );
        switch( $this->getSessionType() )
        {
            case "cookie":
            {
                $this->logger->debug( __FILE__, "Refreshing cookie-based session." );
                if ( ! setcookie( $this->getSessionName(), $this->sessioncookie->toString( $this->config ), time() + $this->config->get( "login_timeout" ), "/" ) )
                {
                    $this->logger->error( __FILE__, "Unable to set cookie!" );
                }
                break;
            }
            case "request":
            {
                # A bit of a hack.  The filter adds the session info
                # to each page emitted from the Template Engine.
                $this->request->set( $this->getSessionName(), $this->sessioncookie->toString( $this->config) );
                $this->logger->debug( __FILE__, "Refreshing request-based session." );
                $this->te->registerPostfilter( "addSessionInfoToPage" );
                break;
            }
            case "phpsession":
            {
                $this->logger->debug( __FILE__, "Refreshing phpsession-based session." );
                $_SESSION[ $this->getSessionName() ] = $this->sessioncookie->toString( $this->config );
                break;
            }
            default:
            {
                $this->logger->error( __FILE__, "Invalid session type specified: '".$this->getSessionType()."'" );
            }
        }
    }

    #.................................................. createSession
    #
    # Create a new login session, overwriting any old one.
    #
    function createSession( $newsessioncookie )
    {
        $this->sessioncookie = $newsessioncookie;
        $this->logger->debug( __FILE__, "Creating new session." );
        // change the php session_id in order to prevent
        // session fixation attacks.
        if ($this->getSessionType() == "phpsession" )
        {
            session_regenerate_id();
        }
        $this->refreshSession();
    }

    #.................................................. expireSession
    #
    # Expire the session (log the user out)
    #
    function expireSession()
    {
        $this->logger->debug( __FILE__, "Expiring session: " );
        $this->logger->debug( __FILE__, " - session type is '".$this->getSessionType()."'" );
        $this->logger->debug( __FILE__, " - session name is '".$this->getSessionName()."'" );
        $this->logger->debug( __FILE__, " - session id is '".$this->sessioncookie->toString( $this->config )."' (but not for long)" );
        switch( $this->getSessionType() )
        {
            case "cookie":
            {
                $_COOKIE[ $this->getSessionName() ] = NULL;
                if ( ! setcookie( $this->getSessionName(), "", 0, "/" ) )
                {
                    $this->logger->error( __FILE__, "Unable to set cookie!  User is still logged in!" );
                }
                break;
            }
            case "request":
            {
                $this->request->set( $this->getSessionName(), NULL );
                break;
            }
            case "phpsession":
            {
                $_SESSION[ $this->getSessionName() ] = NULL;
                // change the php session_id to be safe.
                session_regenerate_id();
                break;
            }
            default:
            {
                $this->logger->error( __FILE__, "Invalid session type specified: '".$this->getSessionType()."'" );
            }
        }
    }

    #.................................................. getUser
    #
    # Get the current logged in user, based on the login
    # session information passed in the request, in a cookie,
    # or in the session.
    #
    # If no one is logged in, create an anonymous user.
    #
    function getUser()
    {
        if( $this->sessioncookie )
        {
            $sesscookie = $this->sessioncookie;
            $username = $sesscookie->username;
            if( $username )
            {
                $user = new User( $this->config, $this->logger, $this->db, $username );
                if( $user->isAnonymous() )
                {
                    $this->logger->warning( __FILE__, "Failed login attempt by '".$username."'.  No such active user." );
                    return $user;
                }
                # If user exists, compare password hashes.
                if( "md5" == $this->config->get( "hash_algorithm" ) )
                {
                    $password = $user->getPassword(); // really already a hash.
                    if( $sesscookie->passhash == md5($password.":".$sesscookie->nonce) )
                    {
                        if( ! $this->config->get( "login_allow_simultaneous" ) )
                        {
                            $login_timestamp = $this->ustate->getValue( $user->getId(), 0, '', '', "login_timestamp" );
                            if( $login_timestamp == $sesscookie->timestamp )
                            {
                                $this->refreshSession();
                                $user->updateLastActivity();
                                $this->logger->debug( __FILE__, "'".$username."' is currently logged in" );
                                return $user;
                            }
                            else
                            {
                                $this->expireSession();
                                $this->request->set( "display", $this->config->get( "forcedlogout_display" ) );
                                $this->logger->warning( __FILE__, "User '$username' was logged out due to a login from a different location." );
                            }
                        }
                        else
                        {
                            $this->refreshSession();
                            $user->updateLastActivity();
                            $this->logger->debug( __FILE__, "'".$username."' is currently logged in" );
                            return $user;
                        }
                    }
                    else
                    {
                        $this->logger->warning( __FILE__, "Invalid password hash in cookie for user '$username'!" );
                    }
                }
                else
                {
                    $this->logger->error( __FILE__, "Invalid hashing algorithm specified: '$hash_algorithm'" );
                }
            }
        }
        return new User( $this->config, $this->logger, $this->db, "anonymous" );
    }
}
?>

cvsadmin@voter2voter.org
CVS Snapshots (updated daily)