diff --git a/Cargo.toml b/Cargo.toml index 4b298056..cdaead35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ serde_json = "^1.0" syslog = "^4.0" toml = "^0.4" tokio = "^0.1" +uuid = "0.7" xml-rs = "0.8.0" # XXX Temporarily diff --git a/defaults/krill.conf b/defaults/krill.conf index 89779cfd..a1ebee7e 100644 --- a/defaults/krill.conf +++ b/defaults/krill.conf @@ -34,9 +34,6 @@ # in their certificates. #rrdp_base_uri = "http://127.0.0.1:3000/rrdp/" -# Specify the base service URI where publishers can connect. -#service_uri = "http://127.0.0.1:3000/rfc8181/" - # Log level # # The maximum log level ("off", "error", "warn", "info", or "debug") for diff --git a/src/client/data.rs b/src/client/data.rs index 58120818..cd49e5ad 100644 --- a/src/client/data.rs +++ b/src/client/data.rs @@ -163,6 +163,23 @@ impl PublisherSummary { } } + +//------------ Rfc8181Details ------------------------------------------------ + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Rfc8181Details { + #[serde( + serialize_with = "ext_serde::ser_http_uri", + deserialize_with = "ext_serde::de_http_uri")] + service_uri: uri::Http, + + #[serde( + serialize_with = "ext_serde::ser_id_cert", + deserialize_with = "ext_serde::de_id_cert")] + id_cert: IdCert +} + + //------------ PublisherDetails ---------------------------------------------- /// This type defines the publisher details fro: @@ -177,16 +194,7 @@ pub struct PublisherDetails { )] base_uri: uri::Rsync, - #[serde( - deserialize_with = "ext_serde::de_http_uri", - serialize_with = "ext_serde::ser_http_uri" - )] - service_uri: uri::Http, - #[serde( - deserialize_with = "ext_serde::de_id_cert", - serialize_with = "ext_serde::ser_id_cert" - )] - identity_certificate: IdCert, + rfc8181: Option, links: Vec } @@ -195,8 +203,11 @@ impl PublisherDetails { pub fn publisher_handle(&self) -> &str { &self.publisher_handle } - pub fn identity_cert(&self) -> &IdCert { - &self.identity_certificate + pub fn identity_cert(&self) -> Option<&IdCert> { + match self.rfc8181 { + None => None, + Some(ref details) => Some(&details.id_cert) + } } } @@ -219,12 +230,28 @@ impl Report for PublisherDetails { }, ReportFormat::Text => { - let res = format!( - "publisher_handle: {}\n\ - base uri: {}\n\ - service_uri: {}", - self.publisher_handle, self.base_uri, self.service_uri - ); + let mut res = String::new(); + + res.push_str("handle: "); + res.push_str(self.publisher_handle.as_str()); + res.push_str("\n"); + + res.push_str("base uri: "); + res.push_str(self.base_uri.to_string().as_str()); + res.push_str("\n"); + + if let Some(ref rfc8181) = self.rfc8181 { + res.push_str("RFC8181 Details:\n"); + res.push_str(" service uri: "); + res.push_str(rfc8181.service_uri.to_string().as_str()); + res.push_str("\n"); + res.push_str(" id cert (base64): "); + res.push_str( + base64::encode( + rfc8181.id_cert.to_bytes().as_ref() + ).as_str()); + res.push_str("\n"); + } Ok(res) }, diff --git a/src/client/krillc.rs b/src/client/krillc.rs index 75f1ac5d..9cb0aa8c 100644 --- a/src/client/krillc.rs +++ b/src/client/krillc.rs @@ -113,9 +113,15 @@ impl KrillClient { let uri = format!("api/v1/publishers/{}", handle); let res = self.get(uri.as_str())?; let details: PublisherDetails = serde_json::from_str(&res)?; - let bytes = details.identity_cert().to_bytes(); - file::save(&bytes, &file)?; - Ok(ApiResponse::Empty) + match details.identity_cert() { + Some(cert) => { + let bytes = cert.to_bytes(); + file::save(&bytes, &file)?; + Ok(ApiResponse::Empty) + }, + None => Err(Error::NoIdCert) + } + } } } @@ -271,6 +277,9 @@ pub enum Error { #[display(fmt="Can't read file: {}", _0)] IoError(io::Error), + + #[display(fmt="There is no known IdCert for this publisher")] + NoIdCert } impl From for Error { diff --git a/src/daemon/api/admin.rs b/src/daemon/api/endpoints.rs similarity index 74% rename from src/daemon/api/admin.rs rename to src/daemon/api/endpoints.rs index 17ecf3b3..93a64ff6 100644 --- a/src/daemon/api/admin.rs +++ b/src/daemon/api/endpoints.rs @@ -1,4 +1,4 @@ -//! Support for various admin API methods +//! Process requests received, delegate, and wrap up the responses. use std::error; use std::sync::{RwLockReadGuard, RwLockWriteGuard}; use actix_web::{HttpResponse, ResponseError}; @@ -8,7 +8,22 @@ use crate::daemon::api::responses::{PublisherDetails, PublisherList}; use crate::daemon::http::server::{HttpRequest, PublisherHandle}; use crate::daemon::publishers; use crate::daemon::krillserver::{self, KrillServer}; -use crate::remote::rfc8183::PublisherRequest; +use remote::sigmsg::SignedMessage; +use daemon::api::requests::PublishDelta; +use daemon::api::requests::PublisherRequestChoice; + + +//------------ Support Functions --------------------------------------------- + +/// Returns a server in a read lock +pub fn ro_server(req: &HttpRequest) -> RwLockReadGuard { + req.state().read().unwrap() +} + +/// Returns a server in a write lock +pub fn rw_server(req: &HttpRequest) -> RwLockWriteGuard { + req.state().write().unwrap() +} /// Helper function to render json output. fn render_json(object: O) -> HttpResponse { @@ -29,26 +44,24 @@ fn server_error(error: Error) -> HttpResponse { error.error_response() } -/// Returns a server in a read lock -fn ro_server(req: &HttpRequest) -> RwLockReadGuard { - req.state().read().unwrap() -} - -/// Returns a server in a write lock -fn rw_server(req: &HttpRequest) -> RwLockWriteGuard { - req.state().write().unwrap() -} - /// A clean 404 result for the API (no content, not for humans) fn api_not_found() -> HttpResponse { HttpResponse::build(StatusCode::NOT_FOUND).finish() } /// A clean 200 result for the API (no content, not for humans) -fn api_ok() -> HttpResponse { +pub fn api_ok() -> HttpResponse { HttpResponse::Ok().finish() } +/// Returns the server health. XXX TODO: do a real test! +pub fn health(_r: &HttpRequest) -> HttpResponse { + api_ok() +} + + +//------------ Admin: Publishers --------------------------------------------- + /// Returns a json structure with all publishers in it. pub fn publishers(req: &HttpRequest) -> HttpResponse { match ro_server(req).publishers() { @@ -65,23 +78,23 @@ pub fn publishers(req: &HttpRequest) -> HttpResponse { /// Request XML is posted. pub fn add_publisher( req: HttpRequest, - pr: PublisherRequest + prc: PublisherRequestChoice ) -> HttpResponse { let mut server = rw_server(&req); - let handle = pr.handle().clone(); - match server.add_publisher(pr, &handle) { + match server.add_publisher(prc, None) { Ok(()) => api_ok(), Err(e) => server_error(Error::ServerError(e)) } } +/// Adds a an explicitly named publisher. pub fn add_named_publisher( req: HttpRequest, - pr: PublisherRequest, + prc: PublisherRequestChoice, handle: PublisherHandle ) -> HttpResponse { let mut server = rw_server(&req); - match server.add_publisher(pr, handle.as_ref()) { + match server.add_publisher(prc, Some(handle.as_ref())) { Ok(()) => api_ok(), Err(e) => server_error(Error::ServerError(e)) } @@ -101,41 +114,26 @@ pub fn remove_publisher( } } - /// Returns a json structure with publisher details pub fn publisher_details( req: HttpRequest, handle: PublisherHandle ) -> HttpResponse { - match ro_server(&req).publisher(handle) { + let server = ro_server(&req); + match server.publisher(handle) { Ok(None) => api_not_found(), Ok(Some(publisher)) => { render_json( - PublisherDetails::from(&publisher, "/api/v1/publishers") + PublisherDetails::from( + &publisher, + "/api/v1/publishers", + server.service_base_uri()) ) }, Err(e) => server_error(Error::ServerError(e)) } } - -/// Returns the id.cer for a publisher -pub fn id_cert( - req: HttpRequest, - handle: PublisherHandle -) -> HttpResponse { - match ro_server(&req).publisher(handle) { - Ok(None) => api_not_found(), - Ok(Some(publisher)) => { - let bytes = publisher.id_cert().to_bytes(); - HttpResponse::Ok() - .content_type("application/pkix-cert") - .body(bytes) - }, - Err(e) => server_error(Error::ServerError(e)) - } -} - /// Shows the server's RFC8183 section 5.2.4 Repository Response XML /// file for a known publisher. pub fn repository_response( @@ -158,6 +156,55 @@ pub fn repository_response( } } + +//------------ Publication --------------------------------------------------- + +/// Processes an RFC8181 query and returns the appropriate response. +pub fn handle_rfc8181_request( + req: HttpRequest, + msg: SignedMessage, + handle: PublisherHandle +) -> HttpResponse { + let mut server: RwLockWriteGuard = rw_server(&req); + match server.handle_rfc8181_request(&msg, handle.as_ref()) { + Ok(captured) => { + HttpResponse::build(StatusCode::OK) + .content_type("application/rpki-publication") + .body(captured.into_bytes()) + } + Err(e) => { + server_error(Error::ServerError(e)) + } + } +} + +/// Processes a publishdelta request sent to the API. +pub fn handle_delta( + req: HttpRequest, + delta: PublishDelta, + handle: PublisherHandle +) -> HttpResponse { + match rw_server(&req).handle_delta(delta, handle.as_ref()) { + Ok(()) => api_ok(), + Err(e) => server_error(Error::ServerError(e)) + } +} + +/// Processes a list request sent to the API. +pub fn handle_list( + req: HttpRequest, + handle: PublisherHandle +) -> HttpResponse { + match ro_server(&req).handle_list(handle.as_ref()) { + Ok(list) => render_json(list), + Err(e) => server_error(Error::ServerError(e)) + } +} + + + + + //------------ Error --------------------------------------------------------- #[derive(Debug, Display)] @@ -214,6 +261,7 @@ impl ErrorToStatus for krillserver::Error { krillserver::Error::CmsProxy(_) => StatusCode::BAD_REQUEST, krillserver::Error::PublisherStore(e) => e.status(), krillserver::Error::Repository(_) => StatusCode::BAD_REQUEST, + krillserver::Error::NoIdCert => StatusCode::FORBIDDEN, } } } @@ -224,6 +272,8 @@ impl ErrorToCode for krillserver::Error { krillserver::Error::PublisherStore(e) => e.code(), krillserver::Error::Repository(_) => 3002, krillserver::Error::CmsProxy(_) => 3003, + krillserver::Error::NoIdCert => 2001, + } } } @@ -253,7 +303,6 @@ impl ErrorToStatus for publishers::Error { } } - #[derive(Debug, Serialize)] struct ErrorResponse { code: usize, @@ -269,7 +318,6 @@ impl Error { } } - impl actix_web::ResponseError for Error { fn error_response(&self) -> HttpResponse { HttpResponse::build(self.status()) diff --git a/src/daemon/api/mod.rs b/src/daemon/api/mod.rs index 314efc4d..66b3be72 100644 --- a/src/daemon/api/mod.rs +++ b/src/daemon/api/mod.rs @@ -1,4 +1,4 @@ -pub mod admin; +pub mod endpoints; pub mod auth; pub mod responses; pub mod requests; \ No newline at end of file diff --git a/src/daemon/api/requests.rs b/src/daemon/api/requests.rs index ddae5404..85a75d4d 100644 --- a/src/daemon/api/requests.rs +++ b/src/daemon/api/requests.rs @@ -1,18 +1,45 @@ //! Support for requests sent to the Json API -//! -//! So, contrary to the responses, we need to deal with actual values here -//! when we deserialize things being sent on the wire. use bytes::Bytes; use rpki::uri; +use uuid::Uuid; +use crate::remote::rfc8183; use crate::util::ext_serde; +/// Auto-generate a token in case none is supplied. +pub fn generate_random_token() -> String { + Uuid::new_v4().to_string() +} +#[derive(Deserialize, Serialize)] +pub struct PublisherRequest { + handle: String, + + #[serde(default = "generate_random_token")] + token: String, +} + +impl PublisherRequest { + pub fn parts(self) -> (String, String) { (self.handle, self.token) } +} + + +/// This type provides a convenience wrapper so that either XML (rfc81838) or +/// Json (our CMS-less api) bodies may be sent when a publisher is added. +/// Dependent on the content the body sent this will be converted into the +/// right type. +pub enum PublisherRequestChoice { + Api(PublisherRequest), + Rfc8183(rfc8183::PublisherRequest) +} + + +/// This type provides a convenience wrapper to contain the request found +/// inside of a validated RFC8181 request. pub enum PublishRequest { List, Delta(PublishDelta) } - /// This type represents the request containing the complete delta of objects /// to publish, update, or withdraw. #[derive(Deserialize, Serialize)] diff --git a/src/daemon/api/responses.rs b/src/daemon/api/responses.rs index 6645c8f0..e8b40bf2 100644 --- a/src/daemon/api/responses.rs +++ b/src/daemon/api/responses.rs @@ -5,9 +5,9 @@ use std::sync::Arc; use rpki::uri; use crate::daemon::publishers::Publisher; +use crate::remote::id::IdCert; use crate::util::ext_serde; use crate::util::file::CurrentFile; -use crate::remote::id::IdCert; //------------ Link ---------------------------------------------------------- @@ -35,7 +35,7 @@ impl<'a> PublisherSummaryInfo<'a> { publisher: &'a Publisher, path_publishers: &'a str ) -> PublisherSummaryInfo<'a> { - let id = publisher.name().as_str(); + let id = publisher.handle().as_str(); let mut links = Vec::new(); let response_link = Link { @@ -88,6 +88,16 @@ impl<'a> PublisherList<'a> { //------------ PublisherDetails ---------------------------------------------- +#[derive(Clone, Debug, Serialize)] +pub struct Rfc8181Details<'a> { + #[serde(serialize_with = "ext_serde::ser_http_uri")] + service_uri: uri::Http, + + #[serde(serialize_with = "ext_serde::ser_id_cert")] + id_cert: &'a IdCert +} + + #[derive(Clone, Debug, Serialize)] pub struct PublisherDetails<'a> { publisher_handle: &'a str, @@ -95,11 +105,7 @@ pub struct PublisherDetails<'a> { #[serde(serialize_with = "ext_serde::ser_rsync_uri")] base_uri: &'a uri::Rsync, - #[serde(serialize_with = "ext_serde::ser_http_uri")] - service_uri: &'a uri::Http, - - #[serde(serialize_with = "ext_serde::ser_id_cert")] - identity_certificate: &'a IdCert, + rfc8181: Option>, links: Vec> } @@ -107,12 +113,25 @@ pub struct PublisherDetails<'a> { impl<'a> PublisherDetails<'a> { pub fn from( publisher: &'a Arc, - path_publishers: &'a str + path_publishers: &'a str, + base_service_uri: &uri::Http ) -> PublisherDetails<'a> { - let handle = publisher.name().as_str(); + let handle = publisher.handle().as_str(); let base_uri = publisher.base_uri(); - let service_uri = publisher.service_uri(); - let identity_certificate = publisher.id_cert(); + + // Derive the RFC8181 service URI. + let service_uri = format!("{}{}", base_service_uri, handle); + let service_uri = uri::Http::from_string(service_uri).unwrap(); + + let rfc8181 = match publisher.rfc8181() { + None => None, + Some(details) => Some( + Rfc8181Details { + service_uri, + id_cert: details.id_cert() + } + ) + }; let mut links = Vec::new(); links.push(Link { @@ -123,8 +142,7 @@ impl<'a> PublisherDetails<'a> { PublisherDetails { publisher_handle: handle, base_uri, - service_uri, - identity_certificate, + rfc8181, links } } diff --git a/src/daemon/config.rs b/src/daemon/config.rs index 05206f8d..b8e88c88 100644 --- a/src/daemon/config.rs +++ b/src/daemon/config.rs @@ -30,9 +30,6 @@ impl ConfigDefaults { fn rrdp_base_uri() -> uri::Http { uri::Http::from_str("http://127.0.0.1:3000/rrdp/").unwrap() } - fn service_uri() -> uri::Http { - uri::Http::from_str("http://127.0.0.1:3000/rfc8181/").unwrap() - } fn log_level() -> LevelFilter { LevelFilter::Warn } fn log_type() -> LogType { LogType::Syslog } fn syslog_facility() -> Facility { Facility::LOG_DAEMON } @@ -86,12 +83,6 @@ pub struct Config { )] pub rrdp_base_uri: uri::Http, - #[serde( - default = "ConfigDefaults::service_uri", - deserialize_with = "ext_serde::de_http_uri" - )] - pub service_uri: uri::Http, - #[serde( default = "ConfigDefaults::log_level", deserialize_with = "ext_serde::de_level_filter" @@ -141,6 +132,20 @@ impl Config { path.push(ssl::KEY_FILE); path } + + pub fn service_uri(&self) -> uri::Http { + let mut uri = String::new(); + if self.use_ssl() { + uri.push_str("https://"); + } else { + uri.push_str("http://"); + } + + uri.push_str(&self.socket_addr().to_string()); + uri.push_str("/"); + + uri::Http::from_string(uri).unwrap() + } } /// # Create @@ -154,7 +159,6 @@ impl Config { let data_dir = data_dir.clone(); let rsync_base = ConfigDefaults::rsync_base(); let rrdp_base_uri = ConfigDefaults::rrdp_base_uri(); - let service_uri = ConfigDefaults::service_uri(); let log_level = ConfigDefaults::log_level(); let log_type = LogType::Stderr; let log_file = ConfigDefaults::log_file(); @@ -168,7 +172,6 @@ impl Config { data_dir, rsync_base, rrdp_base_uri, - service_uri, log_level, log_type, log_file, diff --git a/src/daemon/http/server.rs b/src/daemon/http/server.rs index 73c4c357..d7b0d6eb 100644 --- a/src/daemon/http/server.rs +++ b/src/daemon/http/server.rs @@ -1,23 +1,29 @@ //! Actix-web based HTTP server for the publication server. +//! +//! Here we deal with booting and setup, and once active deal with parsing +//! arguments and routing of requests, typically handing off to the +//! daemon::api::endpoints functions for processing and responding. use std::error; use std::fs::File; -use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; +use std::sync::{Arc, RwLock, RwLockReadGuard}; use actix_web::{pred, fs, server}; -use actix_web::{App, FromRequest, HttpResponse, ResponseError}; +use actix_web::{App, FromRequest, HttpResponse}; use actix_web::dev::MessageBody; use actix_web::middleware; use actix_web::http::{Method, StatusCode }; use bcder::decode; use futures::Future; use openssl::ssl::{SslMethod, SslAcceptor, SslAcceptorBuilder, SslFiletype}; -use crate::daemon::api::admin; +use crate::daemon::api::endpoints; use crate::daemon::api::auth::{Authorizer, CheckAuthorisation}; +use crate::daemon::api::requests::PublishDelta; use crate::daemon::config::Config; use crate::daemon::http::ssl; use crate::daemon::krillserver; use crate::daemon::krillserver::KrillServer; -use crate::remote::rfc8183::{PublisherRequest, PublisherRequestError}; +use crate::remote::rfc8183; use crate::remote::sigmsg::SignedMessage; +use daemon::api::requests::PublisherRequestChoice; const NOT_FOUND: &'static [u8] = include_bytes!("../../../ui/dev/html/404.html"); @@ -25,6 +31,7 @@ const NOT_FOUND: &'static [u8] = include_bytes!("../../../ui/dev/html/404.html") pub struct PubServerApp(App>>); + /// # Set up methods /// impl PubServerApp { @@ -33,32 +40,32 @@ impl PubServerApp { .middleware(middleware::Logger::default()) .middleware(CheckAuthorisation) .resource("/api/v1/publishers", |r| { - r.method(Method::GET).f(admin::publishers); - r.method(Method::POST).with(admin::add_publisher); + r.method(Method::GET).f(endpoints::publishers); + r.method(Method::POST).with(endpoints::add_publisher); }) .resource("/api/v1/publishers/{handle}", |r| { - r.method(Method::GET).with(admin::publisher_details); - r.method(Method::POST).with(admin::add_named_publisher); - r.method(Method::DELETE).with(admin::remove_publisher); + r.method(Method::GET).with(endpoints::publisher_details); + r.method(Method::POST).with(endpoints::add_named_publisher); + r.method(Method::DELETE).with(endpoints::remove_publisher); }) // For clients that cannot handle http methods .resource("/api/v1/publishers/{handle}/del", |r| { - r.method(Method::POST).with(admin::remove_publisher); + r.method(Method::POST).with(endpoints::remove_publisher); }) .resource("/api/v1/publishers/{handle}/response.xml", |r| { - r.method(Method::GET).with(admin::repository_response) - }) - .resource("/api/v1/health", |r| { - r.method(Method::GET).f(Self::api_ok) + r.method(Method::GET).with(endpoints::repository_response) }) .resource("/rfc8181/{handle}", |r| { - r.method(Method::POST).with(Self::process_publish_request) + r.method(Method::POST).with(endpoints::handle_rfc8181_request) }) .resource("/rrdp/{path:.*}", |r| { r.method(Method::GET).f(Self::serve_rrdp_files) }) - .resource("/health", |r| { - r.method(Method::GET).f(Self::service_ok) + .resource("/health", |r| { // No authentication required + r.method(Method::GET).f(endpoints::health) + }) + .resource("/api/v1/health", |r| { // health with authentication + r.method(Method::GET).f(endpoints::health) }) .default_resource(|r| { // 404 for GET request @@ -90,7 +97,7 @@ impl PubServerApp { let pub_server = match KrillServer::new( &config.data_dir, &config.rsync_base, - &config.service_uri, + config.service_uri(), &config.rrdp_base_uri, authorizer ) { @@ -103,7 +110,7 @@ impl PubServerApp { Arc::new(RwLock::new(pub_server)) } - /// Used to start the server with an existing executor (e.g. in tests) + /// Used to start the server with an existing executor (for tests) /// /// Note https is not supported in tests. pub fn start(config: &Config) { @@ -144,6 +151,8 @@ impl PubServerApp { } } + /// Used to set up HTTPS. Creates keypair and self signed certificate + /// if config has 'use_ssl=test'. fn https_builder(config: &Config) -> Result { if config.test_ssl() { ssl::create_key_cert_if_needed(&config.data_dir) @@ -180,45 +189,6 @@ impl PubServerApp { } } - /// Processes an RFC8181 query and returns the appropriate response. - /// - /// Note this method checks whether the request can be decoded only, and - /// if successful delegates to [`handle_signed_request`] for further - /// processing. - /// - /// [`handle_signed_request`]: #method.handle_signed_request - fn process_publish_request( - req: HttpRequest, - handle: PublisherHandle, - msg: SignedMessage - ) -> HttpResponse { - debug!("Processing publish request"); - Self::handle_signed_request( - req.state().write().unwrap(), - &msg, - handle.0.as_str() - ) - } - - /// Handles a decoded RFC8181 query. - /// - /// This delegates to `PubServer` to do the actual hard work. - fn handle_signed_request( - mut server: RwLockWriteGuard, - msg: &SignedMessage, - handle: &str - ) -> HttpResponse { - match server.handle_request(msg, handle) { - Ok(captured) => { - HttpResponse::build(StatusCode::OK) - .content_type("application/rpki-publication") - .body(captured.into_bytes()) - } - Err(e) => { - Self::server_error(Error::ServerError(e)) - } - } - } // XXX TODO: use a better handler that does not load everything into // memory first, and set the correct headers for caching. @@ -248,24 +218,6 @@ impl PubServerApp { None => Self::p404(req) } } - - /// API health check, expect that caller authenticates. - fn api_ok(_r: &HttpRequest) -> HttpResponse { - HttpResponse::Ok().body("") - } - - /// Simple human server status response page. - fn service_ok(_r: &HttpRequest) -> HttpResponse { - // XXX TODO: do a real check - HttpResponse::Ok().body("I am completely operational, and all my circuits are functioning perfectly.") - } - - /// Helper function to render server side errors. Also responsible for - /// logging the errors. - fn server_error(error: Error) -> HttpResponse { - error!("{}", error); - error.error_response() - } } @@ -313,10 +265,14 @@ impl Default for SignedMessageConvertConfig { } } -//------------ PublisherRequest ---------------------------------------------- -/// Support converting requests into PublisherRequest -impl FromRequest for PublisherRequest { +//------------ PublisherRequestChoice ---------------------------------------- + +/// Converts the body sent to 'add publisher' end-points to a +/// PublisherRequestChoice, which contains either an +/// rfc8183::PublisherRequest, or an API publisher request (no ID certs and +/// CMS etc). +impl FromRequest for PublisherRequestChoice { type Config = (); type Result = Box>; @@ -327,12 +283,15 @@ impl FromRequest for PublisherRequest { Box::new(MessageBody::new(req) .from_err() .and_then(|bytes| { - match PublisherRequest::decode(bytes.as_ref()) { - Ok(req) => Ok(req), - Err(e) => Err(Error::PublisherRequestError(e).into()) + if bytes.starts_with(b"<") { // check content-type instead? + match rfc8183::PublisherRequest::decode(bytes.as_ref()) { + Ok(req) => Ok(PublisherRequestChoice::Rfc8183(req)), + Err(e) => Err(Error::Wrong8183Xml(e).into()) + } + } else { + unimplemented!() } }) - ) } } @@ -368,6 +327,29 @@ impl AsRef for PublisherHandle { } +//------------ PublishDelta -------------------------------------------------- +/// Support converting request body into PublishDelta +impl FromRequest for PublishDelta { + type Config = (); + type Result = Box>; + + fn from_request( + req: &actix_web::HttpRequest, + _cfg: &Self::Config + ) -> Self::Result { + Box::new(MessageBody::new(req) + .from_err() + .and_then(|bytes| { + let delta: PublishDelta = + serde_json::from_reader(bytes.as_ref()) + .map_err(|e| Error::JsonError(e))?; + Ok(delta) + }) + ) + } +} + + //------------ IntoHttpHandler ----------------------------------------------- impl server::IntoHttpHandler for PubServerApp { @@ -409,7 +391,7 @@ pub enum Error { DecodeError(decode::Error), #[display(fmt = "Cannot decode request: {}", _0)] - PublisherRequestError(PublisherRequestError), + Wrong8183Xml(rfc8183::PublisherRequestError), #[display(fmt = "Wrong path")] WrongPath, diff --git a/src/daemon/krillserver.rs b/src/daemon/krillserver.rs index 0bfdf51b..1cc1443a 100644 --- a/src/daemon/krillserver.rs +++ b/src/daemon/krillserver.rs @@ -10,8 +10,9 @@ use crate::daemon::api::responses; use crate::daemon::publishers::{self, Publisher, PublisherStore}; use crate::daemon::repo::{self, Repository, RRDP_FOLDER}; use crate::remote::cmsproxy::{self, CmsProxy}; -use crate::remote::rfc8183::{PublisherRequest, RepositoryResponse}; use crate::remote::sigmsg::SignedMessage; +use daemon::api::requests::PublisherRequestChoice; +use remote::rfc8183; /// # Naming things in the keystore. const ACTOR: &'static str = "krill pubd"; @@ -33,6 +34,9 @@ const ACTOR: &'static str = "krill pubd"; /// * Updates the RRDP files #[derive(Clone, Debug)] pub struct KrillServer { + // The base URI for this service + service_uri: uri::Http, + // The base working directory, used for various storage work_dir: PathBuf, @@ -56,16 +60,17 @@ impl KrillServer { pub fn new( work_dir: &PathBuf, base_uri: &uri::Rsync, - service_uri: &uri::Http, + service_uri: uri::Http, rrdp_base_uri: &uri::Http, authorizer: Authorizer ) -> Result { - let cms_proxy = CmsProxy::new(work_dir, service_uri)?; + let cms_proxy = CmsProxy::new(work_dir)?; let publisher_store = PublisherStore::new(work_dir, base_uri)?; let repository = Repository::new(rrdp_base_uri, work_dir)?; Ok( KrillServer { + service_uri, work_dir: work_dir.clone(), authorizer, cms_proxy, @@ -74,6 +79,10 @@ impl KrillServer { } ) } + + pub fn service_base_uri(&self) -> &uri::Http { + &self.service_uri + } } impl KrillServer { @@ -94,13 +103,12 @@ impl KrillServer { /// Adds the publishers, blows up if it already existed. pub fn add_publisher( &mut self, - req: PublisherRequest, - handle: &str, + prc: PublisherRequestChoice, + handle_override: Option<&str>, ) -> Result<(), Error> { self.publisher_store.add_publisher( - req, - handle, - self.cms_proxy.base_service_uri(), + prc, + handle_override, ACTOR )?; Ok(()) @@ -133,11 +141,14 @@ impl KrillServer { pub fn repository_response( &self, name: impl AsRef - ) -> Result { + ) -> Result { let publisher = self.publisher_store.get_publisher(name)?; let rrdp_notification = self.repository.rrdp_notification_uri(); self.cms_proxy - .repository_response(publisher, rrdp_notification) + .repository_response( + publisher, + self.service_base_uri(), + rrdp_notification) .map_err(|e| Error::CmsProxy(e)) } @@ -164,7 +175,7 @@ impl KrillServer { /// Also note that if garbage is sent to the daemon, this garbage will /// fail to parse as a SignedMessage, and the daemon will just respond /// with an HTTP error response, without invoking any of this. - pub fn handle_request( + pub fn handle_rfc8181_request( &mut self, sigmsg: &SignedMessage, handle: &str @@ -172,15 +183,23 @@ impl KrillServer { debug!("Handling request for: {}", handle); let publisher = self.publisher_store.get_publisher(handle)?; - match self.cms_proxy.publish_request(sigmsg, publisher.id_cert()) { + let id_cert = match publisher.rfc8181() { + Some(details) => details.id_cert(), + None => return Err(Error::NoIdCert) + }; + + match self.cms_proxy.publish_request(sigmsg, id_cert) { Err(e) => self.cms_proxy.wrap_error(e).map_err(|e| Error::CmsProxy(e)), Ok(req) => { let reply = match req { PublishRequest::List => { - self.handle_list(handle) + self.handle_list(handle).map(|list| + responses::PublishReply::List(list)) + }, PublishRequest::Delta(delta) => { - self.handle_delta(delta, handle) + self.handle_delta(delta, handle).map(|_| + responses::PublishReply::Success) } }; @@ -199,7 +218,7 @@ impl KrillServer { &mut self, delta: PublishDelta, handle: &str - ) -> Result { + ) -> Result<(), Error> { let publisher = self.publisher_store.get_publisher(handle)?; let base_uri = publisher.base_uri(); self.repository.publish(&delta, base_uri) @@ -208,9 +227,9 @@ impl KrillServer { /// Handles a list request sent to the API, or.. through the CmsProxy. pub fn handle_list( - &mut self, + &self, handle: &str - ) -> Result { + ) -> Result { let publisher = self.publisher_store.get_publisher(handle)?; let base_uri = publisher.base_uri(); self.repository.list(base_uri).map_err(|e| Error::Repository(e)) @@ -231,6 +250,9 @@ pub enum Error { #[display(fmt="{}", _0)] Repository(repo::Error), + + #[display(fmt="No IdCert known for this publisher")] + NoIdCert } impl From for Error { diff --git a/src/daemon/publishers.rs b/src/daemon/publishers.rs index faf77c5a..39e3ea1b 100644 --- a/src/daemon/publishers.rs +++ b/src/daemon/publishers.rs @@ -5,91 +5,29 @@ use std::io; use std::path::PathBuf; use std::sync::Arc; use rpki::uri; +use daemon::api::requests; +use daemon::api::requests::PublisherRequestChoice; use crate::remote::id::IdCert; -use crate::remote::rfc8183::{PublisherRequest, PublisherRequestError}; +use crate::remote::rfc8183; use crate::storage::keystore::{self, Info, Key, KeyStore}; use crate::storage::caching_ks::CachingDiskKeyStore; use crate::util::ext_serde; -//------------ Publisher ----------------------------------------------------- -/// This type defines Publisher CAs that are allowed to publish. #[derive(Clone, Debug, Deserialize, Serialize)] -pub struct Publisher { +pub struct Rfc8181PublisherDetails { // The optional tag in the request. None maps to empty string. tag: String, - name: String, - - #[serde( - deserialize_with = "ext_serde::de_rsync_uri", - serialize_with = "ext_serde::ser_rsync_uri")] - base_uri: uri::Rsync, - - #[serde( - deserialize_with = "ext_serde::de_http_uri", - serialize_with = "ext_serde::ser_http_uri")] - service_uri: uri::Http, - #[serde( deserialize_with = "ext_serde::de_id_cert", serialize_with = "ext_serde::ser_id_cert")] id_cert: IdCert } -impl Publisher { - pub fn new( - tag: Option, - name: String, - base_uri: uri::Rsync, - service_uri: uri::Http, - id_cert: IdCert - ) -> Self { - - let tag = tag.unwrap_or("".to_string()); - - Publisher { - tag, - name, - base_uri, - service_uri, - id_cert - } - } - - /// Returns a new Publisher that is the same as this Publisher, except - /// that it has an updated IdCert - pub fn with_new_id_cert(&self, id_cert: IdCert) -> Self { - Publisher { - tag: self.tag.clone(), - name: self.name.clone(), - base_uri: self.base_uri.clone(), - service_uri: self.service_uri.clone(), - id_cert - } - } -} - -impl Publisher { - pub fn tag(&self) -> Option { - let tag = &self.tag; - if tag.is_empty() { - None - } else { - Some(tag.clone()) - } - } - - pub fn name(&self) -> &String { - &self.name - } - - pub fn base_uri(&self) -> &uri::Rsync { - &self.base_uri - } - - pub fn service_uri(&self) -> &uri::Http { - &self.service_uri +impl Rfc8181PublisherDetails { + pub fn tag(&self) -> &String { + &self.tag } pub fn id_cert(&self) -> &IdCert { @@ -97,12 +35,80 @@ impl Publisher { } } +impl Rfc8181PublisherDetails { + pub fn new(tag: Option, id_cert: IdCert) -> Self { + let tag = tag.unwrap_or("".to_string()); + Rfc8181PublisherDetails { tag, id_cert } + } +} + +impl PartialEq for Rfc8181PublisherDetails { + fn eq(&self, other: &Rfc8181PublisherDetails) -> bool { + self.tag == other.tag && + self.id_cert.to_bytes() == other.id_cert.to_bytes() + } +} + +impl Eq for Rfc8181PublisherDetails {} + + +//------------ Publisher ----------------------------------------------------- + +/// This type defines Publisher CAs that are allowed to publish. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct Publisher { + handle: String, + + /// The token used by the API + token: String, + + #[serde( + deserialize_with = "ext_serde::de_rsync_uri", + serialize_with = "ext_serde::ser_rsync_uri")] + base_uri: uri::Rsync, + + rfc8181: Option +} + +impl Publisher { + pub fn new( + handle: String, + token: String, + base_uri: uri::Rsync, + rfc8181: Option + ) -> Self { + Publisher { + handle, + token, + base_uri, + rfc8181 + } + } +} + +impl Publisher { + pub fn handle(&self) -> &String { + &self.handle + } + + pub fn token(&self) -> &String { + &self.token + } + + pub fn base_uri(&self) -> &uri::Rsync { + &self.base_uri + } + + pub fn rfc8181(&self) -> &Option { + &self.rfc8181 + } +} + impl PartialEq for Publisher { fn eq(&self, other: &Publisher) -> bool { - self.name == other.name && - self.base_uri == other.base_uri && - self.service_uri == other.service_uri && - self.id_cert.to_bytes() == other.id_cert.to_bytes() + self.handle == other.handle && + self.base_uri == other.base_uri && + self.rfc8181 == other.rfc8181 } } @@ -141,19 +147,7 @@ impl PublisherStore { ) } - /// Adds a Publisher based on a PublisherRequest (from the RFC 8183 xml). - /// - /// Will return an error if the publisher already exists! Use - /// update_publisher in case you want to update an existing publisher. - pub fn add_publisher( - &mut self, - pr: PublisherRequest, - handle: &str, - base_service_uri: &uri::Http, - actor: &str - ) -> Result<(), Error> { - let (tag, _, id_cert) = pr.into_parts(); - + fn verify_handle(&self, handle: &str) -> Result<(), Error> { if handle.contains("/") { return Err(Error::ForwardSlashInHandle(handle.to_string())) } @@ -162,29 +156,74 @@ impl PublisherStore { return Err(Error::DuplicatePublisher(handle.to_string())) } - let mut base_uri = self.base_uri.to_string(); - base_uri.push_str(handle); - base_uri.push_str("/"); + Ok(()) + } + + fn publisher_base_uri(&self, handle: &str) -> Result { + let base_uri = format!("{}{}/", self.base_uri.to_string(), handle); let base_uri = uri::Rsync::from_string(base_uri)?; + Ok(base_uri) + } - let mut service_uri = base_service_uri.to_string(); - service_uri.push_str(handle); - let service_uri = uri::Http::from_string(service_uri)?; + /// Adds a Publisher based on a PublisherRequest (from the RFC 8183 xml). + /// + /// Will return an error if the publisher already exists! Use + /// update_publisher in case you want to update an existing publisher. + pub fn add_publisher( + &mut self, + prc: PublisherRequestChoice, + handle_override: Option<&str>, + actor: &str + ) -> Result<(), Error> { - let key = Key::from_str(handle); + let publisher = match prc { + PublisherRequestChoice::Api(pr) => { + if handle_override.is_some() { + return Err(Error::HandleOverrideNotAllowed) + } + let (handle, token) = pr.parts(); + self.verify_handle(&handle)?; + let base_uri = self.publisher_base_uri(&handle)?; + + Publisher::new( + handle, + token, + base_uri, + None + ) + }, + PublisherRequestChoice::Rfc8183(pr) => { + let (tag, mut handle, id_cert) = pr.into_parts(); + + match handle_override { + Some(handle_override) => { + handle = handle_override.to_string() + }, + _ => {} + } + + self.verify_handle(&handle)?; + let base_uri = self.publisher_base_uri(&handle)?; + let rfc8181 = Rfc8181PublisherDetails::new(tag, id_cert); + + let token = requests::generate_random_token(); + + Publisher::new( + handle, + token, + base_uri, + Some(rfc8181) + ) + } + }; + + let key = Key::from_str(&publisher.handle); let info = Info::now( actor, - &format!("Added publisher: {}", handle) - ); - let publisher = Publisher::new( - tag, - handle.to_string(), - base_uri, - service_uri, - id_cert + &format!("Added publisher: {}", &publisher.handle) ); - info!("Adding publisher: {}", handle); + info!("Added publisher: {}", &publisher.handle); self.store.store(key, publisher, info)?; Ok(()) @@ -195,10 +234,10 @@ impl PublisherStore { /// Will return an error if ths publisher does not exist. pub fn remove_publisher( &mut self, - name: impl AsRef, + handle: impl AsRef, actor: &str ) -> Result<(), Error> { - let name = name.as_ref(); + let name = handle.as_ref(); match self.publisher(name)? { None => Err(Error::UnknownPublisher(name.to_string())), Some(_p) => { @@ -215,43 +254,15 @@ impl PublisherStore { } } - - /// Updates the IdCert for a known publisher. - pub fn update_id_cert_publisher( - &mut self, - name: &str, - id_cert: IdCert, - actor: &str - ) -> Result<(), Error> { - let publisher_opt = self.publisher(name)?; - - match publisher_opt { - None => Err(Error::UnknownPublisher(name.to_string())), - Some(publisher) => { - let key = Key::from_str(name); - let new_publisher = publisher.with_new_id_cert(id_cert); - let info = Info::now( - actor, - "Updated the IdCert" - ); - - info!("Updated Id for publisher: {}", publisher.name()); - self.store.store(key, new_publisher, info)?; - - Ok(()) - } - } - } - /// Returns whether a publisher exists for this name. - pub fn has_publisher(&self, name: &str) -> bool { - let key = Key::from_str(name); + pub fn has_publisher(&self, handle: &str) -> bool { + let key = Key::from_str(handle); match self.store.version(&key) { Ok(Some(version)) => { if version > 0 { true } else { - debug!("Publisher {} was archived.", name); + debug!("Publisher {} was archived.", handle); false } }, @@ -262,9 +273,9 @@ impl PublisherStore { /// Returns an Optional Arc to a publisher for this name. pub fn publisher( &self, - name: impl AsRef + handle: impl AsRef ) -> Result>, Error> { - let key = Key::from_str(name.as_ref()); + let key = Key::from_str(handle.as_ref()); self.store.get(&key).map_err(|e| { Error::KeyStoreError(e)}) } @@ -272,9 +283,9 @@ impl PublisherStore { /// does not exist. pub fn get_publisher( &self, - name: impl AsRef + handle: impl AsRef ) -> Result, Error> { - let name = name.as_ref(); + let name = handle.as_ref(); match self.publisher(name)? { None => Err(Error::UnknownPublisher(name.to_string())), Some(p) => Ok(p) @@ -324,8 +335,11 @@ pub enum Error { #[display(fmt = "Error in base URI: {}.", _0)] UriError(uri::Error), - #[display(fmt = "Invalide Publisher Request: {}.", _0)] - PublisherRequestError(PublisherRequestError) + #[display(fmt = "Invalid Publisher Request: {}.", _0)] + PublisherRequestError(rfc8183::PublisherRequestError), + + #[display(fmt = "Cannot override handle using path parameter for json api")] + HandleOverrideNotAllowed } impl From for Error { @@ -346,8 +360,8 @@ impl From for Error { } } -impl From for Error { - fn from(e: PublisherRequestError) -> Self { +impl From for Error { + fn from(e: rfc8183::PublisherRequestError) -> Self { Error::PublisherRequestError(e) } } @@ -361,10 +375,6 @@ mod tests { use super::*; use crate::util::test; - fn base_service_uri() -> uri::Http { - test::http_uri("http://127.0.0.1:3000/rfc8181/") - } - fn test_publisher_store(dir: &PathBuf) -> PublisherStore { let uri = test::rsync_uri("rsync://host/module/"); PublisherStore::new(dir, &uri).unwrap() @@ -375,10 +385,11 @@ mod tests { test::test_with_tmp_dir(|d| { let mut ps = test_publisher_store(&d); let pr = test::new_publisher_request("test/below", &d); + let prc = PublisherRequestChoice::Rfc8183(pr); let handle = "test/below"; - match ps.add_publisher(pr, handle, &base_service_uri(), "test") { + match ps.add_publisher(prc, Some(handle), "test") { Err(Error::ForwardSlashInHandle(_)) => { }, // Ok _ => panic!("Should have seen error.") } @@ -390,27 +401,29 @@ mod tests { test::test_with_tmp_dir(|d| { let mut ps = test_publisher_store(&d); let name = "alice"; + let pr = test::new_publisher_request(name, &d); let id_cert = pr.id_cert().clone(); + + let prc = PublisherRequestChoice::Rfc8183(pr); + let actor = "test"; - ps.add_publisher(pr, name, &base_service_uri(), actor).unwrap(); + ps.add_publisher(prc, Some(name), actor).unwrap(); assert!(ps.has_publisher(&name)); // Get the Arc out of the Result>, Error> let publisher_found = ps.publisher(&name).unwrap().unwrap(); - let expected_publisher = Publisher::new( - None, - name.to_string(), - test::rsync_uri(&format!("rsync://host/module/{}/", name)), - test::http_uri( - &format!("http://127.0.0.1:3000/rfc8181/{}",name)), - id_cert - ); + let expected_rfc8181 = Rfc8181PublisherDetails::new(None, id_cert); + + assert_eq!(publisher_found.handle(), "alice"); + assert_eq!( + publisher_found.base_uri().to_string().as_str(), + "rsync://host/module/alice/"); + assert_eq!(publisher_found.rfc8181(), &Some(expected_rfc8181)); - assert_eq!(publisher_found.as_ref(), &expected_publisher); }) } @@ -420,13 +433,15 @@ mod tests { let mut ps = test_publisher_store(&d); let name = "alice"; let pr = test::new_publisher_request(name, &d); + let prc = PublisherRequestChoice::Rfc8183(pr); let actor = "test"; - ps.add_publisher(pr, name, &base_service_uri(), actor).unwrap(); + ps.add_publisher(prc, None, actor).unwrap(); assert!(ps.has_publisher(&name)); let pr = test::new_publisher_request(name, &d); - match ps.add_publisher(pr, name, &base_service_uri(), actor) { + let prc = PublisherRequestChoice::Rfc8183(pr); + match ps.add_publisher(prc, None, actor) { Err(Error::DuplicatePublisher(_)) => { }, // Ok _ => panic!("Should have seen error.") } @@ -434,42 +449,6 @@ mod tests { } - #[test] - fn should_update_id_cert_publisher() { - test::test_with_tmp_dir(|d| { - let mut ps = test_publisher_store(&d); - let name = "alice"; - let pr = test::new_publisher_request(name, &d); - let actor = "test"; - - ps.add_publisher(pr, name, &base_service_uri(), actor).unwrap(); - - // Make a new publisher request for alice, using a new cert - let pr = test::new_publisher_request(name, &d); - let id_cert = pr.id_cert().clone(); - - ps.update_id_cert_publisher( - name, - id_cert.clone(), - actor.clone() - ).unwrap(); - - // Get the Arc out of the Result>, Error> - let publisher_found = ps.publisher(&name).unwrap().unwrap(); - - let expected_publisher = Publisher::new( - None, - name.to_string(), - test::rsync_uri(&format!("rsync://host/module/{}/", name)), - test::http_uri( - &format!("http://127.0.0.1:3000/rfc8181/{}",name)), - id_cert - ); - - assert_eq!(publisher_found.as_ref(), &expected_publisher); - }) - } - #[test] fn should_remove_publisher() { test::test_with_tmp_dir(|d| { @@ -478,8 +457,9 @@ mod tests { let name = "alice"; let actor = "test"; let pr = test::new_publisher_request(name, &d); + let prc = PublisherRequestChoice::Rfc8183(pr); - ps.add_publisher(pr, name, &base_service_uri(), actor).unwrap(); + ps.add_publisher(prc, None, actor).unwrap(); assert_eq!(1, ps.publishers().unwrap(). len()); ps.remove_publisher(name, actor).unwrap(); diff --git a/src/daemon/repo.rs b/src/daemon/repo.rs index 97b84b7a..ada1231e 100644 --- a/src/daemon/repo.rs +++ b/src/daemon/repo.rs @@ -63,11 +63,11 @@ impl Repository { &mut self, delta: &PublishDelta, base_uri: &uri::Rsync - ) -> Result { + ) -> Result<(), Error> { debug!("Processing update with {} elements", delta.len()); self.fs.publish(delta, base_uri)?; self.rrdp.publish(delta)?; - Ok(responses::PublishReply::Success) + Ok(()) } /// Lists the objects for a base_uri, presumably all for the same @@ -75,11 +75,10 @@ impl Repository { pub fn list( &self, base_uri: &uri::Rsync - ) -> Result { + ) -> Result { debug!("Processing list query"); let files = self.fs.list(base_uri)?; - Ok(responses::PublishReply::List( - responses::ListReply::new(files))) + Ok(responses::ListReply::new(files)) } } diff --git a/src/lib.rs b/src/lib.rs index 76bb95b4..cdad4e07 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ extern crate serde_json; extern crate syslog; extern crate tokio; extern crate toml; +extern crate uuid; extern crate xml as xmlrs; // XXX Temporarily diff --git a/src/remote/cmsproxy.rs b/src/remote/cmsproxy.rs index 521c70b6..4c061351 100644 --- a/src/remote/cmsproxy.rs +++ b/src/remote/cmsproxy.rs @@ -29,23 +29,15 @@ use crate::remote::sigmsg::SignedMessage; pub struct CmsProxy { // The component that manages server id, and wraps responses to clients responder: Responder, - - // The URI that publishers need to access to publish (see config) - service_uri: uri::Http, } /// # Set up impl CmsProxy { pub fn new( - work_dir: &PathBuf, - service_uri: &uri::Http + work_dir: &PathBuf ) -> Result { let responder = Responder::init(work_dir)?; - Ok(CmsProxy { responder, service_uri: service_uri.clone() }) - } - - pub fn base_service_uri(&self) -> &uri::Http { - &self.service_uri + Ok(CmsProxy { responder }) } } @@ -107,10 +99,22 @@ impl CmsProxy { pub fn repository_response( &self, publisher: Arc, + base_service_uri: &uri::Http, rrdp_notification_uri: uri::Http ) -> Result { + + let service_uri = format!( + "{}rfc8181/{}", + base_service_uri.to_string(), + publisher.handle() + ); + let service_uri = uri::Http::from_string(service_uri).unwrap(); + self.responder - .repository_response(publisher, rrdp_notification_uri) + .repository_response( + publisher, + service_uri, + rrdp_notification_uri) .map_err(|e| Error::ResponderError(e)) } diff --git a/src/remote/responder.rs b/src/remote/responder.rs index 8a2e2136..36aea2dc 100644 --- a/src/remote/responder.rs +++ b/src/remote/responder.rs @@ -96,20 +96,26 @@ impl Responder { pub fn repository_response( &self, publisher: Arc, + service_uri: uri::Http, rrdp_notification_uri: uri::Http ) -> Result { - if let Some(my_id) = self.my_identity()? { - let tag = publisher.tag(); - let publisher_handle = publisher.name().clone(); + + let tag = match publisher.rfc8181() { + Some(details) => Some(details.tag().clone()), + None => return Err(Error::ClientUnitialised) + }; + + + let handle = publisher.handle(); let id_cert = my_id.id_cert().clone(); - let service_uri = publisher.service_uri().clone(); + let sia_base = publisher.base_uri().clone(); Ok( RepositoryResponse::new( tag, - publisher_handle, + handle.clone(), id_cert, service_uri, sia_base, @@ -156,6 +162,9 @@ pub enum Error { #[display(fmt="Identity of server is not initialised.")] Unitialised, + + #[display(fmt="Identity of client is not initialised.")] + ClientUnitialised, } impl From for Error { @@ -188,6 +197,7 @@ impl From> for Error { mod tests { use super::*; use crate::util::test; + use daemon::publishers::Rfc8181PublisherDetails; #[test] fn should_have_response_for_publisher() { @@ -202,17 +212,22 @@ mod tests { let base_uri = test::rsync_uri("rsync://host/module/alice/"); let service_uri = test::http_uri("http://127.0.0.1:3000/rfc8181/alice"); + let rfc8181 = Rfc8181PublisherDetails::new(tag, id_cert); + let publisher = Arc::new(Publisher::new( - tag, name, + "token".to_string(), base_uri, - service_uri, - id_cert + Some(rfc8181) )); let rrdp_uri = test::http_uri("http://host/rrdp/"); - responder.repository_response(publisher, rrdp_uri).unwrap(); + responder.repository_response( + publisher, + service_uri, + rrdp_uri + ).unwrap(); }); } diff --git a/tests/client_publish_at_server.rs b/tests/client_publish_at_server.rs index d1a3f2f1..45c315c9 100644 --- a/tests/client_publish_at_server.rs +++ b/tests/client_publish_at_server.rs @@ -78,7 +78,6 @@ fn client_publish_at_server() { res.text().unwrap().as_bytes() ).unwrap(); - repo_res.validate().unwrap(); client.process_repo_response(repo_res).unwrap();