1<?php
2// Icinga Web 2 Cube Module | (c) 2016 Icinga GmbH | GPLv2
3
4namespace Icinga\Module\Cube\Ido;
5
6use Icinga\Application\Config;
7use Icinga\Authentication\Auth;
8use Icinga\Data\Filter\Filter;
9use Icinga\Exception\ConfigurationError;
10use Icinga\Exception\QueryException;
11use Icinga\Module\Cube\DbCube;
12use Icinga\Module\Monitoring\Backend\MonitoringBackend;
13use Icinga\Util\GlobFilter;
14
15/**
16 * IdoCube
17 *
18 * Base class for IDO-related cubes
19 *
20 * @package Icinga\Module\Cube\Ido
21 */
22abstract class IdoCube extends DbCube
23{
24    /** @var array  */
25    protected $availableFacts = array();
26
27    /** @var string We ask for the IDO version for compatibility reasons */
28    protected $idoVersion;
29
30    /** @var MonitoringBackend */
31    protected $backend;
32
33    /**
34     * Cache for {@link filterProtectedCustomvars()}
35     *
36     * @var string|null
37     */
38    protected $protectedCustomvars;
39
40    /** @var GlobFilter The properties to hide from the user */
41    protected $blacklistedProperties;
42
43    /**
44     * We can steal the DB connection directly from a Monitoring backend
45     *
46     * @param MonitoringBackend $backend
47     * @return $this
48     */
49    public function setBackend(MonitoringBackend $backend)
50    {
51        $this->backend = $backend;
52
53        $this->setConnection($backend->getResource());
54
55        return $this;
56    }
57
58    /**
59     * Provice access to our DB resource
60     *
61     * This lazy-loads the default monitoring backend in case no DB has been
62     * given
63     *
64     * @return \Zend_Db_Adapter_Abstract
65     */
66    public function db()
67    {
68        $this->requireBackend();
69        return parent::db();
70    }
71
72    /**
73     * Returns the Icinga IDO version
74     *
75     * @return string
76     */
77    protected function getIdoVersion()
78    {
79        if ($this->idoVersion === null) {
80            $db = $this->db();
81            $this->idoVersion = $db->fetchOne(
82                $db->select()->from('icinga_dbversion', 'version')
83            );
84        }
85
86        return $this->idoVersion;
87    }
88
89    /**
90     * Steal the default monitoring DB resource...
91     *
92     * ...in case none has been defined otherwise
93     *
94     * @return void
95     */
96    protected function requireBackend()
97    {
98        if ($this->db === null) {
99            $this->setBackend(MonitoringBackend::instance());
100        }
101    }
102
103    protected function getMonitoringRestriction()
104    {
105        $restriction = Filter::matchAny();
106        $restriction->setAllowedFilterColumns(array(
107            'host_name',
108            'hostgroup_name',
109            'instance_name',
110            'service_description',
111            'servicegroup_name',
112            function ($c) {
113                return preg_match('/^_(?:host|service)_/i', $c);
114            }
115        ));
116
117        $filters = Auth::getInstance()->getUser()->getRestrictions('monitoring/filter/objects');
118
119        foreach ($filters as $filter) {
120            if ($filter === '*') {
121                return Filter::matchAny();
122            }
123            try {
124                $restriction->addFilter(Filter::fromQueryString($filter));
125            } catch (QueryException $e) {
126                throw new ConfigurationError(
127                    'Cannot apply restriction %s using the filter %s. You can only use the following columns: %s',
128                    'monitoring/filter/objects',
129                    $filter,
130                    implode(', ', array(
131                        'instance_name',
132                        'host_name',
133                        'hostgroup_name',
134                        'service_description',
135                        'servicegroup_name',
136                        '_(host|service)_<customvar-name>'
137                    )),
138                    $e
139                );
140            }
141        }
142
143        return $restriction;
144    }
145
146    /**
147     * Return the given array without values matching the custom variables protected by the monitoring module
148     *
149     * @param   string[]    $customvars
150     *
151     * @return  string[]
152     */
153    protected function filterProtectedCustomvars(array $customvars)
154    {
155        if ($this->blacklistedProperties === null) {
156            $this->blacklistedProperties = new GlobFilter(
157                Auth::getInstance()->getRestrictions('monitoring/blacklist/properties')
158            );
159        }
160
161        if ($this instanceof IdoServiceStatusCube) {
162            $type = 'service';
163        } else {
164            $type = 'host';
165        }
166
167        $customvars = $this->blacklistedProperties->removeMatching(
168            [$type => ['vars' => array_flip($customvars)]]
169        );
170
171        $customvars = isset($customvars[$type]['vars']) ? array_flip($customvars[$type]['vars']) : [];
172
173        if ($this->protectedCustomvars === null) {
174            $config = Config::module('monitoring')->get('security', 'protected_customvars');
175            $protectedCustomvars = array();
176
177            foreach (preg_split('~,~', $config, -1, PREG_SPLIT_NO_EMPTY) as $pattern) {
178                $regex = array();
179                foreach (explode('*', $pattern) as $literal) {
180                    $regex[] = preg_quote($literal, '/');
181                }
182
183                $protectedCustomvars[] = implode('.*', $regex);
184            }
185
186            $this->protectedCustomvars = empty($protectedCustomvars)
187                ? '/^$/'
188                : '/^(?:' . implode('|', $protectedCustomvars) . ')$/';
189        }
190
191        return preg_grep($this->protectedCustomvars, $customvars, PREG_GREP_INVERT);
192    }
193}
194