summaryrefslogtreecommitdiff
path: root/app/Auth/Ldap.php
diff options
context:
space:
mode:
Diffstat (limited to 'app/Auth/Ldap.php')
-rw-r--r--app/Auth/Ldap.php422
1 files changed, 320 insertions, 102 deletions
diff --git a/app/Auth/Ldap.php b/app/Auth/Ldap.php
index c1459b4e..0ccd09a4 100644
--- a/app/Auth/Ldap.php
+++ b/app/Auth/Ldap.php
@@ -20,6 +20,178 @@ class Ldap extends Base
const AUTH_NAME = 'LDAP';
/**
+ * Get LDAP server name
+ *
+ * @access public
+ * @return string
+ */
+ public function getLdapServer()
+ {
+ return LDAP_SERVER;
+ }
+
+ /**
+ * Get LDAP server port
+ *
+ * @access public
+ * @return integer
+ */
+ public function getLdapPort()
+ {
+ return LDAP_PORT;
+ }
+
+ /**
+ * Get LDAP username (proxy auth)
+ *
+ * @access public
+ * @return string
+ */
+ public function getLdapUsername()
+ {
+ return LDAP_USERNAME;
+ }
+
+ /**
+ * Get LDAP password (proxy auth)
+ *
+ * @access public
+ * @return string
+ */
+ public function getLdapPassword()
+ {
+ return LDAP_PASSWORD;
+ }
+
+ /**
+ * Get LDAP Base DN
+ *
+ * @access public
+ * @return string
+ */
+ public function getLdapBaseDn()
+ {
+ return LDAP_ACCOUNT_BASE;
+ }
+
+ /**
+ * Get LDAP account id attribute
+ *
+ * @access public
+ * @return string
+ */
+ public function getLdapAccountId()
+ {
+ return LDAP_ACCOUNT_ID;
+ }
+
+ /**
+ * Get LDAP account email attribute
+ *
+ * @access public
+ * @return string
+ */
+ public function getLdapAccountEmail()
+ {
+ return LDAP_ACCOUNT_EMAIL;
+ }
+
+ /**
+ * Get LDAP account name attribute
+ *
+ * @access public
+ * @return string
+ */
+ public function getLdapAccountName()
+ {
+ return LDAP_ACCOUNT_FULLNAME;
+ }
+
+ /**
+ * Get LDAP account memberof attribute
+ *
+ * @access public
+ * @return string
+ */
+ public function getLdapAccountMemberOf()
+ {
+ return LDAP_ACCOUNT_MEMBEROF;
+ }
+
+ /**
+ * Get LDAP admin group DN
+ *
+ * @access public
+ * @return string
+ */
+ public function getLdapGroupAdmin()
+ {
+ return LDAP_GROUP_ADMIN_DN;
+ }
+
+ /**
+ * Get LDAP project admin group DN
+ *
+ * @access public
+ * @return string
+ */
+ public function getLdapGroupProjectAdmin()
+ {
+ return LDAP_GROUP_PROJECT_ADMIN_DN;
+ }
+
+ /**
+ * Get LDAP username pattern
+ *
+ * @access public
+ * @return string
+ */
+ public function getLdapUserPattern($username)
+ {
+ return sprintf(LDAP_USER_PATTERN, $username);
+ }
+
+ /**
+ * Return true if the LDAP username is case sensitive
+ *
+ * @access public
+ * @return boolean
+ */
+ public function isLdapAccountCaseSensitive()
+ {
+ return LDAP_USERNAME_CASE_SENSITIVE;
+ }
+
+ /**
+ * Return true if the automatic account creation is enabled
+ *
+ * @access public
+ * @return boolean
+ */
+ public function isLdapAccountCreationEnabled()
+ {
+ return LDAP_ACCOUNT_CREATION;
+ }
+
+ /**
+ * Ge the list of attributes to fetch when reading the LDAP user entry
+ *
+ * Must returns array with index that start at 0 otherwise ldap_search returns a warning "Array initialization wrong"
+ *
+ * @access public
+ * @return array
+ */
+ public function getProfileAttributes()
+ {
+ return array_values(array_filter(array(
+ $this->getLdapAccountId(),
+ $this->getLdapAccountName(),
+ $this->getLdapAccountEmail(),
+ $this->getLdapAccountMemberOf()
+ )));
+ }
+
+ /**
* Authenticate the user
*
* @access public
@@ -29,7 +201,7 @@ class Ldap extends Base
*/
public function authenticate($username, $password)
{
- $username = LDAP_USERNAME_CASE_SENSITIVE ? $username : strtolower($username);
+ $username = $this->isLdapAccountCaseSensitive() ? $username : strtolower($username);
$result = $this->findUser($username, $password);
if (is_array($result)) {
@@ -46,7 +218,7 @@ class Ldap extends Base
else {
// We create automatically a new user
- if (LDAP_ACCOUNT_CREATION && $this->createUser($username, $result['name'], $result['email'])) {
+ if ($this->isLdapAccountCreationEnabled() && $this->user->create($result) !== false) {
$user = $this->user->getByUsername($username);
}
else {
@@ -65,28 +237,6 @@ class Ldap extends Base
}
/**
- * Create a new local user after the LDAP authentication
- *
- * @access public
- * @param string $username Username
- * @param string $name Name of the user
- * @param string $email Email address
- * @return bool
- */
- public function createUser($username, $name, $email)
- {
- $values = array(
- 'username' => $username,
- 'name' => $name,
- 'email' => $email,
- 'is_admin' => 0,
- 'is_ldap_user' => 1,
- );
-
- return $this->user->create($values);
- }
-
- /**
* Find the user from the LDAP server
*
* @access public
@@ -98,8 +248,8 @@ class Ldap extends Base
{
$ldap = $this->connect();
- if (is_resource($ldap) && $this->bind($ldap, $username, $password)) {
- return $this->search($ldap, $username, $password);
+ if ($ldap !== false && $this->bind($ldap, $username, $password)) {
+ return $this->getProfile($ldap, $username, $password);
}
return false;
@@ -108,13 +258,14 @@ class Ldap extends Base
/**
* LDAP connection
*
- * @access private
- * @return resource $ldap LDAP connection
+ * @access public
+ * @return resource|boolean
*/
- private function connect()
+ public function connect()
{
if (! function_exists('ldap_connect')) {
- die('The PHP LDAP extension is required');
+ $this->logger->error('The PHP LDAP extension is required');
+ return false;
}
// Skip SSL certificate verification
@@ -122,10 +273,11 @@ class Ldap extends Base
putenv('LDAPTLS_REQCERT=never');
}
- $ldap = ldap_connect(LDAP_SERVER, LDAP_PORT);
+ $ldap = ldap_connect($this->getLdapServer(), $this->getLdapPort());
- if (! is_resource($ldap)) {
- die('Unable to connect to the LDAP server: "'.LDAP_SERVER.'"');
+ if ($ldap === false) {
+ $this->logger->error('Unable to connect to the LDAP server');
+ return false;
}
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
@@ -134,30 +286,32 @@ class Ldap extends Base
ldap_set_option($ldap, LDAP_OPT_TIMELIMIT, 1);
if (LDAP_START_TLS && ! @ldap_start_tls($ldap)) {
- die('Unable to use ldap_start_tls()');
+ $this->logger->error('Unable to use ldap_start_tls()');
+ return false;
}
return $ldap;
}
/**
- * LDAP bind
+ * LDAP authentication
*
- * @access private
- * @param resource $ldap LDAP connection
- * @param string $username Username
- * @param string $password Password
+ * @access public
+ * @param resource $ldap
+ * @param string $username
+ * @param string $password
+ * @param string $ldap_type
* @return boolean
*/
- private function bind($ldap, $username, $password)
+ public function bind($ldap, $username, $password, $ldap_type = LDAP_BIND_TYPE)
{
- if (LDAP_BIND_TYPE === 'user') {
- $ldap_username = sprintf(LDAP_USERNAME, $username);
+ if ($ldap_type === 'user') {
+ $ldap_username = $this->getLdapUserPattern($username);
$ldap_password = $password;
}
- else if (LDAP_BIND_TYPE === 'proxy') {
- $ldap_username = LDAP_USERNAME;
- $ldap_password = LDAP_PASSWORD;
+ else if ($ldap_type === 'proxy') {
+ $ldap_username = $this->getLdapUsername();
+ $ldap_password = $this->getLdapPassword();
}
else {
$ldap_username = null;
@@ -172,118 +326,182 @@ class Ldap extends Base
}
/**
- * LDAP user lookup
+ * Get LDAP user profile
*
- * @access private
- * @param resource $ldap LDAP connection
- * @param string $username Username
- * @param string $password Password
+ * @access public
+ * @param resource $ldap
+ * @param string $username
+ * @param string $password
* @return boolean|array
*/
- private function search($ldap, $username, $password)
+ public function getProfile($ldap, $username, $password)
{
- $sr = @ldap_search($ldap, LDAP_ACCOUNT_BASE, sprintf(LDAP_USER_PATTERN, $username), array(LDAP_ACCOUNT_FULLNAME, LDAP_ACCOUNT_EMAIL));
-
- if ($sr === false) {
+ $entries = $this->executeQuery($ldap, $this->getLdapUserPattern($username));
+ if ($entries === false) {
return false;
}
- $info = ldap_get_entries($ldap, $sr);
+ if (@ldap_bind($ldap, $entries[0]['dn'], $password)) {
+ return $this->prepareProfile($ldap, $entries, $username);
+ }
- // User not found
- if (count($info) == 0 || $info['count'] == 0) {
- return false;
+ return false;
+ }
+
+ /**
+ * Build user profile from LDAP information
+ *
+ * @access public
+ * @param resource $ldap
+ * @param array $entries
+ * @param string $username
+ * @return boolean|array
+ */
+ public function prepareProfile($ldap, array $entries, $username)
+ {
+ if ($this->getLdapAccountId() !== '') {
+ $username = $this->getEntry($entries, $this->getLdapAccountId(), $username);
}
- // We got our user
- if (@ldap_bind($ldap, $info[0]['dn'], $password)) {
+ return array(
+ 'username' => $username,
+ 'name' => $this->getEntry($entries, $this->getLdapAccountName()),
+ 'email' => $this->getEntry($entries, $this->getLdapAccountEmail()),
+ 'is_admin' => (int) $this->isMemberOf($this->getEntries($entries, $this->getLdapAccountMemberOf()), $this->getLdapGroupAdmin()),
+ 'is_project_admin' => (int) $this->isMemberOf($this->getEntries($entries, $this->getLdapAccountMemberOf()), $this->getLdapGroupProjectAdmin()),
+ 'is_ldap_user' => 1,
+ );
+ }
- return array(
- 'username' => $username,
- 'name' => $this->getFromInfo($info, LDAP_ACCOUNT_FULLNAME),
- 'email' => $this->getFromInfo($info, LDAP_ACCOUNT_EMAIL),
- );
+ /**
+ * Check group membership
+ *
+ * @access public
+ * @param array $group_entries
+ * @param string $group_dn
+ * @return boolean
+ */
+ public function isMemberOf(array $group_entries, $group_dn)
+ {
+ if (! isset($group_entries['count']) || empty($group_dn)) {
+ return false;
+ }
+
+ for ($i = 0; $i < $group_entries['count']; $i++) {
+ if ($group_entries[$i] === $group_dn) {
+ return true;
+ }
}
return false;
}
/**
- * Retrieve info on LDAP user
+ * Retrieve info on LDAP user by username or email
*
- * @param string $username Username
- * @param string $email Email address
+ * @access public
+ * @param string $username
+ * @param string $email
+ * @return boolean|array
*/
public function lookup($username = null, $email = null)
{
- $query = $this->getQuery($username, $email);
- if ($query === false) {
+ $query = $this->getLookupQuery($username, $email);
+ if ($query === '') {
return false;
}
- // Connect and attempt anonymous bind
+ // Connect and attempt anonymous or proxy binding
$ldap = $this->connect();
- if (! is_resource($ldap) || ! $this->bind($ldap, null, null)) {
+ if ($ldap === false || ! $this->bind($ldap, null, null)) {
return false;
}
// Try to find user
- $sr = @ldap_search($ldap, LDAP_ACCOUNT_BASE, $query, array(LDAP_ACCOUNT_FULLNAME, LDAP_ACCOUNT_EMAIL, LDAP_ACCOUNT_ID));
- if ($sr === false) {
+ $entries = $this->executeQuery($ldap, $query);
+ if ($entries === false) {
+ return false;
+ }
+
+ // User id not retrieved: LDAP_ACCOUNT_ID not properly configured
+ if (empty($username) && ! isset($entries[0][$this->getLdapAccountId()][0])) {
return false;
}
- $info = ldap_get_entries($ldap, $sr);
+ return $this->prepareProfile($ldap, $entries, $username);
+ }
- // User not found
- if (count($info) == 0 || $info['count'] == 0) {
+ /**
+ * Execute LDAP query
+ *
+ * @access private
+ * @param resource $ldap
+ * @param string $query
+ * @return boolean|array
+ */
+ private function executeQuery($ldap, $query)
+ {
+ $sr = ldap_search($ldap, $this->getLdapBaseDn(), $query, $this->getProfileAttributes());
+ if ($sr === false) {
return false;
}
- // User id not retrieved: LDAP_ACCOUNT_ID not properly configured
- if (empty($username) && ! isset($info[0][LDAP_ACCOUNT_ID][0])) {
+ $entries = ldap_get_entries($ldap, $sr);
+ if ($entries === false || count($entries) === 0 || $entries['count'] == 0) {
return false;
}
- return array(
- 'username' => $this->getFromInfo($info, LDAP_ACCOUNT_ID, $username),
- 'name' => $this->getFromInfo($info, LDAP_ACCOUNT_FULLNAME),
- 'email' => $this->getFromInfo($info, LDAP_ACCOUNT_EMAIL, $email),
- );
+ return $entries;
}
/**
* Get the LDAP query to find a user
*
- * @param string $username Username
- * @param string $email Email address
+ * @access private
+ * @param string $username
+ * @param string $email
+ * @return string
*/
- private function getQuery($username, $email)
+ private function getLookupQuery($username, $email)
{
- if ($username && $email) {
- return '(&('.sprintf(LDAP_USER_PATTERN, $username).')('.LDAP_ACCOUNT_EMAIL.'='.$email.'))';
+ if (! empty($username) && ! empty($email)) {
+ return '(&('.$this->getLdapUserPattern($username).')('.$this->getLdapAccountEmail().'='.$email.'))';
}
- else if ($username) {
- return sprintf(LDAP_USER_PATTERN, $username);
+ else if (! empty($username)) {
+ return $this->getLdapUserPattern($username);
}
- else if ($email) {
- return '('.LDAP_ACCOUNT_EMAIL.'='.$email.')';
- }
- else {
- return false;
+ else if (! empty($email)) {
+ return '('.$this->getLdapAccountEmail().'='.$email.')';
}
+
+ return '';
}
/**
- * Return a value from the LDAP info
+ * Return one entry from a list of entries
*
- * @param array $info LDAP info
- * @param string $key Key
- * @param string $default Default value if key not set in entry
+ * @access private
+ * @param array $entries LDAP entries
+ * @param string $key Key
+ * @param string $default Default value if key not set in entry
* @return string
*/
- private function getFromInfo($info, $key, $default = '')
+ private function getEntry(array $entries, $key, $default = '')
+ {
+ return isset($entries[0][$key][0]) ? $entries[0][$key][0] : $default;
+ }
+
+ /**
+ * Return subset of entries
+ *
+ * @access private
+ * @param array $entries
+ * @param string $key
+ * @param array $default
+ * @return array
+ */
+ private function getEntries(array $entries, $key, $default = array())
{
- return isset($info[0][$key][0]) ? $info[0][$key][0] : $default;
+ return isset($entries[0][$key]) ? $entries[0][$key] : $default;
}
}