diff options
Diffstat (limited to 'application')
-rw-r--r-- | application/ApplicationUtils.php | 3 | ||||
-rw-r--r-- | application/config/ConfigManager.php | 77 | ||||
-rw-r--r-- | application/security/LoginManager.php | 42 | ||||
-rw-r--r-- | application/security/SessionManager.php | 4 |
4 files changed, 104 insertions, 22 deletions
diff --git a/application/ApplicationUtils.php b/application/ApplicationUtils.php index 911873a0..f21a1ef3 100644 --- a/application/ApplicationUtils.php +++ b/application/ApplicationUtils.php | |||
@@ -191,6 +191,9 @@ class ApplicationUtils | |||
191 | $conf->get('resource.page_cache'), | 191 | $conf->get('resource.page_cache'), |
192 | $conf->get('resource.raintpl_tmp'), | 192 | $conf->get('resource.raintpl_tmp'), |
193 | ) as $path) { | 193 | ) as $path) { |
194 | if (! is_dir($path)) { | ||
195 | mkdir($path, 0755, true); | ||
196 | } | ||
194 | if (! is_readable(realpath($path))) { | 197 | if (! is_readable(realpath($path))) { |
195 | $errors[] = '"'.$path.'" '. t('directory is not readable'); | 198 | $errors[] = '"'.$path.'" '. t('directory is not readable'); |
196 | } | 199 | } |
diff --git a/application/config/ConfigManager.php b/application/config/ConfigManager.php index 32aaea48..99efc156 100644 --- a/application/config/ConfigManager.php +++ b/application/config/ConfigManager.php | |||
@@ -22,6 +22,11 @@ class ConfigManager | |||
22 | public static $DEFAULT_PLUGINS = array('qrcode'); | 22 | public static $DEFAULT_PLUGINS = array('qrcode'); |
23 | 23 | ||
24 | /** | 24 | /** |
25 | * @var string User space. | ||
26 | */ | ||
27 | protected $userSpace; | ||
28 | |||
29 | /** | ||
25 | * @var string Config folder. | 30 | * @var string Config folder. |
26 | */ | 31 | */ |
27 | protected $configFile; | 32 | protected $configFile; |
@@ -41,12 +46,36 @@ class ConfigManager | |||
41 | * | 46 | * |
42 | * @param string $configFile Configuration file path without extension. | 47 | * @param string $configFile Configuration file path without extension. |
43 | */ | 48 | */ |
44 | public function __construct($configFile = 'data/config') | 49 | public function __construct($configFile = null, $userSpace = null) |
45 | { | 50 | { |
46 | $this->configFile = $configFile; | 51 | $this->userSpace = $this->findLDAPUser($userSpace); |
52 | if ($configFile !== null) { | ||
53 | $this->configFile = $configFile; | ||
54 | } else { | ||
55 | $this->configFile = ($this->userSpace === null) ? 'data/config' : 'data/' . $this->userSpace . '/config'; | ||
56 | } | ||
47 | $this->initialize(); | 57 | $this->initialize(); |
48 | } | 58 | } |
49 | 59 | ||
60 | public function findLDAPUser($login, $password = null) { | ||
61 | $connect = ldap_connect(getenv('SHAARLI_LDAP_HOST')); | ||
62 | ldap_set_option($connect, LDAP_OPT_PROTOCOL_VERSION, 3); | ||
63 | if (!$connect || !ldap_bind($connect, getenv('SHAARLI_LDAP_DN'), getenv('SHAARLI_LDAP_PASSWORD'))) { | ||
64 | return false; | ||
65 | } | ||
66 | |||
67 | $search_query = str_replace('%login%', ldap_escape($login), getenv('SHAARLI_LDAP_FILTER')); | ||
68 | |||
69 | $search = ldap_search($connect, getenv('SHAARLI_LDAP_BASE'), $search_query); | ||
70 | $info = ldap_get_entries($connect, $search); | ||
71 | |||
72 | if (ldap_count_entries($connect, $search) == 1 && (is_null($password) || ldap_bind($connect, $info[0]["dn"], $password))) { | ||
73 | return $login; | ||
74 | } else { | ||
75 | return null; | ||
76 | } | ||
77 | } | ||
78 | |||
50 | /** | 79 | /** |
51 | * Reset the ConfigManager instance. | 80 | * Reset the ConfigManager instance. |
52 | */ | 81 | */ |
@@ -270,6 +299,16 @@ class ConfigManager | |||
270 | } | 299 | } |
271 | 300 | ||
272 | /** | 301 | /** |
302 | * Get the current userspace. | ||
303 | * | ||
304 | * @return mixed User space. | ||
305 | */ | ||
306 | public function getUserSpace() | ||
307 | { | ||
308 | return $this->userSpace; | ||
309 | } | ||
310 | |||
311 | /** | ||
273 | * Recursive function which find asked setting in the loaded config. | 312 | * Recursive function which find asked setting in the loaded config. |
274 | * | 313 | * |
275 | * @param array $settings Ordered array which contains keys to find. | 314 | * @param array $settings Ordered array which contains keys to find. |
@@ -342,19 +381,31 @@ class ConfigManager | |||
342 | */ | 381 | */ |
343 | protected function setDefaultValues() | 382 | protected function setDefaultValues() |
344 | { | 383 | { |
345 | $this->setEmpty('resource.data_dir', 'data'); | 384 | if ($this->userSpace === null) { |
346 | $this->setEmpty('resource.config', 'data/config.php'); | 385 | $data = 'data'; |
347 | $this->setEmpty('resource.datastore', 'data/datastore.php'); | 386 | $tmp = 'tmp'; |
348 | $this->setEmpty('resource.ban_file', 'data/ipbans.php'); | 387 | $cache = 'cache'; |
349 | $this->setEmpty('resource.updates', 'data/updates.txt'); | 388 | $pagecache = 'pagecache'; |
350 | $this->setEmpty('resource.log', 'data/log.txt'); | 389 | } else { |
351 | $this->setEmpty('resource.update_check', 'data/lastupdatecheck.txt'); | 390 | $data = 'data/' . ($this->userSpace); |
352 | $this->setEmpty('resource.history', 'data/history.php'); | 391 | $tmp = 'tmp/' . ($this->userSpace); |
392 | $cache = 'cache/' . ($this->userSpace); | ||
393 | $pagecache = 'pagecache/' . ($this->userSpace); | ||
394 | } | ||
395 | |||
396 | $this->setEmpty('resource.data_dir', $data); | ||
397 | $this->setEmpty('resource.config', $data . '/config.php'); | ||
398 | $this->setEmpty('resource.datastore', $data . '/datastore.php'); | ||
399 | $this->setEmpty('resource.ban_file', $data . '/ipbans.php'); | ||
400 | $this->setEmpty('resource.updates', $data . '/updates.txt'); | ||
401 | $this->setEmpty('resource.log', $data . '/log.txt'); | ||
402 | $this->setEmpty('resource.update_check', $data . '/lastupdatecheck.txt'); | ||
403 | $this->setEmpty('resource.history', $data . '/history.php'); | ||
353 | $this->setEmpty('resource.raintpl_tpl', 'tpl/'); | 404 | $this->setEmpty('resource.raintpl_tpl', 'tpl/'); |
354 | $this->setEmpty('resource.theme', 'default'); | 405 | $this->setEmpty('resource.theme', 'default'); |
355 | $this->setEmpty('resource.raintpl_tmp', 'tmp/'); | 406 | $this->setEmpty('resource.raintpl_tmp', $tmp); |
356 | $this->setEmpty('resource.thumbnails_cache', 'cache'); | 407 | $this->setEmpty('resource.thumbnails_cache', $cache); |
357 | $this->setEmpty('resource.page_cache', 'pagecache'); | 408 | $this->setEmpty('resource.page_cache', $pagecache); |
358 | 409 | ||
359 | $this->setEmpty('security.ban_after', 4); | 410 | $this->setEmpty('security.ban_after', 4); |
360 | $this->setEmpty('security.ban_duration', 1800); | 411 | $this->setEmpty('security.ban_duration', 1800); |
diff --git a/application/security/LoginManager.php b/application/security/LoginManager.php index d6784d6d..bdfaca7b 100644 --- a/application/security/LoginManager.php +++ b/application/security/LoginManager.php | |||
@@ -32,6 +32,9 @@ class LoginManager | |||
32 | /** @var string User sign-in token depending on remote IP and credentials */ | 32 | /** @var string User sign-in token depending on remote IP and credentials */ |
33 | protected $staySignedInToken = ''; | 33 | protected $staySignedInToken = ''; |
34 | 34 | ||
35 | protected $lastErrorReason = ''; | ||
36 | protected $lastErrorIsBanishable = false; | ||
37 | |||
35 | /** | 38 | /** |
36 | * Constructor | 39 | * Constructor |
37 | * | 40 | * |
@@ -83,7 +86,7 @@ class LoginManager | |||
83 | */ | 86 | */ |
84 | public function checkLoginState($cookie, $clientIpId) | 87 | public function checkLoginState($cookie, $clientIpId) |
85 | { | 88 | { |
86 | if (! $this->configManager->exists('credentials.login')) { | 89 | if (! $this->configManager->exists('credentials.login') || (isset($_SESSION['username']) && $_SESSION['username'] && $this->configManager->get('credentials.login') !== $_SESSION['username'])) { |
87 | // Shaarli is not configured yet | 90 | // Shaarli is not configured yet |
88 | $this->isLoggedIn = false; | 91 | $this->isLoggedIn = false; |
89 | return; | 92 | return; |
@@ -133,20 +136,40 @@ class LoginManager | |||
133 | */ | 136 | */ |
134 | public function checkCredentials($remoteIp, $clientIpId, $login, $password) | 137 | public function checkCredentials($remoteIp, $clientIpId, $login, $password) |
135 | { | 138 | { |
136 | $hash = sha1($password . $login . $this->configManager->get('credentials.salt')); | 139 | $this->lastErrorIsBanishable = false; |
140 | |||
141 | if ($this->configManager->getUserSpace() !== null && $this->configManager->getUserSpace() !== $login) { | ||
142 | logm($this->configManager->get('resource.log'), | ||
143 | $remoteIp, | ||
144 | 'Trying to login to wrong user space'); | ||
145 | $this->lastErrorReason = 'You’re trying to access the wrong account.'; | ||
146 | return false; | ||
147 | } | ||
137 | 148 | ||
138 | if ($login != $this->configManager->get('credentials.login') | 149 | logm($this->configManager->get('resource.log'), |
139 | || $hash != $this->configManager->get('credentials.hash') | 150 | $remoteIp, |
140 | ) { | 151 | 'Trying LDAP connection'); |
152 | $result = $this->configManager->findLDAPUser($login, $password); | ||
153 | if ($result === false) { | ||
141 | logm( | 154 | logm( |
142 | $this->configManager->get('resource.log'), | 155 | $this->configManager->get('resource.log'), |
143 | $remoteIp, | 156 | $remoteIp, |
144 | 'Login failed for user ' . $login | 157 | 'Impossible to connect to LDAP' |
145 | ); | 158 | ); |
159 | $this->lastErrorReason = 'Server error.'; | ||
160 | return false; | ||
161 | } else if (is_null($result)) { | ||
162 | logm( | ||
163 | $this->configManager->get('resource.log'), | ||
164 | $remoteIp, | ||
165 | 'Login failed for user ' . $login | ||
166 | ); | ||
167 | $this->lastErrorIsBanishable = true; | ||
168 | $this->lastErrorReason = 'Wrong login/password.'; | ||
146 | return false; | 169 | return false; |
147 | } | 170 | } |
148 | 171 | ||
149 | $this->sessionManager->storeLoginInfo($clientIpId); | 172 | $this->sessionManager->storeLoginInfo($clientIpId, $login); |
150 | logm( | 173 | logm( |
151 | $this->configManager->get('resource.log'), | 174 | $this->configManager->get('resource.log'), |
152 | $remoteIp, | 175 | $remoteIp, |
@@ -187,6 +210,10 @@ class LoginManager | |||
187 | */ | 210 | */ |
188 | public function handleFailedLogin($server) | 211 | public function handleFailedLogin($server) |
189 | { | 212 | { |
213 | if (!$this->lastErrorIsBanishable) { | ||
214 | return $this->lastErrorReason ?: 'Error during login.'; | ||
215 | }; | ||
216 | |||
190 | $ip = $server['REMOTE_ADDR']; | 217 | $ip = $server['REMOTE_ADDR']; |
191 | $trusted = $this->configManager->get('security.trusted_proxies', []); | 218 | $trusted = $this->configManager->get('security.trusted_proxies', []); |
192 | 219 | ||
@@ -215,6 +242,7 @@ class LoginManager | |||
215 | ); | 242 | ); |
216 | } | 243 | } |
217 | $this->writeBanFile(); | 244 | $this->writeBanFile(); |
245 | return $this->lastErrorReason ?: 'Error during login.'; | ||
218 | } | 246 | } |
219 | 247 | ||
220 | /** | 248 | /** |
diff --git a/application/security/SessionManager.php b/application/security/SessionManager.php index b8b8ab8d..5eb4aac5 100644 --- a/application/security/SessionManager.php +++ b/application/security/SessionManager.php | |||
@@ -111,10 +111,10 @@ class SessionManager | |||
111 | * | 111 | * |
112 | * @param string $clientIpId Client IP address identifier | 112 | * @param string $clientIpId Client IP address identifier |
113 | */ | 113 | */ |
114 | public function storeLoginInfo($clientIpId) | 114 | public function storeLoginInfo($clientIpId, $login = null) |
115 | { | 115 | { |
116 | $this->session['ip'] = $clientIpId; | 116 | $this->session['ip'] = $clientIpId; |
117 | $this->session['username'] = $this->conf->get('credentials.login'); | 117 | $this->session['username'] = $login ?: $this->conf->get('credentials.login'); |
118 | $this->extendTimeValidityBy(self::$SHORT_TIMEOUT); | 118 | $this->extendTimeValidityBy(self::$SHORT_TIMEOUT); |
119 | } | 119 | } |
120 | 120 | ||