mod common;
use common::*;
use parse_rust_server::{IpAllowlist, ServerConfig};
use serde_json::json;
const ELSEWHERE: &str = "203.0.113.9";
fn excluding_loopback(mut config: ServerConfig) -> ServerConfig {
config.master_key_ips = IpAllowlist::parse([ELSEWHERE]).expect("entries");
config.maintenance_key_ips = IpAllowlist::parse([ELSEWHERE]).expect("entries");
config
}
fn assert_unauthorized(response: &Response) {
assert_eq!(response.status, 403, "{}", response.raw);
assert_eq!(response.error(), "unauthorized");
assert_eq!(response.code(), None, "upstream sends no code on this one");
}
#[tokio::test]
#[ignore = "needs MongoDB on 127.0.0.1:27017"]
async fn a_master_key_from_a_non_allowlisted_address_is_refused() {
let server = boot_fresh_with(excluding_loopback).await;
let ordinary = post(
&server.host,
"/classes/Post",
&As::anonymous(),
&json!({"title": "x"}),
)
.await;
assert_eq!(ordinary.status, 201, "{}", ordinary.raw);
assert_unauthorized(&get(&server.host, "/classes/Post", &As::master()).await);
assert_unauthorized(&get(&server.host, "/schemas", &As::master()).await);
}
#[tokio::test]
#[ignore = "needs MongoDB on 127.0.0.1:27017"]
async fn the_same_request_succeeds_when_the_address_is_allowed() {
let server = boot_fresh_with(|mut config: ServerConfig| {
config.master_key_ips = IpAllowlist::parse([ELSEWHERE, "127.0.0.1"]).expect("entries");
config
})
.await;
let response = get(&server.host, "/schemas", &As::master()).await;
assert_eq!(response.status, 200, "{}", response.raw);
}
#[tokio::test]
#[ignore = "needs MongoDB on 127.0.0.1:27017"]
async fn the_shipped_default_admits_loopback() {
let server = boot().await;
let response = get(&server.host, "/schemas", &As::master()).await;
assert_eq!(response.status, 200, "{}", response.raw);
}
#[tokio::test]
#[ignore = "needs MongoDB on 127.0.0.1:27017"]
async fn a_forwarded_header_cannot_move_a_caller_in_or_out() {
let refusing = boot_fresh_with(excluding_loopback).await;
for header in ["X-Forwarded-For", "Forwarded", "X-Real-IP"] {
assert_unauthorized(
&get(
&refusing.host,
"/schemas",
&As::master().with_header(header, ELSEWHERE),
)
.await,
);
}
let allowing = boot().await;
let response = get(
&allowing.host,
"/schemas",
&As::master().with_header("X-Forwarded-For", ELSEWHERE),
)
.await;
assert_eq!(response.status, 200, "{}", response.raw);
}
#[tokio::test]
#[ignore = "needs MongoDB on 127.0.0.1:27017"]
async fn a_refused_master_key_is_not_demoted_to_a_client_request() {
let server = boot_fresh_with(excluding_loopback).await;
assert_unauthorized(
&post(
&server.host,
"/classes/Post",
&As::master(),
&json!({"title": "x"}),
)
.await,
);
}
#[tokio::test]
#[ignore = "needs MongoDB on 127.0.0.1:27017"]
async fn an_empty_allowlist_refuses_the_master_key_from_the_server_itself() {
let server = boot_fresh_with(|mut config: ServerConfig| {
config.master_key_ips = IpAllowlist::deny_all();
config
})
.await;
assert_unauthorized(&get(&server.host, "/schemas", &As::master()).await);
}
#[tokio::test]
#[ignore = "needs MongoDB on 127.0.0.1:27017"]
async fn the_maintenance_key_carries_the_same_filter() {
let refusing = boot_fresh_with(excluding_loopback).await;
assert_unauthorized(
&post(
&refusing.host,
"/classes/Post",
&As::maintenance(),
&json!({"title": "x"}),
)
.await,
);
let allowing = boot().await;
let response = post(
&allowing.host,
"/classes/Post",
&As::maintenance(),
&json!({"title": "x"}),
)
.await;
assert_eq!(response.status, 201, "{}", response.raw);
}