Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion security/acme-client/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PLUGIN_NAME= acme-client
PLUGIN_VERSION= 1.1
PLUGIN_VERSION= 1.2
PLUGIN_COMMENT= Let's Encrypt client
PLUGIN_MAINTAINER= opnsense@moov.de

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ public function searchAction()
$grid = new UIModelGrid($mdlAcme->certificates->certificate);
return $grid->fetchBindRequest(
$this->request,
array("enabled", "name", "altNames", "description"),
array("enabled", "name", "altNames", "description", "lastUpdate", "statusCode", "statusLastUpdate"),
"name"
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,11 @@ public function fetchHAProxyIntegrationAction()
(string)$validation->method == "http01" and
(string)$validation->http_service == "haproxy") {
//$this->getLogger()->error("LE HAProxy DEBUG: checking validation method: " . (string)$validation->name);
// Check if HAProxy frontends were specified.
if (empty((string)$validation->http_haproxyFrontends)) {
// Skip item, no HAProxy frontends were specified.
continue;
}
$_frontends = explode(',', $validation->http_haproxyFrontends);
// Walk through all linked frontends.
foreach ($_frontends as $_frontend) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
</field>
<field>
<id>certificate.account</id>
<label>CA Account</label>
<label>LE Account</label>
<type>dropdown</type>
<help><![CDATA[Set the CA account to use for this certificate.]]></help>
<help><![CDATA[Set the Let's Encrypt account to use for this certificate.]]></help>
</field>
<field>
<id>certificate.validationMethod</id>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,18 @@
<lastUpdate type="IntegerField">
<Required>N</Required>
</lastUpdate>
<!-- hidden field; status of last operation -->
<statusCode type="IntegerField">
<Required>N</Required>
<!-- XXX: enable once data migration is working -->
<!-- <default>100</default> -->
<MinimumValue>100</MinimumValue>
<MaximumValue>1000</MaximumValue>
</statusCode>
<!-- hidden field; timestamp for statusCode -->
<statusLastUpdate type="IntegerField">
<Required>N</Required>
</statusLastUpdate>
</certificate>
</certificates>
<validations>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,52 @@ POSSIBILITY OF SUCH DAMAGE.
} else {
return "<span style=\"cursor: pointer;\" class=\"fa fa-square-o command-toggle\" data-value=\"0\" data-row-id=\"" + row.uuid + "\"></span>";
}
},
"certdate": function (column, row) {
if (row.lastUpdate == "" || row.lastUpdate == undefined) {
return "{{ lang._('pending') }}";
} else {
var certdate = new Date(row.lastUpdate*1000);
return certdate.toLocaleString();
}
},
"acmestatus": function (column, row) {
if (row.statusCode == "" || row.statusCode == undefined) {
// fallback to lastUpdate value (unset if cert was never issued/imported)
if (row.lastUpdate == "" || row.lastUpdate == undefined) {
return "{{ lang._('unknown') }}";
} else {
return "{{ lang._('OK') }}";
}
} else if (row.statusCode == "100") {
return "{{ lang._('unknown') }}";
} else if (row.statusCode == "200") {
return "{{ lang._('OK') }}";
} else if (row.statusCode == "250") {
return "{{ lang._('cert revoked') }}";
} else if (row.statusCode == "300") {
return "{{ lang._('configuration error') }}";
} else if (row.statusCode == "400") {
return "{{ lang._('validation failed') }}";
} else if (row.statusCode == "500") {
return "{{ lang._('internal error') }}";
} else {
return "{{ lang._('unknown') }}";
}
},
"acmestatusdate": function (column, row) {
if (row.statusLastUpdate == "" || row.statusCode == undefined) {
// fallback to lastUpdate value
if (row.lastUpdate == "" || row.lastUpdate == undefined) {
return "{{ lang._('unknown') }}";
} else {
var legacydate = new Date(row.lastUpdate*1000);
return legacydate.toLocaleString();
}
} else {
var statusdate = new Date(row.statusLastUpdate*1000);
return statusdate.toLocaleString();
}
}
},
};
Expand Down Expand Up @@ -339,6 +385,9 @@ POSSIBILITY OF SUCH DAMAGE.
<th data-column-id="name" data-type="string">{{ lang._('Certificate Name') }}</th>
<th data-column-id="altNames" data-type="string">{{ lang._('Multi-Domain (SAN)') }}</th>
<th data-column-id="description" data-type="string">{{ lang._('Description') }}</th>
<th data-column-id="lastUpdate" data-type="string" data-formatter="certdate">{{ lang._('Issue/Renewal Date') }}</th>
<th data-column-id="statusCode" data-type="string" data-formatter="acmestatus">{{ lang._('Last Acme Status') }}</th>
<th data-column-id="statusLastUpdate" data-type="string" data-formatter="acmestatusdate">{{ lang._('Last Acme Run') }}</th>
<th data-column-id="commands" data-width="11em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
</tr>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ function cert_action_validator($opt_cert_id)
} else {
//echo "DEBUG: account registration failed\n";
log_error("AcmeClient: account registration failed");
log_cert_acme_status($certObj, $modelObj, '400');
if (isset($options["A"])) {
continue; // skip to next item
}
Expand All @@ -166,6 +167,7 @@ function cert_action_validator($opt_cert_id)
} else {
//echo "DEBUG: account not found\n";
log_error("AcmeClient: account not found");
log_cert_acme_status($certObj, $modelObj, '300');
if (isset($options["A"])) {
continue; // skip to next item
}
Expand Down Expand Up @@ -193,10 +195,12 @@ function cert_action_validator($opt_cert_id)
// Start acme client to revoke the certificate
$rev_result = revoke_cert($certObj, $valObj, $acctObj);
if (!$rev_result) {
log_cert_acme_status($certObj, $modelObj, '250');
return(0); // Success!
} else {
// Revocation failure
log_error("AcmeClient: revocation for certificate failed");
log_cert_acme_status($certObj, $modelObj, '400');
if (isset($options["A"])) {
continue; // skip to next item
}
Expand All @@ -215,8 +219,10 @@ function cert_action_validator($opt_cert_id)
//echo "DEBUG: cert import done\n";
// Prepare certificate for restart action
$restart_certs[] = $certObj;
log_cert_acme_status($certObj, $modelObj, '200');
} else {
log_error("AcmeClient: unable to import certificate: " . (string)$certObj->name);
log_cert_acme_status($certObj, $modelObj, '500');
if (isset($options["A"])) {
continue; // skip to next item
}
Expand All @@ -227,20 +233,23 @@ function cert_action_validator($opt_cert_id)
} else {
// validation failure
log_error("AcmeClient: validation for certificate failed: " . (string)$certObj->name);
log_cert_acme_status($certObj, $modelObj, '400');
if (isset($options["A"])) {
continue; // skip to next item
}
return(1);
}
} else {
log_error("AcmeClient: invalid validation method specified: " . (string)$valObj->method);
log_cert_acme_status($certObj, $modelObj, '300');
if (isset($options["A"])) {
continue; // skip to next item
}
return(1);
}
} else {
log_error("AcmeClient: validation method not found for cert " . $certObj->name);
log_cert_acme_status($certObj, $modelObj, '300');
if (isset($options["A"])) {
continue; // skip to next item
}
Expand Down Expand Up @@ -887,8 +896,11 @@ function run_restart_actions($certlist, $modelObj)
}
// Extract restart actions
$_actions = explode(',', $certObj->restartActions);
if (empty($_actions)) {
// No restart actions configured.
continue;
}
// Walk through all linked restart actions.
$_actions = explode(',', $certObj->restartActions);
foreach ($_actions as $_action) {
// Extract restart action
$action = $modelObj->getByActionID($_action);
Expand Down Expand Up @@ -1007,6 +1019,32 @@ function run_restart_actions($certlist, $modelObj)
return($return);
}

/* Update certificate object to log the status of the current acme run.
* Supported status codes are:
* 100 pending
* 200 issue/renew OK
* 250 certificate revoked
* 300 configuration error (validation method, account, ...)
* 400 issue/renew failed
* 500 internal error (code issues, bad luck, unexpected errors, ...)
* Feel free to add more status codes to make it more useful.
*/
function log_cert_acme_status($certObj, $modelObj, $statusCode)
{
$uuid = $certObj->attributes()->uuid;
$node = $modelObj->getNodeByReference('certificates.certificate.' . $uuid);
if ($node != null) {
$node->statusCode = $statusCode;
$node->statusLastUpdate = time();
// serialize to config and save
$modelObj->serializeToConfig();
Config::getInstance()->save();
} else {
log_error("AcmeClient: unable to update acme status for certificate " . (string)$certObj->name);
return(1);
}
}

// taken from certs.inc
function local_cert_get_subject_array($str_crt, $decode = true)
{
Expand Down