Completed
Push — master ( 627023...930aad )
by Morris
15:19
created
core/Controller/LoginController.php 2 patches
Indentation   +269 added lines, -269 removed lines patch added patch discarded remove patch
@@ -57,301 +57,301 @@
 block discarded – undo
57 57
 use OCP\Util;
58 58
 
59 59
 class LoginController extends Controller {
60
-	/** @var IUserManager */
61
-	private $userManager;
62
-	/** @var IConfig */
63
-	private $config;
64
-	/** @var ISession */
65
-	private $session;
66
-	/** @var IUserSession|Session */
67
-	private $userSession;
68
-	/** @var IURLGenerator */
69
-	private $urlGenerator;
70
-	/** @var ILogger */
71
-	private $logger;
72
-	/** @var Manager */
73
-	private $twoFactorManager;
74
-	/** @var Defaults */
75
-	private $defaults;
76
-	/** @var Throttler */
77
-	private $throttler;
60
+    /** @var IUserManager */
61
+    private $userManager;
62
+    /** @var IConfig */
63
+    private $config;
64
+    /** @var ISession */
65
+    private $session;
66
+    /** @var IUserSession|Session */
67
+    private $userSession;
68
+    /** @var IURLGenerator */
69
+    private $urlGenerator;
70
+    /** @var ILogger */
71
+    private $logger;
72
+    /** @var Manager */
73
+    private $twoFactorManager;
74
+    /** @var Defaults */
75
+    private $defaults;
76
+    /** @var Throttler */
77
+    private $throttler;
78 78
 
79
-	/**
80
-	 * @param string $appName
81
-	 * @param IRequest $request
82
-	 * @param IUserManager $userManager
83
-	 * @param IConfig $config
84
-	 * @param ISession $session
85
-	 * @param IUserSession $userSession
86
-	 * @param IURLGenerator $urlGenerator
87
-	 * @param ILogger $logger
88
-	 * @param Manager $twoFactorManager
89
-	 * @param Defaults $defaults
90
-	 * @param Throttler $throttler
91
-	 */
92
-	public function __construct($appName,
93
-								IRequest $request,
94
-								IUserManager $userManager,
95
-								IConfig $config,
96
-								ISession $session,
97
-								IUserSession $userSession,
98
-								IURLGenerator $urlGenerator,
99
-								ILogger $logger,
100
-								Manager $twoFactorManager,
101
-								Defaults $defaults,
102
-								Throttler $throttler) {
103
-		parent::__construct($appName, $request);
104
-		$this->userManager = $userManager;
105
-		$this->config = $config;
106
-		$this->session = $session;
107
-		$this->userSession = $userSession;
108
-		$this->urlGenerator = $urlGenerator;
109
-		$this->logger = $logger;
110
-		$this->twoFactorManager = $twoFactorManager;
111
-		$this->defaults = $defaults;
112
-		$this->throttler = $throttler;
113
-	}
79
+    /**
80
+     * @param string $appName
81
+     * @param IRequest $request
82
+     * @param IUserManager $userManager
83
+     * @param IConfig $config
84
+     * @param ISession $session
85
+     * @param IUserSession $userSession
86
+     * @param IURLGenerator $urlGenerator
87
+     * @param ILogger $logger
88
+     * @param Manager $twoFactorManager
89
+     * @param Defaults $defaults
90
+     * @param Throttler $throttler
91
+     */
92
+    public function __construct($appName,
93
+                                IRequest $request,
94
+                                IUserManager $userManager,
95
+                                IConfig $config,
96
+                                ISession $session,
97
+                                IUserSession $userSession,
98
+                                IURLGenerator $urlGenerator,
99
+                                ILogger $logger,
100
+                                Manager $twoFactorManager,
101
+                                Defaults $defaults,
102
+                                Throttler $throttler) {
103
+        parent::__construct($appName, $request);
104
+        $this->userManager = $userManager;
105
+        $this->config = $config;
106
+        $this->session = $session;
107
+        $this->userSession = $userSession;
108
+        $this->urlGenerator = $urlGenerator;
109
+        $this->logger = $logger;
110
+        $this->twoFactorManager = $twoFactorManager;
111
+        $this->defaults = $defaults;
112
+        $this->throttler = $throttler;
113
+    }
114 114
 
115
-	/**
116
-	 * @NoAdminRequired
117
-	 * @UseSession
118
-	 *
119
-	 * @return RedirectResponse
120
-	 */
121
-	public function logout() {
122
-		$loginToken = $this->request->getCookie('nc_token');
123
-		if (!is_null($loginToken)) {
124
-			$this->config->deleteUserValue($this->userSession->getUser()->getUID(), 'login_token', $loginToken);
125
-		}
126
-		$this->userSession->logout();
115
+    /**
116
+     * @NoAdminRequired
117
+     * @UseSession
118
+     *
119
+     * @return RedirectResponse
120
+     */
121
+    public function logout() {
122
+        $loginToken = $this->request->getCookie('nc_token');
123
+        if (!is_null($loginToken)) {
124
+            $this->config->deleteUserValue($this->userSession->getUser()->getUID(), 'login_token', $loginToken);
125
+        }
126
+        $this->userSession->logout();
127 127
 
128
-		$response = new RedirectResponse($this->urlGenerator->linkToRouteAbsolute('core.login.showLoginForm'));
129
-		$response->addHeader('Clear-Site-Data', '"cache", "cookies", "storage", "executionContexts"');
130
-		return $response;
131
-	}
128
+        $response = new RedirectResponse($this->urlGenerator->linkToRouteAbsolute('core.login.showLoginForm'));
129
+        $response->addHeader('Clear-Site-Data', '"cache", "cookies", "storage", "executionContexts"');
130
+        return $response;
131
+    }
132 132
 
133
-	/**
134
-	 * @PublicPage
135
-	 * @NoCSRFRequired
136
-	 * @UseSession
137
-	 *
138
-	 * @param string $user
139
-	 * @param string $redirect_url
140
-	 * @param string $remember_login
141
-	 *
142
-	 * @return TemplateResponse|RedirectResponse
143
-	 */
144
-	public function showLoginForm($user, $redirect_url, $remember_login) {
145
-		if ($this->userSession->isLoggedIn()) {
146
-			return new RedirectResponse(OC_Util::getDefaultPageUrl());
147
-		}
133
+    /**
134
+     * @PublicPage
135
+     * @NoCSRFRequired
136
+     * @UseSession
137
+     *
138
+     * @param string $user
139
+     * @param string $redirect_url
140
+     * @param string $remember_login
141
+     *
142
+     * @return TemplateResponse|RedirectResponse
143
+     */
144
+    public function showLoginForm($user, $redirect_url, $remember_login) {
145
+        if ($this->userSession->isLoggedIn()) {
146
+            return new RedirectResponse(OC_Util::getDefaultPageUrl());
147
+        }
148 148
 
149
-		$parameters = array();
150
-		$loginMessages = $this->session->get('loginMessages');
151
-		$errors = [];
152
-		$messages = [];
153
-		if (is_array($loginMessages)) {
154
-			list($errors, $messages) = $loginMessages;
155
-		}
156
-		$this->session->remove('loginMessages');
157
-		foreach ($errors as $value) {
158
-			$parameters[$value] = true;
159
-		}
149
+        $parameters = array();
150
+        $loginMessages = $this->session->get('loginMessages');
151
+        $errors = [];
152
+        $messages = [];
153
+        if (is_array($loginMessages)) {
154
+            list($errors, $messages) = $loginMessages;
155
+        }
156
+        $this->session->remove('loginMessages');
157
+        foreach ($errors as $value) {
158
+            $parameters[$value] = true;
159
+        }
160 160
 
161
-		$parameters['messages'] = $messages;
162
-		if ($user !== null && $user !== '') {
163
-			$parameters['loginName'] = $user;
164
-			$parameters['user_autofocus'] = false;
165
-		} else {
166
-			$parameters['loginName'] = '';
167
-			$parameters['user_autofocus'] = true;
168
-		}
169
-		if (!empty($redirect_url)) {
170
-			$parameters['redirect_url'] = $redirect_url;
171
-		}
161
+        $parameters['messages'] = $messages;
162
+        if ($user !== null && $user !== '') {
163
+            $parameters['loginName'] = $user;
164
+            $parameters['user_autofocus'] = false;
165
+        } else {
166
+            $parameters['loginName'] = '';
167
+            $parameters['user_autofocus'] = true;
168
+        }
169
+        if (!empty($redirect_url)) {
170
+            $parameters['redirect_url'] = $redirect_url;
171
+        }
172 172
 
173
-		$parameters['canResetPassword'] = true;
174
-		$parameters['resetPasswordLink'] = $this->config->getSystemValue('lost_password_link', '');
175
-		if (!$parameters['resetPasswordLink']) {
176
-			if ($user !== null && $user !== '') {
177
-				$userObj = $this->userManager->get($user);
178
-				if ($userObj instanceof IUser) {
179
-					$parameters['canResetPassword'] = $userObj->canChangePassword();
180
-				}
181
-			}
182
-		} elseif ($parameters['resetPasswordLink'] === 'disabled') {
183
-			$parameters['canResetPassword'] = false;
184
-		}
173
+        $parameters['canResetPassword'] = true;
174
+        $parameters['resetPasswordLink'] = $this->config->getSystemValue('lost_password_link', '');
175
+        if (!$parameters['resetPasswordLink']) {
176
+            if ($user !== null && $user !== '') {
177
+                $userObj = $this->userManager->get($user);
178
+                if ($userObj instanceof IUser) {
179
+                    $parameters['canResetPassword'] = $userObj->canChangePassword();
180
+                }
181
+            }
182
+        } elseif ($parameters['resetPasswordLink'] === 'disabled') {
183
+            $parameters['canResetPassword'] = false;
184
+        }
185 185
 
186
-		$parameters['alt_login'] = OC_App::getAlternativeLogIns();
187
-		$parameters['rememberLoginState'] = !empty($remember_login) ? $remember_login : 0;
188
-		$parameters['hideRemeberLoginState'] = !empty($redirect_url) && $this->session->exists('client.flow.state.token');
186
+        $parameters['alt_login'] = OC_App::getAlternativeLogIns();
187
+        $parameters['rememberLoginState'] = !empty($remember_login) ? $remember_login : 0;
188
+        $parameters['hideRemeberLoginState'] = !empty($redirect_url) && $this->session->exists('client.flow.state.token');
189 189
 
190
-		if ($user !== null && $user !== '') {
191
-			$parameters['loginName'] = $user;
192
-			$parameters['user_autofocus'] = false;
193
-		} else {
194
-			$parameters['loginName'] = '';
195
-			$parameters['user_autofocus'] = true;
196
-		}
190
+        if ($user !== null && $user !== '') {
191
+            $parameters['loginName'] = $user;
192
+            $parameters['user_autofocus'] = false;
193
+        } else {
194
+            $parameters['loginName'] = '';
195
+            $parameters['user_autofocus'] = true;
196
+        }
197 197
 
198
-		$parameters['throttle_delay'] = $this->throttler->getDelay($this->request->getRemoteAddress());
198
+        $parameters['throttle_delay'] = $this->throttler->getDelay($this->request->getRemoteAddress());
199 199
 
200
-		// OpenGraph Support: http://ogp.me/
201
-		Util::addHeader('meta', ['property' => 'og:title', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
202
-		Util::addHeader('meta', ['property' => 'og:description', 'content' => Util::sanitizeHTML($this->defaults->getSlogan())]);
203
-		Util::addHeader('meta', ['property' => 'og:site_name', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
204
-		Util::addHeader('meta', ['property' => 'og:url', 'content' => $this->urlGenerator->getAbsoluteURL('/')]);
205
-		Util::addHeader('meta', ['property' => 'og:type', 'content' => 'website']);
206
-		Util::addHeader('meta', ['property' => 'og:image', 'content' => $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core','favicon-touch.png'))]);
200
+        // OpenGraph Support: http://ogp.me/
201
+        Util::addHeader('meta', ['property' => 'og:title', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
202
+        Util::addHeader('meta', ['property' => 'og:description', 'content' => Util::sanitizeHTML($this->defaults->getSlogan())]);
203
+        Util::addHeader('meta', ['property' => 'og:site_name', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
204
+        Util::addHeader('meta', ['property' => 'og:url', 'content' => $this->urlGenerator->getAbsoluteURL('/')]);
205
+        Util::addHeader('meta', ['property' => 'og:type', 'content' => 'website']);
206
+        Util::addHeader('meta', ['property' => 'og:image', 'content' => $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core','favicon-touch.png'))]);
207 207
 
208
-		return new TemplateResponse(
209
-			$this->appName, 'login', $parameters, 'guest'
210
-		);
211
-	}
208
+        return new TemplateResponse(
209
+            $this->appName, 'login', $parameters, 'guest'
210
+        );
211
+    }
212 212
 
213
-	/**
214
-	 * @param string $redirectUrl
215
-	 * @return RedirectResponse
216
-	 */
217
-	private function generateRedirect($redirectUrl) {
218
-		if (!is_null($redirectUrl) && $this->userSession->isLoggedIn()) {
219
-			$location = $this->urlGenerator->getAbsoluteURL(urldecode($redirectUrl));
220
-			// Deny the redirect if the URL contains a @
221
-			// This prevents unvalidated redirects like ?redirect_url=:[email protected]
222
-			if (strpos($location, '@') === false) {
223
-				return new RedirectResponse($location);
224
-			}
225
-		}
226
-		return new RedirectResponse(OC_Util::getDefaultPageUrl());
227
-	}
213
+    /**
214
+     * @param string $redirectUrl
215
+     * @return RedirectResponse
216
+     */
217
+    private function generateRedirect($redirectUrl) {
218
+        if (!is_null($redirectUrl) && $this->userSession->isLoggedIn()) {
219
+            $location = $this->urlGenerator->getAbsoluteURL(urldecode($redirectUrl));
220
+            // Deny the redirect if the URL contains a @
221
+            // This prevents unvalidated redirects like ?redirect_url=:[email protected]
222
+            if (strpos($location, '@') === false) {
223
+                return new RedirectResponse($location);
224
+            }
225
+        }
226
+        return new RedirectResponse(OC_Util::getDefaultPageUrl());
227
+    }
228 228
 
229
-	/**
230
-	 * @PublicPage
231
-	 * @UseSession
232
-	 * @NoCSRFRequired
233
-	 * @BruteForceProtection(action=login)
234
-	 *
235
-	 * @param string $user
236
-	 * @param string $password
237
-	 * @param string $redirect_url
238
-	 * @param boolean $remember_login
239
-	 * @param string $timezone
240
-	 * @param string $timezone_offset
241
-	 * @return RedirectResponse
242
-	 */
243
-	public function tryLogin($user, $password, $redirect_url, $remember_login = false, $timezone = '', $timezone_offset = '') {
244
-		if(!is_string($user)) {
245
-			throw new \InvalidArgumentException('Username must be string');
246
-		}
229
+    /**
230
+     * @PublicPage
231
+     * @UseSession
232
+     * @NoCSRFRequired
233
+     * @BruteForceProtection(action=login)
234
+     *
235
+     * @param string $user
236
+     * @param string $password
237
+     * @param string $redirect_url
238
+     * @param boolean $remember_login
239
+     * @param string $timezone
240
+     * @param string $timezone_offset
241
+     * @return RedirectResponse
242
+     */
243
+    public function tryLogin($user, $password, $redirect_url, $remember_login = false, $timezone = '', $timezone_offset = '') {
244
+        if(!is_string($user)) {
245
+            throw new \InvalidArgumentException('Username must be string');
246
+        }
247 247
 
248
-		// If the user is already logged in and the CSRF check does not pass then
249
-		// simply redirect the user to the correct page as required. This is the
250
-		// case when an user has already logged-in, in another tab.
251
-		if(!$this->request->passesCSRFCheck()) {
252
-			return $this->generateRedirect($redirect_url);
253
-		}
248
+        // If the user is already logged in and the CSRF check does not pass then
249
+        // simply redirect the user to the correct page as required. This is the
250
+        // case when an user has already logged-in, in another tab.
251
+        if(!$this->request->passesCSRFCheck()) {
252
+            return $this->generateRedirect($redirect_url);
253
+        }
254 254
 
255
-		if ($this->userManager instanceof PublicEmitter) {
256
-			$this->userManager->emit('\OC\User', 'preLogin', array($user, $password));
257
-		}
255
+        if ($this->userManager instanceof PublicEmitter) {
256
+            $this->userManager->emit('\OC\User', 'preLogin', array($user, $password));
257
+        }
258 258
 
259
-		$originalUser = $user;
260
-		// TODO: Add all the insane error handling
261
-		/* @var $loginResult IUser */
262
-		$loginResult = $this->userManager->checkPasswordNoLogging($user, $password);
263
-		if ($loginResult === false) {
264
-			$users = $this->userManager->getByEmail($user);
265
-			// we only allow login by email if unique
266
-			if (count($users) === 1) {
267
-				$previousUser = $user;
268
-				$user = $users[0]->getUID();
269
-				if($user !== $previousUser) {
270
-					$loginResult = $this->userManager->checkPassword($user, $password);
271
-				}
272
-			}
273
-		}
274
-		if ($loginResult === false) {
275
-			$this->logger->warning('Login failed: \''. $user .'\' (Remote IP: \''. $this->request->getRemoteAddress(). '\')', ['app' => 'core']);
276
-			// Read current user and append if possible - we need to return the unmodified user otherwise we will leak the login name
277
-			$args = !is_null($user) ? ['user' => $originalUser] : [];
278
-			if (!is_null($redirect_url)) {
279
-				$args['redirect_url'] = $redirect_url;
280
-			}
281
-			$response = new RedirectResponse($this->urlGenerator->linkToRoute('core.login.showLoginForm', $args));
282
-			$response->throttle(['user' => $user]);
283
-			$this->session->set('loginMessages', [
284
-				['invalidpassword'], []
285
-			]);
286
-			return $response;
287
-		}
288
-		// TODO: remove password checks from above and let the user session handle failures
289
-		// requires https://github.com/owncloud/core/pull/24616
290
-		$this->userSession->completeLogin($loginResult, ['loginName' => $user, 'password' => $password]);
291
-		$this->userSession->createSessionToken($this->request, $loginResult->getUID(), $user, $password, (int)$remember_login);
259
+        $originalUser = $user;
260
+        // TODO: Add all the insane error handling
261
+        /* @var $loginResult IUser */
262
+        $loginResult = $this->userManager->checkPasswordNoLogging($user, $password);
263
+        if ($loginResult === false) {
264
+            $users = $this->userManager->getByEmail($user);
265
+            // we only allow login by email if unique
266
+            if (count($users) === 1) {
267
+                $previousUser = $user;
268
+                $user = $users[0]->getUID();
269
+                if($user !== $previousUser) {
270
+                    $loginResult = $this->userManager->checkPassword($user, $password);
271
+                }
272
+            }
273
+        }
274
+        if ($loginResult === false) {
275
+            $this->logger->warning('Login failed: \''. $user .'\' (Remote IP: \''. $this->request->getRemoteAddress(). '\')', ['app' => 'core']);
276
+            // Read current user and append if possible - we need to return the unmodified user otherwise we will leak the login name
277
+            $args = !is_null($user) ? ['user' => $originalUser] : [];
278
+            if (!is_null($redirect_url)) {
279
+                $args['redirect_url'] = $redirect_url;
280
+            }
281
+            $response = new RedirectResponse($this->urlGenerator->linkToRoute('core.login.showLoginForm', $args));
282
+            $response->throttle(['user' => $user]);
283
+            $this->session->set('loginMessages', [
284
+                ['invalidpassword'], []
285
+            ]);
286
+            return $response;
287
+        }
288
+        // TODO: remove password checks from above and let the user session handle failures
289
+        // requires https://github.com/owncloud/core/pull/24616
290
+        $this->userSession->completeLogin($loginResult, ['loginName' => $user, 'password' => $password]);
291
+        $this->userSession->createSessionToken($this->request, $loginResult->getUID(), $user, $password, (int)$remember_login);
292 292
 
293
-		// User has successfully logged in, now remove the password reset link, when it is available
294
-		$this->config->deleteUserValue($loginResult->getUID(), 'core', 'lostpassword');
293
+        // User has successfully logged in, now remove the password reset link, when it is available
294
+        $this->config->deleteUserValue($loginResult->getUID(), 'core', 'lostpassword');
295 295
 
296
-		$this->session->set('last-password-confirm', $loginResult->getLastLogin());
296
+        $this->session->set('last-password-confirm', $loginResult->getLastLogin());
297 297
 
298
-		if ($timezone_offset !== '') {
299
-			$this->config->setUserValue($loginResult->getUID(), 'core', 'timezone', $timezone);
300
-			$this->session->set('timezone', $timezone_offset);
301
-		}
298
+        if ($timezone_offset !== '') {
299
+            $this->config->setUserValue($loginResult->getUID(), 'core', 'timezone', $timezone);
300
+            $this->session->set('timezone', $timezone_offset);
301
+        }
302 302
 
303
-		if ($this->twoFactorManager->isTwoFactorAuthenticated($loginResult)) {
304
-			$this->twoFactorManager->prepareTwoFactorLogin($loginResult, $remember_login);
303
+        if ($this->twoFactorManager->isTwoFactorAuthenticated($loginResult)) {
304
+            $this->twoFactorManager->prepareTwoFactorLogin($loginResult, $remember_login);
305 305
 
306
-			$providers = $this->twoFactorManager->getProviders($loginResult);
307
-			if (count($providers) === 1) {
308
-				// Single provider, hence we can redirect to that provider's challenge page directly
309
-				/* @var $provider IProvider */
310
-				$provider = array_pop($providers);
311
-				$url = 'core.TwoFactorChallenge.showChallenge';
312
-				$urlParams = [
313
-					'challengeProviderId' => $provider->getId(),
314
-				];
315
-			} else {
316
-				$url = 'core.TwoFactorChallenge.selectChallenge';
317
-				$urlParams = [];
318
-			}
306
+            $providers = $this->twoFactorManager->getProviders($loginResult);
307
+            if (count($providers) === 1) {
308
+                // Single provider, hence we can redirect to that provider's challenge page directly
309
+                /* @var $provider IProvider */
310
+                $provider = array_pop($providers);
311
+                $url = 'core.TwoFactorChallenge.showChallenge';
312
+                $urlParams = [
313
+                    'challengeProviderId' => $provider->getId(),
314
+                ];
315
+            } else {
316
+                $url = 'core.TwoFactorChallenge.selectChallenge';
317
+                $urlParams = [];
318
+            }
319 319
 
320
-			if (!is_null($redirect_url)) {
321
-				$urlParams['redirect_url'] = $redirect_url;
322
-			}
320
+            if (!is_null($redirect_url)) {
321
+                $urlParams['redirect_url'] = $redirect_url;
322
+            }
323 323
 
324
-			return new RedirectResponse($this->urlGenerator->linkToRoute($url, $urlParams));
325
-		}
324
+            return new RedirectResponse($this->urlGenerator->linkToRoute($url, $urlParams));
325
+        }
326 326
 
327
-		if ($remember_login) {
328
-			$this->userSession->createRememberMeToken($loginResult);
329
-		}
327
+        if ($remember_login) {
328
+            $this->userSession->createRememberMeToken($loginResult);
329
+        }
330 330
 
331
-		return $this->generateRedirect($redirect_url);
332
-	}
331
+        return $this->generateRedirect($redirect_url);
332
+    }
333 333
 
334
-	/**
335
-	 * @NoAdminRequired
336
-	 * @UseSession
337
-	 * @BruteForceProtection(action=sudo)
338
-	 *
339
-	 * @license GNU AGPL version 3 or any later version
340
-	 *
341
-	 * @param string $password
342
-	 * @return DataResponse
343
-	 */
344
-	public function confirmPassword($password) {
345
-		$loginName = $this->userSession->getLoginName();
346
-		$loginResult = $this->userManager->checkPassword($loginName, $password);
347
-		if ($loginResult === false) {
348
-			$response = new DataResponse([], Http::STATUS_FORBIDDEN);
349
-			$response->throttle();
350
-			return $response;
351
-		}
334
+    /**
335
+     * @NoAdminRequired
336
+     * @UseSession
337
+     * @BruteForceProtection(action=sudo)
338
+     *
339
+     * @license GNU AGPL version 3 or any later version
340
+     *
341
+     * @param string $password
342
+     * @return DataResponse
343
+     */
344
+    public function confirmPassword($password) {
345
+        $loginName = $this->userSession->getLoginName();
346
+        $loginResult = $this->userManager->checkPassword($loginName, $password);
347
+        if ($loginResult === false) {
348
+            $response = new DataResponse([], Http::STATUS_FORBIDDEN);
349
+            $response->throttle();
350
+            return $response;
351
+        }
352 352
 
353
-		$confirmTimestamp = time();
354
-		$this->session->set('last-password-confirm', $confirmTimestamp);
355
-		return new DataResponse(['lastLogin' => $confirmTimestamp], Http::STATUS_OK);
356
-	}
353
+        $confirmTimestamp = time();
354
+        $this->session->set('last-password-confirm', $confirmTimestamp);
355
+        return new DataResponse(['lastLogin' => $confirmTimestamp], Http::STATUS_OK);
356
+    }
357 357
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -203,7 +203,7 @@  discard block
 block discarded – undo
203 203
 		Util::addHeader('meta', ['property' => 'og:site_name', 'content' => Util::sanitizeHTML($this->defaults->getName())]);
204 204
 		Util::addHeader('meta', ['property' => 'og:url', 'content' => $this->urlGenerator->getAbsoluteURL('/')]);
205 205
 		Util::addHeader('meta', ['property' => 'og:type', 'content' => 'website']);
206
-		Util::addHeader('meta', ['property' => 'og:image', 'content' => $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core','favicon-touch.png'))]);
206
+		Util::addHeader('meta', ['property' => 'og:image', 'content' => $this->urlGenerator->getAbsoluteURL($this->urlGenerator->imagePath('core', 'favicon-touch.png'))]);
207 207
 
208 208
 		return new TemplateResponse(
209 209
 			$this->appName, 'login', $parameters, 'guest'
@@ -241,14 +241,14 @@  discard block
 block discarded – undo
241 241
 	 * @return RedirectResponse
242 242
 	 */
243 243
 	public function tryLogin($user, $password, $redirect_url, $remember_login = false, $timezone = '', $timezone_offset = '') {
244
-		if(!is_string($user)) {
244
+		if (!is_string($user)) {
245 245
 			throw new \InvalidArgumentException('Username must be string');
246 246
 		}
247 247
 
248 248
 		// If the user is already logged in and the CSRF check does not pass then
249 249
 		// simply redirect the user to the correct page as required. This is the
250 250
 		// case when an user has already logged-in, in another tab.
251
-		if(!$this->request->passesCSRFCheck()) {
251
+		if (!$this->request->passesCSRFCheck()) {
252 252
 			return $this->generateRedirect($redirect_url);
253 253
 		}
254 254
 
@@ -266,13 +266,13 @@  discard block
 block discarded – undo
266 266
 			if (count($users) === 1) {
267 267
 				$previousUser = $user;
268 268
 				$user = $users[0]->getUID();
269
-				if($user !== $previousUser) {
269
+				if ($user !== $previousUser) {
270 270
 					$loginResult = $this->userManager->checkPassword($user, $password);
271 271
 				}
272 272
 			}
273 273
 		}
274 274
 		if ($loginResult === false) {
275
-			$this->logger->warning('Login failed: \''. $user .'\' (Remote IP: \''. $this->request->getRemoteAddress(). '\')', ['app' => 'core']);
275
+			$this->logger->warning('Login failed: \''.$user.'\' (Remote IP: \''.$this->request->getRemoteAddress().'\')', ['app' => 'core']);
276 276
 			// Read current user and append if possible - we need to return the unmodified user otherwise we will leak the login name
277 277
 			$args = !is_null($user) ? ['user' => $originalUser] : [];
278 278
 			if (!is_null($redirect_url)) {
@@ -288,7 +288,7 @@  discard block
 block discarded – undo
288 288
 		// TODO: remove password checks from above and let the user session handle failures
289 289
 		// requires https://github.com/owncloud/core/pull/24616
290 290
 		$this->userSession->completeLogin($loginResult, ['loginName' => $user, 'password' => $password]);
291
-		$this->userSession->createSessionToken($this->request, $loginResult->getUID(), $user, $password, (int)$remember_login);
291
+		$this->userSession->createSessionToken($this->request, $loginResult->getUID(), $user, $password, (int) $remember_login);
292 292
 
293 293
 		// User has successfully logged in, now remove the password reset link, when it is available
294 294
 		$this->config->deleteUserValue($loginResult->getUID(), 'core', 'lostpassword');
Please login to merge, or discard this patch.
apps/user_ldap/lib/Connection.php 2 patches
Indentation   +604 added lines, -604 removed lines patch added patch discarded remove patch
@@ -58,609 +58,609 @@
 block discarded – undo
58 58
  * @property string ldapExpertUUIDGroupAttr
59 59
  */
60 60
 class Connection extends LDAPUtility {
61
-	private $ldapConnectionRes = null;
62
-	private $configPrefix;
63
-	private $configID;
64
-	private $configured = false;
65
-	private $hasPagedResultSupport = true;
66
-	//whether connection should be kept on __destruct
67
-	private $dontDestruct = false;
68
-
69
-	/**
70
-	 * @var bool runtime flag that indicates whether supported primary groups are available
71
-	 */
72
-	public $hasPrimaryGroups = true;
73
-
74
-	/**
75
-	 * @var bool runtime flag that indicates whether supported POSIX gidNumber are available
76
-	 */
77
-	public $hasGidNumber = true;
78
-
79
-	//cache handler
80
-	protected $cache;
81
-
82
-	/** @var Configuration settings handler **/
83
-	protected $configuration;
84
-
85
-	protected $doNotValidate = false;
86
-
87
-	protected $ignoreValidation = false;
88
-
89
-	protected $bindResult = [];
90
-
91
-	/**
92
-	 * Constructor
93
-	 * @param ILDAPWrapper $ldap
94
-	 * @param string $configPrefix a string with the prefix for the configkey column (appconfig table)
95
-	 * @param string|null $configID a string with the value for the appid column (appconfig table) or null for on-the-fly connections
96
-	 */
97
-	public function __construct(ILDAPWrapper $ldap, $configPrefix = '', $configID = 'user_ldap') {
98
-		parent::__construct($ldap);
99
-		$this->configPrefix = $configPrefix;
100
-		$this->configID = $configID;
101
-		$this->configuration = new Configuration($configPrefix,
102
-												 !is_null($configID));
103
-		$memcache = \OC::$server->getMemCacheFactory();
104
-		if($memcache->isAvailable()) {
105
-			$this->cache = $memcache->createDistributed();
106
-		}
107
-		$helper = new Helper(\OC::$server->getConfig());
108
-		$this->doNotValidate = !in_array($this->configPrefix,
109
-			$helper->getServerConfigurationPrefixes());
110
-		$this->hasPagedResultSupport =
111
-			(int)$this->configuration->ldapPagingSize !== 0
112
-			|| $this->ldap->hasPagedResultSupport();
113
-	}
114
-
115
-	public function __destruct() {
116
-		if(!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
117
-			@$this->ldap->unbind($this->ldapConnectionRes);
118
-			$this->bindResult = [];
119
-		}
120
-	}
121
-
122
-	/**
123
-	 * defines behaviour when the instance is cloned
124
-	 */
125
-	public function __clone() {
126
-		$this->configuration = new Configuration($this->configPrefix,
127
-												 !is_null($this->configID));
128
-		$this->ldapConnectionRes = null;
129
-		$this->dontDestruct = true;
130
-	}
131
-
132
-	/**
133
-	 * @param string $name
134
-	 * @return bool|mixed
135
-	 */
136
-	public function __get($name) {
137
-		if(!$this->configured) {
138
-			$this->readConfiguration();
139
-		}
140
-
141
-		if($name === 'hasPagedResultSupport') {
142
-			return $this->hasPagedResultSupport;
143
-		}
144
-
145
-		return $this->configuration->$name;
146
-	}
147
-
148
-	/**
149
-	 * @param string $name
150
-	 * @param mixed $value
151
-	 */
152
-	public function __set($name, $value) {
153
-		$this->doNotValidate = false;
154
-		$before = $this->configuration->$name;
155
-		$this->configuration->$name = $value;
156
-		$after = $this->configuration->$name;
157
-		if($before !== $after) {
158
-			if ($this->configID !== '' && $this->configID !== null) {
159
-				$this->configuration->saveConfiguration();
160
-			}
161
-			$this->validateConfiguration();
162
-		}
163
-	}
164
-
165
-	/**
166
-	 * sets whether the result of the configuration validation shall
167
-	 * be ignored when establishing the connection. Used by the Wizard
168
-	 * in early configuration state.
169
-	 * @param bool $state
170
-	 */
171
-	public function setIgnoreValidation($state) {
172
-		$this->ignoreValidation = (bool)$state;
173
-	}
174
-
175
-	/**
176
-	 * initializes the LDAP backend
177
-	 * @param bool $force read the config settings no matter what
178
-	 */
179
-	public function init($force = false) {
180
-		$this->readConfiguration($force);
181
-		$this->establishConnection();
182
-	}
183
-
184
-	/**
185
-	 * Returns the LDAP handler
186
-	 */
187
-	public function getConnectionResource() {
188
-		if(!$this->ldapConnectionRes) {
189
-			$this->init();
190
-		} else if(!$this->ldap->isResource($this->ldapConnectionRes)) {
191
-			$this->ldapConnectionRes = null;
192
-			$this->establishConnection();
193
-		}
194
-		if(is_null($this->ldapConnectionRes)) {
195
-			\OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server ' . $this->configuration->ldapHost, \OCP\Util::ERROR);
196
-			throw new ServerNotAvailableException('Connection to LDAP server could not be established');
197
-		}
198
-		return $this->ldapConnectionRes;
199
-	}
200
-
201
-	/**
202
-	 * resets the connection resource
203
-	 */
204
-	public function resetConnectionResource() {
205
-		if(!is_null($this->ldapConnectionRes)) {
206
-			@$this->ldap->unbind($this->ldapConnectionRes);
207
-			$this->ldapConnectionRes = null;
208
-			$this->bindResult = [];
209
-		}
210
-	}
211
-
212
-	/**
213
-	 * @param string|null $key
214
-	 * @return string
215
-	 */
216
-	private function getCacheKey($key) {
217
-		$prefix = 'LDAP-'.$this->configID.'-'.$this->configPrefix.'-';
218
-		if(is_null($key)) {
219
-			return $prefix;
220
-		}
221
-		return $prefix.md5($key);
222
-	}
223
-
224
-	/**
225
-	 * @param string $key
226
-	 * @return mixed|null
227
-	 */
228
-	public function getFromCache($key) {
229
-		if(!$this->configured) {
230
-			$this->readConfiguration();
231
-		}
232
-		if(is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
233
-			return null;
234
-		}
235
-		$key = $this->getCacheKey($key);
236
-
237
-		return json_decode(base64_decode($this->cache->get($key)), true);
238
-	}
239
-
240
-	/**
241
-	 * @param string $key
242
-	 * @param mixed $value
243
-	 *
244
-	 * @return string
245
-	 */
246
-	public function writeToCache($key, $value) {
247
-		if(!$this->configured) {
248
-			$this->readConfiguration();
249
-		}
250
-		if(is_null($this->cache)
251
-			|| !$this->configuration->ldapCacheTTL
252
-			|| !$this->configuration->ldapConfigurationActive) {
253
-			return null;
254
-		}
255
-		$key   = $this->getCacheKey($key);
256
-		$value = base64_encode(json_encode($value));
257
-		$this->cache->set($key, $value, $this->configuration->ldapCacheTTL);
258
-	}
259
-
260
-	public function clearCache() {
261
-		if(!is_null($this->cache)) {
262
-			$this->cache->clear($this->getCacheKey(null));
263
-		}
264
-	}
265
-
266
-	/**
267
-	 * Caches the general LDAP configuration.
268
-	 * @param bool $force optional. true, if the re-read should be forced. defaults
269
-	 * to false.
270
-	 * @return null
271
-	 */
272
-	private function readConfiguration($force = false) {
273
-		if((!$this->configured || $force) && !is_null($this->configID)) {
274
-			$this->configuration->readConfiguration();
275
-			$this->configured = $this->validateConfiguration();
276
-		}
277
-	}
278
-
279
-	/**
280
-	 * set LDAP configuration with values delivered by an array, not read from configuration
281
-	 * @param array $config array that holds the config parameters in an associated array
282
-	 * @param array &$setParameters optional; array where the set fields will be given to
283
-	 * @return boolean true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
284
-	 */
285
-	public function setConfiguration($config, &$setParameters = null) {
286
-		if(is_null($setParameters)) {
287
-			$setParameters = array();
288
-		}
289
-		$this->doNotValidate = false;
290
-		$this->configuration->setConfiguration($config, $setParameters);
291
-		if(count($setParameters) > 0) {
292
-			$this->configured = $this->validateConfiguration();
293
-		}
294
-
295
-
296
-		return $this->configured;
297
-	}
298
-
299
-	/**
300
-	 * saves the current Configuration in the database and empties the
301
-	 * cache
302
-	 * @return null
303
-	 */
304
-	public function saveConfiguration() {
305
-		$this->configuration->saveConfiguration();
306
-		$this->clearCache();
307
-	}
308
-
309
-	/**
310
-	 * get the current LDAP configuration
311
-	 * @return array
312
-	 */
313
-	public function getConfiguration() {
314
-		$this->readConfiguration();
315
-		$config = $this->configuration->getConfiguration();
316
-		$cta = $this->configuration->getConfigTranslationArray();
317
-		$result = array();
318
-		foreach($cta as $dbkey => $configkey) {
319
-			switch($configkey) {
320
-				case 'homeFolderNamingRule':
321
-					if(strpos($config[$configkey], 'attr:') === 0) {
322
-						$result[$dbkey] = substr($config[$configkey], 5);
323
-					} else {
324
-						$result[$dbkey] = '';
325
-					}
326
-					break;
327
-				case 'ldapBase':
328
-				case 'ldapBaseUsers':
329
-				case 'ldapBaseGroups':
330
-				case 'ldapAttributesForUserSearch':
331
-				case 'ldapAttributesForGroupSearch':
332
-					if(is_array($config[$configkey])) {
333
-						$result[$dbkey] = implode("\n", $config[$configkey]);
334
-						break;
335
-					} //else follows default
336
-				default:
337
-					$result[$dbkey] = $config[$configkey];
338
-			}
339
-		}
340
-		return $result;
341
-	}
342
-
343
-	private function doSoftValidation() {
344
-		//if User or Group Base are not set, take over Base DN setting
345
-		foreach(array('ldapBaseUsers', 'ldapBaseGroups') as $keyBase) {
346
-			$val = $this->configuration->$keyBase;
347
-			if(empty($val)) {
348
-				$this->configuration->$keyBase = $this->configuration->ldapBase;
349
-			}
350
-		}
351
-
352
-		foreach(array('ldapExpertUUIDUserAttr'  => 'ldapUuidUserAttribute',
353
-					  'ldapExpertUUIDGroupAttr' => 'ldapUuidGroupAttribute')
354
-				as $expertSetting => $effectiveSetting) {
355
-			$uuidOverride = $this->configuration->$expertSetting;
356
-			if(!empty($uuidOverride)) {
357
-				$this->configuration->$effectiveSetting = $uuidOverride;
358
-			} else {
359
-				$uuidAttributes = Access::UUID_ATTRIBUTES;
360
-				array_unshift($uuidAttributes, 'auto');
361
-				if(!in_array($this->configuration->$effectiveSetting,
362
-							$uuidAttributes)
363
-					&& (!is_null($this->configID))) {
364
-					$this->configuration->$effectiveSetting = 'auto';
365
-					$this->configuration->saveConfiguration();
366
-					\OCP\Util::writeLog('user_ldap',
367
-										'Illegal value for the '.
368
-										$effectiveSetting.', '.'reset to '.
369
-										'autodetect.', \OCP\Util::INFO);
370
-				}
371
-
372
-			}
373
-		}
374
-
375
-		$backupPort = (int)$this->configuration->ldapBackupPort;
376
-		if ($backupPort <= 0) {
377
-			$this->configuration->backupPort = $this->configuration->ldapPort;
378
-		}
379
-
380
-		//make sure empty search attributes are saved as simple, empty array
381
-		$saKeys = array('ldapAttributesForUserSearch',
382
-						'ldapAttributesForGroupSearch');
383
-		foreach($saKeys as $key) {
384
-			$val = $this->configuration->$key;
385
-			if(is_array($val) && count($val) === 1 && empty($val[0])) {
386
-				$this->configuration->$key = array();
387
-			}
388
-		}
389
-
390
-		if((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
391
-			&& $this->configuration->ldapTLS) {
392
-			$this->configuration->ldapTLS = false;
393
-			\OCP\Util::writeLog('user_ldap',
394
-								'LDAPS (already using secure connection) and '.
395
-								'TLS do not work together. Switched off TLS.',
396
-								\OCP\Util::INFO);
397
-		}
398
-	}
399
-
400
-	/**
401
-	 * @return bool
402
-	 */
403
-	private function doCriticalValidation() {
404
-		$configurationOK = true;
405
-		$errorStr = 'Configuration Error (prefix '.
406
-			(string)$this->configPrefix .'): ';
407
-
408
-		//options that shall not be empty
409
-		$options = array('ldapHost', 'ldapPort', 'ldapUserDisplayName',
410
-						 'ldapGroupDisplayName', 'ldapLoginFilter');
411
-		foreach($options as $key) {
412
-			$val = $this->configuration->$key;
413
-			if(empty($val)) {
414
-				switch($key) {
415
-					case 'ldapHost':
416
-						$subj = 'LDAP Host';
417
-						break;
418
-					case 'ldapPort':
419
-						$subj = 'LDAP Port';
420
-						break;
421
-					case 'ldapUserDisplayName':
422
-						$subj = 'LDAP User Display Name';
423
-						break;
424
-					case 'ldapGroupDisplayName':
425
-						$subj = 'LDAP Group Display Name';
426
-						break;
427
-					case 'ldapLoginFilter':
428
-						$subj = 'LDAP Login Filter';
429
-						break;
430
-					default:
431
-						$subj = $key;
432
-						break;
433
-				}
434
-				$configurationOK = false;
435
-				\OCP\Util::writeLog('user_ldap',
436
-									$errorStr.'No '.$subj.' given!',
437
-									\OCP\Util::WARN);
438
-			}
439
-		}
440
-
441
-		//combinations
442
-		$agent = $this->configuration->ldapAgentName;
443
-		$pwd = $this->configuration->ldapAgentPassword;
444
-		if (
445
-			($agent === ''  && $pwd !== '')
446
-			|| ($agent !== '' && $pwd === '')
447
-		) {
448
-			\OCP\Util::writeLog('user_ldap',
449
-								$errorStr.'either no password is given for the '.
450
-								'user agent or a password is given, but not an '.
451
-								'LDAP agent.',
452
-				\OCP\Util::WARN);
453
-			$configurationOK = false;
454
-		}
455
-
456
-		$base = $this->configuration->ldapBase;
457
-		$baseUsers = $this->configuration->ldapBaseUsers;
458
-		$baseGroups = $this->configuration->ldapBaseGroups;
459
-
460
-		if(empty($base) && empty($baseUsers) && empty($baseGroups)) {
461
-			\OCP\Util::writeLog('user_ldap',
462
-								$errorStr.'Not a single Base DN given.',
463
-								\OCP\Util::WARN);
464
-			$configurationOK = false;
465
-		}
466
-
467
-		if(mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
468
-		   === false) {
469
-			\OCP\Util::writeLog('user_ldap',
470
-								$errorStr.'login filter does not contain %uid '.
471
-								'place holder.',
472
-								\OCP\Util::WARN);
473
-			$configurationOK = false;
474
-		}
475
-
476
-		return $configurationOK;
477
-	}
478
-
479
-	/**
480
-	 * Validates the user specified configuration
481
-	 * @return bool true if configuration seems OK, false otherwise
482
-	 */
483
-	private function validateConfiguration() {
484
-
485
-		if($this->doNotValidate) {
486
-			//don't do a validation if it is a new configuration with pure
487
-			//default values. Will be allowed on changes via __set or
488
-			//setConfiguration
489
-			return false;
490
-		}
491
-
492
-		// first step: "soft" checks: settings that are not really
493
-		// necessary, but advisable. If left empty, give an info message
494
-		$this->doSoftValidation();
495
-
496
-		//second step: critical checks. If left empty or filled wrong, mark as
497
-		//not configured and give a warning.
498
-		return $this->doCriticalValidation();
499
-	}
500
-
501
-
502
-	/**
503
-	 * Connects and Binds to LDAP
504
-	 */
505
-	private function establishConnection() {
506
-		if(!$this->configuration->ldapConfigurationActive) {
507
-			return null;
508
-		}
509
-		static $phpLDAPinstalled = true;
510
-		if(!$phpLDAPinstalled) {
511
-			return false;
512
-		}
513
-		if(!$this->ignoreValidation && !$this->configured) {
514
-			\OCP\Util::writeLog('user_ldap',
515
-								'Configuration is invalid, cannot connect',
516
-								\OCP\Util::WARN);
517
-			return false;
518
-		}
519
-		if(!$this->ldapConnectionRes) {
520
-			if(!$this->ldap->areLDAPFunctionsAvailable()) {
521
-				$phpLDAPinstalled = false;
522
-				\OCP\Util::writeLog('user_ldap',
523
-									'function ldap_connect is not available. Make '.
524
-									'sure that the PHP ldap module is installed.',
525
-									\OCP\Util::ERROR);
526
-
527
-				return false;
528
-			}
529
-			if($this->configuration->turnOffCertCheck) {
530
-				if(putenv('LDAPTLS_REQCERT=never')) {
531
-					\OCP\Util::writeLog('user_ldap',
532
-						'Turned off SSL certificate validation successfully.',
533
-						\OCP\Util::DEBUG);
534
-				} else {
535
-					\OCP\Util::writeLog('user_ldap',
536
-										'Could not turn off SSL certificate validation.',
537
-										\OCP\Util::WARN);
538
-				}
539
-			}
540
-
541
-			$isOverrideMainServer = ($this->configuration->ldapOverrideMainServer
542
-				|| $this->getFromCache('overrideMainServer'));
543
-			$isBackupHost = (trim($this->configuration->ldapBackupHost) !== "");
544
-			$bindStatus = false;
545
-			$error = -1;
546
-			try {
547
-				if (!$isOverrideMainServer) {
548
-					$this->doConnect($this->configuration->ldapHost,
549
-						$this->configuration->ldapPort);
550
-					$bindStatus = $this->bind();
551
-					$error = $this->ldap->isResource($this->ldapConnectionRes) ?
552
-						$this->ldap->errno($this->ldapConnectionRes) : -1;
553
-				}
554
-				if($bindStatus === true) {
555
-					return $bindStatus;
556
-				}
557
-			} catch (ServerNotAvailableException $e) {
558
-				if(!$isBackupHost) {
559
-					throw $e;
560
-				}
561
-			}
562
-
563
-			//if LDAP server is not reachable, try the Backup (Replica!) Server
564
-			if($isBackupHost && ($error !== 0 || $isOverrideMainServer)) {
565
-				$this->doConnect($this->configuration->ldapBackupHost,
566
-								 $this->configuration->ldapBackupPort);
567
-				$this->bindResult = [];
568
-				$bindStatus = $this->bind();
569
-				$error = $this->ldap->isResource($this->ldapConnectionRes) ?
570
-					$this->ldap->errno($this->ldapConnectionRes) : -1;
571
-				if($bindStatus && $error === 0 && !$this->getFromCache('overrideMainServer')) {
572
-					//when bind to backup server succeeded and failed to main server,
573
-					//skip contacting him until next cache refresh
574
-					$this->writeToCache('overrideMainServer', true);
575
-				}
576
-			}
577
-
578
-			return $bindStatus;
579
-		}
580
-		return null;
581
-	}
582
-
583
-	/**
584
-	 * @param string $host
585
-	 * @param string $port
586
-	 * @return bool
587
-	 * @throws \OC\ServerNotAvailableException
588
-	 */
589
-	private function doConnect($host, $port) {
590
-		if ($host === '') {
591
-			return false;
592
-		}
593
-
594
-		$this->ldapConnectionRes = $this->ldap->connect($host, $port);
595
-
596
-		if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
597
-			throw new ServerNotAvailableException('Could not set required LDAP Protocol version.');
598
-		}
599
-
600
-		if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
601
-			throw new ServerNotAvailableException('Could not disable LDAP referrals.');
602
-		}
603
-
604
-		if($this->configuration->ldapTLS) {
605
-			if(!$this->ldap->startTls($this->ldapConnectionRes)) {
606
-				throw new ServerNotAvailableException('Start TLS failed, when connecting to LDAP host ' . $host . '.');
607
-			}
608
-		}
609
-
610
-		return true;
611
-	}
612
-
613
-	/**
614
-	 * Binds to LDAP
615
-	 */
616
-	public function bind() {
617
-		if(!$this->configuration->ldapConfigurationActive) {
618
-			return false;
619
-		}
620
-		$cr = $this->ldapConnectionRes;
621
-		if(!$this->ldap->isResource($cr)) {
622
-			$cr = $this->getConnectionResource();
623
-		}
624
-
625
-		if(
626
-			count($this->bindResult) !== 0
627
-			&& $this->bindResult['dn'] === $this->configuration->ldapAgentName
628
-			&& \OC::$server->getHasher()->verify(
629
-				$this->configPrefix . $this->configuration->ldapAgentPassword,
630
-				$this->bindResult['hash']
631
-			)
632
-		) {
633
-			// don't attempt to bind again with the same data as before
634
-			// bind might have been invoked via getConnectionResource(),
635
-			// but we need results specifically for e.g. user login
636
-			return $this->bindResult['result'];
637
-		}
638
-
639
-		$ldapLogin = @$this->ldap->bind($cr,
640
-										$this->configuration->ldapAgentName,
641
-										$this->configuration->ldapAgentPassword);
642
-
643
-		$this->bindResult = [
644
-			'dn' => $this->configuration->ldapAgentName,
645
-			'hash' => \OC::$server->getHasher()->hash($this->configPrefix . $this->configuration->ldapAgentPassword),
646
-			'result' => $ldapLogin,
647
-		];
648
-
649
-		if(!$ldapLogin) {
650
-			$errno = $this->ldap->errno($cr);
651
-
652
-			\OCP\Util::writeLog('user_ldap',
653
-				'Bind failed: ' . $errno . ': ' . $this->ldap->error($cr),
654
-				\OCP\Util::WARN);
655
-
656
-			// Set to failure mode, if LDAP error code is not LDAP_SUCCESS or LDAP_INVALID_CREDENTIALS
657
-			if($errno !== 0x00 && $errno !== 0x31) {
658
-				$this->ldapConnectionRes = null;
659
-			}
660
-
661
-			return false;
662
-		}
663
-		return true;
664
-	}
61
+    private $ldapConnectionRes = null;
62
+    private $configPrefix;
63
+    private $configID;
64
+    private $configured = false;
65
+    private $hasPagedResultSupport = true;
66
+    //whether connection should be kept on __destruct
67
+    private $dontDestruct = false;
68
+
69
+    /**
70
+     * @var bool runtime flag that indicates whether supported primary groups are available
71
+     */
72
+    public $hasPrimaryGroups = true;
73
+
74
+    /**
75
+     * @var bool runtime flag that indicates whether supported POSIX gidNumber are available
76
+     */
77
+    public $hasGidNumber = true;
78
+
79
+    //cache handler
80
+    protected $cache;
81
+
82
+    /** @var Configuration settings handler **/
83
+    protected $configuration;
84
+
85
+    protected $doNotValidate = false;
86
+
87
+    protected $ignoreValidation = false;
88
+
89
+    protected $bindResult = [];
90
+
91
+    /**
92
+     * Constructor
93
+     * @param ILDAPWrapper $ldap
94
+     * @param string $configPrefix a string with the prefix for the configkey column (appconfig table)
95
+     * @param string|null $configID a string with the value for the appid column (appconfig table) or null for on-the-fly connections
96
+     */
97
+    public function __construct(ILDAPWrapper $ldap, $configPrefix = '', $configID = 'user_ldap') {
98
+        parent::__construct($ldap);
99
+        $this->configPrefix = $configPrefix;
100
+        $this->configID = $configID;
101
+        $this->configuration = new Configuration($configPrefix,
102
+                                                    !is_null($configID));
103
+        $memcache = \OC::$server->getMemCacheFactory();
104
+        if($memcache->isAvailable()) {
105
+            $this->cache = $memcache->createDistributed();
106
+        }
107
+        $helper = new Helper(\OC::$server->getConfig());
108
+        $this->doNotValidate = !in_array($this->configPrefix,
109
+            $helper->getServerConfigurationPrefixes());
110
+        $this->hasPagedResultSupport =
111
+            (int)$this->configuration->ldapPagingSize !== 0
112
+            || $this->ldap->hasPagedResultSupport();
113
+    }
114
+
115
+    public function __destruct() {
116
+        if(!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
117
+            @$this->ldap->unbind($this->ldapConnectionRes);
118
+            $this->bindResult = [];
119
+        }
120
+    }
121
+
122
+    /**
123
+     * defines behaviour when the instance is cloned
124
+     */
125
+    public function __clone() {
126
+        $this->configuration = new Configuration($this->configPrefix,
127
+                                                    !is_null($this->configID));
128
+        $this->ldapConnectionRes = null;
129
+        $this->dontDestruct = true;
130
+    }
131
+
132
+    /**
133
+     * @param string $name
134
+     * @return bool|mixed
135
+     */
136
+    public function __get($name) {
137
+        if(!$this->configured) {
138
+            $this->readConfiguration();
139
+        }
140
+
141
+        if($name === 'hasPagedResultSupport') {
142
+            return $this->hasPagedResultSupport;
143
+        }
144
+
145
+        return $this->configuration->$name;
146
+    }
147
+
148
+    /**
149
+     * @param string $name
150
+     * @param mixed $value
151
+     */
152
+    public function __set($name, $value) {
153
+        $this->doNotValidate = false;
154
+        $before = $this->configuration->$name;
155
+        $this->configuration->$name = $value;
156
+        $after = $this->configuration->$name;
157
+        if($before !== $after) {
158
+            if ($this->configID !== '' && $this->configID !== null) {
159
+                $this->configuration->saveConfiguration();
160
+            }
161
+            $this->validateConfiguration();
162
+        }
163
+    }
164
+
165
+    /**
166
+     * sets whether the result of the configuration validation shall
167
+     * be ignored when establishing the connection. Used by the Wizard
168
+     * in early configuration state.
169
+     * @param bool $state
170
+     */
171
+    public function setIgnoreValidation($state) {
172
+        $this->ignoreValidation = (bool)$state;
173
+    }
174
+
175
+    /**
176
+     * initializes the LDAP backend
177
+     * @param bool $force read the config settings no matter what
178
+     */
179
+    public function init($force = false) {
180
+        $this->readConfiguration($force);
181
+        $this->establishConnection();
182
+    }
183
+
184
+    /**
185
+     * Returns the LDAP handler
186
+     */
187
+    public function getConnectionResource() {
188
+        if(!$this->ldapConnectionRes) {
189
+            $this->init();
190
+        } else if(!$this->ldap->isResource($this->ldapConnectionRes)) {
191
+            $this->ldapConnectionRes = null;
192
+            $this->establishConnection();
193
+        }
194
+        if(is_null($this->ldapConnectionRes)) {
195
+            \OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server ' . $this->configuration->ldapHost, \OCP\Util::ERROR);
196
+            throw new ServerNotAvailableException('Connection to LDAP server could not be established');
197
+        }
198
+        return $this->ldapConnectionRes;
199
+    }
200
+
201
+    /**
202
+     * resets the connection resource
203
+     */
204
+    public function resetConnectionResource() {
205
+        if(!is_null($this->ldapConnectionRes)) {
206
+            @$this->ldap->unbind($this->ldapConnectionRes);
207
+            $this->ldapConnectionRes = null;
208
+            $this->bindResult = [];
209
+        }
210
+    }
211
+
212
+    /**
213
+     * @param string|null $key
214
+     * @return string
215
+     */
216
+    private function getCacheKey($key) {
217
+        $prefix = 'LDAP-'.$this->configID.'-'.$this->configPrefix.'-';
218
+        if(is_null($key)) {
219
+            return $prefix;
220
+        }
221
+        return $prefix.md5($key);
222
+    }
223
+
224
+    /**
225
+     * @param string $key
226
+     * @return mixed|null
227
+     */
228
+    public function getFromCache($key) {
229
+        if(!$this->configured) {
230
+            $this->readConfiguration();
231
+        }
232
+        if(is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
233
+            return null;
234
+        }
235
+        $key = $this->getCacheKey($key);
236
+
237
+        return json_decode(base64_decode($this->cache->get($key)), true);
238
+    }
239
+
240
+    /**
241
+     * @param string $key
242
+     * @param mixed $value
243
+     *
244
+     * @return string
245
+     */
246
+    public function writeToCache($key, $value) {
247
+        if(!$this->configured) {
248
+            $this->readConfiguration();
249
+        }
250
+        if(is_null($this->cache)
251
+            || !$this->configuration->ldapCacheTTL
252
+            || !$this->configuration->ldapConfigurationActive) {
253
+            return null;
254
+        }
255
+        $key   = $this->getCacheKey($key);
256
+        $value = base64_encode(json_encode($value));
257
+        $this->cache->set($key, $value, $this->configuration->ldapCacheTTL);
258
+    }
259
+
260
+    public function clearCache() {
261
+        if(!is_null($this->cache)) {
262
+            $this->cache->clear($this->getCacheKey(null));
263
+        }
264
+    }
265
+
266
+    /**
267
+     * Caches the general LDAP configuration.
268
+     * @param bool $force optional. true, if the re-read should be forced. defaults
269
+     * to false.
270
+     * @return null
271
+     */
272
+    private function readConfiguration($force = false) {
273
+        if((!$this->configured || $force) && !is_null($this->configID)) {
274
+            $this->configuration->readConfiguration();
275
+            $this->configured = $this->validateConfiguration();
276
+        }
277
+    }
278
+
279
+    /**
280
+     * set LDAP configuration with values delivered by an array, not read from configuration
281
+     * @param array $config array that holds the config parameters in an associated array
282
+     * @param array &$setParameters optional; array where the set fields will be given to
283
+     * @return boolean true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
284
+     */
285
+    public function setConfiguration($config, &$setParameters = null) {
286
+        if(is_null($setParameters)) {
287
+            $setParameters = array();
288
+        }
289
+        $this->doNotValidate = false;
290
+        $this->configuration->setConfiguration($config, $setParameters);
291
+        if(count($setParameters) > 0) {
292
+            $this->configured = $this->validateConfiguration();
293
+        }
294
+
295
+
296
+        return $this->configured;
297
+    }
298
+
299
+    /**
300
+     * saves the current Configuration in the database and empties the
301
+     * cache
302
+     * @return null
303
+     */
304
+    public function saveConfiguration() {
305
+        $this->configuration->saveConfiguration();
306
+        $this->clearCache();
307
+    }
308
+
309
+    /**
310
+     * get the current LDAP configuration
311
+     * @return array
312
+     */
313
+    public function getConfiguration() {
314
+        $this->readConfiguration();
315
+        $config = $this->configuration->getConfiguration();
316
+        $cta = $this->configuration->getConfigTranslationArray();
317
+        $result = array();
318
+        foreach($cta as $dbkey => $configkey) {
319
+            switch($configkey) {
320
+                case 'homeFolderNamingRule':
321
+                    if(strpos($config[$configkey], 'attr:') === 0) {
322
+                        $result[$dbkey] = substr($config[$configkey], 5);
323
+                    } else {
324
+                        $result[$dbkey] = '';
325
+                    }
326
+                    break;
327
+                case 'ldapBase':
328
+                case 'ldapBaseUsers':
329
+                case 'ldapBaseGroups':
330
+                case 'ldapAttributesForUserSearch':
331
+                case 'ldapAttributesForGroupSearch':
332
+                    if(is_array($config[$configkey])) {
333
+                        $result[$dbkey] = implode("\n", $config[$configkey]);
334
+                        break;
335
+                    } //else follows default
336
+                default:
337
+                    $result[$dbkey] = $config[$configkey];
338
+            }
339
+        }
340
+        return $result;
341
+    }
342
+
343
+    private function doSoftValidation() {
344
+        //if User or Group Base are not set, take over Base DN setting
345
+        foreach(array('ldapBaseUsers', 'ldapBaseGroups') as $keyBase) {
346
+            $val = $this->configuration->$keyBase;
347
+            if(empty($val)) {
348
+                $this->configuration->$keyBase = $this->configuration->ldapBase;
349
+            }
350
+        }
351
+
352
+        foreach(array('ldapExpertUUIDUserAttr'  => 'ldapUuidUserAttribute',
353
+                        'ldapExpertUUIDGroupAttr' => 'ldapUuidGroupAttribute')
354
+                as $expertSetting => $effectiveSetting) {
355
+            $uuidOverride = $this->configuration->$expertSetting;
356
+            if(!empty($uuidOverride)) {
357
+                $this->configuration->$effectiveSetting = $uuidOverride;
358
+            } else {
359
+                $uuidAttributes = Access::UUID_ATTRIBUTES;
360
+                array_unshift($uuidAttributes, 'auto');
361
+                if(!in_array($this->configuration->$effectiveSetting,
362
+                            $uuidAttributes)
363
+                    && (!is_null($this->configID))) {
364
+                    $this->configuration->$effectiveSetting = 'auto';
365
+                    $this->configuration->saveConfiguration();
366
+                    \OCP\Util::writeLog('user_ldap',
367
+                                        'Illegal value for the '.
368
+                                        $effectiveSetting.', '.'reset to '.
369
+                                        'autodetect.', \OCP\Util::INFO);
370
+                }
371
+
372
+            }
373
+        }
374
+
375
+        $backupPort = (int)$this->configuration->ldapBackupPort;
376
+        if ($backupPort <= 0) {
377
+            $this->configuration->backupPort = $this->configuration->ldapPort;
378
+        }
379
+
380
+        //make sure empty search attributes are saved as simple, empty array
381
+        $saKeys = array('ldapAttributesForUserSearch',
382
+                        'ldapAttributesForGroupSearch');
383
+        foreach($saKeys as $key) {
384
+            $val = $this->configuration->$key;
385
+            if(is_array($val) && count($val) === 1 && empty($val[0])) {
386
+                $this->configuration->$key = array();
387
+            }
388
+        }
389
+
390
+        if((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
391
+            && $this->configuration->ldapTLS) {
392
+            $this->configuration->ldapTLS = false;
393
+            \OCP\Util::writeLog('user_ldap',
394
+                                'LDAPS (already using secure connection) and '.
395
+                                'TLS do not work together. Switched off TLS.',
396
+                                \OCP\Util::INFO);
397
+        }
398
+    }
399
+
400
+    /**
401
+     * @return bool
402
+     */
403
+    private function doCriticalValidation() {
404
+        $configurationOK = true;
405
+        $errorStr = 'Configuration Error (prefix '.
406
+            (string)$this->configPrefix .'): ';
407
+
408
+        //options that shall not be empty
409
+        $options = array('ldapHost', 'ldapPort', 'ldapUserDisplayName',
410
+                            'ldapGroupDisplayName', 'ldapLoginFilter');
411
+        foreach($options as $key) {
412
+            $val = $this->configuration->$key;
413
+            if(empty($val)) {
414
+                switch($key) {
415
+                    case 'ldapHost':
416
+                        $subj = 'LDAP Host';
417
+                        break;
418
+                    case 'ldapPort':
419
+                        $subj = 'LDAP Port';
420
+                        break;
421
+                    case 'ldapUserDisplayName':
422
+                        $subj = 'LDAP User Display Name';
423
+                        break;
424
+                    case 'ldapGroupDisplayName':
425
+                        $subj = 'LDAP Group Display Name';
426
+                        break;
427
+                    case 'ldapLoginFilter':
428
+                        $subj = 'LDAP Login Filter';
429
+                        break;
430
+                    default:
431
+                        $subj = $key;
432
+                        break;
433
+                }
434
+                $configurationOK = false;
435
+                \OCP\Util::writeLog('user_ldap',
436
+                                    $errorStr.'No '.$subj.' given!',
437
+                                    \OCP\Util::WARN);
438
+            }
439
+        }
440
+
441
+        //combinations
442
+        $agent = $this->configuration->ldapAgentName;
443
+        $pwd = $this->configuration->ldapAgentPassword;
444
+        if (
445
+            ($agent === ''  && $pwd !== '')
446
+            || ($agent !== '' && $pwd === '')
447
+        ) {
448
+            \OCP\Util::writeLog('user_ldap',
449
+                                $errorStr.'either no password is given for the '.
450
+                                'user agent or a password is given, but not an '.
451
+                                'LDAP agent.',
452
+                \OCP\Util::WARN);
453
+            $configurationOK = false;
454
+        }
455
+
456
+        $base = $this->configuration->ldapBase;
457
+        $baseUsers = $this->configuration->ldapBaseUsers;
458
+        $baseGroups = $this->configuration->ldapBaseGroups;
459
+
460
+        if(empty($base) && empty($baseUsers) && empty($baseGroups)) {
461
+            \OCP\Util::writeLog('user_ldap',
462
+                                $errorStr.'Not a single Base DN given.',
463
+                                \OCP\Util::WARN);
464
+            $configurationOK = false;
465
+        }
466
+
467
+        if(mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
468
+            === false) {
469
+            \OCP\Util::writeLog('user_ldap',
470
+                                $errorStr.'login filter does not contain %uid '.
471
+                                'place holder.',
472
+                                \OCP\Util::WARN);
473
+            $configurationOK = false;
474
+        }
475
+
476
+        return $configurationOK;
477
+    }
478
+
479
+    /**
480
+     * Validates the user specified configuration
481
+     * @return bool true if configuration seems OK, false otherwise
482
+     */
483
+    private function validateConfiguration() {
484
+
485
+        if($this->doNotValidate) {
486
+            //don't do a validation if it is a new configuration with pure
487
+            //default values. Will be allowed on changes via __set or
488
+            //setConfiguration
489
+            return false;
490
+        }
491
+
492
+        // first step: "soft" checks: settings that are not really
493
+        // necessary, but advisable. If left empty, give an info message
494
+        $this->doSoftValidation();
495
+
496
+        //second step: critical checks. If left empty or filled wrong, mark as
497
+        //not configured and give a warning.
498
+        return $this->doCriticalValidation();
499
+    }
500
+
501
+
502
+    /**
503
+     * Connects and Binds to LDAP
504
+     */
505
+    private function establishConnection() {
506
+        if(!$this->configuration->ldapConfigurationActive) {
507
+            return null;
508
+        }
509
+        static $phpLDAPinstalled = true;
510
+        if(!$phpLDAPinstalled) {
511
+            return false;
512
+        }
513
+        if(!$this->ignoreValidation && !$this->configured) {
514
+            \OCP\Util::writeLog('user_ldap',
515
+                                'Configuration is invalid, cannot connect',
516
+                                \OCP\Util::WARN);
517
+            return false;
518
+        }
519
+        if(!$this->ldapConnectionRes) {
520
+            if(!$this->ldap->areLDAPFunctionsAvailable()) {
521
+                $phpLDAPinstalled = false;
522
+                \OCP\Util::writeLog('user_ldap',
523
+                                    'function ldap_connect is not available. Make '.
524
+                                    'sure that the PHP ldap module is installed.',
525
+                                    \OCP\Util::ERROR);
526
+
527
+                return false;
528
+            }
529
+            if($this->configuration->turnOffCertCheck) {
530
+                if(putenv('LDAPTLS_REQCERT=never')) {
531
+                    \OCP\Util::writeLog('user_ldap',
532
+                        'Turned off SSL certificate validation successfully.',
533
+                        \OCP\Util::DEBUG);
534
+                } else {
535
+                    \OCP\Util::writeLog('user_ldap',
536
+                                        'Could not turn off SSL certificate validation.',
537
+                                        \OCP\Util::WARN);
538
+                }
539
+            }
540
+
541
+            $isOverrideMainServer = ($this->configuration->ldapOverrideMainServer
542
+                || $this->getFromCache('overrideMainServer'));
543
+            $isBackupHost = (trim($this->configuration->ldapBackupHost) !== "");
544
+            $bindStatus = false;
545
+            $error = -1;
546
+            try {
547
+                if (!$isOverrideMainServer) {
548
+                    $this->doConnect($this->configuration->ldapHost,
549
+                        $this->configuration->ldapPort);
550
+                    $bindStatus = $this->bind();
551
+                    $error = $this->ldap->isResource($this->ldapConnectionRes) ?
552
+                        $this->ldap->errno($this->ldapConnectionRes) : -1;
553
+                }
554
+                if($bindStatus === true) {
555
+                    return $bindStatus;
556
+                }
557
+            } catch (ServerNotAvailableException $e) {
558
+                if(!$isBackupHost) {
559
+                    throw $e;
560
+                }
561
+            }
562
+
563
+            //if LDAP server is not reachable, try the Backup (Replica!) Server
564
+            if($isBackupHost && ($error !== 0 || $isOverrideMainServer)) {
565
+                $this->doConnect($this->configuration->ldapBackupHost,
566
+                                    $this->configuration->ldapBackupPort);
567
+                $this->bindResult = [];
568
+                $bindStatus = $this->bind();
569
+                $error = $this->ldap->isResource($this->ldapConnectionRes) ?
570
+                    $this->ldap->errno($this->ldapConnectionRes) : -1;
571
+                if($bindStatus && $error === 0 && !$this->getFromCache('overrideMainServer')) {
572
+                    //when bind to backup server succeeded and failed to main server,
573
+                    //skip contacting him until next cache refresh
574
+                    $this->writeToCache('overrideMainServer', true);
575
+                }
576
+            }
577
+
578
+            return $bindStatus;
579
+        }
580
+        return null;
581
+    }
582
+
583
+    /**
584
+     * @param string $host
585
+     * @param string $port
586
+     * @return bool
587
+     * @throws \OC\ServerNotAvailableException
588
+     */
589
+    private function doConnect($host, $port) {
590
+        if ($host === '') {
591
+            return false;
592
+        }
593
+
594
+        $this->ldapConnectionRes = $this->ldap->connect($host, $port);
595
+
596
+        if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
597
+            throw new ServerNotAvailableException('Could not set required LDAP Protocol version.');
598
+        }
599
+
600
+        if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
601
+            throw new ServerNotAvailableException('Could not disable LDAP referrals.');
602
+        }
603
+
604
+        if($this->configuration->ldapTLS) {
605
+            if(!$this->ldap->startTls($this->ldapConnectionRes)) {
606
+                throw new ServerNotAvailableException('Start TLS failed, when connecting to LDAP host ' . $host . '.');
607
+            }
608
+        }
609
+
610
+        return true;
611
+    }
612
+
613
+    /**
614
+     * Binds to LDAP
615
+     */
616
+    public function bind() {
617
+        if(!$this->configuration->ldapConfigurationActive) {
618
+            return false;
619
+        }
620
+        $cr = $this->ldapConnectionRes;
621
+        if(!$this->ldap->isResource($cr)) {
622
+            $cr = $this->getConnectionResource();
623
+        }
624
+
625
+        if(
626
+            count($this->bindResult) !== 0
627
+            && $this->bindResult['dn'] === $this->configuration->ldapAgentName
628
+            && \OC::$server->getHasher()->verify(
629
+                $this->configPrefix . $this->configuration->ldapAgentPassword,
630
+                $this->bindResult['hash']
631
+            )
632
+        ) {
633
+            // don't attempt to bind again with the same data as before
634
+            // bind might have been invoked via getConnectionResource(),
635
+            // but we need results specifically for e.g. user login
636
+            return $this->bindResult['result'];
637
+        }
638
+
639
+        $ldapLogin = @$this->ldap->bind($cr,
640
+                                        $this->configuration->ldapAgentName,
641
+                                        $this->configuration->ldapAgentPassword);
642
+
643
+        $this->bindResult = [
644
+            'dn' => $this->configuration->ldapAgentName,
645
+            'hash' => \OC::$server->getHasher()->hash($this->configPrefix . $this->configuration->ldapAgentPassword),
646
+            'result' => $ldapLogin,
647
+        ];
648
+
649
+        if(!$ldapLogin) {
650
+            $errno = $this->ldap->errno($cr);
651
+
652
+            \OCP\Util::writeLog('user_ldap',
653
+                'Bind failed: ' . $errno . ': ' . $this->ldap->error($cr),
654
+                \OCP\Util::WARN);
655
+
656
+            // Set to failure mode, if LDAP error code is not LDAP_SUCCESS or LDAP_INVALID_CREDENTIALS
657
+            if($errno !== 0x00 && $errno !== 0x31) {
658
+                $this->ldapConnectionRes = null;
659
+            }
660
+
661
+            return false;
662
+        }
663
+        return true;
664
+    }
665 665
 
666 666
 }
Please login to merge, or discard this patch.
Spacing   +66 added lines, -66 removed lines patch added patch discarded remove patch
@@ -101,19 +101,19 @@  discard block
 block discarded – undo
101 101
 		$this->configuration = new Configuration($configPrefix,
102 102
 												 !is_null($configID));
103 103
 		$memcache = \OC::$server->getMemCacheFactory();
104
-		if($memcache->isAvailable()) {
104
+		if ($memcache->isAvailable()) {
105 105
 			$this->cache = $memcache->createDistributed();
106 106
 		}
107 107
 		$helper = new Helper(\OC::$server->getConfig());
108 108
 		$this->doNotValidate = !in_array($this->configPrefix,
109 109
 			$helper->getServerConfigurationPrefixes());
110 110
 		$this->hasPagedResultSupport =
111
-			(int)$this->configuration->ldapPagingSize !== 0
111
+			(int) $this->configuration->ldapPagingSize !== 0
112 112
 			|| $this->ldap->hasPagedResultSupport();
113 113
 	}
114 114
 
115 115
 	public function __destruct() {
116
-		if(!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
116
+		if (!$this->dontDestruct && $this->ldap->isResource($this->ldapConnectionRes)) {
117 117
 			@$this->ldap->unbind($this->ldapConnectionRes);
118 118
 			$this->bindResult = [];
119 119
 		}
@@ -134,11 +134,11 @@  discard block
 block discarded – undo
134 134
 	 * @return bool|mixed
135 135
 	 */
136 136
 	public function __get($name) {
137
-		if(!$this->configured) {
137
+		if (!$this->configured) {
138 138
 			$this->readConfiguration();
139 139
 		}
140 140
 
141
-		if($name === 'hasPagedResultSupport') {
141
+		if ($name === 'hasPagedResultSupport') {
142 142
 			return $this->hasPagedResultSupport;
143 143
 		}
144 144
 
@@ -154,7 +154,7 @@  discard block
 block discarded – undo
154 154
 		$before = $this->configuration->$name;
155 155
 		$this->configuration->$name = $value;
156 156
 		$after = $this->configuration->$name;
157
-		if($before !== $after) {
157
+		if ($before !== $after) {
158 158
 			if ($this->configID !== '' && $this->configID !== null) {
159 159
 				$this->configuration->saveConfiguration();
160 160
 			}
@@ -169,7 +169,7 @@  discard block
 block discarded – undo
169 169
 	 * @param bool $state
170 170
 	 */
171 171
 	public function setIgnoreValidation($state) {
172
-		$this->ignoreValidation = (bool)$state;
172
+		$this->ignoreValidation = (bool) $state;
173 173
 	}
174 174
 
175 175
 	/**
@@ -185,14 +185,14 @@  discard block
 block discarded – undo
185 185
 	 * Returns the LDAP handler
186 186
 	 */
187 187
 	public function getConnectionResource() {
188
-		if(!$this->ldapConnectionRes) {
188
+		if (!$this->ldapConnectionRes) {
189 189
 			$this->init();
190
-		} else if(!$this->ldap->isResource($this->ldapConnectionRes)) {
190
+		} else if (!$this->ldap->isResource($this->ldapConnectionRes)) {
191 191
 			$this->ldapConnectionRes = null;
192 192
 			$this->establishConnection();
193 193
 		}
194
-		if(is_null($this->ldapConnectionRes)) {
195
-			\OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server ' . $this->configuration->ldapHost, \OCP\Util::ERROR);
194
+		if (is_null($this->ldapConnectionRes)) {
195
+			\OCP\Util::writeLog('user_ldap', 'No LDAP Connection to server '.$this->configuration->ldapHost, \OCP\Util::ERROR);
196 196
 			throw new ServerNotAvailableException('Connection to LDAP server could not be established');
197 197
 		}
198 198
 		return $this->ldapConnectionRes;
@@ -202,7 +202,7 @@  discard block
 block discarded – undo
202 202
 	 * resets the connection resource
203 203
 	 */
204 204
 	public function resetConnectionResource() {
205
-		if(!is_null($this->ldapConnectionRes)) {
205
+		if (!is_null($this->ldapConnectionRes)) {
206 206
 			@$this->ldap->unbind($this->ldapConnectionRes);
207 207
 			$this->ldapConnectionRes = null;
208 208
 			$this->bindResult = [];
@@ -215,7 +215,7 @@  discard block
 block discarded – undo
215 215
 	 */
216 216
 	private function getCacheKey($key) {
217 217
 		$prefix = 'LDAP-'.$this->configID.'-'.$this->configPrefix.'-';
218
-		if(is_null($key)) {
218
+		if (is_null($key)) {
219 219
 			return $prefix;
220 220
 		}
221 221
 		return $prefix.md5($key);
@@ -226,10 +226,10 @@  discard block
 block discarded – undo
226 226
 	 * @return mixed|null
227 227
 	 */
228 228
 	public function getFromCache($key) {
229
-		if(!$this->configured) {
229
+		if (!$this->configured) {
230 230
 			$this->readConfiguration();
231 231
 		}
232
-		if(is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
232
+		if (is_null($this->cache) || !$this->configuration->ldapCacheTTL) {
233 233
 			return null;
234 234
 		}
235 235
 		$key = $this->getCacheKey($key);
@@ -244,10 +244,10 @@  discard block
 block discarded – undo
244 244
 	 * @return string
245 245
 	 */
246 246
 	public function writeToCache($key, $value) {
247
-		if(!$this->configured) {
247
+		if (!$this->configured) {
248 248
 			$this->readConfiguration();
249 249
 		}
250
-		if(is_null($this->cache)
250
+		if (is_null($this->cache)
251 251
 			|| !$this->configuration->ldapCacheTTL
252 252
 			|| !$this->configuration->ldapConfigurationActive) {
253 253
 			return null;
@@ -258,7 +258,7 @@  discard block
 block discarded – undo
258 258
 	}
259 259
 
260 260
 	public function clearCache() {
261
-		if(!is_null($this->cache)) {
261
+		if (!is_null($this->cache)) {
262 262
 			$this->cache->clear($this->getCacheKey(null));
263 263
 		}
264 264
 	}
@@ -270,7 +270,7 @@  discard block
 block discarded – undo
270 270
 	 * @return null
271 271
 	 */
272 272
 	private function readConfiguration($force = false) {
273
-		if((!$this->configured || $force) && !is_null($this->configID)) {
273
+		if ((!$this->configured || $force) && !is_null($this->configID)) {
274 274
 			$this->configuration->readConfiguration();
275 275
 			$this->configured = $this->validateConfiguration();
276 276
 		}
@@ -283,12 +283,12 @@  discard block
 block discarded – undo
283 283
 	 * @return boolean true if config validates, false otherwise. Check with $setParameters for detailed success on single parameters
284 284
 	 */
285 285
 	public function setConfiguration($config, &$setParameters = null) {
286
-		if(is_null($setParameters)) {
286
+		if (is_null($setParameters)) {
287 287
 			$setParameters = array();
288 288
 		}
289 289
 		$this->doNotValidate = false;
290 290
 		$this->configuration->setConfiguration($config, $setParameters);
291
-		if(count($setParameters) > 0) {
291
+		if (count($setParameters) > 0) {
292 292
 			$this->configured = $this->validateConfiguration();
293 293
 		}
294 294
 
@@ -315,10 +315,10 @@  discard block
 block discarded – undo
315 315
 		$config = $this->configuration->getConfiguration();
316 316
 		$cta = $this->configuration->getConfigTranslationArray();
317 317
 		$result = array();
318
-		foreach($cta as $dbkey => $configkey) {
319
-			switch($configkey) {
318
+		foreach ($cta as $dbkey => $configkey) {
319
+			switch ($configkey) {
320 320
 				case 'homeFolderNamingRule':
321
-					if(strpos($config[$configkey], 'attr:') === 0) {
321
+					if (strpos($config[$configkey], 'attr:') === 0) {
322 322
 						$result[$dbkey] = substr($config[$configkey], 5);
323 323
 					} else {
324 324
 						$result[$dbkey] = '';
@@ -329,7 +329,7 @@  discard block
 block discarded – undo
329 329
 				case 'ldapBaseGroups':
330 330
 				case 'ldapAttributesForUserSearch':
331 331
 				case 'ldapAttributesForGroupSearch':
332
-					if(is_array($config[$configkey])) {
332
+					if (is_array($config[$configkey])) {
333 333
 						$result[$dbkey] = implode("\n", $config[$configkey]);
334 334
 						break;
335 335
 					} //else follows default
@@ -342,23 +342,23 @@  discard block
 block discarded – undo
342 342
 
343 343
 	private function doSoftValidation() {
344 344
 		//if User or Group Base are not set, take over Base DN setting
345
-		foreach(array('ldapBaseUsers', 'ldapBaseGroups') as $keyBase) {
345
+		foreach (array('ldapBaseUsers', 'ldapBaseGroups') as $keyBase) {
346 346
 			$val = $this->configuration->$keyBase;
347
-			if(empty($val)) {
347
+			if (empty($val)) {
348 348
 				$this->configuration->$keyBase = $this->configuration->ldapBase;
349 349
 			}
350 350
 		}
351 351
 
352
-		foreach(array('ldapExpertUUIDUserAttr'  => 'ldapUuidUserAttribute',
352
+		foreach (array('ldapExpertUUIDUserAttr'  => 'ldapUuidUserAttribute',
353 353
 					  'ldapExpertUUIDGroupAttr' => 'ldapUuidGroupAttribute')
354 354
 				as $expertSetting => $effectiveSetting) {
355 355
 			$uuidOverride = $this->configuration->$expertSetting;
356
-			if(!empty($uuidOverride)) {
356
+			if (!empty($uuidOverride)) {
357 357
 				$this->configuration->$effectiveSetting = $uuidOverride;
358 358
 			} else {
359 359
 				$uuidAttributes = Access::UUID_ATTRIBUTES;
360 360
 				array_unshift($uuidAttributes, 'auto');
361
-				if(!in_array($this->configuration->$effectiveSetting,
361
+				if (!in_array($this->configuration->$effectiveSetting,
362 362
 							$uuidAttributes)
363 363
 					&& (!is_null($this->configID))) {
364 364
 					$this->configuration->$effectiveSetting = 'auto';
@@ -372,7 +372,7 @@  discard block
 block discarded – undo
372 372
 			}
373 373
 		}
374 374
 
375
-		$backupPort = (int)$this->configuration->ldapBackupPort;
375
+		$backupPort = (int) $this->configuration->ldapBackupPort;
376 376
 		if ($backupPort <= 0) {
377 377
 			$this->configuration->backupPort = $this->configuration->ldapPort;
378 378
 		}
@@ -380,14 +380,14 @@  discard block
 block discarded – undo
380 380
 		//make sure empty search attributes are saved as simple, empty array
381 381
 		$saKeys = array('ldapAttributesForUserSearch',
382 382
 						'ldapAttributesForGroupSearch');
383
-		foreach($saKeys as $key) {
383
+		foreach ($saKeys as $key) {
384 384
 			$val = $this->configuration->$key;
385
-			if(is_array($val) && count($val) === 1 && empty($val[0])) {
385
+			if (is_array($val) && count($val) === 1 && empty($val[0])) {
386 386
 				$this->configuration->$key = array();
387 387
 			}
388 388
 		}
389 389
 
390
-		if((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
390
+		if ((stripos($this->configuration->ldapHost, 'ldaps://') === 0)
391 391
 			&& $this->configuration->ldapTLS) {
392 392
 			$this->configuration->ldapTLS = false;
393 393
 			\OCP\Util::writeLog('user_ldap',
@@ -403,15 +403,15 @@  discard block
 block discarded – undo
403 403
 	private function doCriticalValidation() {
404 404
 		$configurationOK = true;
405 405
 		$errorStr = 'Configuration Error (prefix '.
406
-			(string)$this->configPrefix .'): ';
406
+			(string) $this->configPrefix.'): ';
407 407
 
408 408
 		//options that shall not be empty
409 409
 		$options = array('ldapHost', 'ldapPort', 'ldapUserDisplayName',
410 410
 						 'ldapGroupDisplayName', 'ldapLoginFilter');
411
-		foreach($options as $key) {
411
+		foreach ($options as $key) {
412 412
 			$val = $this->configuration->$key;
413
-			if(empty($val)) {
414
-				switch($key) {
413
+			if (empty($val)) {
414
+				switch ($key) {
415 415
 					case 'ldapHost':
416 416
 						$subj = 'LDAP Host';
417 417
 						break;
@@ -442,7 +442,7 @@  discard block
 block discarded – undo
442 442
 		$agent = $this->configuration->ldapAgentName;
443 443
 		$pwd = $this->configuration->ldapAgentPassword;
444 444
 		if (
445
-			($agent === ''  && $pwd !== '')
445
+			($agent === '' && $pwd !== '')
446 446
 			|| ($agent !== '' && $pwd === '')
447 447
 		) {
448 448
 			\OCP\Util::writeLog('user_ldap',
@@ -457,14 +457,14 @@  discard block
 block discarded – undo
457 457
 		$baseUsers = $this->configuration->ldapBaseUsers;
458 458
 		$baseGroups = $this->configuration->ldapBaseGroups;
459 459
 
460
-		if(empty($base) && empty($baseUsers) && empty($baseGroups)) {
460
+		if (empty($base) && empty($baseUsers) && empty($baseGroups)) {
461 461
 			\OCP\Util::writeLog('user_ldap',
462 462
 								$errorStr.'Not a single Base DN given.',
463 463
 								\OCP\Util::WARN);
464 464
 			$configurationOK = false;
465 465
 		}
466 466
 
467
-		if(mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
467
+		if (mb_strpos($this->configuration->ldapLoginFilter, '%uid', 0, 'UTF-8')
468 468
 		   === false) {
469 469
 			\OCP\Util::writeLog('user_ldap',
470 470
 								$errorStr.'login filter does not contain %uid '.
@@ -482,7 +482,7 @@  discard block
 block discarded – undo
482 482
 	 */
483 483
 	private function validateConfiguration() {
484 484
 
485
-		if($this->doNotValidate) {
485
+		if ($this->doNotValidate) {
486 486
 			//don't do a validation if it is a new configuration with pure
487 487
 			//default values. Will be allowed on changes via __set or
488 488
 			//setConfiguration
@@ -503,21 +503,21 @@  discard block
 block discarded – undo
503 503
 	 * Connects and Binds to LDAP
504 504
 	 */
505 505
 	private function establishConnection() {
506
-		if(!$this->configuration->ldapConfigurationActive) {
506
+		if (!$this->configuration->ldapConfigurationActive) {
507 507
 			return null;
508 508
 		}
509 509
 		static $phpLDAPinstalled = true;
510
-		if(!$phpLDAPinstalled) {
510
+		if (!$phpLDAPinstalled) {
511 511
 			return false;
512 512
 		}
513
-		if(!$this->ignoreValidation && !$this->configured) {
513
+		if (!$this->ignoreValidation && !$this->configured) {
514 514
 			\OCP\Util::writeLog('user_ldap',
515 515
 								'Configuration is invalid, cannot connect',
516 516
 								\OCP\Util::WARN);
517 517
 			return false;
518 518
 		}
519
-		if(!$this->ldapConnectionRes) {
520
-			if(!$this->ldap->areLDAPFunctionsAvailable()) {
519
+		if (!$this->ldapConnectionRes) {
520
+			if (!$this->ldap->areLDAPFunctionsAvailable()) {
521 521
 				$phpLDAPinstalled = false;
522 522
 				\OCP\Util::writeLog('user_ldap',
523 523
 									'function ldap_connect is not available. Make '.
@@ -526,8 +526,8 @@  discard block
 block discarded – undo
526 526
 
527 527
 				return false;
528 528
 			}
529
-			if($this->configuration->turnOffCertCheck) {
530
-				if(putenv('LDAPTLS_REQCERT=never')) {
529
+			if ($this->configuration->turnOffCertCheck) {
530
+				if (putenv('LDAPTLS_REQCERT=never')) {
531 531
 					\OCP\Util::writeLog('user_ldap',
532 532
 						'Turned off SSL certificate validation successfully.',
533 533
 						\OCP\Util::DEBUG);
@@ -551,24 +551,24 @@  discard block
 block discarded – undo
551 551
 					$error = $this->ldap->isResource($this->ldapConnectionRes) ?
552 552
 						$this->ldap->errno($this->ldapConnectionRes) : -1;
553 553
 				}
554
-				if($bindStatus === true) {
554
+				if ($bindStatus === true) {
555 555
 					return $bindStatus;
556 556
 				}
557 557
 			} catch (ServerNotAvailableException $e) {
558
-				if(!$isBackupHost) {
558
+				if (!$isBackupHost) {
559 559
 					throw $e;
560 560
 				}
561 561
 			}
562 562
 
563 563
 			//if LDAP server is not reachable, try the Backup (Replica!) Server
564
-			if($isBackupHost && ($error !== 0 || $isOverrideMainServer)) {
564
+			if ($isBackupHost && ($error !== 0 || $isOverrideMainServer)) {
565 565
 				$this->doConnect($this->configuration->ldapBackupHost,
566 566
 								 $this->configuration->ldapBackupPort);
567 567
 				$this->bindResult = [];
568 568
 				$bindStatus = $this->bind();
569 569
 				$error = $this->ldap->isResource($this->ldapConnectionRes) ?
570 570
 					$this->ldap->errno($this->ldapConnectionRes) : -1;
571
-				if($bindStatus && $error === 0 && !$this->getFromCache('overrideMainServer')) {
571
+				if ($bindStatus && $error === 0 && !$this->getFromCache('overrideMainServer')) {
572 572
 					//when bind to backup server succeeded and failed to main server,
573 573
 					//skip contacting him until next cache refresh
574 574
 					$this->writeToCache('overrideMainServer', true);
@@ -593,17 +593,17 @@  discard block
 block discarded – undo
593 593
 
594 594
 		$this->ldapConnectionRes = $this->ldap->connect($host, $port);
595 595
 
596
-		if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
596
+		if (!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_PROTOCOL_VERSION, 3)) {
597 597
 			throw new ServerNotAvailableException('Could not set required LDAP Protocol version.');
598 598
 		}
599 599
 
600
-		if(!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
600
+		if (!$this->ldap->setOption($this->ldapConnectionRes, LDAP_OPT_REFERRALS, 0)) {
601 601
 			throw new ServerNotAvailableException('Could not disable LDAP referrals.');
602 602
 		}
603 603
 
604
-		if($this->configuration->ldapTLS) {
605
-			if(!$this->ldap->startTls($this->ldapConnectionRes)) {
606
-				throw new ServerNotAvailableException('Start TLS failed, when connecting to LDAP host ' . $host . '.');
604
+		if ($this->configuration->ldapTLS) {
605
+			if (!$this->ldap->startTls($this->ldapConnectionRes)) {
606
+				throw new ServerNotAvailableException('Start TLS failed, when connecting to LDAP host '.$host.'.');
607 607
 			}
608 608
 		}
609 609
 
@@ -614,19 +614,19 @@  discard block
 block discarded – undo
614 614
 	 * Binds to LDAP
615 615
 	 */
616 616
 	public function bind() {
617
-		if(!$this->configuration->ldapConfigurationActive) {
617
+		if (!$this->configuration->ldapConfigurationActive) {
618 618
 			return false;
619 619
 		}
620 620
 		$cr = $this->ldapConnectionRes;
621
-		if(!$this->ldap->isResource($cr)) {
621
+		if (!$this->ldap->isResource($cr)) {
622 622
 			$cr = $this->getConnectionResource();
623 623
 		}
624 624
 
625
-		if(
625
+		if (
626 626
 			count($this->bindResult) !== 0
627 627
 			&& $this->bindResult['dn'] === $this->configuration->ldapAgentName
628 628
 			&& \OC::$server->getHasher()->verify(
629
-				$this->configPrefix . $this->configuration->ldapAgentPassword,
629
+				$this->configPrefix.$this->configuration->ldapAgentPassword,
630 630
 				$this->bindResult['hash']
631 631
 			)
632 632
 		) {
@@ -642,19 +642,19 @@  discard block
 block discarded – undo
642 642
 
643 643
 		$this->bindResult = [
644 644
 			'dn' => $this->configuration->ldapAgentName,
645
-			'hash' => \OC::$server->getHasher()->hash($this->configPrefix . $this->configuration->ldapAgentPassword),
645
+			'hash' => \OC::$server->getHasher()->hash($this->configPrefix.$this->configuration->ldapAgentPassword),
646 646
 			'result' => $ldapLogin,
647 647
 		];
648 648
 
649
-		if(!$ldapLogin) {
649
+		if (!$ldapLogin) {
650 650
 			$errno = $this->ldap->errno($cr);
651 651
 
652 652
 			\OCP\Util::writeLog('user_ldap',
653
-				'Bind failed: ' . $errno . ': ' . $this->ldap->error($cr),
653
+				'Bind failed: '.$errno.': '.$this->ldap->error($cr),
654 654
 				\OCP\Util::WARN);
655 655
 
656 656
 			// Set to failure mode, if LDAP error code is not LDAP_SUCCESS or LDAP_INVALID_CREDENTIALS
657
-			if($errno !== 0x00 && $errno !== 0x31) {
657
+			if ($errno !== 0x00 && $errno !== 0x31) {
658 658
 				$this->ldapConnectionRes = null;
659 659
 			}
660 660
 
Please login to merge, or discard this patch.