summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBryan Newbold <bnewbold@robocracy.org>2018-12-31 17:11:30 -0800
committerBryan Newbold <bnewbold@robocracy.org>2018-12-31 17:11:32 -0800
commitf19288ca809d87a286336e04f8e6b46ddbef300c (patch)
tree771bc5d36fce6a4f9781b6b37cf5e618059108ba
parentf198a9870130484b0ba36b552c7c37ffa5d4d6ca (diff)
downloadfatcat-f19288ca809d87a286336e04f8e6b46ddbef300c.tar.gz
fatcat-f19288ca809d87a286336e04f8e6b46ddbef300c.zip
add auth middleware back in
I was hoping I didn't need this middleware, but I actually do, or the swagger generated code returns unauthenticated. The middleware doesn't actually do much validation, just extracts the (string) token and does nothing with it. Acutal verification happens in user code using AuthData struct.
-rw-r--r--rust/src/auth.rs97
-rw-r--r--rust/src/bin/fatcatd.rs1
2 files changed, 95 insertions, 3 deletions
diff --git a/rust/src/auth.rs b/rust/src/auth.rs
index ee3c6fb0..16fd4fe2 100644
--- a/rust/src/auth.rs
+++ b/rust/src/auth.rs
@@ -2,7 +2,8 @@
use data_encoding::BASE64;
use macaroon::{Format, Macaroon, Verifier};
-use swagger::auth::AuthData;
+use std::fmt;
+use swagger::auth::{AuthData, Authorization, Scopes};
use api_helpers::*;
use chrono::prelude::*;
@@ -59,7 +60,7 @@ impl AuthContext {
pub fn require_editgroup(&self, conn: &DbConn, editgroup_id: FatCatId) -> Result<()> {
if self.has_role(FatcatRole::Admin) {
- return Ok(())
+ return Ok(());
}
let editgroup: EditgroupRow = editgroup::table
.find(editgroup_id.to_uuid())
@@ -74,6 +75,94 @@ impl AuthContext {
}
}
+#[derive(Debug)]
+pub struct AuthError {
+ msg: String,
+}
+
+impl fmt::Display for AuthError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "AuthError: {}", &self.msg)
+ }
+}
+
+impl iron::Error for AuthError {
+ fn description(&self) -> &str {
+ &self.msg
+ }
+ fn cause(&self) -> Option<&iron::Error> {
+ None
+ }
+}
+
+fn new_auth_ironerror(m: &str) -> iron::error::IronError {
+ iron::error::IronError::new(
+ AuthError { msg: m.to_string() },
+ (iron::status::BadRequest, m.to_string()),
+ )
+}
+
+#[derive(Debug)]
+pub struct OpenAuthMiddleware;
+
+impl OpenAuthMiddleware {
+ /// Create a middleware that authorizes with the configured subject.
+ pub fn new() -> OpenAuthMiddleware {
+ OpenAuthMiddleware
+ }
+}
+
+impl iron::middleware::BeforeMiddleware for OpenAuthMiddleware {
+ fn before(&self, req: &mut iron::Request) -> iron::IronResult<()> {
+ req.extensions.insert::<Authorization>(Authorization {
+ subject: "undefined".to_string(),
+ scopes: Scopes::All,
+ issuer: None,
+ });
+ Ok(())
+ }
+}
+
+#[derive(Debug)]
+pub struct MacaroonAuthMiddleware;
+
+impl MacaroonAuthMiddleware {
+ pub fn new() -> MacaroonAuthMiddleware {
+ MacaroonAuthMiddleware
+ }
+}
+impl iron::middleware::BeforeMiddleware for MacaroonAuthMiddleware {
+ fn before(&self, req: &mut iron::Request) -> iron::IronResult<()> {
+ // Structure here is sorta funky because we might some day actually want to parse token
+ // here in some way
+ let token: Option<String> = match req.extensions.get::<AuthData>() {
+ Some(AuthData::ApiKey(header)) => {
+ let header: Vec<String> =
+ header.split_whitespace().map(|s| s.to_string()).collect();
+ if !(header.len() == 2 && header[0] == "Bearer") {
+ return Err(new_auth_ironerror("invalid bearer auth HTTP Header"));
+ }
+ Some(header[1].to_string())
+ }
+ None => None,
+ _ => {
+ return Err(new_auth_ironerror(
+ "auth HTTP Header should be empty or API token",
+ ));
+ }
+ };
+ if let Some(_token) = token {
+ req.extensions.insert::<Authorization>(Authorization {
+ // This is just a dummy; all actual authentication happens later
+ subject: "undefined".to_string(),
+ scopes: Scopes::All,
+ issuer: None,
+ });
+ };
+ Ok(())
+ }
+}
+
#[derive(Clone)]
pub struct AuthConfectionary {
pub location: String,
@@ -88,6 +177,7 @@ impl AuthConfectionary {
identifier: String,
key_base64: String,
) -> Result<AuthConfectionary> {
+ macaroon::initialize().unwrap();
let key = BASE64.decode(key_base64.as_bytes())?;
let mut root_keys = HashMap::new();
root_keys.insert(identifier.clone(), key.clone());
@@ -180,7 +270,8 @@ impl AuthConfectionary {
));
let editor: EditorRow = editor::table.find(&editor_id.to_uuid()).get_result(conn)?;
let auth_epoch = DateTime::<Utc>::from_utc(editor.auth_epoch, Utc);
- if created < auth_epoch {
+ // allow a second of wiggle room for precision and, eg, tests
+ if created < (auth_epoch - chrono::Duration::seconds(1)) {
return Err(ErrorKind::InvalidCredentials(
"token created before current auth_epoch (was probably revoked by editor)"
.to_string(),
diff --git a/rust/src/bin/fatcatd.rs b/rust/src/bin/fatcatd.rs
index 7d77d90b..a4f20ddb 100644
--- a/rust/src/bin/fatcatd.rs
+++ b/rust/src/bin/fatcatd.rs
@@ -77,6 +77,7 @@ fn main() {
// authentication
chain.link_before(fatcat_api_spec::server::ExtractAuthData);
+ chain.link_before(fatcat::auth::MacaroonAuthMiddleware::new());
chain.link_after(fatcat::XClacksOverheadMiddleware);