From 6e92ed37320f04b29511f6e3614086cffcab6eb0 Mon Sep 17 00:00:00 2001 From: Bryan Newbold Date: Sat, 29 Dec 2018 00:04:46 -0800 Subject: start trying 'macaroons' crate I initially thought that this might be better than 'macaroon'; macaroons, despite being in "archive" mode, had more crates.io downloads and I hoped might be better implemented. It seems half-complete though, and, eg, doesn't support the V2 macaroon encoding format. This patch isn't complete (didn't figure out verification), but I probably won't pursure it. --- rust/src/auth.rs | 71 ++++++++++++++++++++++++++++++-------------------------- rust/src/lib.rs | 2 +- 2 files changed, 39 insertions(+), 34 deletions(-) (limited to 'rust/src') diff --git a/rust/src/auth.rs b/rust/src/auth.rs index 0fe21ebe..f9283329 100644 --- a/rust/src/auth.rs +++ b/rust/src/auth.rs @@ -1,7 +1,10 @@ //! Editor bearer token authentication use swagger::auth::AuthData; -use macaroon::{Format, Macaroon, Verifier}; +use macaroons::v1::V1Token; +use macaroons::verifier::*; +use macaroons::caveat::Caveat; +use macaroons::token::Token; use data_encoding::BASE64; use std::collections::HashMap; @@ -59,51 +62,49 @@ impl AuthConfectionary { } pub fn create_token(&self, editor_id: FatCatId, expires: Option>) -> Result { - let mut mac = Macaroon::create(&self.location, &self.key, &self.identifier).expect("Macaroon creation"); - mac.add_first_party_caveat(&format!("editor_id = {}", editor_id.to_string())); + let mut token = V1Token::new(&self.key, self.identifier.as_bytes().to_vec(), Some(self.location.as_bytes().to_vec())); + token.add_caveat( + &Caveat::first_party(Vec::from(format!("editor_id = {}", editor_id.to_string())))); // TODO: put created one second in the past to prevent timing synchronization glitches? let now = Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true); - mac.add_first_party_caveat(&format!("created = {}", now)); + token.add_caveat( + &Caveat::first_party(Vec::from(format!("created = {}", now)))); if let Some(expires) = expires { - mac.add_first_party_caveat(&format!("expires = {:?}", - &expires.to_rfc3339_opts(SecondsFormat::Secs, true))); + token.add_caveat( + &Caveat::first_party(Vec::from(format!("expires = {:?}", + &expires.to_rfc3339_opts(SecondsFormat::Secs, true))))); }; - let raw = mac.serialize(Format::V2).expect("macaroon serialization"); + let raw = token.serialize().expect("macaroon serialization"); Ok(BASE64.encode(&raw)) } /// On success, returns Some((editor_id, scopes)), where `scopes` is a vector of strings. pub fn parse_macaroon_token(&self, conn: &DbConn, s: &str) -> Result { let raw = BASE64.decode(s.as_bytes())?; - let mac = match Macaroon::deserialize(&raw) { + let mac = match V1Token::deserialize(raw) { Ok(m) => m, Err(e) => bail!("macaroon deserialize error: {:?}", e), }; - let mac = match mac.validate() { - Ok(m) => m, - Err(e) => bail!("macaroon validate error: {:?}", e), - }; - let mut verifier = Verifier::new(); let mut editor_id: Option = None; - for caveat in mac.first_party_caveats() { - if caveat.predicate().starts_with("editor_id = ") { - editor_id = Some(FatCatId::from_str(caveat.predicate().get(12..).unwrap())?); + for caveat in mac.caveats.iter() { + let caveat = String::from_utf8_lossy(&caveat.caveat_id); + if caveat.starts_with("editor_id = ") { + editor_id = Some(FatCatId::from_str(caveat.get(12..).unwrap())?); break } } let editor_id = editor_id.expect("expected an editor_id caveat"); - verifier.satisfy_exact(&format!("editor_id = {}", editor_id.to_string())); let mut created: Option> = None; - for caveat in mac.first_party_caveats() { - if caveat.predicate().starts_with("created = ") { - created = Some(DateTime::parse_from_rfc3339(caveat.predicate().get(10..).unwrap()) + for caveat in mac.caveats.iter() { + let caveat = String::from_utf8_lossy(&caveat.caveat_id); + if caveat.starts_with("created = ") { + created = Some(DateTime::parse_from_rfc3339(caveat.get(10..).unwrap()) .unwrap() .with_timezone(&Utc)); break } } let created = created.expect("expected a 'created' caveat"); - verifier.satisfy_exact(&format!("created = {}", created.to_rfc3339_opts(SecondsFormat::Secs, true))); let editor: EditorRow = editor::table .find(&editor_id.to_uuid()) .get_result(conn)?; @@ -111,6 +112,9 @@ impl AuthConfectionary { if created < auth_epoch { bail!("token created before current auth_epoch (was probably revoked by editor)") } + /* XXX: haven't implemented verification + verifier.satisfy_exact(&format!("editor_id = {}", editor_id.to_string())); + verifier.satisfy_exact(&format!("created = {}", created.to_rfc3339_opts(SecondsFormat::Secs, true))); verifier.satisfy_general(|p: &str| -> bool { // not expired (based on expires) if p.starts_with("expires = ") { @@ -122,15 +126,16 @@ impl AuthConfectionary { false } }); - let verify_key = match self.root_keys.get(mac.identifier()) { + let identifier = String::from_utf8_lossy(&mac.identifier).to_string(); + let verify_key = match self.root_keys.get(&identifier) { Some(key) => key, - None => bail!("key not found for identifier: {}", mac.identifier()), + None => bail!("key not found for identifier: {}", identifier), }; match mac.verify(verify_key, &mut verifier) { - Ok(true) => (), - Ok(false) => bail!("token overall verification failed"), + Ok(()) => (), Err(e) => bail!("token parsing failed: {:?}", e), } + */ Ok(editor) } @@ -162,20 +167,20 @@ impl AuthConfectionary { // TODO: refactor out of this file? /// Only used from CLI tool - pub fn inspect_token(&self, conn: &DbConn, token: &str) -> Result<()> { - let raw = BASE64.decode(token.as_bytes())?; - let mac = match Macaroon::deserialize(&raw) { + pub fn inspect_token(&self, conn: &DbConn, raw_token: &str) -> Result<()> { + let raw = BASE64.decode(raw_token.as_bytes())?; + let token = match V1Token::deserialize(raw) { Ok(m) => m, Err(e) => bail!("macaroon deserialize error: {:?}", e), }; let now = Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true); println!("current time: {}", now); - println!("domain (location): {:?}", mac.location()); - println!("signing key name (identifier): {}", mac.identifier()); - for caveat in mac.first_party_caveats() { - println!("caveat: {}", caveat.predicate()); + println!("domain (location): {:?}", token.location); + println!("signing key name (identifier): {}", String::from_utf8_lossy(&token.identifier)); + for caveat in token.caveats.iter() { + println!("caveat: {}", String::from_utf8_lossy(&caveat.caveat_id)); } - println!("verify: {:?}", self.parse_macaroon_token(conn, token)); + println!("verify: {:?}", self.parse_macaroon_token(conn, raw_token)); Ok(()) } } diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 983645d8..b2cfe38a 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -23,7 +23,7 @@ extern crate regex; #[macro_use] extern crate lazy_static; extern crate sha1; -extern crate macaroon; +extern crate macaroons; pub mod api_entity_crud; pub mod api_helpers; -- cgit v1.2.3