Show parents in list, and parent contact only as separate call in API and CLI (Closes #138)

This commit is contained in:
Tim Bruijnzeels
2019-11-14 15:13:39 +01:00
parent 610e67fd1b
commit 26bb82014f
7 changed files with 125 additions and 22 deletions
+9 -3
View File
@@ -8,12 +8,12 @@ use rpki::uri;
use crate::cli::options::{BulkCaCommand, CaCommand, Command, Options, PublishersCommand};
use crate::cli::report::{ApiResponse, ReportError};
use crate::commons::api::{
CaRepoDetails, CertAuthInfo, ParentCaContact, PublisherDetails, PublisherList, Token,
CaRepoDetails, CertAuthInfo, ChildCaInfo, ParentCaContact, PublisherDetails, PublisherList,
Token,
};
use crate::commons::remote::rfc8183;
use crate::commons::util::httpclient;
use crate::constants::KRILL_CLI_API_ENV;
use commons::api::ChildCaInfo;
/// Command line tool for Krill admin tasks
pub struct KrillClient {
@@ -94,7 +94,7 @@ impl KrillClient {
}
CaCommand::ParentResponse(handle, child) => {
let uri = format!("api/v1/cas/{}/parent_contact/{}", handle, child);
let uri = format!("api/v1/cas/{}/children/{}/contact", handle, child);
let info: ParentCaContact = self.get_json(&uri)?;
Ok(ApiResponse::ParentCaContact(info))
}
@@ -142,6 +142,12 @@ impl KrillClient {
Ok(ApiResponse::Empty)
}
CaCommand::MyParentCaContact(handle, parent) => {
let uri = format!("api/v1/cas/{}/parents/{}", handle, parent);
let parent: ParentCaContact = self.get_json(&uri)?;
Ok(ApiResponse::ParentCaContact(parent))
}
CaCommand::ChildInfo(handle, child) => {
let uri = format!("api/v1/cas/{}/children/{}", handle, child);
let info: ChildCaInfo = self.get_json(&uri)?;
+27 -1
View File
@@ -386,6 +386,17 @@ impl Options {
app.subcommand(sub)
}
fn make_cas_parents_contact_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
let mut sub =
SubCommand::with_name("contact").about("Show contact information for parent.");
sub = Self::add_general_args(sub);
sub = Self::add_my_ca_arg(sub);
sub = Self::add_parent_arg(sub);
app.subcommand(sub)
}
fn make_cas_parents_remove_sc<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
let mut sub =
SubCommand::with_name("remove").about("Remove an existing parent from this CA.");
@@ -403,6 +414,7 @@ impl Options {
sub = Self::make_cas_parents_myid_sc(sub);
sub = Self::make_cas_parents_add_sc(sub);
sub = Self::make_cas_parents_update_sc(sub);
sub = Self::make_cas_parents_contact_sc(sub);
sub = Self::make_cas_parents_remove_sc(sub);
app.subcommand(sub)
@@ -875,6 +887,16 @@ impl Options {
}
}
fn parse_matches_cas_parents_info(matches: &ArgMatches) -> Result<Options, Error> {
let general_args = GeneralArgs::from_matches(matches)?;
let my_ca = Self::parse_my_ca(matches)?;
let parent = matches.value_of("parent").unwrap();
let parent = Handle::from_str(parent).map_err(|_| Error::InvalidHandle)?;
let command = Command::CertAuth(CaCommand::MyParentCaContact(my_ca, parent));
Ok(Options::make(general_args, command))
}
fn parse_matches_cas_parents_remove(matches: &ArgMatches) -> Result<Options, Error> {
let general_args = GeneralArgs::from_matches(matches)?;
let my_ca = Self::parse_my_ca(matches)?;
@@ -892,6 +914,8 @@ impl Options {
Self::parse_matches_cas_parents_add(m)
} else if let Some(m) = matches.subcommand_matches("update") {
Self::parse_matches_cas_parents_update(m)
} else if let Some(m) = matches.subcommand_matches("contact") {
Self::parse_matches_cas_parents_info(m)
} else if let Some(m) = matches.subcommand_matches("remove") {
Self::parse_matches_cas_parents_remove(m)
} else {
@@ -1165,7 +1189,7 @@ pub enum CaCommand {
// Update CA id
UpdateId(Handle),
// Get an RFC8183 parent response
// Get an RFC8183 parent response for a child
ParentResponse(Handle, ChildHandle),
// Get the RFC8183 child request
@@ -1178,6 +1202,8 @@ pub enum CaCommand {
// Add a parent to this CA
AddParent(Handle, ParentCaReq),
// Show my parent's contact
MyParentCaContact(Handle, ParentHandle),
// Update parent contact
UpdateParentContact(Handle, ParentHandle, ParentCaContact),
+11 -7
View File
@@ -1,12 +1,12 @@
use std::str::{from_utf8_unchecked, FromStr};
use crate::commons::api::{
CaRepoDetails, CertAuthHistory, CertAuthInfo, CertAuthList, CurrentObjects, CurrentRepoState,
ParentCaContact, PublisherDetails, PublisherList, RepositoryContact, RoaDefinition,
CaRepoDetails, CertAuthHistory, CertAuthInfo, CertAuthList, ChildCaInfo, CurrentObjects,
CurrentRepoState, ParentCaContact, PublisherDetails, PublisherList, RepositoryContact,
RoaDefinition,
};
use crate::commons::remote::api::ClientInfo;
use crate::commons::remote::rfc8183;
use commons::api::ChildCaInfo;
//------------ ApiResponse ---------------------------------------------------
@@ -162,10 +162,14 @@ impl Report for CertAuthInfo {
}
}
for (name, kind) in self.parents().iter() {
res.push_str(&format!("Parent: {}, Kind: {}\n", name, kind));
res.push_str("Parents:\n");
if !self.parents().is_empty() {
for parent in self.parents().iter() {
res.push_str(&format!("{}\n", parent));
}
} else {
res.push_str("<none>\n")
}
res.push_str("\n");
for (name, rc) in self.resources() {
res.push_str(&format!("Resource Class: {}\n", name,));
@@ -183,7 +187,7 @@ impl Report for CertAuthInfo {
res.push_str(&format!("{}\n", child_handle));
}
} else {
res.push_str("<none>");
res.push_str("<none>\n");
}
Ok(res)
+47 -10
View File
@@ -19,12 +19,11 @@ use rpki::roa::Roa;
use rpki::uri;
use rpki::x509::{Serial, Time};
use crate::commons::api::admin::{Handle, ParentCaContact};
use crate::commons::api::publication;
use crate::commons::api::publication::Publish;
use crate::commons::api::{
Base64, ChildHandle, HexEncodedHash, IssuanceRequest, ListReply, ParentHandle,
RepositoryContact, RequestResourceLimit, RoaDefinition,
Base64, ChildHandle, Handle, HexEncodedHash, IssuanceRequest, ListReply, ParentCaContact,
ParentHandle, RepositoryContact, RequestResourceLimit, RoaDefinition,
};
use crate::commons::eventsourcing::AggregateHistory;
use crate::commons::remote::id::IdCert;
@@ -1416,6 +1415,43 @@ impl CertAuthSummary {
}
}
//------------ ParentKindInfo ------------------------------------------------
#[derive(Clone, Debug, Deserialize, Display, Eq, PartialEq, Serialize)]
pub enum ParentKindInfo {
#[display(fmt = "This CA is a TA")]
Ta,
#[display(fmt = "Embedded parent")]
Embedded,
#[display(fmt = "RFC 6492 Parent")]
Rfc6492,
}
//------------ ParentInfo ----------------------------------------------------
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct ParentInfo {
handle: ParentHandle,
kind: ParentKindInfo,
}
impl ParentInfo {
pub fn new(handle: ParentHandle, contact: ParentCaContact) -> Self {
let kind = match contact {
ParentCaContact::Ta(_) => ParentKindInfo::Ta,
ParentCaContact::Embedded => ParentKindInfo::Embedded,
ParentCaContact::Rfc6492(_) => ParentKindInfo::Rfc6492,
};
ParentInfo { handle, kind }
}
}
impl fmt::Display for ParentInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}", self.handle, self.kind)
}
}
//------------ CertAuthInfo --------------------------------------------------
/// This type represents the details of a CertAuth that need
@@ -1424,7 +1460,7 @@ impl CertAuthSummary {
pub struct CertAuthInfo {
handle: Handle,
repo_info: RepoInfo,
parents: HashMap<Handle, ParentCaContact>,
parents: Vec<ParentInfo>,
resources: HashMap<ResourceClassName, ResourceClassInfo>,
children: Vec<ChildHandle>,
roa_definitions: HashSet<RoaDefinition>,
@@ -1434,11 +1470,16 @@ impl CertAuthInfo {
pub fn new(
handle: Handle,
repo_info: RepoInfo,
parents: HashMap<Handle, ParentCaContact>,
parents: HashMap<ParentHandle, ParentCaContact>,
resources: HashMap<ResourceClassName, ResourceClassInfo>,
children: Vec<ChildHandle>,
roa_definitions: HashSet<RoaDefinition>,
) -> Self {
let parents = parents
.into_iter()
.map(|(handle, contact)| ParentInfo::new(handle, contact))
.collect();
CertAuthInfo {
handle,
repo_info,
@@ -1457,14 +1498,10 @@ impl CertAuthInfo {
&self.repo_info
}
pub fn parents(&self) -> &HashMap<Handle, ParentCaContact> {
pub fn parents(&self) -> &Vec<ParentInfo> {
&self.parents
}
pub fn parent(&self, parent: &Handle) -> Option<&ParentCaContact> {
self.parents.get(parent)
}
pub fn resources(&self) -> &HashMap<ResourceClassName, ResourceClassInfo> {
&self.resources
}
+14
View File
@@ -318,6 +318,20 @@ pub fn ca_info(server: web::Data<AppServer>, auth: Auth, handle: Path<Handle>) -
})
}
pub fn ca_my_parent_contact(
server: web::Data<AppServer>,
auth: Auth,
ca_and_parent: Path<(Handle, Handle)>,
) -> HttpResponse {
let (ca, parent) = ca_and_parent.into_inner();
if_api_allowed(&server, &auth, || {
match server.read().ca_my_parent_contact(&ca, &parent) {
Some(info) => render_json(info),
None => api_not_found(),
}
})
}
pub fn ca_history(server: web::Data<AppServer>, auth: Auth, handle: Path<Handle>) -> HttpResponse {
if_api_allowed(&server, &auth, || {
match server.read().ca_history(&handle.into_inner()) {
+2 -1
View File
@@ -82,11 +82,12 @@ pub fn start(config: &Config) -> Result<(), Error> {
.route("/cas/{ca}/repo/request", get().to(ca_publisher_req))
.route("/cas/{ca}/repo/", post().to(ca_repo_update))
.route("/cas/{ca}/parents", post().to(ca_add_parent))
.route("/cas/{ca}/parents/{parent}", get().to(ca_my_parent_contact))
.route("/cas/{ca}/parents/{parent}", post().to(ca_update_parent))
.route("/cas/{ca}/parents/{parent}", delete().to(ca_remove_parent))
.route("/cas/{ca}/children", post().to(ca_add_child))
.route(
"/cas/{ca}/parent_contact/{child}",
"/cas/{ca}/children/{child}/contact",
get().to(ca_parent_contact),
)
.route("/cas/{ca}/children/{child}", get().to(ca_show_child))
+15
View File
@@ -326,6 +326,21 @@ impl KrillServer {
self.caserver.get_ca(handle).map(|ca| ca.as_ca_info()).ok()
}
/// Returns the parent contact for a CA and parent, or NONE if either the CA or the parent cannot be found.
pub fn ca_my_parent_contact(
&self,
handle: &Handle,
parent: &ParentHandle,
) -> Option<ParentCaContact> {
match self.caserver.get_ca(handle) {
Err(_) => None,
Ok(ca) => match ca.parent(parent) {
Err(_) => None,
Ok(parent) => Some(parent.clone()),
},
}
}
/// Returns the history for a CA, or NONE in case of issues (i.e. it does not exist).
pub fn ca_history(&self, handle: &Handle) -> Option<CertAuthHistory> {
self.caserver.get_ca_history(handle).ok()