Skip to content

Commit

Permalink
Merge pull request #160 from fission-codes/blaine/wip
Browse files Browse the repository at this point in the history
UCAN validation
  • Loading branch information
blaine authored Aug 22, 2023
2 parents 421528e + ed708d2 commit 07e7b33
Show file tree
Hide file tree
Showing 12 changed files with 718 additions and 94 deletions.
36 changes: 32 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ ed25519-zebra = "3.1"
rand = "0.8"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
ucan = "=0.2.0"
ucan-key-support = "=0.1.3"
ucan = { path = "../rs-ucan/ucan" }
ucan-key-support = { path = "../rs-ucan/ucan-key-support" }
url = "2.3"

# Speedup build on macOS
Expand Down
3 changes: 3 additions & 0 deletions fission-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ base64-url = "2.0.0"
bb8 = "0.8.0"
bytes = "1.4.0"
chrono = { version = "0.4", default-features = false, features = ["clock", "serde"] }
cid = "0.10.1"
config = "0.13"
console-subscriber = { version = "0.1", default-features = false, features = [ "parking_lot" ], optional = true }
const_format = "0.2"
Expand Down Expand Up @@ -99,6 +100,7 @@ tracing = "0.1"
tracing-appender = "0.2"
tracing-opentelemetry = "0.18"
tracing-subscriber = { version = "0.3", features = ["env-filter", "json", "parking_lot", "registry"] }
tracing-test = "0.2.4"
trust-dns-server = { version = "0.22.0", features = ["dns-over-rustls"] }
ucan = { workspace = true }
ucan-key-support = { workspace = true }
Expand All @@ -111,6 +113,7 @@ validator = { version = "0.16.0", features = ["derive"] }
[dev-dependencies]
assert-json-diff = "2.0"
rsa = { version = "0.9" }
stringreader = "0.1.1"
tokio-test = "0.4"
uuid = "1.4.1"
wiremock = "0.5"
Expand Down
82 changes: 80 additions & 2 deletions fission-server/src/authority.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@ use fission_core::authority::key_material::SUPPORTED_KEYS;
use std::time::{SystemTime, UNIX_EPOCH};
use ucan::crypto::did::DidParser;

use ucan::store::{MemoryStore, UcanJwtStore};

use ucan::capability::CapabilitySemantics;

///////////
// TYPES //
///////////

#[derive(Debug)]
#[derive(Debug, Clone)]
/// Represents the authority of an incoming request
pub struct Authority {
/// https://github.com/ucan-wg/ucan-as-bearer-token#21-entry-point
pub ucan: ucan::Ucan,
/// proofs from `ucan` header
pub proofs: Vec<ucan::Ucan>,
}

/////////////////////
Expand All @@ -32,6 +38,57 @@ impl Authority {
.await
.map_err(|err| err.to_string())
}

/// Validates whether or not the UCAN and proofs have the capability to
/// perform the given action, with the given issuer as the root of that
/// authority.
pub async fn has_capability(
&self,
with: &str,
can: &str,
issuer_did: &str,
) -> Result<bool, String> {
let mut did_parser = DidParser::new(SUPPORTED_KEYS);
let mut store = MemoryStore::default();
let current_time = SystemTime::now()
.duration_since(UNIX_EPOCH)
.ok()
.map(|t| t.as_secs());

for proof in &self.proofs {
if let Ok(ucan_str) = proof.encode() {
tracing::debug!("Adding proof: {}", ucan_str);
store
.write_token(&ucan_str)
.await
.map_err(|err| err.to_string())?;
}
}

let my_ucan = self.ucan.clone();
let chain =
ucan::chain::ProofChain::from_ucan(my_ucan, current_time, &mut did_parser, &store)
.await
.map_err(|err| err.to_string())?;

let capability_infos =
chain.reduce_capabilities(&fission_core::capabilities::delegation::SEMANTICS);

let expected_capability = fission_core::capabilities::delegation::SEMANTICS
.parse(with, can)
.unwrap();

for info in capability_infos {
tracing::debug!("Checking capabilities: {:?} {}", info, issuer_did);
if info.originators.contains(issuer_did)
&& info.capability.enables(&expected_capability)
{
return Ok(true);
}
}

Ok(false)
}
}

///////////
Expand All @@ -57,8 +114,29 @@ mod tests {
.await
.unwrap();

let authority = Authority { ucan };
let authority = Authority {
ucan,
proofs: vec![],
};

assert!(authority.validate().await.is_ok());
}

#[tokio::test]
#[ignore]
async fn invalid_ucan_test() {
panic!("pending")
}

#[tokio::test]
#[ignore]
async fn incomplete_proofs_test() {
panic!("pending")
}

#[tokio::test]
#[ignore]
async fn invalid_delegation_test() {
panic!("pending")
}
}
25 changes: 25 additions & 0 deletions fission-server/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use axum::{
Json,
};

use http::header::ToStrError;
use serde::{Deserialize, Serialize};
use tracing::warn;
use ulid::Ulid;
Expand Down Expand Up @@ -133,6 +134,30 @@ impl From<diesel::result::Error> for AppError {
}
}

impl From<ToStrError> for AppError {
fn from(_err: ToStrError) -> Self {
Self {
status: StatusCode::BAD_REQUEST,
title: StatusCode::BAD_REQUEST
.canonical_reason()
.map(|r| r.to_string()),
detail: None,
}
}
}

impl From<String> for AppError {
fn from(_err: String) -> Self {
Self {
status: StatusCode::INTERNAL_SERVER_ERROR,
title: StatusCode::INTERNAL_SERVER_ERROR
.canonical_reason()
.map(|r| r.to_string()),
detail: None, //Some(err),
}
}
}

/// Serialize/Deserializer for status codes.
///
/// This is needed because status code according to JSON API spec must
Expand Down
Loading

0 comments on commit 07e7b33

Please sign in to comment.