diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 4b623be68a..c0f718350f 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -817,6 +817,7 @@ phutil_register_library_map(array( 'PhabricatorAuthController' => 'applications/auth/controller/PhabricatorAuthController.php', 'PhabricatorAuthLoginController' => 'applications/auth/controller/PhabricatorAuthLoginController.php', 'PhabricatorAuthProvider' => 'applications/auth/provider/PhabricatorAuthProvider.php', + 'PhabricatorAuthProviderLDAP' => 'applications/auth/provider/PhabricatorAuthProviderLDAP.php', 'PhabricatorAuthProviderOAuth' => 'applications/auth/provider/PhabricatorAuthProviderOAuth.php', 'PhabricatorAuthProviderOAuthDisqus' => 'applications/auth/provider/PhabricatorAuthProviderOAuthDisqus.php', 'PhabricatorAuthProviderOAuthFacebook' => 'applications/auth/provider/PhabricatorAuthProviderOAuthFacebook.php', @@ -2680,6 +2681,7 @@ phutil_register_library_map(array( 'PhabricatorAuditReplyHandler' => 'PhabricatorMailReplyHandler', 'PhabricatorAuthController' => 'PhabricatorController', 'PhabricatorAuthLoginController' => 'PhabricatorAuthController', + 'PhabricatorAuthProviderLDAP' => 'PhabricatorAuthProvider', 'PhabricatorAuthProviderOAuth' => 'PhabricatorAuthProvider', 'PhabricatorAuthProviderOAuthDisqus' => 'PhabricatorAuthProviderOAuth', 'PhabricatorAuthProviderOAuthFacebook' => 'PhabricatorAuthProviderOAuth', diff --git a/src/applications/auth/provider/PhabricatorAuthProviderLDAP.php b/src/applications/auth/provider/PhabricatorAuthProviderLDAP.php new file mode 100644 index 0000000000..aedd731757 --- /dev/null +++ b/src/applications/auth/provider/PhabricatorAuthProviderLDAP.php @@ -0,0 +1,162 @@ +adapter) { + $adapter = id(new PhutilAuthAdapterLDAP()) + ->setHostname(PhabricatorEnv::getEnvConfig('ldap.hostname')) + ->setPort(PhabricatorEnv::getEnvConfig('ldap.port')) + ->setBaseDistinguishedName(PhabricatorEnv::getEnvConfig('ldap.base_dn')) + ->setSearchAttribute( + PhabricatorEnv::getEnvConfig('ldap.search_attribute')) + ->setUsernameAttribute( + PhabricatorEnv::getEnvConfig('ldap.username-attribute')) + ->setLDAPVersion(PhabricatorEnv::getEnvConfig('ldap.version')) + ->setLDAPReferrals(PhabricatorEnv::getEnvConfig('ldap.referrals')) + ->setLDAPStartTLS(PhabricatorEnv::getEnvConfig('ldap.start-tls')) + ->setAnonymousUsername( + PhabricatorEnv::getEnvConfig('ldap.anonymous-user-name')) + ->setAnonymousPassword( + new PhutilOpaqueEnvelope( + PhabricatorEnv::getEnvConfig('ldap.anonymous-user-password'))) + ->setSearchFirst(PhabricatorEnv::getEnvConfig('ldap.search-first')) + ->setActiveDirectoryDomain( + PhabricatorEnv::getEnvConfig('ldap.activedirectory_domain')); + $this->adapter = $adapter; + } + return $this->adapter; + } + + public function shouldAllowLogin() { + return true; + } + + public function shouldAllowRegistration() { + return true; + } + + public function shouldAllowAccountLink() { + return false; + } + + public function shouldAllowAccountUnlink() { + return false; + } + + public function buildLoginForm( + PhabricatorAuthStartController $controller) { + + $request = $controller->getRequest(); + return $this->renderLoginForm($request); + } + + private function renderLoginForm(AphrontRequest $request) { + + $viewer = $request->getUser(); + + $submit = id(new AphrontFormSubmitControl()) + ->setValue(pht('Login or Register')); + + $header = id(new PhabricatorHeaderView()) + ->setHeader(pht('Login with LDAP')); + + $v_user = $request->getStr('ldap_username'); + + $e_user = null; + $e_pass = null; + + $errors = array(); + if ($request->isHTTPPost()) { + // NOTE: This is intentionally vague so as not to disclose whether a + // given username exists. + $e_user = pht('Invalid'); + $e_pass = pht('Invalid'); + $errors[] = pht('Username or password are incorrect.'); + } + + $form = id(new AphrontFormView()) + ->setAction($this->getLoginURI()) + ->setUser($viewer) + ->setFlexible(true) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('LDAP Username') + ->setName('ldap_username') + ->setValue($v_user) + ->setError($e_user)) + ->appendChild( + id(new AphrontFormPasswordControl()) + ->setLabel('LDAP Password') + ->setName('ldap_password') + ->setError($e_pass)) + ->appendChild($submit); + + if ($errors) { + $errors = id(new AphrontErrorView())->setErrors($errors); + } + + return array( + $errors, + $header, + $form, + ); + } + + public function processLoginRequest( + PhabricatorAuthLoginController $controller) { + + $request = $controller->getRequest(); + $viewer = $request->getUser(); + $response = null; + $account = null; + + $username = $request->getStr('ldap_username'); + $password = $request->getStr('ldap_password'); + $has_password = strlen($password); + $password = new PhutilOpaqueEnvelope($password); + + if (!strlen($username) || !$has_password) { + $response = $controller->buildProviderPageResponse( + $this, + $this->renderLoginForm($request)); + return array($account, $response); + } + + try { + if (strlen($username) && $has_password) { + $adapter = $this->getAdapter(); + $adapter->setLoginUsername($username); + $adapter->setLoginPassword($password); + + // TODO: This calls ldap_bind() eventually, which dumps cleartext + // passwords to the error log. See note in PhutilAuthAdapterLDAP. + // See T3351. + + DarkConsoleErrorLogPluginAPI::enableDiscardMode(); + $account_id = $adapter->getAccountID(); + DarkConsoleErrorLogPluginAPI::disableDiscardMode(); + } else { + throw new Exception("Username and password are required!"); + } + } catch (Exception $ex) { + // TODO: Make this cleaner. + throw $ex; + } + + return array($this->loadOrCreateAccount($account_id), $response); + } + +} diff --git a/src/applications/auth/provider/PhabricatorAuthProviderPassword.php b/src/applications/auth/provider/PhabricatorAuthProviderPassword.php index d01403f9c5..b8a6ec5da0 100644 --- a/src/applications/auth/provider/PhabricatorAuthProviderPassword.php +++ b/src/applications/auth/provider/PhabricatorAuthProviderPassword.php @@ -164,7 +164,6 @@ final class PhabricatorAuthProviderPassword if (!$require_captcha || $captcha_valid) { $username_or_email = $request->getStr('username'); - if (strlen($username_or_email)) { $user = id(new PhabricatorUser())->loadOneWhere( 'username = %s', @@ -173,13 +172,13 @@ final class PhabricatorAuthProviderPassword if (!$user) { $user = PhabricatorUser::loadOneWithEmailAddress($username_or_email); } - } - if ($user) { - $envelope = new PhutilOpaqueEnvelope($request->getStr('password')); - if ($user->comparePassword($envelope)) { - $account = $this->loadOrCreateAccount($user->getPHID()); - $log_user = $user; + if ($user) { + $envelope = new PhutilOpaqueEnvelope($request->getStr('password')); + if ($user->comparePassword($envelope)) { + $account = $this->loadOrCreateAccount($user->getPHID()); + $log_user = $user; + } } } }