aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBryan Newbold <bnewbold@robocracy.org>2018-12-28 22:04:45 -0800
committerBryan Newbold <bnewbold@robocracy.org>2018-12-28 22:04:45 -0800
commitd50f7729cbc86c62dba9bd4db80786f07b44a7c0 (patch)
tree992677218f37dbd58fbf3ac7bb6035e3a57a1104
parentf9408344464285870409c2209a8edc8d25fd9bfa (diff)
downloadfatcat-d50f7729cbc86c62dba9bd4db80786f07b44a7c0.tar.gz
fatcat-d50f7729cbc86c62dba9bd4db80786f07b44a7c0.zip
more auth refactoring
-rw-r--r--rust/src/api_helpers.rs12
-rw-r--r--rust/src/auth.rs113
-rw-r--r--rust/src/bin/fatcat-auth.rs8
-rw-r--r--rust/src/lib.rs2
4 files changed, 76 insertions, 59 deletions
diff --git a/rust/src/api_helpers.rs b/rust/src/api_helpers.rs
index ff164bef..da208c0a 100644
--- a/rust/src/api_helpers.rs
+++ b/rust/src/api_helpers.rs
@@ -228,6 +228,18 @@ pub fn make_edit_context(
})
}
+// TODO: verify username (alphanum, etc)
+pub fn create_editor(conn: &DbConn, username: String, is_admin: bool, is_bot: bool) -> Result<EditorRow> {
+ let ed: EditorRow = diesel::insert_into(editor::table)
+ .values((
+ editor::username.eq(username),
+ editor::is_admin.eq(is_admin),
+ editor::is_bot.eq(is_bot),
+ ))
+ .get_result(conn)?;
+ Ok(ed)
+}
+
/// This function should always be run within a transaction
pub fn get_or_create_editgroup(editor_id: Uuid, conn: &DbConn) -> Result<Uuid> {
// check for current active
diff --git a/rust/src/auth.rs b/rust/src/auth.rs
index c188233a..8e9a6309 100644
--- a/rust/src/auth.rs
+++ b/rust/src/auth.rs
@@ -4,7 +4,7 @@ use swagger::auth::AuthData;
use macaroon::{Format, Macaroon, Verifier};
use data_encoding::BASE64;
-use std::collections::{BTreeSet,HashMap};
+use std::collections::HashMap;
use database_models::*;
use database_schema::*;
use api_helpers::*;
@@ -33,21 +33,36 @@ impl AuthContext {
#[derive(Clone)]
pub struct AuthConfectionary {
- pub root_keys: HashMap<String, [u8; 32]>,
+ pub location: String,
+ pub identifier: String,
+ pub key: Vec<u8>,
+ pub root_keys: HashMap<String, Vec<u8>>,
}
impl AuthConfectionary {
- pub fn new() -> AuthConfectionary {
+ pub fn new(location: String, identifier: String, key: Vec<u8>) -> AuthConfectionary {
+ let mut root_keys = HashMap::new();
+ root_keys.insert(identifier.clone(), key.clone());
AuthConfectionary {
- root_keys: HashMap::new(),
+ location: location,
+ identifier: identifier,
+ key: key,
+ root_keys: root_keys,
}
}
+ pub fn new_dummy() -> AuthConfectionary {
+ AuthConfectionary::new(
+ "test.fatcat.wiki".to_string(),
+ "dummy".to_string(),
+ DUMMY_KEY.to_vec())
+ }
+
pub fn create_token(&self, conn: &DbConn, editor_id: FatCatId, expires: Option<DateTime<Utc>>) -> Result<String> {
let _ed: EditorRow = editor::table
.find(&editor_id.to_uuid())
.get_result(conn)?;
- let mut mac = Macaroon::create("fatcat.wiki", DUMMY_KEY, "dummy-key").expect("Macaroon creation");
+ 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()));
// TODO: put created one second in the past to prevent timing synchronization glitches?
let now = Utc::now().to_rfc3339_opts(SecondsFormat::Secs, true);
@@ -110,10 +125,11 @@ impl AuthConfectionary {
false
}
});
- if !mac.verify_signature(DUMMY_KEY) {
- bail!("token signature verification failed");
+ let verify_key = match self.root_keys.get(mac.identifier()) {
+ Some(key) => key,
+ None => bail!("key not found for identifier: {}", mac.identifier()),
};
- match mac.verify(DUMMY_KEY, &mut verifier) {
+ match mac.verify(verify_key, &mut verifier) {
Ok(true) => (),
Ok(false) => bail!("token overall verification failed"),
Err(e) => bail!("token parsing failed: {:?}", e),
@@ -146,8 +162,43 @@ impl AuthConfectionary {
roles: roles,
}))
}
+
+ // 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) {
+ 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!("verify: {:?}", self.parse_macaroon_token(conn, token));
+ Ok(())
+ }
}
+pub fn revoke_tokens(conn: &DbConn, editor_id: FatCatId) -> Result<()>{
+ diesel::update(editor::table.filter(editor::id.eq(&editor_id.to_uuid())))
+ .set(editor::auth_epoch.eq(Utc::now()))
+ .execute(conn)?;
+ Ok(())
+}
+
+pub fn revoke_tokens_everyone(conn: &DbConn) -> Result<()> {
+ diesel::update(editor::table)
+ .set(editor::auth_epoch.eq(Utc::now()))
+ .execute(conn)?;
+ Ok(())
+}
+
+// TODO: refactor out of this file?
+/// Only used from CLI tool
pub fn print_editors(conn: &DbConn) -> Result<()>{
// iterate over all editors. format id, print flags, auth_epoch
let all_editors: Vec<EditorRow> = editor::table
@@ -165,49 +216,3 @@ pub fn print_editors(conn: &DbConn) -> Result<()>{
}
Ok(())
}
-
-// TODO: move to api_helpers or some such
-// TODO: verify username
-pub fn create_editor(conn: &DbConn, username: String, is_admin: bool, is_bot: bool) -> Result<EditorRow> {
- let ed: EditorRow = diesel::insert_into(editor::table)
- .values((
- editor::username.eq(username),
- editor::is_admin.eq(is_admin),
- editor::is_bot.eq(is_bot),
- ))
- .get_result(conn)?;
- Ok(ed)
-}
-
-pub fn inspect_token(conn: &DbConn, token: &str) -> Result<()> {
- let raw = BASE64.decode(token.as_bytes())?;
- let mac = match Macaroon::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());
- }
- let ac = AuthConfectionary::new();
- // TODO: don't display full stacktrace on failure
- println!("verify: {:?}", ac.parse_macaroon_token(conn, token));
- Ok(())
-}
-
-pub fn revoke_tokens(conn: &DbConn, editor_id: FatCatId) -> Result<()>{
- diesel::update(editor::table.filter(editor::id.eq(&editor_id.to_uuid())))
- .set(editor::auth_epoch.eq(Utc::now()))
- .execute(conn)?;
- Ok(())
-}
-
-pub fn revoke_tokens_everyone(conn: &DbConn) -> Result<()> {
- diesel::update(editor::table)
- .set(editor::auth_epoch.eq(Utc::now()))
- .execute(conn)?;
- Ok(())
-}
diff --git a/rust/src/bin/fatcat-auth.rs b/rust/src/bin/fatcat-auth.rs
index f11f7a67..4b90da74 100644
--- a/rust/src/bin/fatcat-auth.rs
+++ b/rust/src/bin/fatcat-auth.rs
@@ -13,7 +13,7 @@ extern crate env_logger;
extern crate serde_json;
extern crate uuid;
-use clap::{App, Arg, SubCommand};
+use clap::{App, SubCommand};
use dotenv::dotenv;
use std::env;
@@ -90,13 +90,13 @@ fn run() -> Result<()> {
.get_matches();
let db_conn = database_worker_pool()?.get().expect("database pool");
- let confectionary = fatcat::auth::AuthConfectionary::new();
+ let confectionary = fatcat::auth::AuthConfectionary::new_dummy();
match m.subcommand() {
("list-editors", Some(_subm)) => {
fatcat::auth::print_editors(&db_conn)?;
},
("create-editor", Some(subm)) => {
- let editor = fatcat::auth::create_editor(
+ let editor = fatcat::api_helpers::create_editor(
&db_conn,
subm.value_of("username").unwrap().to_string(),
subm.is_present("admin"),
@@ -109,7 +109,7 @@ fn run() -> Result<()> {
println!("{}", confectionary.create_token(&db_conn, editor_id, None)?);
},
("inspect-token", Some(subm)) => {
- fatcat::auth::inspect_token(&db_conn, subm.value_of("token").unwrap())?;
+ confectionary.inspect_token(&db_conn, subm.value_of("token").unwrap())?;
},
("revoke-tokens", Some(subm)) => {
let editor_id = FatCatId::from_str(subm.value_of("editor-id").unwrap())?;
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 43911868..983645d8 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -117,7 +117,7 @@ pub fn server() -> Result<api_server::Server> {
let pool = diesel::r2d2::Pool::builder()
.build(manager)
.expect("Failed to create database pool.");
- let confectionary = auth::AuthConfectionary::new();
+ let confectionary = auth::AuthConfectionary::new_dummy();
Ok(api_server::Server { db_pool: pool, auth_confectionary: confectionary })
}