mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-07-27 07:44:04 +02:00
Merge branch 'master' into feature/doc-search-6630
This commit is contained in:
commit
54292eed20
@ -0,0 +1,36 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html class="no-js" lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<title>Accessibility: Text cue for required form control labels</title>
|
||||||
|
<meta name="description" content="Text cue for required form control labels">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<style type="text/css">
|
||||||
|
label.required span.required-indicator:after {
|
||||||
|
content: " *";
|
||||||
|
}
|
||||||
|
.sr-only {
|
||||||
|
border: 0;
|
||||||
|
clip: rect(0 0 0 0);
|
||||||
|
height: 1px;
|
||||||
|
margin: -1px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form>
|
||||||
|
<label class="required">
|
||||||
|
Enter some text
|
||||||
|
<span class="required-indicator" aria-hidden="true"></span>
|
||||||
|
<span class="sr-only"> (required)</span>
|
||||||
|
</label>
|
||||||
|
<input type="text" name="some_text" value="" aria-required="true" required>
|
||||||
|
<input type="submit" name="btn_submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -55,6 +55,14 @@ nginx:
|
|||||||
./bin/icingacli setup config webserver nginx --document-root /usr/share/icingaweb2/public
|
./bin/icingacli setup config webserver nginx --document-root /usr/share/icingaweb2/public
|
||||||
````
|
````
|
||||||
|
|
||||||
|
Save the output as new file in your webserver's configuration directory.
|
||||||
|
|
||||||
|
Example for Apache on RHEL/CentOS:
|
||||||
|
````
|
||||||
|
./bin/icingacli setup config webserver apache --document-root /usr/share/icingaweb2/public > /etc/httpd/conf.d/icingaweb2.conf
|
||||||
|
````
|
||||||
|
|
||||||
|
|
||||||
**Step 4: Preparing Web Setup**
|
**Step 4: Preparing Web Setup**
|
||||||
|
|
||||||
Because both web and CLI must have access to configuration and logs, permissions will be managed using a special
|
Because both web and CLI must have access to configuration and logs, permissions will be managed using a special
|
||||||
|
@ -189,7 +189,7 @@ rm -rf %{buildroot}
|
|||||||
mkdir -p %{buildroot}/{%{basedir}/{modules,library,public},%{bindir},%{configdir}/modules/setup,%{logdir},%{phpdir},%{wwwconfigdir},%{_sysconfdir}/bash_completion.d,%{docsdir}}
|
mkdir -p %{buildroot}/{%{basedir}/{modules,library,public},%{bindir},%{configdir}/modules/setup,%{logdir},%{phpdir},%{wwwconfigdir},%{_sysconfdir}/bash_completion.d,%{docsdir}}
|
||||||
cp -prv application doc %{buildroot}/%{basedir}
|
cp -prv application doc %{buildroot}/%{basedir}
|
||||||
cp -pv etc/bash_completion.d/icingacli %{buildroot}/%{_sysconfdir}/bash_completion.d/icingacli
|
cp -pv etc/bash_completion.d/icingacli %{buildroot}/%{_sysconfdir}/bash_completion.d/icingacli
|
||||||
cp -prv modules/{monitoring,setup} %{buildroot}/%{basedir}/modules
|
cp -prv modules/{monitoring,setup,doc,translation} %{buildroot}/%{basedir}/modules
|
||||||
cp -prv library/Icinga %{buildroot}/%{phpdir}
|
cp -prv library/Icinga %{buildroot}/%{phpdir}
|
||||||
cp -prv library/vendor %{buildroot}/%{basedir}/library
|
cp -prv library/vendor %{buildroot}/%{basedir}/library
|
||||||
cp -prv public/{css,img,js,error_norewrite.html} %{buildroot}/%{basedir}/public
|
cp -prv public/{css,img,js,error_norewrite.html} %{buildroot}/%{basedir}/public
|
||||||
|
@ -5,6 +5,7 @@ namespace Icinga\Authentication\Backend;
|
|||||||
|
|
||||||
use Icinga\User;
|
use Icinga\User;
|
||||||
use Icinga\Authentication\UserBackend;
|
use Icinga\Authentication\UserBackend;
|
||||||
|
use Icinga\Protocol\Ldap\Query;
|
||||||
use Icinga\Protocol\Ldap\Connection;
|
use Icinga\Protocol\Ldap\Connection;
|
||||||
use Icinga\Exception\AuthenticationException;
|
use Icinga\Exception\AuthenticationException;
|
||||||
use Icinga\Protocol\Ldap\Exception as LdapException;
|
use Icinga\Protocol\Ldap\Exception as LdapException;
|
||||||
@ -15,7 +16,7 @@ class LdapUserBackend extends UserBackend
|
|||||||
* Connection to the LDAP server
|
* Connection to the LDAP server
|
||||||
*
|
*
|
||||||
* @var Connection
|
* @var Connection
|
||||||
**/
|
*/
|
||||||
protected $conn;
|
protected $conn;
|
||||||
|
|
||||||
protected $baseDn;
|
protected $baseDn;
|
||||||
@ -36,7 +37,9 @@ class LdapUserBackend extends UserBackend
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return \Icinga\Protocol\Ldap\Query
|
* Create a query to select all usernames
|
||||||
|
*
|
||||||
|
* @return Query
|
||||||
*/
|
*/
|
||||||
protected function selectUsers()
|
protected function selectUsers()
|
||||||
{
|
{
|
||||||
@ -49,18 +52,18 @@ class LdapUserBackend extends UserBackend
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create query
|
* Create a query filtered by the given username
|
||||||
*
|
*
|
||||||
* @param string $username
|
* @param string $username
|
||||||
*
|
*
|
||||||
* @return \Icinga\Protocol\Ldap\Query
|
* @return Query
|
||||||
**/
|
*/
|
||||||
protected function selectUser($username)
|
protected function selectUser($username)
|
||||||
{
|
{
|
||||||
return $this->selectUsers()->where(
|
return $this->selectUsers()->setUsePagedResults(false)->where(
|
||||||
$this->userNameAttribute,
|
$this->userNameAttribute,
|
||||||
str_replace('*', '', $username)
|
str_replace('*', '', $username)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,23 +71,22 @@ class LdapUserBackend extends UserBackend
|
|||||||
*
|
*
|
||||||
* Try to bind to the backend and query all available users to check if:
|
* Try to bind to the backend and query all available users to check if:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>User connection credentials are correct and the bind is possible</li>
|
* <li>Connection credentials are correct and the bind is possible</li>
|
||||||
* <li>At least one user exists</li>
|
* <li>At least one user exists</li>
|
||||||
* <li>The specified userClass has the property specified by userNameAttribute</li>
|
* <li>The specified userClass has the property specified by userNameAttribute</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @throws AuthenticationException When authentication is not possible
|
* @throws AuthenticationException When authentication is not possible
|
||||||
*/
|
*/
|
||||||
public function assertAuthenticationPossible()
|
public function assertAuthenticationPossible()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$q = $this->conn->select()->setBase($this->baseDn)->from($this->userClass);
|
$result = $this->selectUsers()->fetchRow();
|
||||||
$result = $q->fetchRow();
|
|
||||||
} catch (LdapException $e) {
|
} catch (LdapException $e) {
|
||||||
throw new AuthenticationException('Connection not possible.', $e);
|
throw new AuthenticationException('Connection not possible.', $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! isset($result)) {
|
if ($result === null) {
|
||||||
throw new AuthenticationException(
|
throw new AuthenticationException(
|
||||||
'No objects with objectClass="%s" in DN="%s" found.',
|
'No objects with objectClass="%s" in DN="%s" found.',
|
||||||
$this->userClass,
|
$this->userClass,
|
||||||
@ -139,17 +141,16 @@ class LdapUserBackend extends UserBackend
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether the given user exists
|
* Return whether the given user exists
|
||||||
*
|
*
|
||||||
* @param User $user
|
* @param User $user
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
* @throws AuthenticationException
|
|
||||||
*/
|
*/
|
||||||
public function hasUser(User $user)
|
public function hasUser(User $user)
|
||||||
{
|
{
|
||||||
$username = $user->getUsername();
|
$username = $user->getUsername();
|
||||||
$entry = $this->conn->fetchOne($this->selectUser($username));
|
$entry = $this->selectUser($username)->fetchOne();
|
||||||
|
|
||||||
if (is_array($entry)) {
|
if (is_array($entry)) {
|
||||||
return in_array(strtolower($username), array_map('strtolower', $entry));
|
return in_array(strtolower($username), array_map('strtolower', $entry));
|
||||||
@ -159,24 +160,22 @@ class LdapUserBackend extends UserBackend
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticate the given user and return true on success, false on failure and null on error
|
* Return whether the given user credentials are valid
|
||||||
*
|
*
|
||||||
* @param User $user
|
* @param User $user
|
||||||
* @param string $password
|
* @param string $password
|
||||||
* @param boolean $healthCheck Perform additional health checks to generate more useful exceptions in case
|
* @param boolean $healthCheck Assert that authentication is possible at all
|
||||||
* of a configuration or backend error
|
|
||||||
*
|
*
|
||||||
* @return bool True when the authentication was successful, false when the username
|
* @return bool
|
||||||
* or password was invalid
|
*
|
||||||
* @throws AuthenticationException When an error occurred during authentication and authentication is not possible
|
* @throws AuthenticationException In case an error occured or the health check has failed
|
||||||
*/
|
*/
|
||||||
public function authenticate(User $user, $password, $healthCheck = true)
|
public function authenticate(User $user, $password, $healthCheck = false)
|
||||||
{
|
{
|
||||||
if ($healthCheck) {
|
if ($healthCheck) {
|
||||||
try {
|
try {
|
||||||
$this->assertAuthenticationPossible();
|
$this->assertAuthenticationPossible();
|
||||||
} catch (AuthenticationException $e) {
|
} catch (AuthenticationException $e) {
|
||||||
// Authentication not possible
|
|
||||||
throw new AuthenticationException(
|
throw new AuthenticationException(
|
||||||
'Authentication against backend "%s" not possible.',
|
'Authentication against backend "%s" not possible.',
|
||||||
$this->getName(),
|
$this->getName(),
|
||||||
@ -184,24 +183,27 @@ class LdapUserBackend extends UserBackend
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $this->hasUser($user)) {
|
if (! $this->hasUser($user)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$userDn = $this->conn->fetchDN($this->selectUser($user->getUsername()));
|
$userDn = $this->conn->fetchDN($this->selectUser($user->getUsername()));
|
||||||
$authenticated = $this->conn->testCredentials(
|
$authenticated = $this->conn->testCredentials(
|
||||||
$userDn,
|
$userDn,
|
||||||
$password
|
$password
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($authenticated) {
|
if ($authenticated) {
|
||||||
$groups = $this->getGroups($userDn);
|
$groups = $this->getGroups($userDn);
|
||||||
if ($groups !== null) {
|
if ($groups !== null) {
|
||||||
$user->setGroups($groups);
|
$user->setGroups($groups);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $authenticated;
|
return $authenticated;
|
||||||
} catch (LdapException $e) {
|
} catch (LdapException $e) {
|
||||||
// Error during authentication of this specific user
|
|
||||||
throw new AuthenticationException(
|
throw new AuthenticationException(
|
||||||
'Failed to authenticate user "%s" against backend "%s". An exception was thrown:',
|
'Failed to authenticate user "%s" against backend "%s". An exception was thrown:',
|
||||||
$user->getUsername(),
|
$user->getUsername(),
|
||||||
@ -238,6 +240,7 @@ class LdapUserBackend extends UserBackend
|
|||||||
$users[] = $row->{$this->userNameAttribute};
|
$users[] = $row->{$this->userNameAttribute};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $users;
|
return $users;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ class Manager
|
|||||||
$preferences = new Preferences();
|
$preferences = new Preferences();
|
||||||
}
|
}
|
||||||
$user->setPreferences($preferences);
|
$user->setPreferences($preferences);
|
||||||
$groups = array();
|
$groups = $user->getGroups();
|
||||||
foreach (Config::app('groups') as $name => $config) {
|
foreach (Config::app('groups') as $name => $config) {
|
||||||
try {
|
try {
|
||||||
$groupBackend = UserGroupBackend::create($name, $config);
|
$groupBackend = UserGroupBackend::create($name, $config);
|
||||||
|
@ -93,10 +93,10 @@ abstract class UserBackend implements Countable
|
|||||||
break;
|
break;
|
||||||
case 'msldap':
|
case 'msldap':
|
||||||
$groupOptions = array(
|
$groupOptions = array(
|
||||||
'group_base_dn' => $backendConfig->group_base_dn,
|
'group_base_dn' => $backendConfig->get('group_base_dn', $resource->getDN()),
|
||||||
'group_attribute' => $backendConfig->group_attribute,
|
'group_attribute' => $backendConfig->get('group_attribute', 'sAMAccountName'),
|
||||||
'group_member_attribute' => $backendConfig->group_member_attribute,
|
'group_member_attribute' => $backendConfig->get('group_member_attribute', 'member'),
|
||||||
'group_class' => $backendConfig->group_class
|
'group_class' => $backendConfig->get('group_class', 'group')
|
||||||
);
|
);
|
||||||
$backend = new LdapUserBackend(
|
$backend = new LdapUserBackend(
|
||||||
$resource,
|
$resource,
|
||||||
|
@ -32,6 +32,8 @@ class Connection
|
|||||||
{
|
{
|
||||||
const LDAP_NO_SUCH_OBJECT = 32;
|
const LDAP_NO_SUCH_OBJECT = 32;
|
||||||
const LDAP_SIZELIMIT_EXCEEDED = 4;
|
const LDAP_SIZELIMIT_EXCEEDED = 4;
|
||||||
|
const LDAP_ADMINLIMIT_EXCEEDED = 11;
|
||||||
|
const PAGE_SIZE = 1000;
|
||||||
|
|
||||||
protected $ds;
|
protected $ds;
|
||||||
protected $hostname;
|
protected $hostname;
|
||||||
@ -98,9 +100,6 @@ class Connection
|
|||||||
protected $namingContexts;
|
protected $namingContexts;
|
||||||
protected $discoverySuccess = false;
|
protected $discoverySuccess = false;
|
||||||
|
|
||||||
protected $lastResult;
|
|
||||||
protected $pageCookie;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
@ -171,11 +170,9 @@ class Connection
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
throw new LdapException(
|
throw new LdapException(
|
||||||
sprintf(
|
'LDAP list for "%s" failed: %s',
|
||||||
'LDAP list for "%s" failed: %s',
|
$dn,
|
||||||
$dn,
|
ldap_error($this->ds)
|
||||||
ldap_error($this->ds)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$children = ldap_get_entries($this->ds, $result);
|
$children = ldap_get_entries($this->ds, $result);
|
||||||
@ -183,7 +180,7 @@ class Connection
|
|||||||
$result = $this->deleteRecursively($children[$i]['dn']);
|
$result = $this->deleteRecursively($children[$i]['dn']);
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
//return result code, if delete fails
|
//return result code, if delete fails
|
||||||
throw new LdapException(sprintf('Recursively deleting "%s" failed', $dn));
|
throw new LdapException('Recursively deleting "%s" failed', $dn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $this->deleteDN($dn);
|
return $this->deleteDN($dn);
|
||||||
@ -200,11 +197,9 @@ class Connection
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
throw new LdapException(
|
throw new LdapException(
|
||||||
sprintf(
|
'LDAP delete for "%s" failed: %s',
|
||||||
'LDAP delete for "%s" failed: %s',
|
$dn,
|
||||||
$dn,
|
ldap_error($this->ds)
|
||||||
ldap_error($this->ds)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,10 +220,8 @@ class Connection
|
|||||||
$rows = $this->fetchAll($query, $fields);
|
$rows = $this->fetchAll($query, $fields);
|
||||||
if (count($rows) !== 1) {
|
if (count($rows) !== 1) {
|
||||||
throw new LdapException(
|
throw new LdapException(
|
||||||
sprintf(
|
'Cannot fetch single DN for %s',
|
||||||
'Cannot fetch single DN for %s',
|
$query->create()
|
||||||
$query->create()
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return key($rows);
|
return key($rows);
|
||||||
@ -244,6 +237,7 @@ class Connection
|
|||||||
{
|
{
|
||||||
$query = clone $query;
|
$query = clone $query;
|
||||||
$query->limit(1);
|
$query->limit(1);
|
||||||
|
$query->setUsePagedResults(false);
|
||||||
$results = $this->fetchAll($query, $fields);
|
$results = $this->fetchAll($query, $fields);
|
||||||
return array_shift($results);
|
return array_shift($results);
|
||||||
}
|
}
|
||||||
@ -273,35 +267,144 @@ class Connection
|
|||||||
$this->connect();
|
$this->connect();
|
||||||
$this->bind();
|
$this->bind();
|
||||||
|
|
||||||
$offset = $limit = null;
|
if ($query->getUsePagedResults() && version_compare(PHP_VERSION, '5.4.0') >= 0) {
|
||||||
if ($query->hasLimit()) {
|
return $this->runPagedQuery($query, $fields);
|
||||||
$offset = $query->getOffset();
|
} else {
|
||||||
$limit = $query->getLimit();
|
return $this->runQuery($query, $fields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function runQuery(Query $query, $fields = array())
|
||||||
|
{
|
||||||
|
$limit = $query->getLimit();
|
||||||
|
$offset = $query->hasOffset() ? $query->getOffset() - 1 : 0;
|
||||||
|
|
||||||
|
$results = @ldap_search(
|
||||||
|
$this->ds,
|
||||||
|
$query->hasBase() ? $query->getBase() : $this->root_dn,
|
||||||
|
$query->create(),
|
||||||
|
empty($fields) ? $query->listFields() : $fields,
|
||||||
|
0, // Attributes and values
|
||||||
|
$limit ? $offset + $limit : 0
|
||||||
|
);
|
||||||
|
if ($results === false) {
|
||||||
|
if (ldap_errno($this->ds) === self::LDAP_NO_SUCH_OBJECT) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new LdapException(
|
||||||
|
'LDAP query "%s" (base %s) failed. Error: %s',
|
||||||
|
$query->create(),
|
||||||
|
$query->hasBase() ? $query->getBase() : $this->root_dn,
|
||||||
|
ldap_error($this->ds)
|
||||||
|
);
|
||||||
|
} elseif (ldap_count_entries($this->ds, $results) === 0) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($query->getSortColumns() as $col) {
|
||||||
|
ldap_sort($this->ds, $results, $col[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$count = 0;
|
$count = 0;
|
||||||
$entries = array();
|
$entries = array();
|
||||||
$results = $this->runQuery($query, $fields);
|
$entry = ldap_first_entry($this->ds, $results);
|
||||||
while (! empty($results)) {
|
do {
|
||||||
|
$count += 1;
|
||||||
|
if ($offset === 0 || $offset < $count) {
|
||||||
|
$entries[ldap_get_dn($this->ds, $entry)] = $this->cleanupAttributes(
|
||||||
|
ldap_get_attributes($this->ds, $entry)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} while (($limit === 0 || $limit !== count($entries)) && ($entry = ldap_next_entry($this->ds, $entry)));
|
||||||
|
|
||||||
|
ldap_free_result($results);
|
||||||
|
return $entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function runPagedQuery(Query $query, $fields = array())
|
||||||
|
{
|
||||||
|
$limit = $query->getLimit();
|
||||||
|
$offset = $query->hasOffset() ? $query->getOffset() - 1 : 0;
|
||||||
|
$queryString = $query->create();
|
||||||
|
$base = $query->hasBase() ? $query->getBase() : $this->root_dn;
|
||||||
|
|
||||||
|
if (empty($fields)) {
|
||||||
|
$fields = $query->listFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = 0;
|
||||||
|
$cookie = '';
|
||||||
|
$entries = array();
|
||||||
|
do {
|
||||||
|
ldap_control_paged_result($this->ds, static::PAGE_SIZE, true, $cookie);
|
||||||
|
$results = @ldap_search($this->ds, $base, $queryString, $fields, 0, $limit ? $offset + $limit : 0);
|
||||||
|
if ($results === false) {
|
||||||
|
if (ldap_errno($this->ds) === self::LDAP_NO_SUCH_OBJECT) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new LdapException(
|
||||||
|
'LDAP query "%s" (base %s) failed. Error: %s',
|
||||||
|
$queryString,
|
||||||
|
$base,
|
||||||
|
ldap_error($this->ds)
|
||||||
|
);
|
||||||
|
} elseif (ldap_count_entries($this->ds, $results) === 0) {
|
||||||
|
if (in_array(
|
||||||
|
ldap_errno($this->ds),
|
||||||
|
array(static::LDAP_SIZELIMIT_EXCEEDED, static::LDAP_ADMINLIMIT_EXCEEDED)
|
||||||
|
)) {
|
||||||
|
Logger::warning(
|
||||||
|
'Unable to request more than %u results. Does the server allow paged search requests? (%s)',
|
||||||
|
$count,
|
||||||
|
ldap_error($this->ds)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
$entry = ldap_first_entry($this->ds, $results);
|
$entry = ldap_first_entry($this->ds, $results);
|
||||||
while ($entry) {
|
do {
|
||||||
$count++;
|
$count += 1;
|
||||||
if (
|
if ($offset === 0 || $offset < $count) {
|
||||||
($offset === null || $offset <= $count)
|
|
||||||
&& ($limit === null || $limit > count($entries))
|
|
||||||
) {
|
|
||||||
$entries[ldap_get_dn($this->ds, $entry)] = $this->cleanupAttributes(
|
$entries[ldap_get_dn($this->ds, $entry)] = $this->cleanupAttributes(
|
||||||
ldap_get_attributes($this->ds, $entry)
|
ldap_get_attributes($this->ds, $entry)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} while (($limit === 0 || $limit !== count($entries)) && ($entry = ldap_next_entry($this->ds, $entry)));
|
||||||
|
|
||||||
$entry = ldap_next_entry($this->ds, $entry);
|
try {
|
||||||
|
ldap_control_paged_result_response($this->ds, $results, $cookie);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// If the page size is greater than or equal to the sizeLimit value, the server should ignore the
|
||||||
|
// control as the request can be satisfied in a single page: https://www.ietf.org/rfc/rfc2696.txt
|
||||||
|
// This applies no matter whether paged search requests are permitted or not. You're done once you
|
||||||
|
// got everything you were out for.
|
||||||
|
if (count($entries) !== $limit) {
|
||||||
|
Logger::warning(
|
||||||
|
'Unable to request paged LDAP results. Does the server allow paged search requests? (%s)',
|
||||||
|
$e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$results = $this->runQuery($query, $fields);
|
ldap_free_result($results);
|
||||||
|
} while ($cookie && ($limit === 0 || count($entries) < $limit));
|
||||||
|
|
||||||
|
if ($cookie) {
|
||||||
|
// A sequence of paged search requests is abandoned by the client sending a search request containing a
|
||||||
|
// pagedResultsControl with the size set to zero (0) and the cookie set to the last cookie returned by
|
||||||
|
// the server: https://www.ietf.org/rfc/rfc2696.txt
|
||||||
|
ldap_control_paged_result($this->ds, 0, false, $cookie);
|
||||||
|
ldap_search($this->ds, $base, $queryString, $fields); // Returns no entries, due to the page size
|
||||||
|
} else {
|
||||||
|
// Reset the paged search request so that subsequent requests succeed
|
||||||
|
ldap_control_paged_result($this->ds, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $entries;
|
return $entries; // TODO(7693): Sort entries post-processed
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function cleanupAttributes($attrs)
|
protected function cleanupAttributes($attrs)
|
||||||
@ -320,79 +423,6 @@ class Connection
|
|||||||
return $clean;
|
return $clean;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function runQuery(Query $query, $fields = array())
|
|
||||||
{
|
|
||||||
if ($query->getUsePagedResults() && version_compare(PHP_VERSION, '5.4.0') >= 0) {
|
|
||||||
if ($this->pageCookie === null) {
|
|
||||||
$this->pageCookie = '';
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
ldap_control_paged_result_response($this->ds, $this->lastResult, $this->pageCookie);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$this->pageCookie = '';
|
|
||||||
if (! $query->hasLimit() || ldap_errno($this->ds) !== static::LDAP_SIZELIMIT_EXCEEDED) {
|
|
||||||
Logger::error(
|
|
||||||
'Unable to request paged LDAP results. Does the server allow paged search requests? (%s)',
|
|
||||||
$e->getMessage()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ldap_free_result($this->lastResult);
|
|
||||||
if (! $this->pageCookie) {
|
|
||||||
$this->pageCookie = $this->lastResult = null;
|
|
||||||
// Abandon the paged search request so that subsequent requests succeed
|
|
||||||
ldap_control_paged_result($this->ds, 0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Does not matter whether we'll use a valid page size here,
|
|
||||||
// as the server applies its hard limit in case its too high
|
|
||||||
ldap_control_paged_result(
|
|
||||||
$this->ds,
|
|
||||||
$query->hasLimit() ? $query->getLimit() : 500,
|
|
||||||
true,
|
|
||||||
$this->pageCookie
|
|
||||||
);
|
|
||||||
} elseif ($this->lastResult !== null) {
|
|
||||||
ldap_free_result($this->lastResult);
|
|
||||||
$this->lastResult = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$base = $query->hasBase() ? $query->getBase() : $this->root_dn;
|
|
||||||
$results = @ldap_search(
|
|
||||||
$this->ds,
|
|
||||||
$base,
|
|
||||||
$query->create(),
|
|
||||||
empty($fields) ? $query->listFields() : $fields,
|
|
||||||
0, // Attributes and values
|
|
||||||
$query->hasLimit() ? $query->getOffset() + $query->getLimit() : 0 // No limit - at least where possible
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($results === false) {
|
|
||||||
if (ldap_errno($this->ds) === self::LDAP_NO_SUCH_OBJECT) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
throw new LdapException(
|
|
||||||
sprintf(
|
|
||||||
'LDAP query "%s" (root %s) failed: %s',
|
|
||||||
$query->create(),
|
|
||||||
$this->root_dn,
|
|
||||||
ldap_error($this->ds)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($query->getSortColumns() as $col) {
|
|
||||||
ldap_sort($this->ds, $results, $col[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->lastResult = $results;
|
|
||||||
return $results;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testCredentials($username, $password)
|
public function testCredentials($username, $password)
|
||||||
{
|
{
|
||||||
$this->connect();
|
$this->connect();
|
||||||
@ -471,18 +501,14 @@ class Connection
|
|||||||
} else {
|
} else {
|
||||||
Logger::debug('LDAP STARTTLS failed: %s', ldap_error($ds));
|
Logger::debug('LDAP STARTTLS failed: %s', ldap_error($ds));
|
||||||
throw new LdapException(
|
throw new LdapException(
|
||||||
sprintf(
|
'LDAP STARTTLS failed: %s',
|
||||||
'LDAP STARTTLS failed: %s',
|
ldap_error($ds)
|
||||||
ldap_error($ds)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} elseif ($force_tls) {
|
} elseif ($force_tls) {
|
||||||
throw new LdapException(
|
throw new LdapException(
|
||||||
sprintf(
|
'TLS is required but not announced by %s',
|
||||||
'TLS is required but not announced by %s',
|
$this->hostname
|
||||||
$this->hostname
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// TODO: Log noticy -> TLS enabled but not announced
|
// TODO: Log noticy -> TLS enabled but not announced
|
||||||
@ -708,24 +734,20 @@ class Connection
|
|||||||
|
|
||||||
if (! $result) {
|
if (! $result) {
|
||||||
throw new LdapException(
|
throw new LdapException(
|
||||||
sprintf(
|
'Capability query failed (%s:%d): %s. Check if hostname and port of the'
|
||||||
'Capability query failed (%s:%d): %s. Check if hostname and port of the ldap resource are correct '
|
. ' ldap resource are correct and if anonymous access is permitted.',
|
||||||
. ' and if anonymous access is permitted.',
|
$this->hostname,
|
||||||
$this->hostname,
|
$this->port,
|
||||||
$this->port,
|
ldap_error($ds)
|
||||||
ldap_error($ds)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$entry = ldap_first_entry($ds, $result);
|
$entry = ldap_first_entry($ds, $result);
|
||||||
if ($entry === false) {
|
if ($entry === false) {
|
||||||
throw new LdapException(
|
throw new LdapException(
|
||||||
sprintf(
|
'Capabilities not available (%s:%d): %s. Discovery of root DSE probably not permitted.',
|
||||||
'Capabilities not available (%s:%d): %s. Discovery of root DSE probably not permitted.',
|
$this->hostname,
|
||||||
$this->hostname,
|
$this->port,
|
||||||
$this->port,
|
ldap_error($ds)
|
||||||
ldap_error($ds)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -771,14 +793,12 @@ class Connection
|
|||||||
$r = @ldap_bind($this->ds, $this->bind_dn, $this->bind_pw);
|
$r = @ldap_bind($this->ds, $this->bind_dn, $this->bind_pw);
|
||||||
if (! $r) {
|
if (! $r) {
|
||||||
throw new LdapException(
|
throw new LdapException(
|
||||||
sprintf(
|
'LDAP connection to %s:%s (%s / %s) failed: %s',
|
||||||
'LDAP connection to %s:%s (%s / %s) failed: %s',
|
$this->hostname,
|
||||||
$this->hostname,
|
$this->port,
|
||||||
$this->port,
|
$this->bind_dn,
|
||||||
$this->bind_dn,
|
'***' /* $this->bind_pw */,
|
||||||
'***' /* $this->bind_pw */,
|
ldap_error($this->ds)
|
||||||
ldap_error($this->ds)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$this->bound = true;
|
$this->bound = true;
|
||||||
|
@ -3,10 +3,12 @@
|
|||||||
|
|
||||||
namespace Icinga\Protocol\Ldap;
|
namespace Icinga\Protocol\Ldap;
|
||||||
|
|
||||||
|
use Icinga\Exception\IcingaException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class Exception
|
* Class Exception
|
||||||
* @package Icinga\Protocol\Ldap
|
* @package Icinga\Protocol\Ldap
|
||||||
*/
|
*/
|
||||||
class Exception extends \Exception
|
class Exception extends IcingaException
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,8 @@ class Query
|
|||||||
protected $connection;
|
protected $connection;
|
||||||
protected $filters = array();
|
protected $filters = array();
|
||||||
protected $fields = array();
|
protected $fields = array();
|
||||||
protected $limit_count;
|
protected $limit_count = 0;
|
||||||
protected $limit_offset;
|
protected $limit_offset = 0;
|
||||||
protected $sort_columns = array();
|
protected $sort_columns = array();
|
||||||
protected $count;
|
protected $count;
|
||||||
protected $base;
|
protected $base;
|
||||||
@ -111,7 +111,7 @@ class Query
|
|||||||
*/
|
*/
|
||||||
public function hasLimit()
|
public function hasLimit()
|
||||||
{
|
{
|
||||||
return $this->limit_count !== null;
|
return $this->limit_count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -5,34 +5,44 @@ class Zend_View_Helper_PluginOutput extends Zend_View_Helper_Abstract
|
|||||||
{
|
{
|
||||||
protected static $purifier;
|
protected static $purifier;
|
||||||
|
|
||||||
|
protected static $txtPatterns = array(
|
||||||
|
'~\\\n~',
|
||||||
|
'~\\\t~',
|
||||||
|
'~\\\n\\\n~',
|
||||||
|
'~(\[|\()OK(\]|\))~',
|
||||||
|
'~(\[|\()WARNING(\]|\))~',
|
||||||
|
'~(\[|\()CRITICAL(\]|\))~',
|
||||||
|
'~(\[|\()UNKNOWN(\]|\))~',
|
||||||
|
'~\@{6,}~'
|
||||||
|
);
|
||||||
|
|
||||||
|
protected static $txtReplacements = array(
|
||||||
|
"\n",
|
||||||
|
"\t",
|
||||||
|
"\n",
|
||||||
|
'<span class="state ok">$1OK$2</span>',
|
||||||
|
'<span class="state warning">$1WARNING$2</span>',
|
||||||
|
'<span class="state critical">$1CRITICAL$2</span>',
|
||||||
|
'<span class="state error">$1UNKNOWN$2</span>',
|
||||||
|
'@@@@@@',
|
||||||
|
);
|
||||||
|
|
||||||
public function pluginOutput($output)
|
public function pluginOutput($output)
|
||||||
{
|
{
|
||||||
if (empty($output)) {
|
if (empty($output)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
$output = preg_replace('~<br[^>]+>~', "\n", $output);
|
$output = preg_replace('~<br[^>]+>~', "\n", $output);
|
||||||
if (preg_match('~<\w+[^>]*>~', $output)) {
|
if (preg_match('~<\w+[^>^\\\]{,60}>~', $output)) {
|
||||||
// HTML
|
// HTML
|
||||||
$output = preg_replace('~<table~', '<table style="font-size: 0.75em"',
|
$output = preg_replace('~<table~', '<table style="font-size: 0.75em"',
|
||||||
$this->getPurifier()->purify($output)
|
$this->getPurifier()->purify($output)
|
||||||
);
|
);
|
||||||
} elseif (preg_match('~\\\n~', $output)) {
|
|
||||||
// Plaintext
|
|
||||||
$output = '<pre class="pluginoutput">'
|
|
||||||
. preg_replace(
|
|
||||||
'~\\\n~', "\n", preg_replace(
|
|
||||||
'~\\\n\\\n~', "\n",
|
|
||||||
preg_replace('~\[OK\]~', '<span class="ok">[OK]</span>',
|
|
||||||
preg_replace('~\[WARNING\]~', '<span class="warning">[WARNING]</span>',
|
|
||||||
preg_replace('~\[CRITICAL\]~', '<span class="error">[CRITICAL]</span>',
|
|
||||||
preg_replace('~\@{6,}~', '@@@@@@',
|
|
||||||
$this->view->escape($output)
|
|
||||||
))))
|
|
||||||
)
|
|
||||||
) . '</pre>';
|
|
||||||
} else {
|
} else {
|
||||||
$output = '<pre class="pluginoutput">'
|
// Plaintext
|
||||||
. preg_replace('~\@{6,}~', '@@@@@@',
|
$output = '<pre class="pluginoutput">' . preg_replace(
|
||||||
|
self::$txtPatterns,
|
||||||
|
self::$txtReplacements,
|
||||||
$this->view->escape($output)
|
$this->view->escape($output)
|
||||||
) . '</pre>';
|
) . '</pre>';
|
||||||
}
|
}
|
||||||
@ -55,7 +65,7 @@ class Zend_View_Helper_PluginOutput extends Zend_View_Helper_Abstract
|
|||||||
parse_str($m[1], $params);
|
parse_str($m[1], $params);
|
||||||
if (isset($params['host'])) {
|
if (isset($params['host'])) {
|
||||||
$tag->setAttribute('href', $this->view->baseUrl(
|
$tag->setAttribute('href', $this->view->baseUrl(
|
||||||
'/monitoring/detail/show?host=' . urlencode($params['host']
|
'/monitoring/host/show?host=' . urlencode($params['host']
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -737,7 +737,6 @@
|
|||||||
}
|
}
|
||||||
this.icinga.ui.assignUniqueContainerIds();
|
this.icinga.ui.assignUniqueContainerIds();
|
||||||
|
|
||||||
console.log(origFocus);
|
|
||||||
if (origFocus.length == origFocus[0] !== '') {
|
if (origFocus.length == origFocus[0] !== '') {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
$(self.icinga.utils.getElementByDomPath(origFocus)).focus();
|
$(self.icinga.utils.getElementByDomPath(origFocus)).focus();
|
||||||
|
@ -284,10 +284,8 @@
|
|||||||
if (! $element) {
|
if (! $element) {
|
||||||
$element = $(selector);
|
$element = $(selector);
|
||||||
} else {
|
} else {
|
||||||
console.log(selector);
|
|
||||||
$element = $element.children(selector).first();
|
$element = $element.children(selector).first();
|
||||||
if (! $element[0]) {
|
if (! $element[0]) {
|
||||||
console.log("element not existing stopping...");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user