Compute intersection of two lists

Useful for comparing capabilities with required permissions.

VCL

Use this solution in your VCL service (click RUN below to test this solution or clone it to make changes):

Compute@Edge

Use this solution in your Compute@Edge service:

  1. Rust
/// The name of a backend server associated with this service.
const BACKEND_NAME: &str = "httpbin.org";
#[fastly::main]
fn main(req: Request) -> Result<Response, Error> {
// Log initial setup
log_fastly::init_simple("my_log", log::LevelFilter::Info);
match do_req_with_permission_check(req) {
Ok(resp) => Ok(resp),
Err(e) => {
log::info!("{}", e);
Ok(Response::from_status(StatusCode::FORBIDDEN))
}
}
}
/// Request to backend if intersection of permission is found
fn do_req_with_permission_check(req: Request) -> Result<Response> {
// Get permission from requestion
let req_permission = get_req_permission(&req)?;
// Send request and get response from backend
let resp = req.send(BACKEND_NAME)?;
// Get permission from require-group response header
let require_group = resp
.get_header("require-group")
.ok_or_else(|| anyhow!("No require-group header found in response"))?
.to_str()?;
// Check if there is any intersection between two permission sets
let a_set = permissions_into_set(&req_permission);
let b_set = permissions_into_set(require_group);
let mut intersection_set = a_set.intersection(&b_set);
if intersection_set.next().is_none() {
return Err(anyhow!("No intersection in permission found"));
}
Ok(resp)
}
/// Get permission string from request cookie
fn get_req_permission(req: &Request) -> Result<String> {
let cookie_val: &str = req
.get_header(header::COOKIE)
.ok_or_else(|| anyhow!("No cookie found"))?
.to_str()?;
// we split at ";" not "; ", in case the cookie is ending with ";"
cookie_val
.split(';')
.find_map(|kv| {
let index = kv.find('=')?;
let (key, value) = kv.split_at(index);
if key.trim() != "permission" {
return None;
}
// remove the "="
let value = value[1..].to_string();
Some(value)
})
.ok_or_else(|| anyhow!("No permission found in cookie"))
}
/// Parse permission string and put permissions into a HashSet
fn permissions_into_set(p: &str) -> HashSet<&str> {
p.split(':').filter(|s| !s.is_empty()).collect()
}