diff --git a/Cargo.toml b/Cargo.toml index 0d8a749..7b93fdc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mauth-client" -version = "0.7.1" +version = "0.7.2" authors = ["Mason Gup "] edition = "2024" rust-version = "1.88" diff --git a/build.rs b/build.rs index bfc4b21..691dcfb 100644 --- a/build.rs +++ b/build.rs @@ -14,7 +14,7 @@ fn main() { r_path.file_name().unwrap().to_str().unwrap().to_string(), ) }) - .filter(|(path, name)| path.join(format!("{}.sts", &name)).exists()) + .filter(|(path, name)| path.join(format!("{}.sts", name)).exists()) .map(|(_, name)| name) .collect(); @@ -30,8 +30,8 @@ async fn {formatted_name}_generate_headers() {{ test_generate_headers("{name}".to_string()).await; }} "#, - formatted_name = &formatted_name, - name = &name + formatted_name = formatted_name, + name = name )); } fs::write(Path::new(&out_dir).join("protocol_tests.rs"), &code_str).unwrap(); diff --git a/factbook.yaml b/factbook.yaml new file mode 100644 index 0000000..aa22f04 --- /dev/null +++ b/factbook.yaml @@ -0,0 +1,20 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +spec: + type: library + lifecycle: production + owner: ae@mdsol.com + experience: enablement +metadata: + json_schema: https://github.com/mdsol/platform-standards/tree/main/schemas/v1alpha1.schema.json + name: mauth-client-rust + title: MAuth Client Rust + description: A client library for MAuth in Rust. + teams: + - name: Architecture Enablement + number: 119 + people: + - role: technical owner + email: ykitamura@mdsol.com + annotations: + product: N/A diff --git a/src/config.rs b/src/config.rs index 7a4fbd4..275291b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -38,7 +38,7 @@ impl MAuthInfo { pub fn from_config_section(section: &ConfigFileSection) -> Result { let full_uri: Url = format!( "{}/mauth/{}/security_tokens/", - §ion.mauth_baseurl, §ion.mauth_api_version + section.mauth_baseurl, section.mauth_api_version ) .parse()?; diff --git a/src/protocol_test_suite.rs b/src/protocol_test_suite.rs index c9413d0..dda691c 100644 --- a/src/protocol_test_suite.rs +++ b/src/protocol_test_suite.rs @@ -1,4 +1,5 @@ use crate::{MAuthInfo, config::ConfigFileSection}; +use mauth_core::verifier::Verifier; use reqwest::{Method, Request}; use serde::Deserialize; use tokio::fs; @@ -40,11 +41,11 @@ async fn test_generate_headers(file_name: String) { let (mauth_info, req_time) = setup_mauth_info().await; let mut sig_file_path = PathBuf::from(&BASE_PATH); - sig_file_path.push(format!("{name}/{name}.sig", name = &file_name)); + sig_file_path.push(format!("{name}/{name}.sig", name = file_name)); let sig = String::from_utf8(fs::read(sig_file_path).await.unwrap()).unwrap(); let mut authz_file_path = PathBuf::from(&BASE_PATH); - authz_file_path.push(format!("{name}/{name}.authz", name = &file_name)); + authz_file_path.push(format!("{name}/{name}.authz", name = file_name)); let auth_headers: serde_json::Value = serde_json::from_slice(&fs::read(authz_file_path).await.unwrap()).unwrap(); @@ -71,4 +72,40 @@ async fn test_generate_headers(file_name: String) { assert_eq!(expected_sig, sig_header); } +#[tokio::test] +async fn sign_request_v1_sets_protocol_compliant_headers() { + let (mauth_info, _) = setup_mauth_info().await; + let app_uuid = mauth_info.app_id; + let mut request = Request::new(Method::GET, url::Url::parse("http://www.a.com/").unwrap()); + mauth_info.sign_request_v1(&mut request).unwrap(); + + let headers = request.headers(); + let timestamp = headers.get("X-MWS-Time").unwrap().to_str().unwrap(); + let auth_header = headers + .get("X-MWS-Authentication") + .unwrap() + .to_str() + .unwrap(); + let signature = auth_header + .strip_prefix(&format!("MWS {app_uuid}:")) + .expect("v1 authentication header must contain its protocol token and app UUID"); + assert!(!signature.is_empty()); + + let public_key = fs::read_to_string("mauth-protocol-test-suite/signing-params/rsa-key-pub") + .await + .unwrap(); + Verifier::new(app_uuid, public_key) + .unwrap() + .verify_signature( + 1, + request.method().as_str(), + request.url().path(), + request.url().query().unwrap_or(""), + &[], + timestamp, + signature, + ) + .unwrap(); +} + include!(concat!(env!("OUT_DIR"), "/protocol_tests.rs")); diff --git a/src/sign_outgoing.rs b/src/sign_outgoing.rs index 331e81c..98db998 100644 --- a/src/sign_outgoing.rs +++ b/src/sign_outgoing.rs @@ -51,7 +51,7 @@ impl MAuthInfo { } pub(crate) fn set_headers_v2(&self, req: &mut Request, signature: String, timestamp_str: &str) { - let sig_head_str = format!("MWSV2 {}:{};", self.app_id, &signature); + let sig_head_str = format!("MWSV2 {}:{};", self.app_id, signature); let headers = req.headers_mut(); headers.insert("MCC-Time", HeaderValue::from_str(timestamp_str).unwrap()); headers.insert( @@ -86,11 +86,19 @@ impl MAuthInfo { timestamp_str.clone(), )?; - let headers = req.headers_mut(); - headers.insert("X-MWS-Time", HeaderValue::from_str(×tamp_str).unwrap()); - headers.insert("X-MWS-Authentication", HeaderValue::from_str(&sig).unwrap()); + self.set_headers_v1(req, sig, ×tamp_str); Ok(()) } + + fn set_headers_v1(&self, req: &mut Request, signature: String, timestamp_str: &str) { + let sig_head_str = format!("MWS {}:{}", self.app_id, signature); + let headers = req.headers_mut(); + headers.insert("X-MWS-Time", HeaderValue::from_str(timestamp_str).unwrap()); + headers.insert( + "X-MWS-Authentication", + HeaderValue::from_str(&sig_head_str).unwrap(), + ); + } } /// All of the errors that can take place while attempting to sign a request diff --git a/src/validate_incoming.rs b/src/validate_incoming.rs index a99cefd..e06d90c 100644 --- a/src/validate_incoming.rs +++ b/src/validate_incoming.rs @@ -254,7 +254,7 @@ impl MAuthInfo { return Some(pub_key.clone()); } } - let uri = self.mauth_uri_base.join(&format!("{}", &app_uuid)).unwrap(); + let uri = self.mauth_uri_base.join(&format!("{}", app_uuid)).unwrap(); let mauth_response = CLIENT.get().unwrap().get(uri).send().await; match mauth_response { Err(_) => None,