mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 14:52:41 +01:00
Made it possible to login using LDAP
Summary: Made it possible to link and unlink LDAP accounts with Phabricator accounts. Test Plan: I've tested this code locally and in production where I work. I've tried creating an account from scratch by logging in with LDAP and linking and unlinking an LDAP account with an existing account. I've tried to associate the same LDAP account with different Phabricator accounts and it failed as expected. Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin, auduny, svemir Maniphest Tasks: T742 Differential Revision: https://secure.phabricator.com/D2722
This commit is contained in:
parent
d73a6d3dcd
commit
726041584f
13 changed files with 815 additions and 0 deletions
|
@ -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?
|
||||
|
|
9
resources/sql/patches/ldapinfo.sql
Normal file
9
resources/sql/patches/ldapinfo.sql
Normal file
|
@ -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;
|
|
@ -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',
|
||||
|
|
|
@ -146,6 +146,11 @@ class AphrontDefaultApplicationConfiguration
|
|||
),
|
||||
),
|
||||
|
||||
'/ldap/' => array(
|
||||
'login/' => 'PhabricatorLDAPLoginController',
|
||||
'unlink/' => 'PhabricatorLDAPUnlinkController',
|
||||
),
|
||||
|
||||
'/oauthserver/' => array(
|
||||
'auth/' => 'PhabricatorOAuthServerAuthController',
|
||||
'test/' => 'PhabricatorOAuthServerTestController',
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorLDAPLoginController extends PhabricatorAuthController {
|
||||
private $provider;
|
||||
|
||||
public function shouldRequireLogin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->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(
|
||||
'<p>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.</p>'
|
||||
);
|
||||
$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(
|
||||
'<p>Link your LDAP account to your Phabricator account?</p>');
|
||||
$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('<h1>LDAP login</h1>');
|
||||
$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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorLDAPRegistrationController
|
||||
extends PhabricatorAuthController {
|
||||
private $ldapProvider;
|
||||
private $ldapInfo;
|
||||
|
||||
public function setLDAPProvider($provider) {
|
||||
$this->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',
|
||||
));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorLDAPUnlinkController extends PhabricatorAuthController {
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->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(
|
||||
'<p><strong>You will not be able to login</strong> using this account '.
|
||||
'once you unlink it. Continue?</p>');
|
||||
$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/');
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
|
149
src/applications/auth/ldap/PhabricatorLDAPProvider.php
Normal file
149
src/applications/auth/ldap/PhabricatorLDAPProvider.php
Normal file
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorLDAPProvider {
|
||||
private $userData;
|
||||
private $connection;
|
||||
|
||||
public function __construct() {
|
||||
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
if (isset($this->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];
|
||||
}
|
||||
}
|
|
@ -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');
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorUserLDAPSettingsPanelController
|
||||
extends PhabricatorUserSettingsPanelController {
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->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(
|
||||
'<p class="aphront-form-instructions">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</p>')
|
||||
->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(
|
||||
'<p class="aphront-form-instructions">You may unlink this account '.
|
||||
'from your LDAP account. This will prevent you from logging in with '.
|
||||
'your LDAP credentials.</p>')
|
||||
->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('<br /><h1>'.$name.'</h1><br />');
|
||||
}
|
||||
$panel->appendChild($form);
|
||||
}
|
||||
|
||||
return id(new AphrontNullView())
|
||||
->appendChild(
|
||||
array(
|
||||
$panel,
|
||||
));
|
||||
}
|
||||
}
|
22
src/applications/people/storage/PhabricatorUserLDAPInfo.php
Normal file
22
src/applications/people/storage/PhabricatorUserLDAPInfo.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class PhabricatorUserLDAPInfo extends PhabricatorUserDAO {
|
||||
protected $userID;
|
||||
protected $ldapUsername;
|
||||
}
|
|
@ -883,6 +883,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
|||
'type' => 'sql',
|
||||
'name' => $this->getPatchPath('testdatabase.sql'),
|
||||
),
|
||||
'ldapinfo.sql' => array(
|
||||
'type' => 'sql',
|
||||
'name' => $this->getPatchPath('ldapinfo.sql'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue