diff options
-rw-r--r-- | application/LoginManager.php | 27 | ||||
-rw-r--r-- | application/SessionManager.php | 66 |
2 files changed, 69 insertions, 24 deletions
diff --git a/application/LoginManager.php b/application/LoginManager.php index d81c6c05..347fb3b9 100644 --- a/application/LoginManager.php +++ b/application/LoginManager.php | |||
@@ -1,6 +1,8 @@ | |||
1 | <?php | 1 | <?php |
2 | namespace Shaarli; | 2 | namespace Shaarli; |
3 | 3 | ||
4 | use Shaarli\Config\ConfigManager; | ||
5 | |||
4 | /** | 6 | /** |
5 | * User login management | 7 | * User login management |
6 | */ | 8 | */ |
@@ -62,34 +64,24 @@ class LoginManager | |||
62 | return; | 64 | return; |
63 | } | 65 | } |
64 | 66 | ||
67 | $clientIpId = client_ip_id($server); | ||
68 | |||
65 | if (isset($cookie[SessionManager::$LOGGED_IN_COOKIE]) | 69 | if (isset($cookie[SessionManager::$LOGGED_IN_COOKIE]) |
66 | && $cookie[SessionManager::$LOGGED_IN_COOKIE] === $token | 70 | && $cookie[SessionManager::$LOGGED_IN_COOKIE] === $token |
67 | ) { | 71 | ) { |
68 | $this->sessionManager->storeLoginInfo($server); | 72 | $this->sessionManager->storeLoginInfo($clientIpId); |
69 | $this->isLoggedIn = true; | 73 | $this->isLoggedIn = true; |
70 | } | 74 | } |
71 | 75 | ||
72 | // Logout when: | 76 | if ($this->sessionManager->hasSessionExpired() |
73 | // - the session does not exist on the server side | 77 | || $this->sessionManager->hasClientIpChanged($clientIpId) |
74 | // - the session has expired | ||
75 | // - the client IP address has changed | ||
76 | if (empty($session['uid']) | ||
77 | || ($this->configManager->get('security.session_protection_disabled') === false | ||
78 | && $session['ip'] != client_ip_id($server)) | ||
79 | || time() >= $session['expires_on'] | ||
80 | ) { | 78 | ) { |
81 | $this->sessionManager->logout($webPath); | 79 | $this->sessionManager->logout($webPath); |
82 | $this->isLoggedIn = false; | 80 | $this->isLoggedIn = false; |
83 | return; | 81 | return; |
84 | } | 82 | } |
85 | 83 | ||
86 | // Extend session validity | 84 | $this->sessionManager->extendSession(); |
87 | if (! empty($session['longlastingsession'])) { | ||
88 | // "Stay signed in" is enabled | ||
89 | $session['expires_on'] = time() + $session['longlastingsession']; | ||
90 | } else { | ||
91 | $session['expires_on'] = time() + SessionManager::$INACTIVITY_TIMEOUT; | ||
92 | } | ||
93 | } | 85 | } |
94 | 86 | ||
95 | /** | 87 | /** |
@@ -129,7 +121,8 @@ class LoginManager | |||
129 | return false; | 121 | return false; |
130 | } | 122 | } |
131 | 123 | ||
132 | $this->sessionManager->storeLoginInfo($server); | 124 | $clientIpId = client_ip_id($server); |
125 | $this->sessionManager->storeLoginInfo($clientIpId); | ||
133 | logm( | 126 | logm( |
134 | $this->configManager->get('resource.log'), | 127 | $this->configManager->get('resource.log'), |
135 | $server['REMOTE_ADDR'], | 128 | $server['REMOTE_ADDR'], |
diff --git a/application/SessionManager.php b/application/SessionManager.php index 7bfd2220..63eeb8aa 100644 --- a/application/SessionManager.php +++ b/application/SessionManager.php | |||
@@ -1,21 +1,23 @@ | |||
1 | <?php | 1 | <?php |
2 | namespace Shaarli; | 2 | namespace Shaarli; |
3 | 3 | ||
4 | use Shaarli\Config\ConfigManager; | ||
5 | |||
4 | /** | 6 | /** |
5 | * Manages the server-side session | 7 | * Manages the server-side session |
6 | */ | 8 | */ |
7 | class SessionManager | 9 | class SessionManager |
8 | { | 10 | { |
9 | /** Session expiration timeout, in seconds */ | 11 | /** @var int Session expiration timeout, in seconds */ |
10 | public static $INACTIVITY_TIMEOUT = 3600; | 12 | public static $INACTIVITY_TIMEOUT = 3600; |
11 | 13 | ||
12 | /** Name of the cookie set after logging in **/ | 14 | /** @var string Name of the cookie set after logging in **/ |
13 | public static $LOGGED_IN_COOKIE = 'shaarli_staySignedIn'; | 15 | public static $LOGGED_IN_COOKIE = 'shaarli_staySignedIn'; |
14 | 16 | ||
15 | /** Local reference to the global $_SESSION array */ | 17 | /** @var array Local reference to the global $_SESSION array */ |
16 | protected $session = []; | 18 | protected $session = []; |
17 | 19 | ||
18 | /** ConfigManager instance **/ | 20 | /** @var ConfigManager Configuration Manager instance **/ |
19 | protected $conf = null; | 21 | protected $conf = null; |
20 | 22 | ||
21 | /** | 23 | /** |
@@ -94,18 +96,31 @@ class SessionManager | |||
94 | /** | 96 | /** |
95 | * Store user login information after a successful login | 97 | * Store user login information after a successful login |
96 | * | 98 | * |
97 | * @param array $server The global $_SERVER array | 99 | * @param string $clientIpId Client IP address identifier |
98 | */ | 100 | */ |
99 | public function storeLoginInfo($server) | 101 | public function storeLoginInfo($clientIpId) |
100 | { | 102 | { |
101 | // Generate unique random number (different than phpsessionid) | 103 | // Generate unique random number (different than phpsessionid) |
102 | $this->session['uid'] = sha1(uniqid('', true) . '_' . mt_rand()); | 104 | $this->session['uid'] = sha1(uniqid('', true) . '_' . mt_rand()); |
103 | $this->session['ip'] = client_ip_id($server); | 105 | $this->session['ip'] = $clientIpId; |
104 | $this->session['username'] = $this->conf->get('credentials.login'); | 106 | $this->session['username'] = $this->conf->get('credentials.login'); |
105 | $this->session['expires_on'] = time() + self::$INACTIVITY_TIMEOUT; | 107 | $this->session['expires_on'] = time() + self::$INACTIVITY_TIMEOUT; |
106 | } | 108 | } |
107 | 109 | ||
108 | /** | 110 | /** |
111 | * Extend session validity | ||
112 | */ | ||
113 | public function extendSession() | ||
114 | { | ||
115 | if (! empty($this->session['longlastingsession'])) { | ||
116 | // "Stay signed in" is enabled | ||
117 | $this->session['expires_on'] = time() + $this->session['longlastingsession']; | ||
118 | return; | ||
119 | } | ||
120 | $this->session['expires_on'] = time() + self::$INACTIVITY_TIMEOUT; | ||
121 | } | ||
122 | |||
123 | /** | ||
109 | * Logout a user by unsetting all login information | 124 | * Logout a user by unsetting all login information |
110 | * | 125 | * |
111 | * See: | 126 | * See: |
@@ -124,4 +139,41 @@ class SessionManager | |||
124 | } | 139 | } |
125 | setcookie(self::$LOGGED_IN_COOKIE, 'false', 0, $webPath); | 140 | setcookie(self::$LOGGED_IN_COOKIE, 'false', 0, $webPath); |
126 | } | 141 | } |
142 | |||
143 | /** | ||
144 | * Check whether the session has expired | ||
145 | * | ||
146 | * @param string $clientIpId Client IP address identifier | ||
147 | * | ||
148 | * @return bool true if the session has expired, false otherwise | ||
149 | */ | ||
150 | public function hasSessionExpired() | ||
151 | { | ||
152 | if (empty($this->session['uid'])) { | ||
153 | return true; | ||
154 | } | ||
155 | if (time() >= $this->session['expires_on']) { | ||
156 | return true; | ||
157 | } | ||
158 | return false; | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * Check whether the client IP address has changed | ||
163 | * | ||
164 | * @param string $clientIpId Client IP address identifier | ||
165 | * | ||
166 | * @return bool true if the IP has changed, false if it has not, or | ||
167 | * if session protection has been disabled | ||
168 | */ | ||
169 | public function hasClientIpChanged($clientIpId) | ||
170 | { | ||
171 | if ($this->conf->get('security.session_protection_disabled') === true) { | ||
172 | return false; | ||
173 | } | ||
174 | if ($this->session['ip'] == $clientIpId) { | ||
175 | return false; | ||
176 | } | ||
177 | return true; | ||
178 | } | ||
127 | } | 179 | } |