diff --git a/crates/extensions/c8y_http_proxy/src/actor.rs b/crates/extensions/c8y_http_proxy/src/actor.rs index 725098439c1..38d0e0e00b5 100644 --- a/crates/extensions/c8y_http_proxy/src/actor.rs +++ b/crates/extensions/c8y_http_proxy/src/actor.rs @@ -85,6 +85,13 @@ impl Actor for C8YHttpProxyActor { .await .map(|response| response.into()), + C8YRestRequest::GetFreshJwtToken(_) => { + self.end_point.token = None; + self.get_and_set_jwt_token() + .await + .map(|response| response.into()) + } + C8YRestRequest::C8yCreateEvent(request) => self .create_event(request) .await diff --git a/crates/extensions/c8y_http_proxy/src/handle.rs b/crates/extensions/c8y_http_proxy/src/handle.rs index 5f37d86090b..eca1025b39d 100644 --- a/crates/extensions/c8y_http_proxy/src/handle.rs +++ b/crates/extensions/c8y_http_proxy/src/handle.rs @@ -2,6 +2,7 @@ use crate::messages::C8YRestError; use crate::messages::C8YRestRequest; use crate::messages::C8YRestResponse; use crate::messages::C8YRestResult; +use crate::messages::GetFreshJwtToken; use crate::messages::GetJwtToken; use crate::messages::SoftwareListResponse; use crate::messages::UploadConfigFile; @@ -33,6 +34,16 @@ impl C8YHttpProxy { pub async fn get_jwt_token(&mut self) -> Result { let request: C8YRestRequest = GetJwtToken.into(); + + match self.c8y.await_response(request).await? { + Ok(C8YRestResponse::EventId(id)) => Ok(id), + unexpected => Err(unexpected.into()), + } + } + + pub async fn get_fresh_jwt_token(&mut self) -> Result { + let request: C8YRestRequest = GetFreshJwtToken.into(); + match self.c8y.await_response(request).await? { Ok(C8YRestResponse::EventId(id)) => Ok(id), unexpected => Err(unexpected.into()), diff --git a/crates/extensions/c8y_http_proxy/src/messages.rs b/crates/extensions/c8y_http_proxy/src/messages.rs index e97b02646ec..65fb12de375 100644 --- a/crates/extensions/c8y_http_proxy/src/messages.rs +++ b/crates/extensions/c8y_http_proxy/src/messages.rs @@ -6,7 +6,7 @@ use tedge_actors::ChannelError; use tedge_http_ext::HttpError; use tedge_utils::file::PermissionEntry; -fan_in_message_type!(C8YRestRequest[GetJwtToken, C8yCreateEvent, SoftwareListResponse, UploadLogBinary, UploadConfigFile, DownloadFile]: Debug, PartialEq, Eq); +fan_in_message_type!(C8YRestRequest[GetJwtToken, GetFreshJwtToken, C8yCreateEvent, SoftwareListResponse, UploadLogBinary, UploadConfigFile, DownloadFile]: Debug, PartialEq, Eq); //HIPPO Rename EventId to String as there could be many other String responses as well and this macro doesn't allow another String variant fan_in_message_type!(C8YRestResponse[EventId, Unit]: Debug); @@ -43,6 +43,9 @@ pub type C8YRestResult = Result; #[derive(Debug, PartialEq, Eq)] pub struct GetJwtToken; +#[derive(Debug, PartialEq, Eq)] +pub struct GetFreshJwtToken; + #[derive(Debug, PartialEq, Eq)] pub struct SoftwareListResponse { pub c8y_software_list: C8yUpdateSoftwareListResponse, diff --git a/crates/extensions/c8y_mapper_ext/src/converter.rs b/crates/extensions/c8y_mapper_ext/src/converter.rs index e04f2c42591..a11fbadc9a6 100644 --- a/crates/extensions/c8y_mapper_ext/src/converter.rs +++ b/crates/extensions/c8y_mapper_ext/src/converter.rs @@ -464,7 +464,8 @@ impl CumulocityConverter { .from_smartrest(smartrest)? .to_thin_edge_json()?; - let token = self.http_proxy.get_jwt_token().await?; + // Pass the fresh token to the tedge-agent as it cannot request a new one + let token = self.http_proxy.get_fresh_jwt_token().await?; software_update_request .update_list diff --git a/crates/extensions/c8y_mapper_ext/src/tests.rs b/crates/extensions/c8y_mapper_ext/src/tests.rs index f4dbc0ed1c2..c746a9be53b 100644 --- a/crates/extensions/c8y_mapper_ext/src/tests.rs +++ b/crates/extensions/c8y_mapper_ext/src/tests.rs @@ -12,6 +12,7 @@ use std::fs::File; use std::io::Read; use std::path::Path; use std::time::Duration; +use std::time::SystemTime; use tedge_actors::test_helpers::MessageReceiverExt; use tedge_actors::Actor; use tedge_actors::Builder; @@ -111,6 +112,38 @@ async fn mapper_publishes_software_update_request() { .await; } +#[tokio::test] +async fn mapper_publishes_software_update_request_with_new_token() { + // The test assures SM Mapper correctly receives software update request smartrest message on `c8y/s/ds` + // and converts it to thin-edge json message published on `tedge/commands/req/software/update` with new JWT token. + let (mqtt, http, _fs, _timer) = spawn_c8y_mapper_actor(&TempTedgeDir::new(), true).await; + spawn_dummy_c8y_http_proxy(http); + + let mut mqtt = mqtt.with_timeout(TEST_TIMEOUT_MS); + + mqtt.skip(6).await; //Skip all init messages + + // Simulate c8y_SoftwareUpdate SmartREST request + mqtt.send(MqttMessage::new( + &C8yTopic::downstream_topic(), + "528,test-device,test-very-large-software,2.0,https://test.c8y.io,install", + )) + .await + .expect("Send failed"); + let first_request = mqtt.recv().await.unwrap(); + // Simulate c8y_SoftwareUpdate SmartREST request + mqtt.send(MqttMessage::new( + &C8yTopic::downstream_topic(), + "528,test-device,test-very-large-software,2.0,https://test.c8y.io,install", + )) + .await + .expect("Send failed"); + let second_request = mqtt.recv().await.unwrap(); + + // Both software update requests will have different tokens in it. So, they are not equal. + assert_ne!(first_request, second_request); +} + #[tokio::test] async fn mapper_publishes_software_update_status_onto_c8y_topic() { // The test assures SM Mapper correctly receives software update response message on `tedge/commands/res/software/update` @@ -1357,6 +1390,14 @@ fn spawn_dummy_c8y_http_proxy(mut http: SimpleMessageBox { + let now = SystemTime::now(); + let _ = http + .send(Ok(c8y_http_proxy::messages::C8YRestResponse::EventId( + format!("dummy-token-{:?}", now), + ))) + .await; + } Some(C8YRestRequest::SoftwareListResponse(_)) => { let _ = http .send(Ok(c8y_http_proxy::messages::C8YRestResponse::Unit(())))