From ccd69bcf2c80ed5c18165629ee1b683426d59c88 Mon Sep 17 00:00:00 2001 From: Jacob Finkelman Date: Mon, 12 Dec 2022 17:49:22 +0000 Subject: [PATCH] Send Asymmetric Tokens to read endpoints --- Cargo.toml | 1 + src/cargo/util/auth.rs | 64 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 99225e4ce..4472f5f3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,6 +60,7 @@ strip-ansi-escapes = "0.1.0" tar = { version = "0.4.38", default-features = false } tempfile = "3.0" termcolor = "1.1" +time = { version = "0.3", features = ["parsing", "formatting"]} toml_edit = { version = "0.15.0", features = ["serde", "easy", "perf"] } unicode-xid = "0.2.0" url = "2.2.2" diff --git a/src/cargo/util/auth.rs b/src/cargo/util/auth.rs index 8e84446c1..4a49d1c85 100644 --- a/src/cargo/util/auth.rs +++ b/src/cargo/util/auth.rs @@ -4,13 +4,15 @@ use crate::util::{config, config::ConfigKey, CanonicalUrl, CargoResult, Config, use anyhow::{bail, format_err, Context as _}; use cargo_util::ProcessError; use core::fmt; -use pasetors::keys::AsymmetricSecretKey; +use pasetors::keys::{AsymmetricPublicKey, AsymmetricSecretKey}; use serde::Deserialize; use std::collections::HashMap; use std::error::Error; use std::io::{Read, Write}; use std::path::PathBuf; use std::process::{Command, Stdio}; +use time::format_description::well_known::Rfc3339; +use time::OffsetDateTime; use url::Url; use crate::core::SourceId; @@ -328,8 +330,40 @@ fn auth_token_optional(config: &Config, sid: &SourceId) -> CargoResult { run_command(config, &process, sid, Action::Get)?.unwrap() } - RegistryCredentialConfig::AsymmetricKey((_secret_key, _secret_key_subject)) => { - todo!("PASETO: sign a read token") + RegistryCredentialConfig::AsymmetricKey((secret_key, secret_key_subject)) => { + let secret: AsymmetricSecretKey = + secret_key.as_str().try_into()?; + let public: AsymmetricPublicKey = (&secret).try_into()?; + let kip: pasetors::paserk::Id = (&public).try_into()?; + let iat = OffsetDateTime::now_utc(); + + let message = Message { + iat: &iat.format(&Rfc3339)?, + sub: secret_key_subject.as_deref(), + mutation: None, + name: None, + vers: None, + cksum: None, + challenge: None, // todo: PASETO with challenges + v: None, + }; + let footer = Footer { + url: &sid.url().to_string(), + kip, + }; + + pasetors::version3::PublicToken::sign( + &secret, + serde_json::to_string(&message) + .expect("cannot serialize") + .as_bytes(), + Some( + serde_json::to_string(&footer) + .expect("cannot serialize") + .as_bytes(), + ), + None, + )? } }; @@ -337,6 +371,30 @@ fn auth_token_optional(config: &Config, sid: &SourceId) -> CargoResult { + iat: &'a str, + #[serde(skip_serializing_if = "Option::is_none")] + sub: Option<&'a str>, + #[serde(skip_serializing_if = "Option::is_none")] + mutation: Option<&'a str>, + #[serde(skip_serializing_if = "Option::is_none")] + name: Option<&'a str>, + #[serde(skip_serializing_if = "Option::is_none")] + vers: Option<&'a str>, + #[serde(skip_serializing_if = "Option::is_none")] + cksum: Option<&'a str>, + #[serde(skip_serializing_if = "Option::is_none")] + challenge: Option<&'a str>, + #[serde(skip_serializing_if = "Option::is_none")] + v: Option, +} +#[derive(serde::Serialize)] +struct Footer<'a> { + url: &'a str, + kip: pasetors::paserk::Id, +} + enum Action { Get, Store(String),