add_hook($host::HOOK_AUTH_USER, $this); Config::add(self::AUTH_IDM_URI, '', Config::T_STRING); Config::add(self::AUTH_IDM_STARTTLS, false, Config::T_BOOL); Config::add(self::AUTH_IDM_BASEDN, '', Config::T_STRING); Config::add(self::AUTH_IDM_SCOPE, 'sub', Config::T_STRING); Config::add(self::AUTH_IDM_FILTER, '', Config::T_STRING); Config::add(self::AUTH_IDM_ADMIN_FILTER, '', Config::T_STRING); Config::add(self::AUTH_IDM_USERNAME_ATTR, 'uid', Config::T_STRING); Config::add(self::AUTH_IDM_FULLNAME_ATTR, 'cn', Config::T_STRING); Config::add(self::AUTH_IDM_EMAIL_ATTR, 'mail', Config::T_STRING); } private function ldap_get_user($username, $filter = null) { switch ($this->scope) { case 'sub': $searchfunc = 'ldap_search'; break; case 'one': $searchfunc = 'ldap_list'; break; case 'base': $searchfunc = 'ldap_read'; break; default: Logger::log(E_USER_ERROR, "auth_idm: invalid search scope: $scope"); return null; } $uid_filter = '(' . ldap_escape($this->username_attr, '', LDAP_ESCAPE_FILTER) . '=' . ldap_escape($username, '', LDAP_ESCAPE_FILTER) . ')'; if (empty($filter)) { $filter = $uid_filter; } else { $filter = "(&$filter$uid_filter)"; } $results = $searchfunc($this->conn, $this->basedn, $filter, [$this->fullname_attr, $this->email_attr]); if ($results && ldap_count_entries($this->conn, $results) == 1) { if ($entry = ldap_first_entry($this->conn, $results)) { if ($dn = ldap_get_dn($this->conn, $entry)) { if ($attrs = ldap_get_attributes($this->conn, $entry)) { return array( 'dn' => $dn, 'email' => $attrs[$this->email_attr][0], 'fullname' => $attrs[$this->fullname_attr][0] ); } } } } return null; } function authenticate($username = null, $password = null, $service = '') { $this->basedn = Config::get(self::AUTH_IDM_BASEDN); $this->scope = Config::get(self::AUTH_IDM_SCOPE); $this->username_attr = Config::get(self::AUTH_IDM_USERNAME_ATTR); $this->fullname_attr = Config::get(self::AUTH_IDM_FULLNAME_ATTR); $this->email_attr = Config::get(self::AUTH_IDM_EMAIL_ATTR); $uri = Config::get(self::AUTH_IDM_URI); $starttls = Config::get(self::AUTH_IDM_STARTTLS); $filter = Config::get(self::AUTH_IDM_FILTER); $admin_filter = Config::get(self::AUTH_IDM_ADMIN_FILTER); // Get ldap connection handle. if (!$this->conn = ldap_connect($uri)) { return false; } // Set protocol version 3. if (!ldap_set_option($this->conn, LDAP_OPT_PROTOCOL_VERSION, 3)) { return false; } // Bind using kerberos credentials from the environment. if (!ldap_sasl_bind($this->conn, null, null, 'GSSAPI')) { return false; } // Initiate STARTTLS (if requested) if ($starttls and !ldap_start_tls($this->conn)) { return false; } // If REMOTE_USER was set by the webserver, use that. if (!empty($_SERVER['REMOTE_USER'])) { $username = $_SERVER['REMOTE_USER']; } elseif (empty($username)) { return false; } $is_admin = false; $user = null; // First, check if the ADIN_FILTER matches (if set). if (!empty($admin_filter)) { $user = $this->ldap_get_user($username, $admin_filter); isset($user) && $is_admin = true; } // If ADMIN_FILTER didn't match, try FILTER. if (!isset($user)) { $user = $this->ldap_get_user($username, $filter); } // If no matching user from LDAP, reject. if (!isset($user)) { return false; } // If webserver didn't validate the password, try an LDAP bind with the provided creds. if (empty($_SERVER['REMOTE_USER']) and !ldap_bind($this->conn, $user['dn'], $password)) { return false; } // Get the TTRSS internal user ID. if (!($userid = $this->auto_create_user($username))) { return false; } // Populate user details using the LDAP attributes. if (Config::get(Config::AUTH_AUTO_CREATE)) { if (!empty($user['fullname'])) { $sth = $this->pdo->prepare('UPDATE ttrss_users SET full_name = ? WHERE id = ?'); $sth->execute([$user['fullname'], $userid]); } if (!empty($user['email'])) { $sth = $this->pdo->prepare('UPDATE ttrss_users SET email = ? WHERE id = ?'); $sth->execute([$user['email'], $userid]); } $sth = $this->pdo->prepare('UPDATE ttrss_users SET access_level = ? WHERE id = ?'); $sth->execute([$is_admin ? 10 : 0, $userid]); } return $userid; } function api_version() { return 2; } }