diff --git a/conf/default.conf.php b/conf/default.conf.php index 15a0f3742f..889e80591f 100644 --- a/conf/default.conf.php +++ b/conf/default.conf.php @@ -548,6 +548,27 @@ return array( // The Google "Client Secret" to use for Google API access. 'google.application-secret' => null, +// -- LDAP Auth ----------------------------------------------------- // + // Enable ldap auth + 'ldap.auth-enabled' => false, + + // The LDAP server hostname + 'ldap.hostname' => '', + + // The LDAP base domain name + 'ldap.base_dn' => '', + + // The attribute to be regarded as 'username'. Has to be unique + 'ldap.search_attribute' => '', + + // The attribute(s) to be regarded as 'real name'. + // If more then one attribute is supplied the values of the attributes in + // the array will be joined + 'ldap.real_name_attributes' => array(), + + // The LDAP version + 'ldap.version' => 3, + // -- Disqus OAuth ---------------------------------------------------------- // // Can users use Disqus credentials to login to Phabricator? diff --git a/resources/sql/patches/ldapinfo.sql b/resources/sql/patches/ldapinfo.sql new file mode 100644 index 0000000000..16ff1fc496 --- /dev/null +++ b/resources/sql/patches/ldapinfo.sql @@ -0,0 +1,9 @@ +CREATE TABLE {$NAMESPACE}_user.user_ldapinfo ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `userID` int(10) unsigned NOT NULL, + `ldapUsername` varchar(255) NOT NULL, + `dateCreated` int(10) unsigned NOT NULL, + `dateModified` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY (`userID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 278fb7e335..b5dedd5606 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -699,6 +699,10 @@ phutil_register_library_map(array( 'PhabricatorInlineSummaryView' => 'infrastructure/diff/view/PhabricatorInlineSummaryView.php', 'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/PhabricatorJavelinLinter.php', 'PhabricatorJumpNavHandler' => 'applications/search/engine/PhabricatorJumpNavHandler.php', + 'PhabricatorLDAPLoginController' => 'applications/auth/controller/PhabricatorLDAPLoginController.php', + 'PhabricatorLDAPProvider' => 'applications/auth/ldap/PhabricatorLDAPProvider.php', + 'PhabricatorLDAPRegistrationController' => 'applications/auth/controller/PhabricatorLDAPRegistrationController.php', + 'PhabricatorLDAPUnlinkController' => 'applications/auth/controller/PhabricatorLDAPUnlinkController.php', 'PhabricatorLintEngine' => 'infrastructure/lint/PhabricatorLintEngine.php', 'PhabricatorLiskDAO' => 'applications/base/storage/PhabricatorLiskDAO.php', 'PhabricatorLocalDiskFileStorageEngine' => 'applications/files/engine/PhabricatorLocalDiskFileStorageEngine.php', @@ -973,6 +977,8 @@ phutil_register_library_map(array( 'PhabricatorUserEmail' => 'applications/people/storage/PhabricatorUserEmail.php', 'PhabricatorUserEmailPreferenceSettingsPanelController' => 'applications/people/controller/settings/panels/PhabricatorUserEmailPreferenceSettingsPanelController.php', 'PhabricatorUserEmailSettingsPanelController' => 'applications/people/controller/settings/panels/PhabricatorUserEmailSettingsPanelController.php', + 'PhabricatorUserLDAPInfo' => 'applications/people/storage/PhabricatorUserLDAPInfo.php', + 'PhabricatorUserLDAPSettingsPanelController' => 'applications/people/controller/settings/panels/PhabricatorUserLDAPSettingsPanelController.php', 'PhabricatorUserLog' => 'applications/people/storage/PhabricatorUserLog.php', 'PhabricatorUserOAuthInfo' => 'applications/people/storage/PhabricatorUserOAuthInfo.php', 'PhabricatorUserOAuthSettingsPanelController' => 'applications/people/controller/settings/panels/PhabricatorUserOAuthSettingsPanelController.php', @@ -1669,6 +1675,9 @@ phutil_register_library_map(array( 'PhabricatorInlineCommentController' => 'PhabricatorController', 'PhabricatorInlineSummaryView' => 'AphrontView', 'PhabricatorJavelinLinter' => 'ArcanistLinter', + 'PhabricatorLDAPLoginController' => 'PhabricatorAuthController', + 'PhabricatorLDAPRegistrationController' => 'PhabricatorAuthController', + 'PhabricatorLDAPUnlinkController' => 'PhabricatorAuthController', 'PhabricatorLintEngine' => 'PhutilLintEngine', 'PhabricatorLiskDAO' => 'LiskDAO', 'PhabricatorLocalDiskFileStorageEngine' => 'PhabricatorFileStorageEngine', @@ -1901,6 +1910,8 @@ phutil_register_library_map(array( 'PhabricatorUserEmail' => 'PhabricatorUserDAO', 'PhabricatorUserEmailPreferenceSettingsPanelController' => 'PhabricatorUserSettingsPanelController', 'PhabricatorUserEmailSettingsPanelController' => 'PhabricatorUserSettingsPanelController', + 'PhabricatorUserLDAPInfo' => 'PhabricatorUserDAO', + 'PhabricatorUserLDAPSettingsPanelController' => 'PhabricatorUserSettingsPanelController', 'PhabricatorUserLog' => 'PhabricatorUserDAO', 'PhabricatorUserOAuthInfo' => 'PhabricatorUserDAO', 'PhabricatorUserOAuthSettingsPanelController' => 'PhabricatorUserSettingsPanelController', diff --git a/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php index 71532f4e92..3e047ff694 100644 --- a/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/configuration/AphrontDefaultApplicationConfiguration.php @@ -146,6 +146,11 @@ class AphrontDefaultApplicationConfiguration ), ), + '/ldap/' => array( + 'login/' => 'PhabricatorLDAPLoginController', + 'unlink/' => 'PhabricatorLDAPUnlinkController', + ), + '/oauthserver/' => array( 'auth/' => 'PhabricatorOAuthServerAuthController', 'test/' => 'PhabricatorOAuthServerTestController', diff --git a/src/applications/auth/controller/PhabricatorLDAPLoginController.php b/src/applications/auth/controller/PhabricatorLDAPLoginController.php new file mode 100644 index 0000000000..0525625373 --- /dev/null +++ b/src/applications/auth/controller/PhabricatorLDAPLoginController.php @@ -0,0 +1,187 @@ +provider = new PhabricatorLDAPProvider(); + } + + public function processRequest() { + if (!$this->provider->isProviderEnabled()) { + return new Aphront400Response(); + } + + $current_user = $this->getRequest()->getUser(); + $request = $this->getRequest(); + + if ($request->isFormPost()) { + try { + $this->provider->auth($request->getStr('username'), + $request->getStr('password')); + + } catch (Exception $e) { + $errors[] = $e->getMessage(); + } + + if (empty($errors)) { + $ldap_info = $this->retrieveLDAPInfo($this->provider); + + if ($current_user->getPHID()) { + if ($ldap_info->getID()) { + $existing_ldap = id(new PhabricatorUserLDAPInfo())->loadOneWhere( + 'userID = %d', + $current_user->getID()); + + if ($ldap_info->getUserID() != $current_user->getID() || + $existing_ldap) { + $dialog = new AphrontDialogView(); + $dialog->setUser($current_user); + $dialog->setTitle('Already Linked to Another Account'); + $dialog->appendChild( + '

The LDAP account you just authorized is already linked to '. + 'another Phabricator account. Before you can link it to a '. + 'different LDAP account, you must unlink the old account.

' + ); + $dialog->addCancelButton('/settings/page/ldap/'); + + return id(new AphrontDialogResponse())->setDialog($dialog); + } else { + return id(new AphrontRedirectResponse()) + ->setURI('/settings/page/ldap/'); + } + } + + if (!$request->isDialogFormPost()) { + $dialog = new AphrontDialogView(); + $dialog->setUser($current_user); + $dialog->setTitle('Link LDAP Account'); + $dialog->appendChild( + '

Link your LDAP account to your Phabricator account?

'); + $dialog->addHiddenInput('username', $request->getStr('username')); + $dialog->addHiddenInput('password', $request->getStr('password')); + $dialog->addSubmitButton('Link Accounts'); + $dialog->addCancelButton('/settings/page/ldap/'); + + return id(new AphrontDialogResponse())->setDialog($dialog); + } + + $ldap_info->setUserID($current_user->getID()); + + $this->saveLDAPInfo($ldap_info); + + return id(new AphrontRedirectResponse()) + ->setURI('/settings/page/ldap/'); + } + + if ($ldap_info->getID()) { + $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); + + $known_user = id(new PhabricatorUser())->load( + $ldap_info->getUserID()); + + $session_key = $known_user->establishSession('web'); + + $this->saveLDAPInfo($ldap_info); + + $request->setCookie('phusr', $known_user->getUsername()); + $request->setCookie('phsid', $session_key); + + $uri = new PhutilURI('/login/validate/'); + $uri->setQueryParams( + array( + 'phusr' => $known_user->getUsername(), + )); + + return id(new AphrontRedirectResponse())->setURI((string)$uri); + } + + $controller = newv('PhabricatorLDAPRegistrationController', + array($this->getRequest())); + $controller->setLDAPProvider($this->provider); + $controller->setLDAPInfo($ldap_info); + + return $this->delegateToController($controller); + } + } + + $ldap_username = $request->getCookie('phusr'); + $ldap_form = new AphrontFormView(); + $ldap_form + ->setUser($request->getUser()) + ->setAction('/ldap/login/') + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('LDAP username') + ->setName('username') + ->setValue($ldap_username)) + ->appendChild( + id(new AphrontFormPasswordControl()) + ->setLabel('Password') + ->setName('password')); + + $ldap_form + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue('Login')); + + $panel = new AphrontPanelView(); + $panel->setWidth(AphrontPanelView::WIDTH_FORM); + $panel->appendChild('

LDAP login

'); + $panel->appendChild($ldap_form); + + if (isset($errors) && count($errors) > 0) { + $error_view = new AphrontErrorView(); + $error_view->setTitle('Login Failed'); + $error_view->setErrors($errors); + } + + return $this->buildStandardPageResponse( + array( + isset($error_view) ? $error_view : null, + $panel, + ), + array( + 'title' => 'Login', + )); + } + + private function retrieveLDAPInfo(PhabricatorLDAPProvider $provider) { + $ldap_info = id(new PhabricatorUserLDAPInfo())->loadOneWhere( + 'ldapUsername = %s', + $provider->retrieveUsername()); + + if (!$ldap_info) { + $ldap_info = new PhabricatorUserLDAPInfo(); + $ldap_info->setLDAPUsername($provider->retrieveUsername()); + } + + return $ldap_info; + } + + private function saveLDAPInfo(PhabricatorUserLDAPInfo $info) { + // UNGUARDED WRITES: Logging-in users don't have their CSRF set up yet. + $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); + $info->save(); + } +} diff --git a/src/applications/auth/controller/PhabricatorLDAPRegistrationController.php b/src/applications/auth/controller/PhabricatorLDAPRegistrationController.php new file mode 100644 index 0000000000..111c21a9e3 --- /dev/null +++ b/src/applications/auth/controller/PhabricatorLDAPRegistrationController.php @@ -0,0 +1,236 @@ +ldapProvider = $provider; + return $this; + } + + public function getLDAProvider() { + return $this->ldapProvider; + } + + public function setLDAPInfo($info) { + $this->ldapInfo = $info; + return $this; + } + + public function getLDAPInfo() { + return $this->ldapInfo; + } + + public function processRequest() { + $provider = $this->getLDAProvider(); + $ldap_info = $this->getLDAPInfo(); + $request = $this->getRequest(); + + $errors = array(); + $e_username = true; + $e_email = true; + $e_realname = true; + + $user = new PhabricatorUser(); + $user->setUsername(); + $user->setRealname($provider->retrieveUserRealName()); + + $new_email = $provider->retrieveUserEmail(); + + if ($new_email) { + // If the user's LDAP provider account has an email address but the + // email address domain is not allowed by the Phabricator configuration, + // we just pretend the provider did not supply an address. + // + // For instance, if the user uses LDAP Auth and their email address + // is "joe@personal.com" but Phabricator is configured to require users + // use "@company.com" addresses, we show a prompt below and tell the user + // to provide their "@company.com" address. They can still use the LDAP + // account to login, they just need to associate their account with an + // allowed address. + // + // If the email address is fine, we just use it and don't prompt the user. + if (!PhabricatorUserEmail::isAllowedAddress($new_email)) { + $new_email = null; + } + } + + $show_email_input = ($new_email === null); + + if ($request->isFormPost()) { + $user->setUsername($request->getStr('username')); + $username = $user->getUsername(); + if (!strlen($user->getUsername())) { + $e_username = 'Required'; + $errors[] = 'Username is required.'; + } else if (!PhabricatorUser::validateUsername($username)) { + $e_username = 'Invalid'; + $errors[] = PhabricatorUser::describeValidUsername(); + } else { + $e_username = null; + } + + if (!$new_email) { + $new_email = trim($request->getStr('email')); + if (!$new_email) { + $e_email = 'Required'; + $errors[] = 'Email is required.'; + } else { + $e_email = null; + } + } + + if ($new_email) { + if (!PhabricatorUserEmail::isAllowedAddress($new_email)) { + $e_email = 'Invalid'; + $errors[] = PhabricatorUserEmail::describeAllowedAddresses(); + } + } + + if (!strlen($user->getRealName())) { + $user->setRealName($request->getStr('realname')); + if (!strlen($user->getRealName())) { + $e_realname = 'Required'; + $errors[] = 'Real name is required.'; + } else { + $e_realname = null; + } + } + + if (!$errors) { + try { + // NOTE: We don't verify LDAP email addresses by default because + // LDAP providers might associate email addresses with accounts that + // haven't actually verified they own them. We could selectively + // auto-verify some providers that we trust here, but the stakes for + // verifying an email address are high because having a corporate + // address at a company is sometimes the key to the castle. + + $email_obj = id(new PhabricatorUserEmail()) + ->setAddress($new_email) + ->setIsVerified(0); + + id(new PhabricatorUserEditor()) + ->setActor($user) + ->createNewUser($user, $email_obj); + + $ldap_info->setUserID($user->getID()); + $ldap_info->save(); + + $session_key = $user->establishSession('web'); + $request->setCookie('phusr', $user->getUsername()); + $request->setCookie('phsid', $session_key); + + $email_obj->sendVerificationEmail($user); + + return id(new AphrontRedirectResponse())->setURI('/'); + } catch (AphrontQueryDuplicateKeyException $exception) { + + $same_username = id(new PhabricatorUser())->loadOneWhere( + 'userName = %s', + $user->getUserName()); + + $same_email = id(new PhabricatorUserEmail())->loadOneWhere( + 'address = %s', + $new_email); + + if ($same_username) { + $e_username = 'Duplicate'; + $errors[] = 'That username or email is not unique.'; + } else if ($same_email) { + $e_email = 'Duplicate'; + $errors[] = 'That email is not unique.'; + } else { + throw $exception; + } + } + } + } + + + $error_view = null; + if ($errors) { + $error_view = new AphrontErrorView(); + $error_view->setTitle('Registration Failed'); + $error_view->setErrors($errors); + } + + // Strip the URI down to the path, because otherwise we'll trigger + // external CSRF protection (by having a protocol in the form "action") + // and generate a form with no CSRF token. + $action_uri = new PhutilURI('/ldap/login/'); + $action_path = $action_uri->getPath(); + + $form = new AphrontFormView(); + $form + ->setUser($request->getUser()) + ->setAction($action_path) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('Username') + ->setName('username') + ->setValue($user->getUsername()) + ->setError($e_username)); + + $form->appendChild( + id(new AphrontFormPasswordControl()) + ->setLabel('Password') + ->setName('password')); + + if ($show_email_input) { + $form->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('Email') + ->setName('email') + ->setValue($request->getStr('email')) + ->setError($e_email)); + } + + if ($provider->retrieveUserRealName() === null) { + $form->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('Real Name') + ->setName('realname') + ->setValue($request->getStr('realname')) + ->setError($e_realname)); + } + + $form + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue('Create Account')); + + $panel = new AphrontPanelView(); + $panel->setHeader('Create New Account'); + $panel->setWidth(AphrontPanelView::WIDTH_FORM); + $panel->appendChild($form); + + return $this->buildStandardPageResponse( + array( + $error_view, + $panel, + ), + array( + 'title' => 'Create New Account', + )); + } + +} diff --git a/src/applications/auth/controller/PhabricatorLDAPUnlinkController.php b/src/applications/auth/controller/PhabricatorLDAPUnlinkController.php new file mode 100644 index 0000000000..c793716d5d --- /dev/null +++ b/src/applications/auth/controller/PhabricatorLDAPUnlinkController.php @@ -0,0 +1,52 @@ +getRequest(); + $user = $request->getUser(); + + $ldap_info = id(new PhabricatorUserLDAPInfo())->loadOneWhere( + 'userID = %d', + $user->getID()); + + if (!$ldap_info) { + return new Aphront400Response(); + } + + if (!$request->isDialogFormPost()) { + $dialog = new AphrontDialogView(); + $dialog->setUser($user); + $dialog->setTitle('Really unlink account?'); + $dialog->appendChild( + '

You will not be able to login using this account '. + 'once you unlink it. Continue?

'); + $dialog->addSubmitButton('Unlink Account'); + $dialog->addCancelButton('/settings/page/ldap/'); + + return id(new AphrontDialogResponse())->setDialog($dialog); + } + + $ldap_info->delete(); + + return id(new AphrontRedirectResponse()) + ->setURI('/settings/page/ldap/'); + } + +} diff --git a/src/applications/auth/controller/PhabricatorLoginController.php b/src/applications/auth/controller/PhabricatorLoginController.php index 5e7df9ee59..bedd20965a 100644 --- a/src/applications/auth/controller/PhabricatorLoginController.php +++ b/src/applications/auth/controller/PhabricatorLoginController.php @@ -187,6 +187,30 @@ final class PhabricatorLoginController // $panel->setCreateButton('Register New Account', '/login/register/'); $forms['Phabricator Login'] = $form; + + $ldap_provider = new PhabricatorLDAPProvider(); + if ($ldap_provider->isProviderEnabled()) { + $ldap_form = new AphrontFormView(); + $ldap_form + ->setUser($request->getUser()) + ->setAction('/ldap/login/') + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('LDAP username') + ->setName('username') + ->setValue($username_or_email)) + ->appendChild( + id(new AphrontFormPasswordControl()) + ->setLabel('Password') + ->setName('password')); + + $ldap_form + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue('Login')); + + $forms['LDAP Login'] = $ldap_form; + } } $providers = PhabricatorOAuthProvider::getAllProviders(); diff --git a/src/applications/auth/ldap/PhabricatorLDAPProvider.php b/src/applications/auth/ldap/PhabricatorLDAPProvider.php new file mode 100644 index 0000000000..d1d0b29c31 --- /dev/null +++ b/src/applications/auth/ldap/PhabricatorLDAPProvider.php @@ -0,0 +1,149 @@ +connection)) { + ldap_unbind($this->connection); + } + } + + public function isProviderEnabled() { + return PhabricatorEnv::getEnvConfig('ldap.auth-enabled'); + } + + public function getHostname() { + return PhabricatorEnv::getEnvConfig('ldap.hostname'); + } + + public function getBaseDN() { + return PhabricatorEnv::getEnvConfig('ldap.base_dn'); + } + + public function getSearchAttribute() { + return PhabricatorEnv::getEnvConfig('ldap.search_attribute'); + } + + public function getLDAPVersion() { + return PhabricatorEnv::getEnvConfig('ldap.version'); + } + + public function retrieveUserEmail() { + return $this->userData['mail'][0]; + } + + public function retrieveUserRealName() { + $name_attributes = PhabricatorEnv::getEnvConfig( + 'ldap.real_name_attributes'); + + $real_name = ''; + if (is_array($name_attributes)) { + foreach ($name_attributes AS $attribute) { + if (isset($this->userData[$attribute][0])) { + $real_name .= $this->userData[$attribute][0] . ' '; + } + } + + trim($real_name); + } else if (isset($this->userData[$name_attributes][0])) { + $real_name = $this->userData[$name_attributes][0]; + } + + if ($real_name == '') { + return null; + } + + return $real_name; + } + + public function retrieveUsername() { + return $this->userData[$this->getSearchAttribute()][0]; + } + + public function getConnection() { + if (!isset($this->connection)) { + $this->connection = ldap_connect($this->getHostname()); + + if (!$this->connection) { + throw new Exception('Could not connect to LDAP host at ' . + $this->getHostname()); + } + + ldap_set_option($this->connection, LDAP_OPT_PROTOCOL_VERSION, + $this->getLDAPVersion()); + } + + return $this->connection; + } + + public function getUserData() { + return $this->userData; + } + + public function auth($username, $password) { + if (strlen(trim($username)) == 0 || strlen(trim($password)) == 0) { + throw new Exception('Username and/or password can not be empty'); + } + + $result = ldap_bind($this->getConnection(), + $this->getSearchAttribute() . '=' . $username . ',' . + $this->getBaseDN(), + $password); + + if (!$result) { + throw new Exception('Bad username/password.'); + } + + $this->userData = $this->getUser($username); + return $this->userData; + } + + private function getUser($username) { + $result = ldap_search($this->getConnection(), $this->getBaseDN(), + $this->getSearchAttribute() . '=' . $username); + + if (!$result) { + throw new Exception('Search failed. Please check your LDAP and HTTP '. + 'logs for more information.'); + } + + $entries = ldap_get_entries($this->getConnection(), $result); + + if ($entries === false) { + throw new Exception('Could not get entries'); + } + + if ($entries['count'] > 1) { + throw new Exception('Found more then one user with this ' . + $this->getSearchAttribute()); + } + + if ($entries['count'] == 0) { + throw new Exception('Could not find user'); + } + + return $entries[0]; + } +} diff --git a/src/applications/people/controller/PhabricatorUserSettingsController.php b/src/applications/people/controller/PhabricatorUserSettingsController.php index a5d3dc4b1f..199cb5cad9 100644 --- a/src/applications/people/controller/PhabricatorUserSettingsController.php +++ b/src/applications/people/controller/PhabricatorUserSettingsController.php @@ -65,6 +65,9 @@ final class PhabricatorUserSettingsController case 'search': $delegate = new PhabricatorUserSearchSettingsPanelController($request); break; + case 'ldap': + $delegate = new PhabricatorUserLDAPSettingsPanelController($request); + break; default: $delegate = new PhabricatorUserOAuthSettingsPanelController($request); $delegate->setOAuthProvider($oauth_providers[$this->page]); @@ -125,6 +128,11 @@ final class PhabricatorUserSettingsController $items[$key] = $name.' Account'; } + $ldap_provider = new PhabricatorLDAPProvider(); + if ($ldap_provider->isProviderEnabled()) { + $items['ldap'] = 'LDAP Account'; + } + if ($items) { $sidenav->addSpacer(); $sidenav->addLabel('Linked Accounts'); diff --git a/src/applications/people/controller/settings/panels/PhabricatorUserLDAPSettingsPanelController.php b/src/applications/people/controller/settings/panels/PhabricatorUserLDAPSettingsPanelController.php new file mode 100644 index 0000000000..c422c1db73 --- /dev/null +++ b/src/applications/people/controller/settings/panels/PhabricatorUserLDAPSettingsPanelController.php @@ -0,0 +1,87 @@ +getRequest(); + $user = $request->getUser(); + + $ldap_info = id(new PhabricatorUserLDAPInfo())->loadOneWhere( + 'userID = %d', + $user->getID()); + + $forms = array(); + + if (!$ldap_info) { + $unlink = 'Link LDAP Account'; + $unlink_form = new AphrontFormView(); + $unlink_form + ->setUser($user) + ->setAction('/ldap/login/') + ->appendChild( + '

There is currently no '. + 'LDAP account linked to your Phabricator account. You can link an ' . + 'account, which will allow you to use it to log into Phabricator

') + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('LDAP username') + ->setName('username')) + ->appendChild( + id(new AphrontFormPasswordControl()) + ->setLabel('Password') + ->setName('password')) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue("Link LDAP Account \xC2\xBB")); + + $forms['Link Account'] = $unlink_form; + } else { + $unlink = 'Unlink LDAP Account'; + $unlink_form = new AphrontFormView(); + $unlink_form + ->setUser($user) + ->appendChild( + '

You may unlink this account '. + 'from your LDAP account. This will prevent you from logging in with '. + 'your LDAP credentials.

') + ->appendChild( + id(new AphrontFormSubmitControl()) + ->addCancelButton('/ldap/unlink/', $unlink)); + + $forms['Unlink Account'] = $unlink_form; + } + + $panel = new AphrontPanelView(); + $panel->setHeader('LDAP Account Settings'); + $panel->setWidth(AphrontPanelView::WIDTH_FORM); + foreach ($forms as $name => $form) { + if ($name) { + $panel->appendChild('

'.$name.'


'); + } + $panel->appendChild($form); + } + + return id(new AphrontNullView()) + ->appendChild( + array( + $panel, + )); + } +} diff --git a/src/applications/people/storage/PhabricatorUserLDAPInfo.php b/src/applications/people/storage/PhabricatorUserLDAPInfo.php new file mode 100644 index 0000000000..a7c901fa23 --- /dev/null +++ b/src/applications/people/storage/PhabricatorUserLDAPInfo.php @@ -0,0 +1,22 @@ + 'sql', 'name' => $this->getPatchPath('testdatabase.sql'), ), + 'ldapinfo.sql' => array( + 'type' => 'sql', + 'name' => $this->getPatchPath('ldapinfo.sql'), + ), ); }