1: <?php
2:
3: /**
4: * Session handling
5: * @package framework
6: * @subpackage session
7: */
8:
9: trait Hm_Session_Auth {
10:
11: /**
12: * Lazy loader for the auth mech so modules can define their own
13: * overrides
14: * @return void
15: */
16: abstract protected function load_auth_mech();
17:
18: /**
19: * Call the configured authentication method to check user credentials
20: * @param string $user username
21: * @param string $pass password
22: * @return bool true if the authentication was successful
23: */
24: public function auth($user, $pass) {
25: $this->load_auth_mech();
26: return $this->auth_mech->check_credentials($user, $pass);
27: }
28:
29: /**
30: * Save auth detail if it's needed (mech specific)
31: * @return void
32: */
33: public function save_auth_detail() {
34: $this->auth_mech->save_auth_detail($this);
35: }
36:
37: /**
38: * Call the configuration authentication method to change the user password
39: * @param string $user username
40: * @param string $pass password
41: * @return bool true if the password was changed
42: */
43: public function change_pass($user, $pass) {
44: $this->load_auth_mech();
45: return $this->auth_mech->change_pass($user, $pass);
46: }
47:
48: /**
49: * Call the configuration authentication method to create an account
50: * @param string $user username
51: * @param string $pass password
52: * @return bool true if the account was created
53: */
54: public function create($user, $pass) {
55: $this->load_auth_mech();
56: return $this->auth_mech->create($user, $pass);
57: }
58: }
59:
60: /**
61: * PHP session data methods
62: * @package framework
63: * @subpackage session
64: */
65: abstract class Hm_PHP_Session_Data extends Hm_Session {
66:
67: /**
68: * @param Hm_Request $request request details
69: * @return void
70: */
71: protected function validate_session_data($request) {
72: if ($this->existing && count($this->data) == 0) {
73: $this->destroy($request);
74: } else {
75: Hm_Debug::add('LOGGED IN', 'success');
76: $this->active = true;
77: }
78: }
79:
80: /**
81: * @param Hm_Request $request request details
82: * @return void
83: */
84: protected function start_session_data($request) {
85: if (array_key_exists('data', $_SESSION)) {
86: $data = $this->plaintext($_SESSION['data']);
87: if (is_array($data)) {
88: $this->data = $data;
89: } elseif (!$this->loaded) {
90: $this->destroy($request);
91: Hm_Debug::add('Mismatched session level encryption key', 'warning');
92: }
93: }
94: }
95:
96: /**
97: * Return a session value, or a user settings value stored in the session
98: * @param string $name session value name to return
99: * @param mixed $default value to return if $name is not found
100: * @param bool $user if true, only search the user_data section of the session
101: * @return mixed the value if found, otherwise $default
102: */
103: public function get($name, $default = false, $user = false) {
104: if ($user) {
105: return array_key_exists('user_data', $this->data) && array_key_exists($name, $this->data['user_data']) ? $this->data['user_data'][$name] : $default;
106: } else {
107: return array_key_exists($name, $this->data) ? $this->data[$name] : $default;
108: }
109: }
110:
111: /**
112: * Save a value in the session
113: * @param string $name the name to save
114: * @param string $value the value to save
115: * @param bool $user if true, save in the user_data section of the session
116: * @return void
117: */
118: public function set($name, $value, $user = false) {
119: if ($user) {
120: $this->data['user_data'][$name] = $value;
121: } else {
122: $this->data[$name] = $value;
123: }
124: }
125:
126: /**
127: * Delete a value from the session
128: * @param string $name name of value to delete
129: * @return void
130: */
131: public function del($name) {
132: if (array_key_exists($name, $this->data)) {
133: unset($this->data[$name]);
134: return true;
135: }
136: return false;
137: }
138:
139: /**
140: * Save session data
141: * @return void
142: */
143: public function save_data() {
144: $enc_data = $this->ciphertext($this->data);
145: $_SESSION = array('data' => $enc_data);
146: session_write_close();
147: $_SESSION = array();
148: }
149: }
150:
151: /**
152: * PHP Sessions that extend the base session class
153: * @package framework
154: * @subpackage session
155: */
156: class Hm_PHP_Session extends Hm_PHP_Session_Data {
157:
158: use Hm_Session_Auth;
159:
160: /* data store connection used by classes that extend this */
161: public $conn;
162:
163: /* flag to indicate an existing session */
164: protected $existing = false;
165:
166: /**
167: * Setup newly authenticated session
168: * @param Hm_Request $request
169: * @param boolean $fingerprint
170: * @return null
171: */
172: protected function authed($request, $fingerprint) {
173: $this->set_key($request);
174: $this->loaded = true;
175: $this->start($request);
176: if ($fingerprint) {
177: $this->set_fingerprint($request);
178: }
179: else {
180: $this->set('fingerprint', '');
181: }
182: $this->save_auth_detail();
183: $this->just_started();
184: }
185:
186: /**
187: * Check for an existing session or a new user/pass login request
188: * @param object $request request details
189: * @param string $user username
190: * @param string $pass password
191: * @return bool
192: */
193: public function check($request, $user = false, $pass = false, $fingerprint = true) {
194: if ($user !== false && $pass !== false) {
195: if ($this->auth($user, $pass)) {
196: $this->authed($request, $fingerprint);
197: }
198: } elseif (array_key_exists($this->cname, $request->cookie)) {
199: $this->get_key($request);
200: $this->existing = true;
201: $this->start($request);
202: $this->check_fingerprint($request);
203: }
204: return $this->is_active();
205: }
206:
207: /**
208: * Start the session. This could be an existing session or a new login
209: * @param Hm_Request $request request details
210: * @return void
211: */
212: public function start($request) {
213: if (array_key_exists($this->cname, $request->cookie)) {
214: session_id($request->cookie[$this->cname]);
215: }
216: list($secure, $path, $domain) = $this->set_session_params($request);
217: session_set_cookie_params($this->lifetime, $path, $domain, $secure);
218: Hm_Functions::session_start();
219: $this->session_key = session_id();
220: $this->start_session_data($request);
221: $this->validate_session_data($request);
222: }
223:
224: /**
225: * Setup the cookie params for a session cookie
226: * @param Hm_Request $request request details
227: * @return array list of cookie fields
228: */
229: public function set_session_params($request) {
230: $path = false;
231: if ($request->tls) {
232: $secure = true;
233: } else {
234: $secure = false;
235: }
236: if (isset($request->path)) {
237: $path = $request->path;
238: }
239: $domain = $this->site_config->get('cookie_domain', false);
240: if (!$domain && array_key_exists('HTTP_HOST', $request->server)) {
241: $host = parse_url($request->server['HTTP_HOST'], PHP_URL_HOST);
242: if (trim((string) $host)) {
243: $domain = $host;
244: } else {
245: $domain = $request->server['HTTP_HOST'];
246: }
247: }
248: if ($domain == 'none') {
249: $domain = '';
250: }
251: return array($secure, $path, $domain);
252: }
253:
254: /**
255: * Write session data to avoid locking, keep session active, but don't allow writing
256: * @return void
257: */
258: public function close_early() {
259: $this->session_closed = true;
260: $this->save_data();
261: }
262:
263: /**
264: * Destroy a session for good
265: * @param Hm_Request $request request details
266: * @return void
267: */
268: public function destroy($request) {
269: if (function_exists('delete_uploaded_files')) {
270: delete_uploaded_files($this);
271: }
272: session_unset();
273: Hm_Functions::session_destroy();
274: $params = session_get_cookie_params();
275: $this->delete_cookie($request, $this->cname, $params['path'], $params['domain']);
276: $this->delete_cookie($request, 'hm_id');
277: $this->delete_cookie($request, 'hm_reload_folders');
278: $this->delete_cookie($request, 'hm_msgs');
279: $this->active = false;
280: }
281:
282: /**
283: * End a session after a page request is complete. This only closes the session and
284: * does not destroy it
285: * @return void
286: */
287: public function end() {
288: if ($this->active) {
289: if (!$this->session_closed) {
290: $this->save_data();
291: }
292: $this->active = false;
293: }
294: }
295: }
296: