diff options
Diffstat (limited to 'tests/authorization')
| -rw-r--r-- | tests/authorization/cedar_authorizer_test.rs | 66 | ||||
| -rw-r--r-- | tests/authorization/check_service_test.rs | 118 | ||||
| -rw-r--r-- | tests/authorization/mod.rs | 3 | ||||
| -rw-r--r-- | tests/authorization/server_test.rs | 48 |
4 files changed, 235 insertions, 0 deletions
diff --git a/tests/authorization/cedar_authorizer_test.rs b/tests/authorization/cedar_authorizer_test.rs new file mode 100644 index 00000000..76bf06df --- /dev/null +++ b/tests/authorization/cedar_authorizer_test.rs @@ -0,0 +1,66 @@ +#[cfg(test)] +mod tests { + use crate::support::factory_bot::*; + use authzd::Authorizer; + use envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest; + use std::collections::HashMap; + + #[test] + fn test_cedar_authorizer_allows_valid_token() { + let request = build_request(|item: &mut HttpRequest| { + item.headers = build_with(|item: &mut HashMap<String, String>| { + item.insert( + String::from("authorization"), + String::from("Bearer valid-token"), + ); + }); + }); + + assert!(build_cedar_authorizer().authorize(request)); + } + + #[test] + fn test_cedar_authorizer_denies_invalid_token() { + let request = build_request(|item: &mut HttpRequest| { + item.headers = build_with(|item: &mut HashMap<String, String>| { + item.insert( + String::from("authorization"), + String::from("Bearer invalid-token"), + ); + }); + }); + + assert!(!build_cedar_authorizer().authorize(request)); + } + + #[test] + fn test_cedar_authorizer_denies_missing_header() { + let request = build_request(|item: &mut HttpRequest| { + item.headers = HashMap::new(); + }); + + assert!(!build_cedar_authorizer().authorize(request)); + } + + #[test] + fn test_cedar_authorizer_allows_static_assets() { + let request = build_request(|item: &mut HttpRequest| { + item.headers = build_with(|item: &mut HashMap<String, String>| { + item.insert(String::from(":path"), String::from("/public/style.css")); + }); + }); + + assert!(build_cedar_authorizer().authorize(request)); + } + + #[test] + fn test_cedar_authorizer_allows_js_assets() { + let mut headers = HashMap::new(); + headers.insert(":path".to_string(), "/app.js".to_string()); + let request = build_request(|item: &mut HttpRequest| { + item.headers = headers; + }); + + assert!(build_cedar_authorizer().authorize(request)); + } +} diff --git a/tests/authorization/check_service_test.rs b/tests/authorization/check_service_test.rs new file mode 100644 index 00000000..3a225974 --- /dev/null +++ b/tests/authorization/check_service_test.rs @@ -0,0 +1,118 @@ +#[cfg(test)] +mod tests { + use crate::support::factory_bot::*; + use authzd::CheckService; + use envoy_types::ext_authz::v3::pb::Authorization; + use envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest; + use std::collections::HashMap; + use std::sync::Arc; + + fn subject() -> CheckService { + CheckService::new(Arc::new(build_cedar_authorizer())) + } + + #[tokio::test] + async fn test_check_allows_valid_bearer_token() { + let request = tonic::Request::new(build_request(|item: &mut HttpRequest| { + item.headers = build_headers(vec![( + "authorization".to_string(), + format!("Bearer {}", String::from("valid-token")), + )]) + })); + + let response = subject().check(request).await; + assert!(response.is_ok()); + + let check_response = response.unwrap().into_inner(); + assert!(check_response.status.is_some()); + + let status = check_response.status.unwrap(); + assert_eq!(status.code, tonic::Code::Ok as i32); + } + + #[tokio::test] + async fn test_check_denies_invalid_bearer_token() { + let request = tonic::Request::new(build_request(|item: &mut HttpRequest| { + item.headers = HashMap::new(); + })); + + let response = subject().check(request).await; + assert!(response.is_ok()); + + let check_response = response.unwrap().into_inner(); + assert!(check_response.status.is_some()); + + let status = check_response.status.unwrap(); + assert_eq!(status.code, tonic::Code::Unauthenticated as i32); + } + + #[tokio::test] + async fn test_static_assets() { + let static_paths = vec![ + "app.js", + "favicon.ico", + "image.jpg", + "index.html", + "logo.png", + "style.css", + ]; + + for path in static_paths { + let request = tonic::Request::new(build_request(|http| { + http.headers = build_headers(vec![(":path".to_string(), path.to_string())]); + })); + + let response = subject().check(request).await; + assert!(response.is_ok()); + + let check_response = response.unwrap().into_inner(); + assert!(check_response.status.is_some()); + + let status = check_response.status.unwrap(); + assert_eq!(status.code, tonic::Code::Ok as i32); + } + } + + #[tokio::test] + async fn test_no_headers() { + let request = tonic::Request::new(build_request(|_http| {})); + + let response = subject().check(request).await; + assert!(response.is_ok()); + + let check_response = response.unwrap().into_inner(); + assert!(check_response.status.is_some()); + + let status = check_response.status.unwrap(); + assert_eq!(status.code, tonic::Code::Unauthenticated as i32); + } + + #[tokio::test] + async fn test_table() { + let test_cases = vec![ + ("Bearer valid-token", true), + ("Bearer invalid-token", false), + ("Basic valid-token", false), + ("", false), + ]; + + for (auth_value, should_succeed) in test_cases { + let request = tonic::Request::new(build_request(|item: &mut HttpRequest| { + item.headers = + build_headers(vec![("authorization".to_string(), auth_value.to_string())]); + })); + + let response = subject().check(request).await; + assert!(response.is_ok()); + + let check_response = response.unwrap().into_inner(); + let status = check_response.status.unwrap(); + + if should_succeed { + assert_eq!(status.code, tonic::Code::Ok as i32); + } else { + assert_eq!(status.code, tonic::Code::Unauthenticated as i32); + } + } + } +} diff --git a/tests/authorization/mod.rs b/tests/authorization/mod.rs new file mode 100644 index 00000000..675247d4 --- /dev/null +++ b/tests/authorization/mod.rs @@ -0,0 +1,3 @@ +mod cedar_authorizer_test; +mod check_service_test; +mod server_test; diff --git a/tests/authorization/server_test.rs b/tests/authorization/server_test.rs new file mode 100644 index 00000000..fe8c8a73 --- /dev/null +++ b/tests/authorization/server_test.rs @@ -0,0 +1,48 @@ +#[cfg(test)] +mod tests { + use crate::support::factory_bot::*; + use std::net::SocketAddr; + use tokio::net::TcpListener; + + async fn available_port() -> SocketAddr { + let listener = TcpListener::bind("127.0.0.1:0") + .await + .expect("Failed to bind to random port"); + let addr = listener.local_addr().expect("Failed to get local address"); + drop(listener); + addr + } + + async fn start_server() -> (SocketAddr, tokio::task::JoinHandle<()>) { + let addr = available_port().await; + let server = authzd::authorization::Server::default(); + + let handle = tokio::spawn(async move { + server.serve(addr).await.expect("Failed to start server"); + }); + + tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; + + (addr, handle) + } + + #[tokio::test] + async fn test_health_check_service() { + let (addr, server) = start_server().await; + let mut client = + build_rpc_client(addr, tonic_health::pb::health_client::HealthClient::new).await; + + let request = tonic::Request::new(tonic_health::pb::HealthCheckRequest { + service: String::new(), + }); + let response = client.check(request).await; + + assert!(response.is_ok()); + assert_eq!( + response.unwrap().into_inner().status(), + tonic_health::pb::health_check_response::ServingStatus::Serving + ); + + server.abort(); + } +} |
