diff options
Diffstat (limited to 'library/X509/ProvidedHook/ServicesImportSource.php')
-rw-r--r-- | library/X509/ProvidedHook/ServicesImportSource.php | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/library/X509/ProvidedHook/ServicesImportSource.php b/library/X509/ProvidedHook/ServicesImportSource.php new file mode 100644 index 0000000..7b87cd8 --- /dev/null +++ b/library/X509/ProvidedHook/ServicesImportSource.php @@ -0,0 +1,143 @@ +<?php + +// Icinga Web 2 X.509 Module | (c) 2019 Icinga GmbH | GPLv2 + +namespace Icinga\Module\X509\ProvidedHook; + +use Icinga\Module\X509\Common\Database; +use Icinga\Module\X509\Job; +use Icinga\Module\X509\Model\X509CertificateSubjectAltName; +use Icinga\Module\X509\Model\X509Target; +use ipl\Sql; + +class ServicesImportSource extends X509ImportSource +{ + public function fetchData() + { + $conn = Database::get(); + $targets = X509Target::on($conn) + ->with([ + 'chain', + 'chain.certificate', + 'chain.certificate.dn', + 'chain.certificate.issuer_certificate' + ]) + ->columns([ + 'ip', + 'host_name' => 'hostname', + 'host_port' => 'port', + 'cert_subject' => 'chain.certificate.subject', + 'cert_issuer' => 'chain.certificate.issuer', + 'cert_trusted' => 'chain.certificate.trusted', + 'cert_valid_from' => 'chain.certificate.valid_from', + 'cert_valid_to' => 'chain.certificate.valid_to', + 'cert_self_signed' => new Sql\Expression('COALESCE(%s, %s)', [ + 'chain.certificate.issuer_certificate.self_signed', + 'chain.certificate.self_signed' + ]) + ]); + + $targets->getWith()['target.chain.certificate.issuer_certificate']->setJoinType('LEFT'); + $targets + ->getSelectBase() + ->where(new Sql\Expression('target_chain_link.order = 0')) + ->groupBy(['ip, hostname, port']); + + $certAltName = X509CertificateSubjectAltName::on($conn); + $certAltName + ->getSelectBase() + ->where(new Sql\Expression('certificate_id = target_chain_certificate.id')) + ->groupBy(['alt_name.certificate_id']); + + if ($conn->getAdapter() instanceof Sql\Adapter\Pgsql) { + $targets + ->withColumns([ + 'cert_fingerprint' => new Sql\Expression("ENCODE(%s, 'hex')", [ + 'chain.certificate.fingerprint' + ]), + 'cert_dn' => new Sql\Expression( + "ARRAY_TO_STRING(ARRAY_AGG(CONCAT(%s, '=', %s)), ',')", + [ + 'chain.certificate.dn.key', + 'chain.certificate.dn.value' + ] + ) + ]) + ->getSelectBase() + ->groupBy(['target_chain_certificate.id', 'target_chain_certificate_issuer_certificate.id']); + + $certAltName->columns([ + new Sql\Expression("ARRAY_TO_STRING(ARRAY_AGG(CONCAT(%s, ':', %s)), ',')", ['type', 'value']) + ]); + } else { + $targets->withColumns([ + 'cert_fingerprint' => new Sql\Expression('HEX(%s)', ['chain.certificate.fingerprint']), + 'cert_dn' => new Sql\Expression( + "GROUP_CONCAT(CONCAT(%s, '=', %s) SEPARATOR ',')", + [ + 'chain.certificate.dn.key', + 'chain.certificate.dn.value' + ] + ) + ]); + + $certAltName->columns([ + new Sql\Expression("GROUP_CONCAT(CONCAT(%s, ':', %s) SEPARATOR ',')", ['type', 'value']) + ]); + } + + list($select, $values) = $certAltName->dump(); + $targets->withColumns(['cert_subject_alt_name' => new Sql\Expression("$select", null, ...$values)]); + + $results = []; + /** @var X509Target $target */ + foreach ($targets as $target) { + $isV6 = Job::isIPV6($target->ip); + $target->host_ip = $target->ip; + $target->host_address = $isV6 ? null : $target->ip; + $target->host_address6 = $isV6 ? $target->ip : null; + + $target->host_name_ip_and_port = sprintf( + '%s/%s:%d', + $target->host_name, + $target->host_ip, + $target->host_port + ); + + // Target ip is now obsolete and must not be included in the results. + // The relation is only used to utilize the query and must not be in the result set as well. + unset($target->ip); + unset($target->chain); + + $results[$target->host_name_ip_and_port] = (object) iterator_to_array($target); + } + + return $results; + } + + public function listColumns() + { + return [ + 'host_name_ip_and_port', + 'host_ip', + 'host_name', + 'host_port', + 'host_address', + 'host_address6', + 'cert_subject', + 'cert_issuer', + 'cert_self_signed', + 'cert_trusted', + 'cert_valid_from', + 'cert_valid_to', + 'cert_fingerprint', + 'cert_dn', + 'cert_subject_alt_name' + ]; + } + + public static function getDefaultKeyColumnName() + { + return 'host_name_ip_and_port'; + } +} |