summaryrefslogtreecommitdiffstats
path: root/application/controllers/UsageController.php
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--application/controllers/UsageController.php155
1 files changed, 155 insertions, 0 deletions
diff --git a/application/controllers/UsageController.php b/application/controllers/UsageController.php
new file mode 100644
index 0000000..287b979
--- /dev/null
+++ b/application/controllers/UsageController.php
@@ -0,0 +1,155 @@
+<?php
+// Icinga Web 2 X.509 Module | (c) 2018 Icinga GmbH | GPLv2
+
+namespace Icinga\Module\X509\Controllers;
+
+use Icinga\Data\Filter\FilterExpression;
+use Icinga\Exception\ConfigurationError;
+use Icinga\Module\X509\Controller;
+use Icinga\Module\X509\FilterAdapter;
+use Icinga\Module\X509\Job;
+use Icinga\Module\X509\SortAdapter;
+use Icinga\Module\X509\SqlFilter;
+use Icinga\Module\X509\UsageTable;
+use ipl\Web\Control\PaginationControl;
+use ipl\Sql;
+use ipl\Web\Url;
+
+class UsageController extends Controller
+{
+ public function indexAction()
+ {
+ $this
+ ->initTabs()
+ ->setTitle($this->translate('Certificate Usage'));
+
+ try {
+ $conn = $this->getDb();
+ } catch (ConfigurationError $_) {
+ $this->render('missing-resource', null, true);
+ return;
+ }
+
+ $select = (new Sql\Select())
+ ->from('x509_target t')
+ ->columns('*')
+ ->join('x509_certificate_chain cc', 'cc.id = t.latest_certificate_chain_id')
+ ->join('x509_certificate_chain_link ccl', 'ccl.certificate_chain_id = cc.id')
+ ->join('x509_certificate c', 'c.id = ccl.certificate_id')
+ ->where(['ccl.order = ?' => 0]);
+
+ $sortAndFilterColumns = [
+ 'hostname' => $this->translate('Hostname'),
+ 'ip' => $this->translate('IP'),
+ 'subject' => $this->translate('Certificate'),
+ 'issuer' => $this->translate('Issuer'),
+ 'version' => $this->translate('Version'),
+ 'self_signed' => $this->translate('Is Self-Signed'),
+ 'ca' => $this->translate('Is Certificate Authority'),
+ 'trusted' => $this->translate('Is Trusted'),
+ 'pubkey_algo' => $this->translate('Public Key Algorithm'),
+ 'pubkey_bits' => $this->translate('Public Key Strength'),
+ 'signature_algo' => $this->translate('Signature Algorithm'),
+ 'signature_hash_algo' => $this->translate('Signature Hash Algorithm'),
+ 'valid_from' => $this->translate('Valid From'),
+ 'valid_to' => $this->translate('Valid To'),
+ 'valid' => $this->translate('Chain Is Valid'),
+ 'duration' => $this->translate('Duration'),
+ 'expires' => $this->translate('Expiration')
+ ];
+
+ $this->view->paginator = new PaginationControl(new Sql\Cursor($conn, $select), Url::fromRequest());
+ $this->view->paginator->apply();
+
+ $this->setupSortControl(
+ $sortAndFilterColumns,
+ new SortAdapter($select, function ($field) {
+ if ($field === 'duration') {
+ return '(valid_to - valid_from)';
+ } elseif ($field === 'expires') {
+ return 'CASE WHEN UNIX_TIMESTAMP() > valid_to'
+ . ' THEN 0 ELSE (valid_to - UNIX_TIMESTAMP()) / 86400 END';
+ }
+ })
+ );
+
+ $this->setupLimitControl();
+
+ $filterAdapter = new FilterAdapter();
+ $this->setupFilterControl(
+ $filterAdapter,
+ $sortAndFilterColumns,
+ ['hostname', 'subject'],
+ ['format']
+ );
+ SqlFilter::apply($select, $filterAdapter->getFilter(), function (FilterExpression $filter) {
+ switch ($filter->getColumn()) {
+ case 'ip':
+ $value = $filter->getExpression();
+
+ if (is_array($value)) {
+ $value = array_map('Job::binary', $value);
+ } else {
+ $value = Job::binary($value);
+ }
+
+ return $filter->setExpression($value);
+ case 'issuer_hash':
+ $value = $filter->getExpression();
+
+ if (is_array($value)) {
+ $value = array_map('hex2bin', $value);
+ } else {
+ $value = hex2bin($value);
+ }
+
+ return $filter->setExpression($value);
+ case 'duration':
+ return $filter->setColumn('(valid_to - valid_from)');
+ case 'expires':
+ return $filter->setColumn(
+ 'CASE WHEN UNIX_TIMESTAMP() > valid_to THEN 0 ELSE (valid_to - UNIX_TIMESTAMP()) / 86400 END'
+ );
+ case 'valid_from':
+ case 'valid_to':
+ $expr = $filter->getExpression();
+ if (! is_numeric($expr)) {
+ return $filter->setExpression(strtotime($expr));
+ }
+
+ // expression doesn't need changing
+ default:
+ return false;
+ }
+ });
+
+ $formatQuery = clone $select;
+ $formatQuery->resetColumns()->columns([
+ 'valid', 'hostname', 'ip', 'port', 'subject', 'issuer', 'version',
+ 'self_signed', 'ca', 'trusted', 'pubkey_algo', 'pubkey_bits',
+ 'signature_algo', 'signature_hash_algo', 'valid_from', 'valid_to'
+ ]);
+
+ $this->handleFormatRequest($conn, $formatQuery, function (\PDOStatement $stmt) {
+ foreach ($stmt as $usage) {
+ $usage['valid_from'] = (new \DateTime())
+ ->setTimestamp($usage['valid_from'])
+ ->format('l F jS, Y H:i:s e');
+ $usage['valid_to'] = (new \DateTime())
+ ->setTimestamp($usage['valid_to'])
+ ->format('l F jS, Y H:i:s e');
+
+ $ip = $usage['ip'];
+ $ipv4 = ltrim($ip, "\0");
+ if (strlen($ipv4) === 4) {
+ $ip = $ipv4;
+ }
+ $usage['ip'] = inet_ntop($ip);
+
+ yield $usage;
+ }
+ });
+
+ $this->view->usageTable = (new UsageTable())->setData($conn->select($select));
+ }
+}