diff options
author | alecpl <alec@alec.pl> | 2011-02-17 14:35:06 +0000 |
---|---|---|
committer | alecpl <alec@alec.pl> | 2011-02-17 14:35:06 +0000 |
commit | 4d982d38a85567491a163d2f1561ad938640dea2 (patch) | |
tree | 75ba9f085ca2e957ab23dd68b7ec4bc99af55a0c | |
parent | 261ea440ddf65c9152089faf9f66ca51629e28d0 (diff) |
- Add LDAP SASL bind and proxy authentication (#1486692)
-rw-r--r-- | CHANGELOG | 1 | ||||
-rw-r--r-- | config/main.inc.php.dist | 5 | ||||
-rw-r--r-- | program/include/rcube_ldap.php | 84 |
3 files changed, 83 insertions, 7 deletions
@@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Add LDAP SASL bind and proxy authentication (#1486692) - Add variable for 'Today' label in date_today option (#1486120) - Fix dont_override setting does not override existing user preferences (#1487664) - Use only one from IMAP authentication methods to prevent login delays (1487784) diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist index 3d9cd0663..db029f152 100644 --- a/config/main.inc.php.dist +++ b/config/main.inc.php.dist @@ -470,6 +470,11 @@ $rcmail_config['ldap_public']['Verisign'] = array( // The login name is used to search for the DN to bind with 'search_base_dn' => '', 'search_filter' => '', // e.g. '(&(objectClass=posixAccount)(uid=%u))' + // Optional authentication identifier to be used as SASL authorization proxy + // bind_dn need to be empty + 'auth_cid' => '', + // SASL authentication method (for proxy auth), e.g. DIGEST-MD5 + 'auth_method' => '', // Indicates if we can write to the LDAP directory or not. // If writable is true then these fields need to be populated: // LDAP_Object_Classes, required_fields, LDAP_rdn diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php index 308c4f238..c8253713b 100644 --- a/program/include/rcube_ldap.php +++ b/program/include/rcube_ldap.php @@ -162,11 +162,16 @@ class rcube_ldap extends rcube_addressbook { $this->ready = true; + $bind_pass = $this->prop['bind_pass']; + $bind_user = $this->prop['bind_user']; + $bind_dn = $this->prop['bind_dn']; + $base_dn = $this->prop['base_dn']; + // User specific access, generate the proper values to use. if ($this->prop['user_specific']) { // No password set, use the session password - if (empty($this->prop['bind_pass'])) { - $this->prop['bind_pass'] = $RCMAIL->decrypt($_SESSION['password']); + if (empty($bind_pass)) { + $bind_pass = $RCMAIL->decrypt($_SESSION['password']); } // Get the pieces needed for variable replacement. @@ -190,19 +195,31 @@ class rcube_ldap extends rcube_addressbook $this->_debug("S: search returned dn: $bind_dn"); if ($bind_dn) { - $this->prop['bind_dn'] = $bind_dn; $dn = ldap_explode_dn($bind_dn, 1); $replaces['%dn'] = $dn[0]; } } } // Replace the bind_dn and base_dn variables. - $this->prop['bind_dn'] = strtr($this->prop['bind_dn'], $replaces); - $this->prop['base_dn'] = strtr($this->prop['base_dn'], $replaces); + $bind_dn = strtr($bind_dn, $replaces); + $base_dn = strtr($base_dn, $replaces); + + if (empty($bind_user)) { + $bind_user = $u; + } } - if (!empty($this->prop['bind_dn']) && !empty($this->prop['bind_pass'])) - $this->ready = $this->_bind($this->prop['bind_dn'], $this->prop['bind_pass']); + if (!empty($bind_pass)) { + if (!empty($bind_dn)) { + $this->ready = $this->_bind($bind_dn, $bind_pass); + } + else if (!empty($this->prop['auth_cid'])) { + $this->ready = $this->_sasl_bind($this->prop['auth_cid'], $bind_pass, $bind_user); + } + else { + $this->ready = $this->_sasl_bind($bind_user, $bind_pass); + } + } } else raise_error(array('code' => 100, 'type' => 'ldap', @@ -217,6 +234,59 @@ class rcube_ldap extends rcube_addressbook /** + * Bind connection with (SASL-) user and password + * + * @param string $authc Authentication user + * @param string $pass Bind password + * @param string $authz Autorization user + * + * @return boolean True on success, False on error + */ + private function _sasl_bind($authc, $pass, $authz=null) + { + if (!$this->conn) { + return false; + } + + if (!function_exists('ldap_sasl_bind')) { + raise_error(array( + 'code' => 100, 'type' => 'ldap', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Unable to bind: ldap_sasl_bind() not exists"), + true, true); + } + + if (!empty($authz)) { + $authz = 'u:' . $authz; + } + + if (!empty($this->prop['auth_method'])) { + $method = $this->prop['auth_method']; + } + else { + $method = 'DIGEST-MD5'; + } + + $this->_debug("C: Bind [mech: $method, authc: $authc, authz: $authz] [pass: $pass]"); + + if (ldap_sasl_bind($this->conn, NULL, $pass, $method, NULL, $authc, $authz)) { + $this->_debug("S: OK"); + return true; + } + + $this->_debug("S: ".ldap_error($this->conn)); + + raise_error(array( + 'code' => ldap_errno($this->conn), 'type' => 'ldap', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Bind failed for authcid=$authc ".ldap_error($this->conn)), + true); + + return false; + } + + + /** * Bind connection with DN and password * * @param string Bind DN |