]>
Commit | Line | Data |
---|---|---|
ebd650c0 | 1 | <?php |
fab87c26 | 2 | namespace Shaarli\Security; |
ebd650c0 | 3 | |
c7721487 V |
4 | use Shaarli\Config\ConfigManager; |
5 | ||
ebd650c0 V |
6 | /** |
7 | * Manages the server-side session | |
8 | */ | |
9 | class SessionManager | |
10 | { | |
c7721487 | 11 | /** @var int Session expiration timeout, in seconds */ |
51f0128c V |
12 | public static $SHORT_TIMEOUT = 3600; // 1 hour |
13 | ||
14 | /** @var int Session expiration timeout, in seconds */ | |
15 | public static $LONG_TIMEOUT = 31536000; // 1 year | |
db45a36a | 16 | |
c7721487 | 17 | /** @var string Name of the cookie set after logging in **/ |
49f18323 V |
18 | public static $LOGGED_IN_COOKIE = 'shaarli_staySignedIn'; |
19 | ||
c7721487 | 20 | /** @var array Local reference to the global $_SESSION array */ |
ebd650c0 V |
21 | protected $session = []; |
22 | ||
c7721487 | 23 | /** @var ConfigManager Configuration Manager instance **/ |
49f18323 V |
24 | protected $conf = null; |
25 | ||
51f0128c V |
26 | /** @var bool Whether the user should stay signed in (LONG_TIMEOUT) */ |
27 | protected $staySignedIn = false; | |
28 | ||
ebd650c0 V |
29 | /** |
30 | * Constructor | |
31 | * | |
32 | * @param array $session The $_SESSION array (reference) | |
dd883aaf | 33 | * @param ConfigManager $conf ConfigManager instance |
ebd650c0 | 34 | */ |
dd883aaf | 35 | public function __construct(& $session, $conf) |
ebd650c0 V |
36 | { |
37 | $this->session = &$session; | |
dd883aaf | 38 | $this->conf = $conf; |
ebd650c0 V |
39 | } |
40 | ||
51f0128c V |
41 | /** |
42 | * Define whether the user should stay signed in across browser sessions | |
43 | * | |
44 | * @param bool $staySignedIn Keep the user signed in | |
45 | */ | |
46 | public function setStaySignedIn($staySignedIn) | |
47 | { | |
48 | $this->staySignedIn = $staySignedIn; | |
49 | } | |
50 | ||
ebd650c0 V |
51 | /** |
52 | * Generates a session token | |
53 | * | |
54 | * @return string token | |
55 | */ | |
56 | public function generateToken() | |
57 | { | |
58 | $token = sha1(uniqid('', true) .'_'. mt_rand() . $this->conf->get('credentials.salt')); | |
59 | $this->session['tokens'][$token] = 1; | |
60 | return $token; | |
61 | } | |
62 | ||
63 | /** | |
64 | * Checks the validity of a session token, and destroys it afterwards | |
65 | * | |
66 | * @param string $token The token to check | |
67 | * | |
68 | * @return bool true if the token is valid, else false | |
69 | */ | |
70 | public function checkToken($token) | |
71 | { | |
72 | if (! isset($this->session['tokens'][$token])) { | |
73 | // the token is wrong, or has already been used | |
74 | return false; | |
75 | } | |
76 | ||
77 | // destroy the token to prevent future use | |
78 | unset($this->session['tokens'][$token]); | |
79 | return true; | |
80 | } | |
fd7d8461 V |
81 | |
82 | /** | |
83 | * Validate session ID to prevent Full Path Disclosure. | |
84 | * | |
85 | * See #298. | |
86 | * The session ID's format depends on the hash algorithm set in PHP settings | |
87 | * | |
88 | * @param string $sessionId Session ID | |
89 | * | |
90 | * @return true if valid, false otherwise. | |
91 | * | |
92 | * @see http://php.net/manual/en/function.hash-algos.php | |
93 | * @see http://php.net/manual/en/session.configuration.php | |
94 | */ | |
95 | public static function checkId($sessionId) | |
96 | { | |
97 | if (empty($sessionId)) { | |
98 | return false; | |
99 | } | |
100 | ||
101 | if (!$sessionId) { | |
102 | return false; | |
103 | } | |
104 | ||
105 | if (!preg_match('/^[a-zA-Z0-9,-]{2,128}$/', $sessionId)) { | |
106 | return false; | |
107 | } | |
108 | ||
109 | return true; | |
110 | } | |
49f18323 V |
111 | |
112 | /** | |
113 | * Store user login information after a successful login | |
114 | * | |
c7721487 | 115 | * @param string $clientIpId Client IP address identifier |
49f18323 | 116 | */ |
c7721487 | 117 | public function storeLoginInfo($clientIpId) |
49f18323 V |
118 | { |
119 | // Generate unique random number (different than phpsessionid) | |
120 | $this->session['uid'] = sha1(uniqid('', true) . '_' . mt_rand()); | |
c7721487 | 121 | $this->session['ip'] = $clientIpId; |
49f18323 | 122 | $this->session['username'] = $this->conf->get('credentials.login'); |
51f0128c | 123 | $this->extendTimeValidityBy(self::$SHORT_TIMEOUT); |
49f18323 V |
124 | } |
125 | ||
c7721487 V |
126 | /** |
127 | * Extend session validity | |
128 | */ | |
129 | public function extendSession() | |
130 | { | |
51f0128c V |
131 | if ($this->staySignedIn) { |
132 | return $this->extendTimeValidityBy(self::$LONG_TIMEOUT); | |
c7721487 | 133 | } |
51f0128c V |
134 | return $this->extendTimeValidityBy(self::$SHORT_TIMEOUT); |
135 | } | |
136 | ||
137 | /** | |
138 | * Extend expiration time | |
139 | * | |
140 | * @param int $duration Expiration time extension (seconds) | |
141 | * | |
142 | * @return int New session expiration time | |
143 | */ | |
144 | protected function extendTimeValidityBy($duration) | |
145 | { | |
146 | $expirationTime = time() + $duration; | |
147 | $this->session['expires_on'] = $expirationTime; | |
148 | return $expirationTime; | |
c7721487 V |
149 | } |
150 | ||
49f18323 V |
151 | /** |
152 | * Logout a user by unsetting all login information | |
153 | * | |
154 | * See: | |
155 | * - https://secure.php.net/manual/en/function.setcookie.php | |
49f18323 | 156 | */ |
51f0128c | 157 | public function logout() |
49f18323 V |
158 | { |
159 | if (isset($this->session)) { | |
160 | unset($this->session['uid']); | |
161 | unset($this->session['ip']); | |
51f0128c | 162 | unset($this->session['expires_on']); |
49f18323 V |
163 | unset($this->session['username']); |
164 | unset($this->session['visibility']); | |
165 | unset($this->session['untaggedonly']); | |
166 | } | |
49f18323 | 167 | } |
c7721487 V |
168 | |
169 | /** | |
170 | * Check whether the session has expired | |
171 | * | |
172 | * @param string $clientIpId Client IP address identifier | |
173 | * | |
174 | * @return bool true if the session has expired, false otherwise | |
175 | */ | |
176 | public function hasSessionExpired() | |
177 | { | |
178 | if (empty($this->session['uid'])) { | |
179 | return true; | |
180 | } | |
181 | if (time() >= $this->session['expires_on']) { | |
182 | return true; | |
183 | } | |
184 | return false; | |
185 | } | |
186 | ||
187 | /** | |
188 | * Check whether the client IP address has changed | |
189 | * | |
190 | * @param string $clientIpId Client IP address identifier | |
191 | * | |
192 | * @return bool true if the IP has changed, false if it has not, or | |
193 | * if session protection has been disabled | |
194 | */ | |
195 | public function hasClientIpChanged($clientIpId) | |
196 | { | |
197 | if ($this->conf->get('security.session_protection_disabled') === true) { | |
198 | return false; | |
199 | } | |
200 | if ($this->session['ip'] == $clientIpId) { | |
201 | return false; | |
202 | } | |
203 | return true; | |
204 | } | |
ebd650c0 | 205 | } |