check dns for lets encrypt when adding/editing domains and via cron; fixes #971

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
This commit is contained in:
Michael Kaufmann 2021-08-04 13:44:13 +02:00
parent bef5cedcd0
commit 0a1a3e023f
No known key found for this signature in database
GPG Key ID: 08A83830520FCECB
7 changed files with 85 additions and 0 deletions

View File

@ -574,6 +574,14 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
$include_specialsettings = 0;
}
// validate dns if lets encrypt is enabled to check whether we can use it at all
if ($letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
$domain_ips = \Froxlor\PhpHelper::gethostbynamel6($domain);
if ($domain_ips == false || count(array_intersect($ssl_ipandports, $domain_ips)) <= 0) {
\Froxlor\UI\Response::standard_error('invaliddnsforletsencrypt', '', true);
}
}
// We can't enable let's encrypt for wildcard-domains
if ($serveraliasoption == '0' && $letsencrypt == '1') {
\Froxlor\UI\Response::standard_error('nowildcardwithletsencrypt', '', true);
@ -1326,6 +1334,14 @@ class Domains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\ResourceEn
$include_specialsettings = 0;
}
// validate dns if lets encrypt is enabled to check whether we can use it at all
if ($letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
$domain_ips = \Froxlor\PhpHelper::gethostbynamel6($result['domain']);
if ($domain_ips == false || count(array_intersect($ssl_ipandports, $domain_ips)) <= 0) {
\Froxlor\UI\Response::standard_error('invaliddnsforletsencrypt', '', true);
}
}
// We can't enable let's encrypt for wildcard-domains
if ($serveraliasoption == '0' && $letsencrypt == '1') {
\Froxlor\UI\Response::standard_error('nowildcardwithletsencrypt', '', true);

View File

@ -2,6 +2,7 @@
namespace Froxlor\Api\Commands;
use Froxlor\Database\Database;
use Froxlor\Domain\Domain;
use Froxlor\Settings;
/**
@ -230,6 +231,15 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
}
}
// validate dns if lets encrypt is enabled to check whether we can use it at all
if ($letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
$our_ips = Domain::getIpsOfDomain($domain_check['id']);
$domain_ips = \Froxlor\PhpHelper::gethostbynamel6($completedomain);
if ($domain_ips == false || count(array_intersect($our_ips, $domain_ips)) <= 0) {
\Froxlor\UI\Response::standard_error('invaliddnsforletsencrypt', '', true);
}
}
// Temporarily deactivate ssl_redirect until Let's Encrypt certificate was generated
if ($ssl_redirect > 0 && $letsencrypt == 1) {
$ssl_redirect = 2;
@ -595,6 +605,15 @@ class SubDomains extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resourc
}
}
// validate dns if lets encrypt is enabled to check whether we can use it at all
if ($result['letsencrypt'] != $letsencrypt && $letsencrypt == '1' && Settings::Get('system.le_domain_dnscheck') == '1') {
$our_ips = Domain::getIpsOfDomain($result['parentdomainid']);
$domain_ips = \Froxlor\PhpHelper::gethostbynamel6($result['domain']);
if ($domain_ips == false || count(array_intersect($our_ips, $domain_ips)) <= 0) {
\Froxlor\UI\Response::standard_error('invaliddnsforletsencrypt', '', true);
}
}
// We can't enable let's encrypt for wildcard-domains
if ($iswildcarddomain == '1' && $letsencrypt == '1') {
\Froxlor\UI\Response::standard_error('nowildcardwithletsencrypt');

View File

@ -293,6 +293,12 @@ class AcmeSh extends \Froxlor\Cron\FroxlorCron
// no common ips...
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Skipping Let's Encrypt generation for " . $domain . " due to no system known IP address via DNS check");
unset($domains[$idx]);
// in order to avoid a cron-loop that tries to get a certificate every 5 minutes, we disable let's encrypt for this domain
$upd_stmt = Database::prepare("UPDATE `" . TABLE_PANEL_DOMAINS . "` SET `letsencrypt` = '0' WHERE `id` = :did");
Database::pexecute($upd_stmt, [
'did' => $domain_id
]);
$cronlog->logAction(FroxlorLogger::CRON_ACTION, LOG_WARNING, "Let's Encrypt deactivated for domain " . $domain);
}
}
}

View File

@ -2128,3 +2128,4 @@ $lng['serversettings']['froxlorusergroup']['title'] = 'Custom system group for a
$lng['serversettings']['froxlorusergroup']['description'] = 'Usage of libnss-extrausers (system-settings) is required for this to take effect. An empty value skips creation or removes existing group.';
$lng['error']['local_group_exists'] = 'The given group already exists on the system.';
$lng['error']['local_group_invalid'] = 'The given group name is invalid';
$lng['error']['invaliddnsforletsencrypt'] = 'The domains DNS does not include any of the chosen IP addresses. Let\'s Encrypt certificate generation not possible.';

View File

@ -1774,3 +1774,4 @@ $lng['serversettings']['froxlorusergroup']['title'] = 'Benutzerdefinierte Gruppe
$lng['serversettings']['froxlorusergroup']['description'] = 'Voraussetzung hierfür ist die Nutzung von libnss-extrausers (System-Einstellungen). Ein leerer Wert bedeutet, es wird keine Gruppe erstellt, bzw. vorhandene Gruppe wird entfernt.';
$lng['error']['local_group_exists'] = 'Die angegebene Gruppe existiert bereits auf dem System';
$lng['error']['local_group_invalid'] = 'Der angegebene Gruppen-Name ist nicht gültig';
$lng['error']['invaliddnsforletsencrypt'] = 'Die DNS-Einträge der Domain enhalten keine der gewählten IP Adressen. Let\'s Encrypt Zertifikats-Erstellung ist nicht möglich.';

View File

@ -24,6 +24,7 @@ class DomainsTest extends TestCase
$json_result = Customers::getLocal($admin_userdata, array(
'loginname' => 'test1'
))->get();
$customer_userdata = json_decode($json_result, true)['data'];
$data = [
'domain' => 'TEST.local',
@ -425,4 +426,25 @@ class DomainsTest extends TestCase
'domainname' => 'उदाहरण.भारत'
])->delete();
}
public function testAdminDomainsAddDnsLetsEncryptFail()
{
global $admin_userdata;
// get customer
$json_result = Customers::getLocal($admin_userdata, array(
'loginname' => 'test1'
))->get();
Settings::Set('system.le_domain_dnscheck', 1);
$customer_userdata = json_decode($json_result, true)['data'];
$data = [
'domain' => 'no-dns.local',
'customerid' => $customer_userdata['customerid'],
'letsencrypt' => 1,
'description' => 'no dns domain'
];
$this->expectExceptionCode(400);
$this->expectExceptionMessage('The domains DNS does not include any of the chosen IP addresses. Let\'s Encrypt certificate generation not possible.');
Domains::getLocal($admin_userdata, $data)->add();
}
}

View File

@ -260,4 +260,24 @@ class SubDomainsTest extends TestCase
$this->assertEquals('mysub.test2.local', $result['domain']);
$this->assertEquals($customer_userdata['customerid'], $result['customerid']);
}
public function testCustomerSubDomainsAddDnsLetsEncryptFail()
{
global $admin_userdata;
// get customer
$json_result = Customers::getLocal($admin_userdata, array(
'loginname' => 'test1'
))->get();
\Froxlor\Settings::Set('system.le_domain_dnscheck', 1);
$customer_userdata = json_decode($json_result, true)['data'];
$data = [
'subdomain' => 'nodns',
'domain' => 'test2.local',
'letsencrypt' => 1
];
$this->expectExceptionCode(400);
$this->expectExceptionMessage('The domains DNS does not include any of the chosen IP addresses. Let\'s Encrypt certificate generation not possible.');
SubDomains::getLocal($customer_userdata, $data)->add();
}
}