Page MenuHomePhabricator

D8160.id.diff
No OneTemporary

D8160.id.diff

diff --git a/src/applications/auth/provider/PhabricatorAuthProviderLDAP.php b/src/applications/auth/provider/PhabricatorAuthProviderLDAP.php
--- a/src/applications/auth/provider/PhabricatorAuthProviderLDAP.php
+++ b/src/applications/auth/provider/PhabricatorAuthProviderLDAP.php
@@ -30,6 +30,10 @@
$realname_attributes = array();
}
+ $search_attributes = $conf->getProperty(self::KEY_SEARCH_ATTRIBUTES);
+ $search_attributes = phutil_split_lines($search_attributes, false);
+ $search_attributes = array_filter($search_attributes);
+
$adapter = id(new PhutilAuthAdapterLDAP())
->setHostname(
$conf->getProperty(self::KEY_HOSTNAME))
@@ -37,8 +41,7 @@
$conf->getProperty(self::KEY_PORT))
->setBaseDistinguishedName(
$conf->getProperty(self::KEY_DISTINGUISHED_NAME))
- ->setSearchAttribute(
- $conf->getProperty(self::KEY_SEARCH_ATTRIBUTE))
+ ->setSearchAttributes($search_attributes)
->setUsernameAttribute(
$conf->getProperty(self::KEY_USERNAME_ATTRIBUTE))
->setRealNameAttributes($realname_attributes)
@@ -53,8 +56,6 @@
->setAnonymousPassword(
new PhutilOpaqueEnvelope(
$conf->getProperty(self::KEY_ANONYMOUS_PASSWORD)))
- ->setSearchFirst(
- $conf->getProperty(self::KEY_SEARCH_FIRST))
->setActiveDirectoryDomain(
$conf->getProperty(self::KEY_ACTIVEDIRECTORY_DOMAIN));
$this->adapter = $adapter;
@@ -167,6 +168,11 @@
} else {
throw new Exception("Username and password are required!");
}
+ } catch (PhutilAuthCredentialException $ex) {
+ $response = $controller->buildProviderPageResponse(
+ $this,
+ $this->renderLoginForm($request, 'login'));
+ return array($account, $response);
} catch (Exception $ex) {
// TODO: Make this cleaner.
throw $ex;
@@ -180,7 +186,7 @@
const KEY_HOSTNAME = 'ldap:host';
const KEY_PORT = 'ldap:port';
const KEY_DISTINGUISHED_NAME = 'ldap:dn';
- const KEY_SEARCH_ATTRIBUTE = 'ldap:search-attribute';
+ const KEY_SEARCH_ATTRIBUTES = 'ldap:search-attribute';
const KEY_USERNAME_ATTRIBUTE = 'ldap:username-attribute';
const KEY_REALNAME_ATTRIBUTES = 'ldap:realname-attributes';
const KEY_VERSION = 'ldap:version';
@@ -188,7 +194,6 @@
const KEY_START_TLS = 'ldap:start-tls';
const KEY_ANONYMOUS_USERNAME = 'ldap:anoynmous-username';
const KEY_ANONYMOUS_PASSWORD = 'ldap:anonymous-password';
- const KEY_SEARCH_FIRST = 'ldap:search-first';
const KEY_ACTIVEDIRECTORY_DOMAIN = 'ldap:activedirectory-domain';
private function getPropertyKeys() {
@@ -200,15 +205,14 @@
self::KEY_HOSTNAME => pht('LDAP Hostname'),
self::KEY_PORT => pht('LDAP Port'),
self::KEY_DISTINGUISHED_NAME => pht('Base Distinguished Name'),
- self::KEY_SEARCH_ATTRIBUTE => pht('Search Attribute'),
+ self::KEY_SEARCH_ATTRIBUTES => pht('Search Attributes'),
+ self::KEY_ANONYMOUS_USERNAME => pht('Anonymous Username'),
+ self::KEY_ANONYMOUS_PASSWORD => pht('Anonymous Password'),
self::KEY_USERNAME_ATTRIBUTE => pht('Username Attribute'),
self::KEY_REALNAME_ATTRIBUTES => pht('Realname Attributes'),
self::KEY_VERSION => pht('LDAP Version'),
self::KEY_REFERRALS => pht('Enable Referrals'),
self::KEY_START_TLS => pht('Use TLS'),
- self::KEY_SEARCH_FIRST => pht('Search First'),
- self::KEY_ANONYMOUS_USERNAME => pht('Anonymous Username'),
- self::KEY_ANONYMOUS_PASSWORD => pht('Anonymous Password'),
self::KEY_ACTIVEDIRECTORY_DOMAIN => pht('ActiveDirectory Domain'),
);
}
@@ -262,24 +266,16 @@
self::KEY_DISTINGUISHED_NAME =>
pht('Example: %s',
phutil_tag('tt', array(), pht('ou=People, dc=example, dc=com'))),
- self::KEY_SEARCH_ATTRIBUTE =>
+ self::KEY_USERNAME_ATTRIBUTE =>
pht('Example: %s',
phutil_tag('tt', array(), pht('sn'))),
- self::KEY_USERNAME_ATTRIBUTE =>
- pht('Optional, if different from search attribute.'),
self::KEY_REALNAME_ATTRIBUTES =>
- pht('Optional. Example: %s',
+ pht('Example: %s',
phutil_tag('tt', array(), pht('firstname, lastname'))),
self::KEY_REFERRALS =>
pht('Follow referrals. Disable this for Windows AD 2003.'),
self::KEY_START_TLS =>
pht('Start TLS after binding to the LDAP server.'),
- self::KEY_SEARCH_FIRST =>
- pht(
- 'When the user enters their username, search for a matching '.
- 'record using the "Search Attribute", then try to bind using '.
- 'the DN for the record. This is useful if usernames are not '.
- 'part of the record DN.'),
self::KEY_ANONYMOUS_USERNAME =>
pht('Username to bind with before searching.'),
self::KEY_ANONYMOUS_PASSWORD =>
@@ -289,11 +285,76 @@
$types = array(
self::KEY_REFERRALS => 'checkbox',
self::KEY_START_TLS => 'checkbox',
- self::KEY_SEARCH_FIRST => 'checkbox',
+ self::KEY_SEARCH_ATTRIBUTES => 'textarea',
self::KEY_REALNAME_ATTRIBUTES => 'list',
self::KEY_ANONYMOUS_PASSWORD => 'password',
);
+ $instructions = array(
+ self::KEY_SEARCH_ATTRIBUTES => pht(
+ "When a user types their LDAP username and password into Phabricator, ".
+ "Phabricator can either bind to LDAP with those credentials directly ".
+ "(which is simpler, but not as powerful) or bind to LDAP with ".
+ "anonymous credentials, then search for record matching the supplied ".
+ "credentials (which is more complicated, but more powerful).\n\n".
+ "For many installs, direct binding is sufficient. However, you may ".
+ "want to search first if:\n\n".
+ " - You want users to be able to login with either their username ".
+ " or their email address.\n".
+ " - The login/username is not part of the distinguished name in ".
+ " your LDAP records.\n".
+ " - You want to restrict logins to a subset of users (like only ".
+ " those in certain departments).\n".
+ " - Your LDAP server is configured in some other way that prevents ".
+ " direct binding from working correctly.\n\n".
+ "**To bind directly**, enter the LDAP attribute corresponding to the ".
+ "login name into this box. Often, this is something like `sn` or ".
+ "`uid`. This is the simplest configuration, but will only work if the ".
+ "username is part of the distinguished name, and won't let you apply ".
+ "complex restrictions to logins.\n\n".
+ " lang=text,name=Simple Direct Binding\n".
+ " sn\n\n".
+ "**To search first**, provide an anonymous username and password ".
+ "below, then enter one or more search queries into this field, one ".
+ "per line. After binding, these queries will be used to identify the ".
+ "record associated with the login name the user typed.\n\n".
+ "Searches will be tried in order until a matching record is found. ".
+ "Each query can be a simple attribute name (like `sn` or `mail`), ".
+ "which will search for a matching record, or it can be a complex ".
+ "query that uses the string `\${login}` to represent the login ".
+ "name.\n\n".
+ "A common simple configuration is just an attribute name, like ".
+ "`sn`, which will work the same way direct binding works:\n\n".
+ " lang=text,name=Simple Example\n".
+ " sn\n\n".
+ "A slightly more complex configuration might let the user login with ".
+ "either their login name or email address:\n\n".
+ " lang=text,name=Match Several Attributes\n".
+ " mail\n".
+ " sn\n\n".
+ "If your LDAP directory is more complex, or you want to perform ".
+ "sophisticated filtering, you can use one or more queries. Depending ".
+ "on your directory structure, this example might allow users to login ".
+ "with either their email address or username, but only if they're in ".
+ "specific departments:\n\n".
+ " lang=text,name=Complex Example\n".
+ " (&(mail=\${login})(|(departmentNumber=1)(departmentNumber=2)))\n".
+ " (&(sn=\${login})(|(departmentNumber=1)(departmentNumber=2)))\n\n".
+ "All of the attribute names used here are just examples: your LDAP ".
+ "server may use different attribute names."),
+ self::KEY_USERNAME_ATTRIBUTE => pht(
+ "Optionally, specify a username attribute to use to prefill usernames ".
+ "when registering a new account. This is purely cosmetic and does not ".
+ "affect the login process, but you can configure it to make sure ".
+ "users get the same default username as their LDAP username, so ".
+ "usernames remain consistent across systems."),
+ self::KEY_REALNAME_ATTRIBUTES => pht(
+ "Optionally, specify one or more comma-separated attributes to use to ".
+ "prefill the \"Real Name\" field when registering a new account. This ".
+ "is purely cosmetic and does not affect the login process, but can ".
+ "make registration a little easier."),
+ );
+
foreach ($labels as $key => $label) {
$caption = idx($captions, $key);
$type = idx($types, $key);
@@ -323,6 +384,13 @@
->setCaption($caption)
->setValue($value);
break;
+ case 'textarea':
+ $control = id(new AphrontFormTextAreaControl())
+ ->setName($key)
+ ->setLabel($label)
+ ->setCaption($caption)
+ ->setValue($value);
+ break;
default:
$control = id(new AphrontFormTextControl())
->setName($key)
@@ -332,6 +400,11 @@
break;
}
+ $instruction_text = idx($instructions, $key);
+ if (strlen($instruction_text)) {
+ $form->appendRemarkupInstructions($instruction_text);
+ }
+
$form->appendChild($control);
}
}

File Metadata

Mime Type
text/plain
Expires
Sun, May 12, 8:41 AM (2 w, 6 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6287268
Default Alt Text
D8160.id.diff (10 KB)

Event Timeline