mirror of
https://github.com/netbirdio/plugins.git
synced 2026-05-22 18:44:07 -07:00
security/acme-client: remove support for defunct highwinds CDN (#3626)
This commit is contained in:
@@ -15,6 +15,9 @@ Added:
|
||||
* add support for DNSExit
|
||||
* add World4You DNS API (#3722)
|
||||
|
||||
Removed:
|
||||
* remove automation: Highwinds CDN (#3626)
|
||||
|
||||
3.19
|
||||
|
||||
Added:
|
||||
|
||||
-17
@@ -23,23 +23,6 @@
|
||||
<type>dropdown</type>
|
||||
<help>Pre-defined commands for this automation.</help>
|
||||
</field>
|
||||
<field>
|
||||
<label>Required Parameters</label>
|
||||
<type>header</type>
|
||||
<style>method_table method_table_configd_upload_highwinds</style>
|
||||
</field>
|
||||
<field>
|
||||
<id>action.highwinds_account_hash</id>
|
||||
<label>Account Hash</label>
|
||||
<type>text</type>
|
||||
<help>Account hash for Highwinds API.</help>
|
||||
</field>
|
||||
<field>
|
||||
<id>action.highwinds_access_token</id>
|
||||
<label>Access Token</label>
|
||||
<type>text</type>
|
||||
<help>Access token for Highwinds API.</help>
|
||||
</field>
|
||||
<field>
|
||||
<label>Required Parameters</label>
|
||||
<type>header</type>
|
||||
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020-2021 Frank Wall
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace OPNsense\AcmeClient\LeAutomation;
|
||||
|
||||
use OPNsense\AcmeClient\LeAutomationInterface;
|
||||
|
||||
/**
|
||||
* Upload certificate to Highwinds CDN API
|
||||
* @package OPNsense\AcmeClient
|
||||
*/
|
||||
class ConfigdUploadHighwinds extends Base implements LeAutomationInterface
|
||||
{
|
||||
public function prepare()
|
||||
{
|
||||
$command = 'acmeclient upload_highwinds ' . $this->cert_id . ' ' . $this->config->id;
|
||||
$this->command = $command;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+1
-12
@@ -1,6 +1,6 @@
|
||||
<model>
|
||||
<mount>//OPNsense/AcmeClient</mount>
|
||||
<version>3.4.0</version>
|
||||
<version>3.5.0</version>
|
||||
<description>A secure ACME Client plugin</description>
|
||||
<items>
|
||||
<settings>
|
||||
@@ -1206,7 +1206,6 @@
|
||||
<configd_restart_gui>Restart OPNsense Web UI</configd_restart_gui>
|
||||
<configd_restart_haproxy>Restart HAProxy (OPNsense plugin)</configd_restart_haproxy>
|
||||
<configd_restart_nginx>Restart Nginx (OPNsense plugin)</configd_restart_nginx>
|
||||
<configd_upload_highwinds>Upload certificate to Highwinds CDN</configd_upload_highwinds>
|
||||
<configd_upload_sftp>Upload certificate via SFTP</configd_upload_sftp>
|
||||
<configd_remote_ssh>Remote Command via SSH</configd_remote_ssh>
|
||||
<acme_fritzbox>Upload certificate to FRITZ!Box router</acme_fritzbox>
|
||||
@@ -1219,16 +1218,6 @@
|
||||
<configd_generic>System or Plugin Command</configd_generic>
|
||||
</OptionValues>
|
||||
</type>
|
||||
<highwinds_account_hash type="TextField">
|
||||
<Required>N</Required>
|
||||
<mask>/^.{1,1024}$/u</mask>
|
||||
<ValidationMessage>Should be a string between 1 and 1024 characters.</ValidationMessage>
|
||||
</highwinds_account_hash>
|
||||
<highwinds_access_token type="TextField">
|
||||
<Required>N</Required>
|
||||
<mask>/^.{1,1024}$/u</mask>
|
||||
<ValidationMessage>Should be a string between 1 and 1024 characters.</ValidationMessage>
|
||||
</highwinds_access_token>
|
||||
<sftp_host type="TextField">
|
||||
<Required>N</Required>
|
||||
<mask>/^.{1,255}$/u</mask>
|
||||
|
||||
@@ -1,254 +0,0 @@
|
||||
#!/usr/local/bin/php
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Frank Wall
|
||||
* Copyright (C) 2015 Deciso B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
require_once("config.inc");
|
||||
require_once("certs.inc");
|
||||
require_once("legacy_bindings.inc");
|
||||
require_once("util.inc");
|
||||
|
||||
use OPNsense\Core\Backend;
|
||||
use OPNsense\Core\Config;
|
||||
use OPNsense\Base;
|
||||
use OPNsense\AcmeClient\AcmeClient;
|
||||
|
||||
$HIGHWINDS_API_URL = 'https://striketracker.highwinds.com/api/v1/accounts';
|
||||
|
||||
function find_certificate($acme_cert_id)
|
||||
{
|
||||
$modelObj = new OPNsense\AcmeClient\AcmeClient();
|
||||
$configObj = Config::getInstance()->object();
|
||||
if (isset($configObj->OPNsense->AcmeClient->certificates) && $configObj->OPNsense->AcmeClient->certificates->count() > 0) {
|
||||
foreach ($configObj->OPNsense->AcmeClient->certificates->children() as $certObj) {
|
||||
$cert_id = (string)$certObj->id;
|
||||
$cert_name = (string)$certObj->name;
|
||||
if ($cert_id == $acme_cert_id) {
|
||||
if ($certObj->enabled == 0) {
|
||||
log_error("AcmeClient: certificate ${cert_name} is disabled, ignoring upload request");
|
||||
return 'None';
|
||||
}
|
||||
if (isset($certObj->certRefId)) {
|
||||
$data = array();
|
||||
$data['name'] = $cert_name;
|
||||
$data['refid'] = (string)$certObj->certRefId;
|
||||
return $data;
|
||||
} else {
|
||||
log_error("AcmeClient: certificate ${cert_name} could not be found in trust storage, ignoring upload request");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 'None';
|
||||
}
|
||||
}
|
||||
|
||||
function export_certificate($cert_refid)
|
||||
{
|
||||
$configObj = Config::getInstance()->object();
|
||||
foreach ($configObj->cert as $cert) {
|
||||
if ($cert_refid == (string)$cert->refid) {
|
||||
$cert_content = str_replace("\n\n", "\n", str_replace("\r", "", base64_decode((string)$cert->crt)));
|
||||
$key_content = str_replace("\n\n", "\n", str_replace("\r", "", base64_decode((string)$cert->prv)));
|
||||
// check if a CA is linked
|
||||
if (!empty((string)$cert->caref)) {
|
||||
$cert = (array)$cert;
|
||||
$ca = ca_chain($cert);
|
||||
$ca_content = $ca;
|
||||
}
|
||||
$result = array();
|
||||
$result['cert'] = $cert_content;
|
||||
$result['key'] = $key_content;
|
||||
$result['ca'] = $ca_content;
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
log_error("AcmeClient: cert with refid ${cert_refid} not found in trust storage");
|
||||
return 'None';
|
||||
}
|
||||
|
||||
function upload_certificate($cert_name, $cert_refid, $acme_cert_id, $acme_automation_id)
|
||||
{
|
||||
$modelObj = new OPNsense\AcmeClient\AcmeClient();
|
||||
$configObj = Config::getInstance()->object();
|
||||
if (isset($configObj->OPNsense->AcmeClient->actions) && $configObj->OPNsense->AcmeClient->actions->count() > 0) {
|
||||
foreach ($configObj->OPNsense->AcmeClient->actions->children() as $automObj) {
|
||||
$autom_id = (string)$automObj->id;
|
||||
if ($autom_id == $acme_automation_id) {
|
||||
if ($automObj->enabled == 0) {
|
||||
log_error("AcmeClient: ignoring disabled upload job for cert ${cert_name}");
|
||||
return 'None';
|
||||
}
|
||||
if (isset($automObj->highwinds_account_hash) && isset($automObj->highwinds_access_token)) {
|
||||
$hw_account_hash = (string)$automObj->highwinds_account_hash;
|
||||
$hw_access_token = (string)$automObj->highwinds_access_token;
|
||||
$cert_data = export_certificate($cert_refid);
|
||||
if ($cert_data !== 'None') {
|
||||
$hw_result = hw_upload_certificate($hw_account_hash, $hw_access_token, $cert_name, $cert_data);
|
||||
if ($hw_result !== 'None') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log_error("AcmeClient: upload job for cert ${cert_name} is incomplete, missing Highwinds configuration");
|
||||
return 'None';
|
||||
}
|
||||
}
|
||||
}
|
||||
return 'None';
|
||||
}
|
||||
}
|
||||
|
||||
function hw_list_certificates($account_hash, $access_token)
|
||||
{
|
||||
global $HIGHWINDS_API_URL;
|
||||
$curl = curl_init();
|
||||
curl_setopt_array($curl, array(
|
||||
CURLOPT_URL => "${HIGHWINDS_API_URL}/${account_hash}/certificates",
|
||||
CURLOPT_CUSTOMREQUEST => 'GET',
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_MAXREDIRS => 1,
|
||||
CURLOPT_TIMEOUT => 10,
|
||||
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
|
||||
CURLOPT_HTTPHEADER => array(
|
||||
"Authorization: Bearer ${access_token}",
|
||||
"Content-Type: application/json",
|
||||
"User-Agent: OPNsense Firewall",
|
||||
"X-Application-Id: OPNsense Firewall"
|
||||
)
|
||||
));
|
||||
$response = curl_exec($curl);
|
||||
$err = curl_error($curl);
|
||||
$info = curl_getinfo($curl);
|
||||
curl_close($curl);
|
||||
$http_code = $info['http_code'];
|
||||
if ($http_code != 200 || $err) {
|
||||
log_error("AcmeClient: failed to access Highwinds API, HTTP Code: ${http_code}, error ${err}");
|
||||
return 'None';
|
||||
}
|
||||
return json_decode($response);
|
||||
}
|
||||
|
||||
function hw_get_certificate($account_hash, $access_token, $cert_name)
|
||||
{
|
||||
$certificates = hw_list_certificates($account_hash, $access_token);
|
||||
if ($certificates !== 'None') {
|
||||
foreach ($certificates->list as $cert) {
|
||||
if ($cert->commonName == $cert_name) {
|
||||
return $cert;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 'None';
|
||||
}
|
||||
|
||||
function hw_upload_certificate($account_hash, $access_token, $cert_name, $cert_data)
|
||||
{
|
||||
global $HIGHWINDS_API_URL;
|
||||
// Check current status of certificate at Highwinds
|
||||
$hw_cert = hw_get_certificate($account_hash, $access_token, $cert_name);
|
||||
$hw_url = 'certificates';
|
||||
$hw_method = 'POST';
|
||||
if ($hw_cert == 'None') {
|
||||
log_error("AcmeClient: cert for ${cert_name} not found in Highwinds API, starting upload...");
|
||||
} else {
|
||||
log_error("AcmeClient: cert for ${cert_name} found in Highwinds API");
|
||||
$hw_method = 'PUT';
|
||||
|
||||
// Extract certificate details
|
||||
$cert = openssl_x509_parse($cert_data['cert']);
|
||||
$cert_sn = (string)$cert['serialNumber'];
|
||||
$hw_cert_sn = (string)$hw_cert->certificateInformation->serialNumber;
|
||||
$hw_cert_id = $hw_cert->id;
|
||||
|
||||
// Compare local and remote certificates
|
||||
if ($cert_sn == $hw_cert_sn) {
|
||||
log_error("AcmeClient: cert ${cert_name} has same serial in Highwinds API, not updating (${cert_sn})");
|
||||
return 'None';
|
||||
}
|
||||
log_error("AcmeClient: cert serial is different in Highwinds API, updating...");
|
||||
$hw_url = "${hw_url}/${hw_cert_id}";
|
||||
}
|
||||
|
||||
// adjust data format for Highwinds API
|
||||
$cert_post = json_encode(array('certificate' => $cert_data['cert'], 'key' => $cert_data['key'], 'caBundle' => $cert_data['ca']));
|
||||
|
||||
$curl = curl_init();
|
||||
curl_setopt_array($curl, array(
|
||||
CURLOPT_URL => "${HIGHWINDS_API_URL}/${account_hash}/${hw_url}",
|
||||
CURLOPT_CUSTOMREQUEST => $hw_method,
|
||||
CURLOPT_POSTFIELDS => (string)$cert_post,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_MAXREDIRS => 1,
|
||||
CURLOPT_TIMEOUT => 10,
|
||||
CURLOPT_SAFE_UPLOAD => true,
|
||||
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
|
||||
CURLOPT_HTTPHEADER => array(
|
||||
"Authorization: Bearer ${access_token}",
|
||||
"Content-Type: application/json",
|
||||
"User-Agent: OPNsense Firewall",
|
||||
"X-Application-Id: OPNsense Firewall",
|
||||
"Expect:"
|
||||
)
|
||||
));
|
||||
$response = curl_exec($curl);
|
||||
$err = curl_error($curl);
|
||||
$info = curl_getinfo($curl);
|
||||
curl_close($curl);
|
||||
$http_code = $info['http_code'];
|
||||
if ($http_code != 200 || $err) {
|
||||
log_error("AcmeClient: Failed to upload cert ${cert_name} to Highwinds API, HTTP Code: ${http_code}, error ${err}");
|
||||
return 'None';
|
||||
}
|
||||
return json_decode($response);
|
||||
}
|
||||
|
||||
// Evaluate CLI arguments
|
||||
$options = getopt("a:c:");
|
||||
if (!isset($options["a"]) or !isset($options["c"])) {
|
||||
print "ERROR: not enough arguments\n";
|
||||
exit(1);
|
||||
}
|
||||
$acme_cert_id = $options["c"];
|
||||
$acme_automation_id = $options["a"];
|
||||
|
||||
// Search certificate in configuration
|
||||
$cert_data = find_certificate($acme_cert_id);
|
||||
if ($cert_data == 'None') {
|
||||
log_error("AcmeClient: ignoring cert ID ${acme_cert_id}");
|
||||
exit(1);
|
||||
} else {
|
||||
// Upload certificate (if required)
|
||||
$upload_result = upload_certificate($cert_data['name'], $cert_data['refid'], $acme_cert_id, $acme_automation_id);
|
||||
if ($upload_result === 'None') {
|
||||
log_error("AcmeClient: cert ID ${acme_cert_id} was neither uploaded nor updated");
|
||||
} else {
|
||||
log_error("AcmeClient: cert ID ${acme_cert_id} was uploaded or updated");
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
@@ -91,12 +91,6 @@ parameters:%s
|
||||
type:script
|
||||
message:registering an account
|
||||
|
||||
[upload_highwinds]
|
||||
command:/usr/local/opnsense/scripts/OPNsense/AcmeClient/upload_highwinds.php
|
||||
parameters:-c %s -a %s
|
||||
type:script
|
||||
message:uploading a certificate to highwinds
|
||||
|
||||
[upload-sftp]
|
||||
command:/usr/local/opnsense/scripts/OPNsense/AcmeClient/upload_sftp.php
|
||||
parameters:--certificates=%s --automation-id=%s
|
||||
|
||||
Reference in New Issue
Block a user