source: trunk/lib/Auth_Simple.inc.php @ 745

Last change on this file since 745 was 745, checked in by anonymous, 3 years ago

Allow checking isLoggedIn() without incrementing last-access-datetime (to allow for session polling)

File size: 10.0 KB
Line 
1<?php
2/*
3* Auth_Simple.inc
4* Code by Strangecode :: www.strangecode.com :: This document contains copyrighted information.
5* @author   Quinn Comendant <quinn@strangecode.com>
6* @version  1.0
7* @since    04 Mar 2009 21:59:03
8*/
9
10class Auth_Simple {
11
12    // Namespace of this auth object.
13    var $_ns;
14
15    // Parameters to be configured by setParam.
16    var $_params = array();
17    var $_default_params = array(
18
19        // The URL to the login script.
20        'login_url' => '/',
21
22        // The maximum amount of time a user is allowed to be logged in. They will be forced to login again if they expire.
23        // In seconds. 21600 seconds = 6 hours.
24        'login_timeout' => 21600,
25
26        // The maximum amount of time a user is allowed to be idle before their session expires. They will be forced to login again if they expire.
27        // In seconds. 3600 seconds = 1 hour.
28        'idle_timeout' => 3600,
29    );
30
31    /**
32     * Constructs a new authentication object.
33     *
34     * @access public
35     * @param optional array $params  A hash containing parameters.
36     */
37    public function __construct($namespace='')
38    {
39        $app =& App::getInstance();
40
41        $this->_ns = $namespace;
42
43        // Initialize default parameters.
44        $this->setParam($this->_default_params);
45
46        // Get create tables config from global context.
47        if (!is_null($app->getParam('db_create_tables'))) {
48            $this->setParam(array('create_table' => $app->getParam('db_create_tables')));
49        }
50
51        if (!isset($_SESSION['_auth_simple'][$this->_ns])) {
52            $this->clear();
53        }
54    }
55
56    /**
57     * Set the params of an auth object.
58     *
59     * @param  array $params   Array of parameter keys and value to set.
60     * @return bool true on success, false on failure
61     */
62    public function setParam($params)
63    {
64        if (isset($params) && is_array($params)) {
65            // Merge new parameters with old overriding only those passed.
66            $this->_params = array_merge($this->_params, $params);
67        }
68    }
69
70    /**
71     * Return the value of a parameter, if it exists.
72     *
73     * @access public
74     * @param string $param        Which parameter to return.
75     * @return mixed               Configured parameter value.
76     */
77    public function getParam($param)
78    {
79        $app =& App::getInstance();
80
81        if (isset($this->_params[$param])) {
82            return $this->_params[$param];
83        } else {
84            $app->logMsg(sprintf('Parameter is not set: %s', $param), LOG_DEBUG, __FILE__, __LINE__);
85            return null;
86        }
87    }
88
89    /**
90     * Sets a variable into a registered auth session.
91     *
92     * @access public
93     * @param mixed $key      Which value to set.
94     * @param mixed $val      Value to set variable to.
95     */
96    public function set($key, $val)
97    {
98        if (!isset($_SESSION['_auth_simple'][$this->_ns]['user_data'])) {
99            $_SESSION['_auth_simple'][$this->_ns]['user_data'] = array();
100        }
101        $_SESSION['_auth_simple'][$this->_ns]['user_data'][$key] = $val;
102    }
103
104    /**
105     * Returns a specified value from a registered auth session.
106     *
107     * @access public
108     * @param mixed $key      Which value to return.
109     * @param mixed $default  Value to return if key not found in user_data.
110     * @return mixed          Value stored in session.
111     */
112    public function get($key, $default='')
113    {
114        if (isset($_SESSION['_auth_simple'][$this->_ns][$key])) {
115            return $_SESSION['_auth_simple'][$this->_ns][$key];
116        } else if (isset($_SESSION['_auth_simple'][$this->_ns]['user_data'][$key])) {
117            return $_SESSION['_auth_simple'][$this->_ns]['user_data'][$key];
118        } else {
119            return $default;
120        }
121    }
122
123    /**
124     * Clear any authentication tokens in the current session. A.K.A. logout.
125     *
126     * @access public
127     */
128    public function clear()
129    {
130        $_SESSION['_auth_simple'][$this->_ns] = array('authenticated' => false);
131    }
132
133    /*
134    * Runs a full login sequence: clear old session, validate auth, create session.
135    *
136    * @access   public
137    * @param    int     $user_id     User ID.
138    * @return   mixed                   False on failure, true on success.
139    * @author   Quinn Comendant <quinn@strangecode.com>
140    * @version  1.0
141    * @since    04 Mar 2009 21:07:33
142    */
143    public function login($user_id, $password, $callback)
144    {
145        global $acct;
146
147        $app =& App::getInstance();
148
149        $this->clear();
150
151        if (!is_callable($callback)) {
152            $app->logMsg(sprintf('Not callable: %s', getDump($callable)), LOG_ERR, __FILE__, __LINE__);
153            return false;
154        }
155
156        if (!call_user_func($callback, $user_id, $password)) {
157            $app->logMsg(sprintf('Authentication failed for user_id: %s', $user_id), LOG_NOTICE, __FILE__, __LINE__);
158            return false;
159        }
160
161        $app->logMsg(sprintf('Authentication successful for user_id: %s', $user_id), LOG_INFO, __FILE__, __LINE__);
162        return $this->createSession($user_id);
163    }
164
165
166    /*
167    *
168    *
169    * @access   public
170    * @param
171    * @return
172    * @author   Quinn Comendant <quinn@strangecode.com>
173    * @version  1.0
174    * @since    04 Mar 2009 21:07:33
175    */
176    public function createSession($user_id)
177    {
178        $app =& App::getInstance();
179
180        // Register authenticated session.
181        $_SESSION['_auth_simple'][$this->_ns] = array(
182            'authenticated'         => true,
183            'user_id'               => $user_id,
184            'login_datetime'        => date('Y-m-d H:i:s'),
185            'last_access_datetime'  => date('Y-m-d H:i:s'),
186            'remote_ip'             => getRemoteAddr(),
187        );
188
189        return true;
190    }
191
192    /*
193    *
194    *
195    * @access   public
196    * @param
197    * @return
198    * @author   Quinn Comendant <quinn@strangecode.com>
199    * @version  1.0
200    * @since    04 Mar 2009 21:10:41
201    */
202    public function isLoggedIn($update_last_access_datetime=true)
203    {
204        $app =& App::getInstance();
205
206        // Test login with information stored in session. Skip IP matching for users from trusted networks.
207        if (isset($_SESSION['_auth_simple'][$this->_ns]['authenticated'])
208            && true === $_SESSION['_auth_simple'][$this->_ns]['authenticated']
209            && !empty($_SESSION['_auth_simple'][$this->_ns]['user_id'])
210            && strtotime($_SESSION['_auth_simple'][$this->_ns]['login_datetime']) > time() - $this->_params['login_timeout']
211            && strtotime($_SESSION['_auth_simple'][$this->_ns]['last_access_datetime']) > time() - $this->_params['idle_timeout']
212        ) {
213            // User is authenticated!
214            if ($update_last_access_datetime) {
215                $_SESSION['_auth_simple'][$this->_ns]['last_access_datetime'] = date('Y-m-d H:i:s');
216            }
217            $seconds_until_login_timeout = max(0, $this->_params['login_timeout'] - $result['seconds_since_last_login']);
218            $seconds_until_idle_timeout = max(0, $this->_params['idle_timeout'] - $result['seconds_since_last_access']);
219            $session_expiry_seconds = min($seconds_until_login_timeout, $seconds_until_idle_timeout);
220            $app->logMsg(sprintf('Returning true login status for user_id %s (session expires in %s seconds)', $_SESSION['_auth_simple'][$this->_ns]['user_id'], $session_expiry_seconds), LOG_DEBUG, __FILE__, __LINE__);
221            return $session_expiry_seconds;
222        } else if (isset($_SESSION['_auth_simple'][$this->_ns]['authenticated']) && true === $_SESSION['_auth_simple'][$this->_ns]['authenticated']) {
223            // User is authenticated, but login has expired.
224            if (strtotime($_SESSION['_auth_simple'][$this->_ns]['last_access_datetime']) > time() - 43200) {
225                // Only raise message if last session is less than 12 hours old.
226                // TODO: Can we move this message to requireLogin() so it doesn't display unless the user expects it to?
227                // $app->raiseMsg(_("Your session has expired. You need to log-in again."), MSG_NOTICE, __FILE__, __LINE__);
228            }
229            // Log the reason for login expiration.
230            $expire_reasons = array();
231            if (empty($_SESSION['_auth_simple'][$this->_ns]['user_id'])) {
232                $expire_reasons[] = 'user_id not found';
233            }
234            if (strtotime($_SESSION['_auth_simple'][$this->_ns]['login_datetime']) <= time() - $this->_params['login_timeout']) {
235                $expire_reasons[] = 'login_timeout expired';
236            }
237            if (strtotime($_SESSION['_auth_simple'][$this->_ns]['last_access_datetime']) <= time() - $this->_params['idle_timeout']) {
238                $expire_reasons[] = 'idle_timeout expired';
239            }
240            $app->logMsg(sprintf('user_id %s session expired: %s', $this->get('user_id'), join(', ', $expire_reasons)), LOG_INFO, __FILE__, __LINE__);
241        }
242
243        // User is not authenticated.
244        $this->clear();
245        return false;
246    }
247
248    /**
249     * Redirect user to login page if they are not logged in.
250     *
251     * @param string $message The text description of a message to raise.
252     * @param int    $type    The type of message: MSG_NOTICE,
253     *                        MSG_SUCCESS, MSG_WARNING, or MSG_ERR.
254     * @param string $file    __FILE__.
255     * @param string $line    __LINE__.
256     * @access public
257     */
258    public function requireLogin($message='', $type=MSG_NOTICE, $file=null, $line=null)
259    {
260        $app =& App::getInstance();
261
262        if (!$this->isLoggedIn()) {
263            // Display message for requiring login. (RaiseMsg will ignore empty strings.)
264            if ('' != $message) {
265                $app->raiseMsg($message, $type, $file, $line);
266            }
267
268            // Login scripts must have the same 'login' tag for boomerangURL verification/manipulation.
269            $app->setBoomerangURL(getenv('REQUEST_URI'), 'login');
270            $app->dieURL($this->_params['login_url']);
271        }
272    }
273
274    /**
275     * Stub method to fulfill requirements by Version()
276     *
277     * @param  string   $null
278     * @return string   Empty string
279     */
280    public function getUsername($null=null)
281    {
282        return '';
283    }
284}
Note: See TracBrowser for help on using the repository browser.