Revised ErrorResponse json. Now using a map for the arguments and a string label instead of a number. (#192)

This commit is contained in:
Tim Bruijnzeels
2020-02-06 11:56:02 +01:00
parent c3ed1ac901
commit 867fdca459
62 changed files with 569 additions and 218 deletions
+13
View File
@@ -3,6 +3,19 @@
Please see [here](https://github.com/NLnetLabs/krill/projects?query=is%3Aopen+sort%3Aname-asc)
for planned releases.
## Unreleased Changes
Features / improvements:
* Added option to CLI to generate a Krill config file.
* Added simple Prometheus endpoint (/metrics)
* Added check for reporting status between CAs and their parents and repository
* Disable the embedded repository by default (see docs for info)
* Added guards against using 'localhost' in non-test environments
Breaking changes:
* The error responses have been overhauled.
## 0.4.2 'Finer Things'
This release fixes a bug, and introduces minor usability improvements:
+1 -1
View File
@@ -21,7 +21,7 @@ fn main() {
if format == ReportFormat::Json {
eprintln!("{}", e);
} else {
eprintln!("Error {}: {}", res.code(), res.msg());
eprintln!("Error: {}", res.msg());
}
}
_ => {
+14 -5
View File
@@ -25,6 +25,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
use rpki::cert::Cert;
use rpki::crl::Crl;
use rpki::crypto::KeyIdentifier;
use rpki::manifest::Manifest;
use rpki::roa::Roa;
@@ -228,15 +229,15 @@ pub struct Link {
/// https://rpki.readthedocs.io/en/latest/krill/pub/api.html#error-responses
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct ErrorResponse {
code: usize,
label: String,
msg: String,
args: HashMap<String, String>,
}
impl ErrorResponse {
pub fn new(code: usize, msg: impl fmt::Display) -> Self {
pub fn new(label: &str, msg: impl fmt::Display) -> Self {
ErrorResponse {
code,
label: label.to_string(),
msg: msg.to_string(),
args: HashMap::new(),
}
@@ -287,8 +288,16 @@ impl ErrorResponse {
res
}
pub fn code(&self) -> usize {
self.code
pub fn with_key_identifier(self, ki: &KeyIdentifier) -> Self {
self.with_arg("key_id", ki)
}
pub fn with_resource_class(self, class_name: &ResourceClassName) -> Self {
self.with_arg("class_name", class_name)
}
pub fn label(&self) -> &str {
&self.label
}
pub fn msg(&self) -> &str {
&self.msg
+472 -197
View File
@@ -19,180 +19,141 @@ use crate::commons::remote::rfc8181::ReportErrorCode;
use crate::commons::util::httpclient;
use crate::commons::util::softsigner::SignerError;
use crate::daemon::ca::RouteAuthorization;
use commons::api::ResourceClassName;
use rpki::x509::ValidationError;
#[derive(Debug, Display)]
pub enum Error {
//-----------------------------------------------------------------
// System Issues (1000-1099)
// System Issues
//-----------------------------------------------------------------
// 1000, internal server error
#[display(fmt = "{}", _0)]
#[display(fmt = "I/O error: {}", _0)]
IoError(io::Error),
// 1001, internal server error
#[display(fmt = "{}", _0)]
#[display(fmt = "Persistence error: {}", _0)]
AggregateStoreError(AggregateStoreError),
// 1002, internal server error
#[display(fmt = "Signing issue: {}", _0)]
SignerError(String),
// not on api (fails at start up)
#[display(fmt = "{}", _0)]
#[display(fmt = "Cannot set up HTTPS: {}", _0)]
HttpsSetup(String),
// not on api
#[display(fmt = "{}", _0)]
#[display(fmt = "HTTP client error: {}", _0)]
HttpClientError(httpclient::Error),
//-----------------------------------------------------------------
// General API Client Issues (2000-2099)
// General API Client Issues
//-----------------------------------------------------------------
// 2000
#[display(fmt = "Invalid JSON: {}", _0)]
JsonError(serde_json::Error),
// 2001, BAD REQUEST
#[display(fmt = "Unknown API method.")]
#[display(fmt = "Unknown API method")]
ApiUnknownMethod,
// 2002, NOT FOUND (generic API not found)
#[display(fmt = "Unknown resource.")]
#[display(fmt = "Unknown resource")]
ApiUnknownResource,
//-----------------------------------------------------------------
// Repository Issues (2100-2199)
// Repository Issues
//-----------------------------------------------------------------
// 2100
#[display(fmt = "No repository configured.")]
#[display(fmt = "No repository configured for CA")]
RepoNotSet,
//-----------------------------------------------------------------
// Publisher Issues (2200-2299)
// Publisher Issues
//-----------------------------------------------------------------
// 2200
#[display(fmt = "Unknown publisher '{}'", _0)]
PublisherUnknown(PublisherHandle),
// 2201
#[display(fmt = "Publishing uri '{}' outside repository uri '{}'", _0, _1)]
PublisherUriOutsideBase(String, String),
// 2202
#[display(fmt = "Publisher uri '{}' must have a trailing slash", _0)]
PublisherBaseUriNoSlash(String),
// 2203
#[display(fmt = "Duplicate publisher '{}'", _0)]
PublisherDuplicate(PublisherHandle),
// 2204
#[display(fmt = "No embedded repository configured")]
PublisherNoEmbeddedRepo,
//-----------------------------------------------------------------
// RF8181 (publishing, not on json API so no error responses)
// RFC 8181 (publishing)
//-----------------------------------------------------------------
#[display(fmt = "Issue with RFC8181 request: {}", _0)]
Rfc8181Validation(ValidationError),
// not on api
#[display(fmt = "Could not decode or validate RFC8181 request: {}", _0)]
Rfc8181Validation(String),
#[display(fmt = "Issue with decoding RFC8181 request: {}", _0)]
Rfc8181Decode(String),
// not on api
#[display(fmt = "{}", _0)]
Rfc8181MessageError(rfc8181::MessageError),
// not on api
#[display(fmt = "{}", _0)]
Rfc8181Delta(PublicationDeltaError),
//-----------------------------------------------------------------
// CA Issues (2300-2399)
// CA Issues
//-----------------------------------------------------------------
// 2300
#[display(fmt = "CA '{}' was already initialised", _0)]
CaDuplicate(Handle),
// 2301
#[display(fmt = "CA '{}' is unknown", _0)]
CaUnknown(Handle),
// CA Repo Issues (2310-2319)
// 2310
#[display(fmt = "CA '{}' already uses this repository.", _0)]
// CA Repo Issues
#[display(fmt = "CA '{}' already uses this repository", _0)]
CaRepoInUse(Handle),
// 2311
#[display(fmt = "CA '{}' got error from repository: {}", _0, _1)]
CaRepoNotResponsive(Handle, String),
// 2312
CaRepoIssue(Handle, String),
#[display(fmt = "CA '{}' got invalid repository response xml: {}", _0, _1)]
CaRepoResponseInvalidXml(Handle, String),
// 2312
#[display(fmt = "CA '{}' got parent instead of repository response.", _0)]
#[display(fmt = "CA '{}' got parent instead of repository response", _0)]
CaRepoResponseWrongXml(Handle),
// CA Parent Issues (2320-2329)
// 2320
// CA Parent Issues
#[display(fmt = "CA '{}' already has a parent named '{}'", _0, _1)]
CaParentDuplicate(Handle, ParentHandle),
// 2321
#[display(fmt = "CA '{}' does not have parent named '{}'", _0, _1)]
CaParentUnknown(Handle, ParentHandle),
// 2322
#[display(fmt = "CA '{}' got error from parent '{}': {}", _0, _1, _2)]
CaParentNotResponsive(Handle, ParentHandle, String),
// 2323
CaParentIssue(Handle, ParentHandle, String),
#[display(fmt = "CA '{}' got invalid parent response xml: {}", _0, _1)]
CaParentResponseInvalidXml(Handle, String),
// 2334
#[display(fmt = "CA '{}' got repository response when adding parent.", _0)]
#[display(fmt = "CA '{}' got repository response when adding parent", _0)]
CaParentResponseWrongXml(Handle),
#[display(
fmt = "Please configure the repository for CA '{}' before adding parents",
_0
)]
CaParentWithoutRepo(Handle),
//-----------------------------------------------------------------
// RFC6492 (requesting resources, not on JSON api)
// RFC6492 (requesting resources)
//-----------------------------------------------------------------
// not on api
#[display(fmt = "{}", _0)]
#[display(fmt = "RFC 6492 Issue: {}", _0)]
Rfc6492(rfc6492::Error),
// not on api
#[display(fmt = "Invalid CSR received: {}.", _0)]
#[display(fmt = "Invalid CSR received: {}", _0)]
Rfc6492InvalidCsrSent(String),
// not on api
#[display(fmt = "Invalidly signed RFC 6492 CMS.")]
#[display(fmt = "Invalidly signed RFC 6492 CMS")]
Rfc6492SignatureInvalid,
// CA Child Issues (2330-2339)
// 2330
#[display(fmt = "CA '{}' already has child named {}.", _0, _1)]
#[display(fmt = "CA '{}' already has child named '{}'", _0, _1)]
CaChildDuplicate(Handle, ChildHandle),
// 2331
#[display(fmt = "CA '{}' does not have child named {}.", _0, _1)]
#[display(fmt = "CA '{}' does not have child named '{}'", _0, _1)]
CaChildUnknown(Handle, ChildHandle),
// 2332
#[display(fmt = "Child '{}' for CA '{}' MUST have resources specified.", _1, _0)]
#[display(fmt = "Child '{}' for CA '{}' MUST have resources specified", _1, _0)]
CaChildMustHaveResources(Handle, ChildHandle),
// 2333
#[display(fmt = "CA '{}' does not know id certificate for child '{}'.", _0, _1)]
#[display(fmt = "CA '{}' does not know id certificate for child '{}'", _0, _1)]
CaChildUnauthorised(Handle, ChildHandle),
// RouteAuthorizations (2340-2349)
@@ -218,7 +179,7 @@ pub enum Error {
//-----------------------------------------------------------------
// not on api
#[display(fmt = "Attempt at re-using keys.")]
#[display(fmt = "Attempt at re-using keys")]
KeyUseAttemptReuse,
// not on api
@@ -238,7 +199,7 @@ pub enum Error {
KeyUseNoIssuedCert,
// not on api
#[display(fmt = "No key found matching key identifier: {}", _0)]
#[display(fmt = "No key found matching key identifier: '{}'", _0)]
KeyUseNoMatch(KeyIdentifier),
//-----------------------------------------------------------------
@@ -246,15 +207,15 @@ pub enum Error {
//-----------------------------------------------------------------
// not on api
#[display(fmt = "Unknown resource class: {}", _0)]
ResourceClassUnknown(String),
#[display(fmt = "Unknown resource class: '{}'", _0)]
ResourceClassUnknown(ResourceClassName),
// not on api
#[display(fmt = "{}", _0)]
ResourceSetError(ResourceSetError),
// not on api
#[display(fmt = "Requester is not entitled to all requested resources.")]
#[display(fmt = "Requester is not entitled to all requested resources")]
MissingResources,
//-----------------------------------------------------------------
@@ -262,11 +223,11 @@ pub enum Error {
//-----------------------------------------------------------------
// 2600
#[display(fmt = "Functionality not supported for TA.")]
#[display(fmt = "Functionality not supported for Trust Anchor")]
TaNotAllowed,
// 2601
#[display(fmt = "Name reserved for embedded TA.")]
#[display(fmt = "Name reserved for embedded Trust Anchor")]
TaNameReserved,
// not on api
@@ -326,10 +287,6 @@ impl Error {
Error::Rfc6492InvalidCsrSent(msg.to_string())
}
pub fn unknown_resource_class(class: impl Display) -> Self {
Error::ResourceClassUnknown(class.to_string())
}
pub fn publishing_outside_jail(uri: &uri::Rsync, jail: &uri::Rsync) -> Self {
Error::PublisherUriOutsideBase(uri.to_string(), jail.to_string())
}
@@ -337,10 +294,6 @@ impl Error {
pub fn custom(msg: impl fmt::Display) -> Self {
Error::Custom(msg.to_string())
}
pub fn rfc8181_validation(e: impl fmt::Display) -> Self {
Error::Rfc8181Validation(e.to_string())
}
}
impl std::error::Error for Error {}
@@ -362,206 +315,218 @@ impl Error {
}
pub fn to_error_response(&self) -> ErrorResponse {
fn not_in_api() -> ErrorResponse {
unimplemented!("Cannot be caused by API")
}
match self {
//-----------------------------------------------------------------
// System Issues (1000-1099)
// System Issues (label: sys-*)
//-----------------------------------------------------------------
// 1000, internal server error
Error::IoError(e) => ErrorResponse::new(1000, self.to_string()).with_cause(e),
// internal server error
Error::IoError(e) => ErrorResponse::new("sys-io", &self).with_cause(e),
// 1001, internal server error
Error::AggregateStoreError(e) => {
ErrorResponse::new(1001, self.to_string()).with_cause(e)
}
// internal server error
Error::AggregateStoreError(e) => ErrorResponse::new("sys-store", &self).with_cause(e),
// 1002, internal server error
Error::SignerError(e) => ErrorResponse::new(1002, self.to_string()).with_cause(e),
// internal server error
Error::SignerError(e) => ErrorResponse::new("sys-signer", &self).with_cause(e),
// not on api (fails at start up)
Error::HttpsSetup(_) => not_in_api(),
// internal server error
Error::HttpsSetup(e) => ErrorResponse::new("sys-https", &self).with_cause(e),
// not on api
Error::HttpClientError(_) => not_in_api(),
// internal server error
Error::HttpClientError(e) => ErrorResponse::new("sys-http-client", &self).with_cause(e),
//-----------------------------------------------------------------
// General API Client Issues (2000-2099)
// General API Client Issues (label: api-*)
//-----------------------------------------------------------------
// 2000
Error::JsonError(e) => ErrorResponse::new(2000, self.to_string()).with_cause(e),
// BAD REQUEST
Error::JsonError(e) => ErrorResponse::new("api-json", &self).with_cause(e),
// 2001, BAD REQUEST
Error::ApiUnknownMethod => ErrorResponse::new(2001, &self),
// BAD REQUEST
Error::ApiUnknownMethod => ErrorResponse::new("api-unknown-method", &self),
// 2002, NOT FOUND (generic API not found)
Error::ApiUnknownResource => ErrorResponse::new(2002, &self),
// NOT FOUND (generic API not found)
Error::ApiUnknownResource => ErrorResponse::new("api-unknown-resource", &self),
//-----------------------------------------------------------------
// Repository Issues (2100-2199)
// Repository Issues (label: repo-*)
//-----------------------------------------------------------------
// 2100
Error::RepoNotSet => ErrorResponse::new(2100, &self),
Error::RepoNotSet => ErrorResponse::new("repo-not-set", &self),
//-----------------------------------------------------------------
// Publisher Issues (2200-2299)
// Publisher Issues (label: pub-*)
//-----------------------------------------------------------------
Error::PublisherUnknown(p) => {
ErrorResponse::new(2200, self.to_string()).with_publisher(p)
ErrorResponse::new("pub-unknown", &self).with_publisher(p)
}
Error::PublisherDuplicate(p) => {
ErrorResponse::new(2201, self.to_string()).with_publisher(p)
ErrorResponse::new("pub-duplicate", &self).with_publisher(p)
}
Error::PublisherUriOutsideBase(uri, base) => ErrorResponse::new(2202, self.to_string())
.with_uri(uri)
.with_base_uri(base),
Error::PublisherUriOutsideBase(uri, base) => {
ErrorResponse::new("pub-outside-jail", &self)
.with_uri(uri)
.with_base_uri(base)
}
Error::PublisherBaseUriNoSlash(uri) => {
ErrorResponse::new(2203, self.to_string()).with_uri(uri)
ErrorResponse::new("pub-uri-no-slash", &self).with_uri(uri)
}
Error::PublisherNoEmbeddedRepo => ErrorResponse::new(2204, &self),
Error::PublisherNoEmbeddedRepo => ErrorResponse::new("pub-no-embedded-repo", &self),
//-----------------------------------------------------------------
// RF8181 (publishing, not on json API so no error responses)
// RFC 8181
//-----------------------------------------------------------------
Error::Rfc8181Validation(_) => not_in_api(),
Error::Rfc8181MessageError(_) => not_in_api(),
Error::Rfc8181Delta(_) => not_in_api(),
Error::Rfc8181Validation(e) => {
ErrorResponse::new("rfc8181-validation", &self).with_cause(e)
}
Error::Rfc8181Decode(e) => ErrorResponse::new("rfc8181-decode", &self).with_cause(e),
Error::Rfc8181MessageError(e) => {
ErrorResponse::new("rfc8181-protocol-message", &self).with_cause(e)
}
Error::Rfc8181Delta(e) => ErrorResponse::new("rfc8181-delta", &self).with_cause(e),
//-----------------------------------------------------------------
// CA Issues (2300-2399)
// CA Issues (label: ca-*)
//-----------------------------------------------------------------
Error::CaDuplicate(ca) => ErrorResponse::new(2300, self.to_string()).with_ca(ca),
Error::CaDuplicate(ca) => ErrorResponse::new("ca-duplicate", &self).with_ca(ca),
Error::CaUnknown(ca) => ErrorResponse::new(2301, self.to_string()).with_ca(ca),
Error::CaUnknown(ca) => ErrorResponse::new("ca-unknown", &self).with_ca(ca),
Error::CaRepoInUse(ca) => ErrorResponse::new(2302, self.to_string()).with_ca(ca),
Error::CaRepoInUse(ca) => ErrorResponse::new("ca-repo-same", &self).with_ca(ca),
Error::CaRepoNotResponsive(ca, err) => ErrorResponse::new(2310, self.to_string())
Error::CaRepoIssue(ca, err) => ErrorResponse::new("ca-repo-issue", &self)
.with_ca(ca)
.with_cause(err),
Error::CaRepoResponseInvalidXml(ca, err) => ErrorResponse::new(2311, self.to_string())
.with_ca(ca)
.with_cause(err),
Error::CaRepoResponseWrongXml(ca) => {
ErrorResponse::new(2312, self.to_string()).with_ca(ca)
}
Error::CaParentDuplicate(ca, parent) => ErrorResponse::new(2320, self.to_string())
.with_ca(ca)
.with_parent(parent),
Error::CaParentUnknown(ca, parent) => ErrorResponse::new(2321, self.to_string())
.with_ca(ca)
.with_parent(parent),
Error::CaParentNotResponsive(ca, parent, err) => {
ErrorResponse::new(2322, self.to_string())
Error::CaRepoResponseInvalidXml(ca, err) => {
ErrorResponse::new("ca-repo-response-invalid-xml", &self)
.with_ca(ca)
.with_parent(parent)
.with_cause(err)
}
Error::CaRepoResponseWrongXml(ca) => {
ErrorResponse::new("ca-repo-response-wrong-xml", &self).with_ca(ca)
}
Error::CaParentDuplicate(ca, parent) => {
ErrorResponse::new("ca-parent-duplicate", &self)
.with_ca(ca)
.with_parent(parent)
}
Error::CaParentUnknown(ca, parent) => ErrorResponse::new("ca-parent-unknown", &self)
.with_ca(ca)
.with_parent(parent),
Error::CaParentIssue(ca, parent, err) => ErrorResponse::new("ca-parent-issue", &self)
.with_ca(ca)
.with_parent(parent)
.with_cause(err),
Error::CaParentResponseInvalidXml(ca, err) => {
ErrorResponse::new(2323, self.to_string())
ErrorResponse::new("ca-parent-response-invalid-xml", &self)
.with_ca(ca)
.with_cause(err)
}
Error::CaParentResponseWrongXml(ca) => {
ErrorResponse::new(2324, self.to_string()).with_ca(ca)
ErrorResponse::new("ca-parent-response-wrong-xml", &self).with_ca(ca)
}
Error::CaParentWithoutRepo(ca) => {
ErrorResponse::new("ca-parent-no-repo", &self).with_ca(ca)
}
//-----------------------------------------------------------------
// RFC6492 (requesting resources, not on JSON api)
//-----------------------------------------------------------------
Error::Rfc6492(_) => not_in_api(),
Error::Rfc6492InvalidCsrSent(_) => not_in_api(),
Error::Rfc6492SignatureInvalid => not_in_api(),
Error::Rfc6492(e) => ErrorResponse::new("rfc6492-protocol", &self).with_cause(e),
Error::Rfc6492InvalidCsrSent(e) => {
ErrorResponse::new("rfc6492-invalid-csr", &self).with_cause(e)
}
Error::Rfc6492SignatureInvalid => {
ErrorResponse::new("rfc6492-invalid-signature", &self)
}
// CA Child Issues (2330-2339)
Error::CaChildDuplicate(ca, child) => ErrorResponse::new(2330, self.to_string())
// CA Child Issues
Error::CaChildDuplicate(ca, child) => ErrorResponse::new("ca-child-duplicate", &self)
.with_ca(ca)
.with_child(child),
Error::CaChildUnknown(ca, child) => ErrorResponse::new(2331, self.to_string())
Error::CaChildUnknown(ca, child) => ErrorResponse::new("ca-child-unknown", &self)
.with_ca(ca)
.with_child(child),
Error::CaChildMustHaveResources(ca, child) => {
ErrorResponse::new(2332, self.to_string())
ErrorResponse::new("ca-child-resources-required", &self)
.with_ca(ca)
.with_child(child)
}
Error::CaChildUnauthorised(ca, child) => {
ErrorResponse::new("ca-child-unauthorised", &self)
.with_ca(ca)
.with_child(child)
}
Error::CaChildUnauthorised(ca, child) => ErrorResponse::new(2333, self.to_string())
.with_ca(ca)
.with_child(child),
// RouteAuthorizations (2340-2349)
Error::CaAuthorisationUnknown(ca, auth) => ErrorResponse::new(2340, self.to_string())
// RouteAuthorizations
Error::CaAuthorisationUnknown(ca, auth) => ErrorResponse::new("ca-auth-unknown", &self)
.with_ca(ca)
.with_auth(auth),
Error::CaAuthorisationDuplicate(ca, auth) => ErrorResponse::new(2341, self.to_string())
.with_ca(ca)
.with_auth(auth),
Error::CaAuthorisationDuplicate(ca, auth) => {
ErrorResponse::new("ca-auth-duplicate", &self)
.with_ca(ca)
.with_auth(auth)
}
Error::CaAuthorisationInvalidMaxlength(ca, auth) => {
ErrorResponse::new(2342, self.to_string())
ErrorResponse::new("ca-auth-invalid-max-length", &self)
.with_ca(ca)
.with_auth(auth)
}
Error::CaAuthorisationNotEntitled(ca, auth) => {
ErrorResponse::new(2343, self.to_string())
ErrorResponse::new("ca-auth-not-entitled", &self)
.with_ca(ca)
.with_auth(auth)
}
//-----------------------------------------------------------------
// Key Usage Issues (2400-2499)
// Key Usage Issues (key-*)
//-----------------------------------------------------------------
// not on api
Error::KeyUseAttemptReuse => not_in_api(),
Error::KeyUseNoNewKey => not_in_api(),
Error::KeyUseNoCurrentKey => not_in_api(),
Error::KeyUseNoOldKey => not_in_api(),
Error::KeyUseNoIssuedCert => not_in_api(),
Error::KeyUseNoMatch(_) => not_in_api(),
Error::KeyUseAttemptReuse => ErrorResponse::new("key-re-use", &self),
Error::KeyUseNoNewKey => ErrorResponse::new("key-no-new", &self),
Error::KeyUseNoCurrentKey => ErrorResponse::new("key-no-current", &self),
Error::KeyUseNoOldKey => ErrorResponse::new("key-no-old", &self),
Error::KeyUseNoIssuedCert => ErrorResponse::new("key-no-cert", &self),
Error::KeyUseNoMatch(ki) => {
ErrorResponse::new("key-no-match", &self).with_key_identifier(ki)
}
//-----------------------------------------------------------------
// Resource Issues (2500-2599)
// Resource Issues (label: rc-*)
//-----------------------------------------------------------------
Error::ResourceClassUnknown(_) => not_in_api(),
Error::ResourceSetError(_) => not_in_api(),
Error::MissingResources => not_in_api(),
Error::ResourceClassUnknown(name) => {
ErrorResponse::new("rc-unknown", &self).with_resource_class(name)
}
Error::ResourceSetError(e) => ErrorResponse::new("rc-resources", &self).with_cause(e),
Error::MissingResources => ErrorResponse::new("rc-missing-resources", &self),
//-----------------------------------------------------------------
// Embedded (test) TA issues (2600-2699)
// Embedded (test) TA issues (label: ta-*)
//-----------------------------------------------------------------
Error::TaNotAllowed => ErrorResponse::new(2600, &self),
Error::TaNameReserved => ErrorResponse::new(2601, &self),
Error::TaAlreadyInitialised => not_in_api(),
Error::TaNotAllowed => ErrorResponse::new("ta-not-allowed", &self),
Error::TaNameReserved => ErrorResponse::new("ta-name-reserved", &self),
Error::TaAlreadyInitialised => ErrorResponse::new("ta-initialised", &self),
//-----------------------------------------------------------------
// If we really don't know any more..
//-----------------------------------------------------------------
Error::Custom(_msg) => ErrorResponse::new(65535, &self),
Error::Custom(_msg) => ErrorResponse::new("general-error", &self),
}
// self.code().clone().into()
}
pub fn to_rfc8181_error_code(&self) -> ReportErrorCode {
@@ -583,3 +548,313 @@ impl Error {
}
}
}
//------------ Tests ---------------------------------------------------------
#[cfg(test)]
mod tests {
use std::str::FromStr;
use crate::commons::api::RoaDefinition;
use crate::commons::remote::id::tests::test_id_certificate;
use super::*;
#[test]
fn error_response_json_regressiongit() {
let ca = Handle::from_str_unsafe("ca");
let parent = ParentHandle::from_str_unsafe("parent");
let child = ChildHandle::from_str_unsafe("child");
let publisher = PublisherHandle::from_str_unsafe("publisher");
let auth =
RouteAuthorization::new(RoaDefinition::from_str("192.168.0.0/16-24 => 64496").unwrap());
fn verify(expected_json: &str, e: Error) {
let actual = e.to_error_response();
let expected: ErrorResponse = serde_json::from_str(expected_json).unwrap();
assert_eq!(expected, actual);
// check that serde works too
let serialized = serde_json::to_string(&actual).unwrap();
let des = serde_json::from_str(&serialized).unwrap();
assert_eq!(actual, des);
}
//-----------------------------------------------------------------
// System Issues
//-----------------------------------------------------------------
let io_err = io::Error::new(io::ErrorKind::Other, "can't read file");
verify(
include_str!("../../test-resources/errors/sys-io.json"),
Error::IoError(io_err),
);
verify(
include_str!("../../test-resources/errors/sys-store.json"),
Error::AggregateStoreError(AggregateStoreError::InitError),
);
verify(
include_str!("../../test-resources/errors/sys-signer.json"),
Error::SignerError("signer issue".to_string()),
);
verify(
include_str!("../../test-resources/errors/sys-https.json"),
Error::HttpsSetup("can't find pem file".to_string()),
);
verify(
include_str!("../../test-resources/errors/sys-http-client.json"),
Error::HttpClientError(httpclient::Error::Forbidden),
);
//-----------------------------------------------------------------
// General API Client Issues
//-----------------------------------------------------------------
let invalid_rsync_json = "\"https://host/module/folder\"";
let json_err = serde_json::from_str::<uri::Rsync>(invalid_rsync_json)
.err()
.unwrap();
verify(
include_str!("../../test-resources/errors/api-json.json"),
Error::JsonError(json_err),
);
verify(
include_str!("../../test-resources/errors/api-unknown-method.json"),
Error::ApiUnknownMethod,
);
verify(
include_str!("../../test-resources/errors/api-unknown-resource.json"),
Error::ApiUnknownResource,
);
//-----------------------------------------------------------------
// Repository Issues
//-----------------------------------------------------------------
verify(
include_str!("../../test-resources/errors/repo-not-set.json"),
Error::RepoNotSet,
);
//-----------------------------------------------------------------
// Publisher Issues
//-----------------------------------------------------------------
verify(
include_str!("../../test-resources/errors/pub-unknown.json"),
Error::PublisherUnknown(publisher.clone()),
);
verify(
include_str!("../../test-resources/errors/pub-duplicate.json"),
Error::PublisherDuplicate(publisher.clone()),
);
verify(
include_str!("../../test-resources/errors/pub-outside-jail.json"),
Error::PublisherUriOutsideBase(
"rsync://somehost/module/folder".to_string(),
"rsync://otherhost/module/folder".to_string(),
),
);
verify(
include_str!("../../test-resources/errors/pub-uri-no-slash.json"),
Error::PublisherBaseUriNoSlash("rsync://host/module/folder".to_string()),
);
verify(
include_str!("../../test-resources/errors/pub-no-embedded-repo.json"),
Error::PublisherNoEmbeddedRepo,
);
//-----------------------------------------------------------------
// RFC 8181
//-----------------------------------------------------------------
verify(
include_str!("../../test-resources/errors/rfc8181-validation.json"),
Error::Rfc8181Validation(ValidationError),
);
verify(
include_str!("../../test-resources/errors/rfc8181-decode.json"),
Error::Rfc8181Decode("could not parse CMS".to_string()),
);
verify(
include_str!("../../test-resources/errors/rfc8181-protocol-message.json"),
Error::Rfc8181MessageError(rfc8181::MessageError::InvalidVersion),
);
verify(
include_str!("../../test-resources/errors/rfc8181-delta.json"),
Error::Rfc8181Delta(PublicationDeltaError::ObjectAlreadyPresent(
uri::Rsync::from_str("rsync://host/module/file.cer").unwrap(),
)),
);
//-----------------------------------------------------------------
// CA Issues (label: ca-*)
//-----------------------------------------------------------------
verify(
include_str!("../../test-resources/errors/ca-duplicate.json"),
Error::CaDuplicate(ca.clone()),
);
verify(
include_str!("../../test-resources/errors/ca-unknown.json"),
Error::CaUnknown(ca.clone()),
);
verify(
include_str!("../../test-resources/errors/ca-repo-same.json"),
Error::CaRepoInUse(ca.clone()),
);
verify(
include_str!("../../test-resources/errors/ca-repo-issue.json"),
Error::CaRepoIssue(ca.clone(), "cannot connect".to_string()),
);
verify(
include_str!("../../test-resources/errors/ca-repo-response-invalid-xml.json"),
Error::CaRepoResponseInvalidXml(ca.clone(), "expected some tag".to_string()),
);
verify(
include_str!("../../test-resources/errors/ca-repo-response-wrong-xml.json"),
Error::CaRepoResponseWrongXml(ca.clone()),
);
verify(
include_str!("../../test-resources/errors/ca-parent-duplicate.json"),
Error::CaParentDuplicate(ca.clone(), parent.clone()),
);
verify(
include_str!("../../test-resources/errors/ca-parent-unknown.json"),
Error::CaParentUnknown(ca.clone(), parent.clone()),
);
verify(
include_str!("../../test-resources/errors/ca-parent-issue.json"),
Error::CaParentIssue(ca.clone(), parent.clone(), "connection refused".to_string()),
);
verify(
include_str!("../../test-resources/errors/ca-parent-response-invalid-xml.json"),
Error::CaParentResponseInvalidXml(ca.clone(), "expected something".to_string()),
);
verify(
include_str!("../../test-resources/errors/ca-parent-response-wrong-xml.json"),
Error::CaParentResponseWrongXml(ca.clone()),
);
verify(
include_str!("../../test-resources/errors/ca-parent-no-repo.json"),
Error::CaParentWithoutRepo(ca.clone()),
);
verify(
include_str!("../../test-resources/errors/rfc6492-protocol.json"),
Error::Rfc6492(rfc6492::Error::InvalidVersion),
);
verify(
include_str!("../../test-resources/errors/rfc6492-invalid-csr.json"),
Error::Rfc6492InvalidCsrSent("invalid signature".to_string()),
);
verify(
include_str!("../../test-resources/errors/rfc6492-invalid-signature.json"),
Error::Rfc6492SignatureInvalid,
);
verify(
include_str!("../../test-resources/errors/ca-child-duplicate.json"),
Error::CaChildDuplicate(ca.clone(), child.clone()),
);
verify(
include_str!("../../test-resources/errors/ca-child-unknown.json"),
Error::CaChildUnknown(ca.clone(), child.clone()),
);
verify(
include_str!("../../test-resources/errors/ca-child-resources-required.json"),
Error::CaChildMustHaveResources(ca.clone(), child.clone()),
);
verify(
include_str!("../../test-resources/errors/ca-child-unauthorised.json"),
Error::CaChildUnauthorised(ca.clone(), child.clone()),
);
verify(
include_str!("../../test-resources/errors/ca-auth-unknown.json"),
Error::CaAuthorisationUnknown(ca.clone(), auth),
);
verify(
include_str!("../../test-resources/errors/ca-auth-duplicate.json"),
Error::CaAuthorisationDuplicate(ca.clone(), auth),
);
verify(
include_str!("../../test-resources/errors/ca-auth-invalid-max-length.json"),
Error::CaAuthorisationInvalidMaxlength(ca.clone(), auth),
);
verify(
include_str!("../../test-resources/errors/ca-auth-not-entitled.json"),
Error::CaAuthorisationNotEntitled(ca.clone(), auth),
);
verify(
include_str!("../../test-resources/errors/key-re-use.json"),
Error::KeyUseAttemptReuse,
);
verify(
include_str!("../../test-resources/errors/key-no-new.json"),
Error::KeyUseNoNewKey,
);
verify(
include_str!("../../test-resources/errors/key-no-current.json"),
Error::KeyUseNoCurrentKey,
);
verify(
include_str!("../../test-resources/errors/key-no-old.json"),
Error::KeyUseNoOldKey,
);
verify(
include_str!("../../test-resources/errors/key-no-cert.json"),
Error::KeyUseNoIssuedCert,
);
let ki = test_id_certificate()
.subject_public_key_info()
.key_identifier();
verify(
include_str!("../../test-resources/errors/key-no-match.json"),
Error::KeyUseNoMatch(ki),
);
verify(
include_str!("../../test-resources/errors/rc-unknown.json"),
Error::ResourceClassUnknown(ResourceClassName::from("RC0")),
);
verify(
include_str!("../../test-resources/errors/rc-resources.json"),
Error::ResourceSetError(ResourceSetError::Mix),
);
verify(
include_str!("../../test-resources/errors/rc-missing-resources.json"),
Error::MissingResources,
);
verify(
include_str!("../../test-resources/errors/ta-not-allowed.json"),
Error::TaNotAllowed,
);
verify(
include_str!("../../test-resources/errors/ta-name-reserved.json"),
Error::TaNameReserved,
);
verify(
include_str!("../../test-resources/errors/ta-initialised.json"),
Error::TaAlreadyInitialised,
);
verify(
include_str!("../../test-resources/errors/general-error.json"),
Error::custom("some unlikely corner case"),
);
// let mut res = String::new();
// for e in errs {
// let error_response = e.to_error_response();
//
// let path = format!("test-resources/errors/{}.json", error_response.label());
// let path = PathBuf::from(&path);
//
// file::save_json(&error_response, &path).unwrap();
// }
}
}
+4 -4
View File
@@ -53,16 +53,16 @@ pub enum AggregateStoreError {
#[display(fmt = "{}", _0)]
KeyStoreError(KeyStoreError),
#[display(fmt = "Unknown aggregate: {}", _0)]
#[display(fmt = "unknown entity: {}", _0)]
UnknownAggregate(Handle),
#[display(fmt = "Aggregate init event exists, but cannot be applied")]
#[display(fmt = "init event exists, but cannot be applied")]
InitError,
#[display(fmt = "Event not applicable to aggregate, id or version is off")]
#[display(fmt = "event not applicable to entity, id or version is off")]
WrongEventForAggregate,
#[display(fmt = "Trying to update outdated aggregate '{}'", _0)]
#[display(fmt = "concurrent modifcation attempt for entity: '{}'", _0)]
ConcurrentModification(Handle),
}
+7 -7
View File
@@ -741,7 +741,7 @@ impl<S: Signer> CertAuth<S> {
let my_rc = self
.resources
.get(&rcn)
.ok_or_else(|| Error::unknown_resource_class(&rcn))?;
.ok_or_else(|| Error::ResourceClassUnknown(rcn))?;
let child = self.get_child(&child)?;
child.resources().apply_limit(&limit)?;
@@ -753,7 +753,7 @@ impl<S: Signer> CertAuth<S> {
/// for updating child certificates.
fn republish_certs(
&self,
class_name: &ResourceClassName,
rcn: &ResourceClassName,
issued_certs: &[&IssuedCert],
removed_certs: &[&Cert],
signer: &S,
@@ -761,8 +761,8 @@ impl<S: Signer> CertAuth<S> {
let repo = self.get_repository_contact()?;
self.resources
.get(&class_name)
.ok_or_else(|| Error::unknown_resource_class(&class_name))?
.get(&rcn)
.ok_or_else(|| Error::ResourceClassUnknown(rcn.clone()))?
.republish_certs(issued_certs, removed_certs, repo.repo_info(), signer)
}
@@ -959,7 +959,7 @@ impl<S: Signer> CertAuth<S> {
/// by this name (handle) is already known.
fn add_parent(&self, parent: Handle, info: ParentCaContact) -> KrillResult<Vec<Evt>> {
if self.repository.is_none() {
Err(Error::RepoNotSet)
Err(Error::CaParentWithoutRepo(self.handle.clone()))
} else if self.has_parent(&parent) {
Err(Error::CaParentDuplicate(self.handle.clone(), parent))
} else if self.is_ta() {
@@ -1241,7 +1241,7 @@ impl<S: Signer> CertAuth<S> {
let rc = self
.resources
.get(&rcn)
.ok_or_else(|| Error::unknown_resource_class(&rcn))?;
.ok_or_else(|| Error::ResourceClassUnknown(rcn))?;
let repo = self.get_repository_contact()?;
@@ -1337,7 +1337,7 @@ impl<S: Signer> CertAuth<S> {
let my_rc = self
.resources
.get(&rcn)
.ok_or_else(|| Error::unknown_resource_class(&rcn))?;
.ok_or_else(|| Error::ResourceClassUnknown(rcn.clone()))?;
let repo = self.get_repository_contact()?;
+1 -1
View File
@@ -520,7 +520,7 @@ impl KrillServer {
RepositoryUpdate::Rfc8181(response) => {
// first check that the new repo can be contacted
if let CurrentRepoState::Error(error) = self.repo_state(&handle, Some(&response)) {
return Err(Error::CaRepoNotResponsive(handle, error.msg().to_string()));
return Err(Error::CaRepoIssue(handle, error.msg().to_string()));
}
RepositoryContact::Rfc8181(response)
+3 -3
View File
@@ -129,12 +129,12 @@ impl PubServer {
let repository = self.repository()?;
let publisher = repository.get_publisher(&publisher_handle)?;
let msg =
SignedMessage::decode(msg_bytes.clone(), false).map_err(Error::rfc8181_validation)?;
let msg = SignedMessage::decode(msg_bytes.clone(), false)
.map_err(|e| Error::Rfc8181Decode(e.to_string()))?;
let cms_logger = CmsLogger::for_rfc8181_rcvd(&self.cms_logger_work_dir, &publisher_handle);
msg.validate(publisher.id_cert())
.map_err(Error::rfc8181_validation)?;
.map_err(Error::Rfc8181Validation)?;
let content = rfc8181::Message::from_signed_message(&msg)?;
let query = content.into_query()?;
+1
View File
@@ -0,0 +1 @@
{"label":"api-json","msg":"Invalid JSON: bad URI scheme at line 1 column 28","args":{"cause":"bad URI scheme at line 1 column 28"}}
@@ -0,0 +1 @@
{"label":"api-unknown-method","msg":"Unknown API method","args":{}}
@@ -0,0 +1 @@
{"label":"api-unknown-resource","msg":"Unknown resource","args":{}}
@@ -0,0 +1 @@
{"label":"ca-auth-duplicate","msg":"Duplicate authorization '192.168.0.0/16-24 => 64496' for CA 'ca'","args":{"asn":"64496","ca":"ca","prefix":"192.168.0.0/16","max_length":"24"}}
@@ -0,0 +1 @@
{"label":"ca-auth-invalid-max-length","msg":"Invalid max length in authorization: '192.168.0.0/16-24 => 64496' for CA 'ca","args":{"ca":"ca","prefix":"192.168.0.0/16","max_length":"24","asn":"64496"}}
@@ -0,0 +1 @@
{"label":"ca-auth-not-entitled","msg":"Authorisation '192.168.0.0/16-24 => 64496' resource not held by CA 'ca'.","args":{"asn":"64496","ca":"ca","prefix":"192.168.0.0/16","max_length":"24"}}
@@ -0,0 +1 @@
{"label":"ca-auth-unknown","msg":"Cannot remove unknown authorization 'ca' from CA '192.168.0.0/16-24 => 64496'","args":{"ca":"ca","max_length":"24","asn":"64496","prefix":"192.168.0.0/16"}}
@@ -0,0 +1 @@
{"label":"ca-child-duplicate","msg":"CA 'ca' already has child named 'child'","args":{"child":"child","ca":"ca"}}
@@ -0,0 +1 @@
{"label":"ca-child-resources-required","msg":"Child 'child' for CA 'ca' MUST have resources specified","args":{"child":"child","ca":"ca"}}
@@ -0,0 +1 @@
{"label":"ca-child-unauthorised","msg":"CA 'ca' does not know id certificate for child 'child'","args":{"ca":"ca","child":"child"}}
@@ -0,0 +1 @@
{"label":"ca-child-unknown","msg":"CA 'ca' does not have child named 'child'","args":{"child":"child","ca":"ca"}}
+1
View File
@@ -0,0 +1 @@
{"label":"ca-duplicate","msg":"CA 'ca' was already initialised","args":{"ca":"ca"}}
@@ -0,0 +1 @@
{"label":"ca-parent-duplicate","msg":"CA 'ca' already has a parent named 'parent'","args":{"ca":"ca","parent":"parent"}}
@@ -0,0 +1 @@
{"label":"ca-parent-issue","msg":"CA 'ca' got error from parent 'parent': connection refused","args":{"parent":"parent","ca":"ca","cause":"connection refused"}}
@@ -0,0 +1 @@
{"label":"ca-parent-no-repo","msg":"Please configure the repository for CA 'ca' before adding parents","args":{"ca":"ca"}}
@@ -0,0 +1 @@
{"label":"ca-parent-response-invalid-xml","msg":"CA 'ca' got invalid parent response xml: expected something","args":{"cause":"expected something","ca":"ca"}}
@@ -0,0 +1 @@
{"label":"ca-parent-response-wrong-xml","msg":"CA 'ca' got repository response when adding parent","args":{"ca":"ca"}}
@@ -0,0 +1 @@
{"label":"ca-parent-unknown","msg":"CA 'ca' does not have parent named 'parent'","args":{"ca":"ca","parent":"parent"}}
+1
View File
@@ -0,0 +1 @@
{"label":"ca-repo-issue","msg":"CA 'ca' got error from repository: cannot connect","args":{"cause":"cannot connect","ca":"ca"}}
@@ -0,0 +1 @@
{"label":"ca-repo-response-invalid-xml","msg":"CA 'ca' got invalid repository response xml: expected some tag","args":{"ca":"ca","cause":"expected some tag"}}
@@ -0,0 +1 @@
{"label":"ca-repo-response-wrong-xml","msg":"CA 'ca' got parent instead of repository response","args":{"ca":"ca"}}
+1
View File
@@ -0,0 +1 @@
{"label":"ca-repo-same","msg":"CA 'ca' already uses this repository","args":{"ca":"ca"}}
+1
View File
@@ -0,0 +1 @@
{"label":"ca-unknown","msg":"CA 'ca' is unknown","args":{"ca":"ca"}}
+1
View File
@@ -0,0 +1 @@
{"label":"general-error","msg":"some unlikely corner case","args":{}}
+1
View File
@@ -0,0 +1 @@
{"label":"key-no-cert","msg":"No issued cert matching pub key","args":{}}
@@ -0,0 +1 @@
{"label":"key-no-current","msg":"No current key in resource class","args":{}}
+1
View File
@@ -0,0 +1 @@
{"label":"key-no-match","msg":"No key found matching key identifier: 'E445382DC63E360A9FB575FC12470E66785BB27E'","args":{"key_id":"E445382DC63E360A9FB575FC12470E66785BB27E"}}
+1
View File
@@ -0,0 +1 @@
{"label":"key-no-new","msg":"No new key in resource class","args":{}}
+1
View File
@@ -0,0 +1 @@
{"label":"key-no-old","msg":"No old key in resource class","args":{}}
+1
View File
@@ -0,0 +1 @@
{"label":"key-re-use","msg":"Attempt at re-using keys","args":{}}
+1
View File
@@ -0,0 +1 @@
{"label":"pub-duplicate","msg":"Duplicate publisher 'publisher'","args":{"publisher":"publisher"}}
@@ -0,0 +1 @@
{"label":"pub-no-embedded-repo","msg":"No embedded repository configured","args":{}}
@@ -0,0 +1 @@
{"label":"pub-outside-jail","msg":"Publishing uri 'rsync://somehost/module/folder' outside repository uri 'rsync://otherhost/module/folder'","args":{"uri":"rsync://somehost/module/folder","base_uri":"rsync://otherhost/module/folder"}}
+1
View File
@@ -0,0 +1 @@
{"label":"pub-unknown","msg":"Unknown publisher 'publisher'","args":{"publisher":"publisher"}}
@@ -0,0 +1 @@
{"label":"pub-uri-no-slash","msg":"Publisher uri 'rsync://host/module/folder' must have a trailing slash","args":{"uri":"rsync://host/module/folder"}}
@@ -0,0 +1 @@
{"label":"rc-missing-resources","msg":"Requester is not entitled to all requested resources","args":{}}
+1
View File
@@ -0,0 +1 @@
{"label":"rc-resources","msg":"Mixed Address Families in configured resource set","args":{"cause":"Mixed Address Families in configured resource set"}}
+1
View File
@@ -0,0 +1 @@
{"label":"rc-unknown","msg":"Unknown resource class: 'RC0'","args":{"class_name":"RC0"}}
+1
View File
@@ -0,0 +1 @@
{"label":"repo-not-set","msg":"No repository configured for CA","args":{}}
@@ -0,0 +1 @@
{"label":"rfc6492-invalid-csr","msg":"Invalid CSR received: invalid signature","args":{"cause":"invalid signature"}}
@@ -0,0 +1 @@
{"label":"rfc6492-invalid-signature","msg":"Invalidly signed RFC 6492 CMS","args":{}}
@@ -0,0 +1 @@
{"label":"rfc6492-protocol","msg":"RFC 6492 Issue: Invalid protocol version, MUST be 1","args":{"cause":"Invalid protocol version, MUST be 1"}}
@@ -0,0 +1 @@
{"label":"rfc8181-decode","msg":"Issue with decoding RFC8181 request: could not parse CMS","args":{"cause":"could not parse CMS"}}
+1
View File
@@ -0,0 +1 @@
{"label":"rfc8181-delta","msg":"File already exists for uri (use update!): rsync://host/module/file.cer","args":{"cause":"File already exists for uri (use update!): rsync://host/module/file.cer"}}
@@ -0,0 +1 @@
{"label":"rfc8181-protocol-message","msg":"Invalid version","args":{"cause":"Invalid version"}}
@@ -0,0 +1 @@
{"label":"rfc8181-validation","msg":"Issue with RFC8181 request: validation error","args":{"cause":"validation error"}}
@@ -0,0 +1 @@
{"label":"sys-http-client","msg":"HTTP client error: Access Forbidden","args":{"cause":"Access Forbidden"}}
+1
View File
@@ -0,0 +1 @@
{"label":"sys-https","msg":"Cannot set up HTTPS: can't find pem file","args":{"cause":"can't find pem file"}}
+1
View File
@@ -0,0 +1 @@
{"label":"sys-io","msg":"I/O error: can't read file","args":{"cause":"can't read file"}}
+1
View File
@@ -0,0 +1 @@
{"label":"sys-signer","msg":"Signing issue: signer issue","args":{"cause":"signer issue"}}
+1
View File
@@ -0,0 +1 @@
{"label":"sys-store","msg":"Persistence error: init event exists, but cannot be applied","args":{"cause":"init event exists, but cannot be applied"}}
@@ -0,0 +1 @@
{"label":"ta-initialised","msg":"TrustAnchor was already initialised","args":{}}
@@ -0,0 +1 @@
{"label":"ta-name-reserved","msg":"Name reserved for embedded Trust Anchor","args":{}}
@@ -0,0 +1 @@
{"label":"ta-not-allowed","msg":"Functionality not supported for Trust Anchor","args":{}}