summaryrefslogtreecommitdiffstats
path: root/lib/SimpleSAML/SessionHandlerPHP.php
blob: afb62a6331f330eb77264617225de9e6b6823fe8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
<?php

/**
 * This file is part of SimpleSAMLphp. See the file COPYING in the
 * root of the distribution for licence information.
 *
 * This file defines a session handler which uses the default php
 * session handler for storage.
 *
 * @author Olav Morken, UNINETT AS. <andreas.solberg@uninett.no>
 * @package simpleSAMLphp
 */
class SimpleSAML_SessionHandlerPHP extends SimpleSAML_SessionHandler {

	/* This variable contains the session cookie name. */
	protected $cookie_name;


	/* Initialize the PHP session handling. This constructor is protected
	 * because it should only be called from
	 * SimpleSAML_SessionHandler::createSessionHandler(...).
	 */
	protected function __construct() {

		/* Call the parent constructor in case it should become
		 * necessary in the future.
		 */
		parent::__construct();

		/* Initialize the php session handling.
		 *
		 * If session_id() returns a blank string, then we need
		 * to call session start. Otherwise the session is already
		 * started, and we should avoid calling session_start().
		 */
		if(session_id() === '') {
			$config = SimpleSAML_Configuration::getInstance();

			$params = $this->getCookieParams();

			$version = explode('.', PHP_VERSION);
			if ((int)$version[0] === 5 && (int)$version[1] < 2) {
				session_set_cookie_params($params['lifetime'], $params['path'], $params['domain'], $params['secure']);
			} else {
				session_set_cookie_params($params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly']);
			}

			$this->cookie_name = $config->getString('session.phpsession.cookiename', NULL);
			if (!empty($this->cookie_name)) {
				session_name($this->cookie_name);
			} else {
				$this->cookie_name = session_name();
			}

			$savepath = $config->getString('session.phpsession.savepath', NULL);
			if(!empty($savepath)) {
				session_save_path($savepath);
			}
		}
	}


	/**
	 * Create and set new session id.
	 *
	 * @return string  The new session id.
	 */
	public function newSessionId() {
		$session_cookie_params = session_get_cookie_params();

		if ($session_cookie_params['secure'] && !SimpleSAML_Utilities::isHTTPS()) {
			throw new SimpleSAML_Error_Exception('Session start with secure cookie not allowed on http.');
		}

		if (headers_sent()) {
			throw new SimpleSAML_Error_Exception('Cannot create new session - headers already sent.');
		}

		/* Generate new (secure) session id. */
		$sessionId = SimpleSAML_Utilities::stringToHex(SimpleSAML_Utilities::generateRandomBytes(16));
		SimpleSAML_Session::createSession($sessionId);

		if (session_id() !== '') {
			/* Session already started, close it. */
			session_write_close();
		}

		session_id($sessionId);
		session_start();

		return session_id();
	}


	/**
	 * Retrieve the session id of saved in the session cookie.
	 *
	 * @return string  The session id saved in the cookie.
	 */
	public function getCookieSessionId() {
		if(session_id() === '') {
			if(!self::hasSessionCookie()) {
				return self::newSessionId();
			}

			$session_cookie_params = session_get_cookie_params();

			if ($session_cookie_params['secure'] && !SimpleSAML_Utilities::isHTTPS()) {
				throw new SimpleSAML_Error_Exception('Session start with secure cookie not allowed on http.');
			}

			session_start();
		}

		return session_id();
	}


	/**
	 * Retrieve the session cookie name.
	 *
	 * @return string  The session cookie name.
	 */
	public function getSessionCookieName() {

		return $this->cookie_name;
	}


	/**
	 * Save the current session to the PHP session array.
	 *
	 * @param SimpleSAML_Session $session  The session object we should save.
	 */
	public function saveSession(SimpleSAML_Session $session) {

		$_SESSION['SimpleSAMLphp_SESSION'] = serialize($session);
	}


	/**
	 * Load the session from the PHP session array.
	 *
	 * @param string|NULL $sessionId  The ID of the session we should load, or NULL to use the default.
	 * @return SimpleSAML_Session|NULL  The session object, or NULL if it doesn't exist.
	 */
	public function loadSession($sessionId = NULL) {
		assert('is_string($sessionId) || is_null($sessionId)');

		if ($sessionId !== NULL) {
			if (session_id() === '') {
				/* session not initiated with getCookieSessionId(), start session without setting cookie */
				$ret = ini_set('session.use_cookies', '0');
				if ($ret === FALSE) {
					throw new SimpleSAML_Error_Exception('Disabling PHP option session.use_cookies failed.');
				}

				session_id($sessionId);
				session_start();
			} elseif ($sessionId !== session_id()) {
				throw new SimpleSAML_Error_Exception('Cannot load PHP session with a specific ID.');
			}
		} elseif (session_id() === '') {
			$sessionId = self::getCookieSessionId();
		}

		if (!isset($_SESSION['SimpleSAMLphp_SESSION'])) {
			return NULL;
		}

		$session = $_SESSION['SimpleSAMLphp_SESSION'];
		assert('is_string($session)');

		$session = unserialize($session);
		assert('$session instanceof SimpleSAML_Session');

		return $session;
	}


	/**
	 * Check whether the session cookie is set.
	 *
	 * This function will only return FALSE if is is certain that the cookie isn't set.
	 *
	 * @return bool  TRUE if it was set, FALSE if not.
	 */
	public function hasSessionCookie() {

		return array_key_exists($this->cookie_name, $_COOKIE);
	}


	/**
	 * Get the cookie parameters that should be used for session cookies.
	 *
	 * This function contains some adjustments from the default to provide backwards-compatibility.
	 *
	 * @return array
	 * @link http://www.php.net/manual/en/function.session-get-cookie-params.php
	 */
	public function getCookieParams() {

		$config = SimpleSAML_Configuration::getInstance();

		$ret = parent::getCookieParams();

		if ($config->hasValue('session.phpsession.limitedpath') && $config->hasValue('session.cookie.path')) {
			throw new SimpleSAML_Error_Exception('You cannot set both the session.phpsession.limitedpath and session.cookie.path options.');
		} elseif ($config->hasValue('session.phpsession.limitedpath')) {
			$ret['path'] = $config->getBoolean('session.phpsession.limitedpath', FALSE) ? '/' . $config->getBaseURL() : '/';
		}

		$ret['httponly'] = $config->getBoolean('session.phpsession.httponly', FALSE);

		return $ret;
	}

}