From d099e77eaa8e51eef14cd775234bfd4b12098a4c Mon Sep 17 00:00:00 2001 From: mo khan Date: Wed, 25 Jun 2025 14:20:33 -0600 Subject: test: move cedar_authorizer tests to integration test suite --- tests/authorization/cedar_authorizer_test.rs | 78 ++++++++++++++++++++++++++++ tests/authorization/mod.rs | 1 + 2 files changed, 79 insertions(+) create mode 100644 tests/authorization/cedar_authorizer_test.rs create mode 100644 tests/authorization/mod.rs (limited to 'tests/authorization') diff --git a/tests/authorization/cedar_authorizer_test.rs b/tests/authorization/cedar_authorizer_test.rs new file mode 100644 index 00000000..2ed3dd68 --- /dev/null +++ b/tests/authorization/cedar_authorizer_test.rs @@ -0,0 +1,78 @@ +#[cfg(test)] +mod tests { + use crate::common::create_request; + use authzd::Authorizer; + use authzd::CedarAuthorizer; + use envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest; + use std::collections::HashMap; + + #[test] + fn test_cedar_authorizer_allows_valid_token() { + let authorizer = CedarAuthorizer::new(); + let mut headers = HashMap::new(); + headers.insert( + "authorization".to_string(), + "Bearer valid-token".to_string(), + ); + let request = create_request(|item: &mut HttpRequest| { + item.headers = headers; + }); + + let result = authorizer.authorize(request); + assert!(result); + } + + #[test] + fn test_cedar_authorizer_denies_invalid_token() { + let authorizer = CedarAuthorizer::new(); + let mut headers = HashMap::new(); + headers.insert( + "authorization".to_string(), + "Bearer invalid-token".to_string(), + ); + let request = create_request(|item: &mut HttpRequest| { + item.headers = headers; + }); + + let result = authorizer.authorize(request); + assert!(!result); + } + + #[test] + fn test_cedar_authorizer_denies_missing_header() { + let authorizer = CedarAuthorizer::new(); + let headers = HashMap::new(); + let request = create_request(|item: &mut HttpRequest| { + item.headers = headers; + }); + + let result = authorizer.authorize(request); + assert!(!result); + } + + #[test] + fn test_cedar_authorizer_allows_static_assets() { + let authorizer = CedarAuthorizer::new(); + let mut headers = HashMap::new(); + headers.insert(":path".to_string(), "/public/style.css".to_string()); + let request = create_request(|item: &mut HttpRequest| { + item.headers = headers; + }); + + let result = authorizer.authorize(request); + assert!(result); + } + + #[test] + fn test_cedar_authorizer_allows_js_assets() { + let authorizer = CedarAuthorizer::new(); + let mut headers = HashMap::new(); + headers.insert(":path".to_string(), "/app.js".to_string()); + let request = create_request(|item: &mut HttpRequest| { + item.headers = headers; + }); + + let result = authorizer.authorize(request); + assert!(result); + } +} diff --git a/tests/authorization/mod.rs b/tests/authorization/mod.rs new file mode 100644 index 00000000..a8aab73a --- /dev/null +++ b/tests/authorization/mod.rs @@ -0,0 +1 @@ +mod cedar_authorizer_test; -- cgit v1.2.3 From 86c9564a82f56b7c5ee60f4bff9fb07ca3e4a6eb Mon Sep 17 00:00:00 2001 From: mo khan Date: Wed, 25 Jun 2025 14:24:19 -0600 Subject: test: move unit tests to integration test suite to share code --- src/authorization/check_service.rs | 62 ------------------------------- tests/authorization/check_service_test.rs | 48 ++++++++++++++++++++++++ tests/authorization/mod.rs | 1 + tests/common/mod.rs | 4 ++ 4 files changed, 53 insertions(+), 62 deletions(-) create mode 100644 tests/authorization/check_service_test.rs (limited to 'tests/authorization') diff --git a/src/authorization/check_service.rs b/src/authorization/check_service.rs index c0a05e21..6c6bd9c6 100644 --- a/src/authorization/check_service.rs +++ b/src/authorization/check_service.rs @@ -33,65 +33,3 @@ impl envoy_types::ext_authz::v3::pb::Authorization for CheckService { } } } - -#[cfg(test)] -mod tests { - use super::super::cedar_authorizer::CedarAuthorizer; - use super::*; - use envoy_types::ext_authz::v3::pb::{Authorization, CheckRequest}; - use envoy_types::pb::envoy::service::auth::v3::AttributeContext; - use envoy_types::pb::envoy::service::auth::v3::attribute_context::{HttpRequest, Request}; - use std::collections::HashMap; - use std::sync::Arc; - - pub fn create_request(f: impl std::ops::FnOnce(&mut HttpRequest)) -> CheckRequest { - please::build_with(|item: &mut CheckRequest| { - item.attributes = Some(please::build_with(|item: &mut AttributeContext| { - item.request = Some(please::build_with(|item: &mut Request| { - item.http = Some(please::build_with(|item: &mut HttpRequest| f(item))); - })); - })); - }) - } - - pub fn create_token() -> String { - return String::from("valid-token"); - } - - #[tokio::test] - async fn test_check_allows_valid_bearer_token() { - let token = create_token(); - let server = CheckService::new(Arc::new(CedarAuthorizer::new())); - - let mut headers = HashMap::new(); - headers.insert("authorization".to_string(), format!("Bearer {}", token)); - let request = tonic::Request::new(create_request(|item: &mut HttpRequest| { - item.headers = headers; - })); - - let response = server.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 authorizer = Arc::new(CedarAuthorizer::new()); - let server = CheckService::new(authorizer); - let request = tonic::Request::new(create_request(|item: &mut HttpRequest| { - item.headers = HashMap::new(); - })); - - let response = server.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); - } -} diff --git a/tests/authorization/check_service_test.rs b/tests/authorization/check_service_test.rs new file mode 100644 index 00000000..23655ffb --- /dev/null +++ b/tests/authorization/check_service_test.rs @@ -0,0 +1,48 @@ +#[cfg(test)] +mod tests { + use crate::common::create_request; + use crate::common::create_token; + use authzd::CedarAuthorizer; + 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; + + #[tokio::test] + async fn test_check_allows_valid_bearer_token() { + let token = create_token(); + let server = CheckService::new(Arc::new(CedarAuthorizer::new())); + + let mut headers = HashMap::new(); + headers.insert("authorization".to_string(), format!("Bearer {}", token)); + let request = tonic::Request::new(create_request(|item: &mut HttpRequest| { + item.headers = headers; + })); + + let response = server.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 authorizer = Arc::new(CedarAuthorizer::new()); + let server = CheckService::new(authorizer); + let request = tonic::Request::new(create_request(|item: &mut HttpRequest| { + item.headers = HashMap::new(); + })); + + let response = server.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); + } +} diff --git a/tests/authorization/mod.rs b/tests/authorization/mod.rs index a8aab73a..a4ece924 100644 --- a/tests/authorization/mod.rs +++ b/tests/authorization/mod.rs @@ -1 +1,2 @@ mod cedar_authorizer_test; +mod check_service_test; diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 9b2370cb..4e879b6f 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -26,3 +26,7 @@ pub fn create_headers_with_auth(auth_value: &str) -> HashMap { headers.insert("authorization".to_string(), auth_value.to_string()); headers } + +pub fn create_token() -> String { + return String::from("valid-token"); +} -- cgit v1.2.3 From ab2a06d2a1e63cdedfd06717114f128e1e9dc1a8 Mon Sep 17 00:00:00 2001 From: mo khan Date: Wed, 25 Jun 2025 14:39:13 -0600 Subject: test: start to extract builders --- tests/authorization/cedar_authorizer_test.rs | 10 +++++----- tests/common/factories.rs | 0 tests/common/mod.rs | 20 +++++++++++++++++--- 3 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 tests/common/factories.rs (limited to 'tests/authorization') diff --git a/tests/authorization/cedar_authorizer_test.rs b/tests/authorization/cedar_authorizer_test.rs index 2ed3dd68..4531da67 100644 --- a/tests/authorization/cedar_authorizer_test.rs +++ b/tests/authorization/cedar_authorizer_test.rs @@ -9,12 +9,12 @@ mod tests { #[test] fn test_cedar_authorizer_allows_valid_token() { let authorizer = CedarAuthorizer::new(); - let mut headers = HashMap::new(); - headers.insert( - "authorization".to_string(), - "Bearer valid-token".to_string(), - ); let request = create_request(|item: &mut HttpRequest| { + let mut headers = HashMap::new(); + headers.insert( + "authorization".to_string(), + "Bearer valid-token".to_string(), + ); item.headers = headers; }); diff --git a/tests/common/factories.rs b/tests/common/factories.rs new file mode 100644 index 00000000..e69de29b diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 4e879b6f..aab3a412 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,10 +1,24 @@ +mod factories; + use envoy_types::ext_authz::v3::pb::CheckRequest; use envoy_types::pb::envoy::service::auth::v3::AttributeContext; use envoy_types::pb::envoy::service::auth::v3::attribute_context::{HttpRequest, Request}; use std::collections::HashMap; +pub fn build() -> T { + return please::build(); +} + +pub fn build_with(initializer: F) -> T +where + T: Default, + F: std::ops::FnOnce(&mut T), +{ + return please::build_with(initializer); +} + pub fn create_request(f: impl std::ops::FnOnce(&mut HttpRequest)) -> CheckRequest { - please::build_with(|item: &mut CheckRequest| { + build_with(|item: &mut CheckRequest| { item.attributes = Some(please::build_with(|item: &mut AttributeContext| { item.request = Some(please::build_with(|item: &mut Request| { item.http = Some(please::build_with(|item: &mut HttpRequest| f(item))); @@ -22,8 +36,8 @@ pub fn create_test_request_with_headers( } pub fn create_headers_with_auth(auth_value: &str) -> HashMap { - let mut headers = HashMap::new(); - headers.insert("authorization".to_string(), auth_value.to_string()); + let mut headers = build::>(); + headers.insert(String::from("authorization"), auth_value.to_string()); headers } -- cgit v1.2.3 From 25412b5ad670d5b8809d399aae4ab63bd5e1de40 Mon Sep 17 00:00:00 2001 From: mo khan Date: Wed, 25 Jun 2025 14:58:12 -0600 Subject: test: improve readability of some of the test code --- tests/authorization/cedar_authorizer_test.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'tests/authorization') diff --git a/tests/authorization/cedar_authorizer_test.rs b/tests/authorization/cedar_authorizer_test.rs index 4531da67..1012d917 100644 --- a/tests/authorization/cedar_authorizer_test.rs +++ b/tests/authorization/cedar_authorizer_test.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod tests { - use crate::common::create_request; + use crate::common::*; use authzd::Authorizer; use authzd::CedarAuthorizer; use envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest; @@ -10,16 +10,15 @@ mod tests { fn test_cedar_authorizer_allows_valid_token() { let authorizer = CedarAuthorizer::new(); let request = create_request(|item: &mut HttpRequest| { - let mut headers = HashMap::new(); - headers.insert( - "authorization".to_string(), - "Bearer valid-token".to_string(), - ); - item.headers = headers; + item.headers = build_with(|item: &mut HashMap| { + item.insert( + String::from("authorization"), + String::from("Bearer valid-token"), + ); + }); }); - let result = authorizer.authorize(request); - assert!(result); + assert!(authorizer.authorize(request)); } #[test] -- cgit v1.2.3 From ff81c53e472857e08eb1333f66f3d96487813732 Mon Sep 17 00:00:00 2001 From: mo khan Date: Wed, 25 Jun 2025 15:08:55 -0600 Subject: test: extract factory_bot module --- tests/authorization/cedar_authorizer_test.rs | 1 + tests/authorization/check_service_test.rs | 2 +- tests/common/factories.rs | 0 tests/common/factory_bot.rs | 13 +++++++++++++ tests/common/mod.rs | 16 +++------------- 5 files changed, 18 insertions(+), 14 deletions(-) delete mode 100644 tests/common/factories.rs create mode 100644 tests/common/factory_bot.rs (limited to 'tests/authorization') diff --git a/tests/authorization/cedar_authorizer_test.rs b/tests/authorization/cedar_authorizer_test.rs index 1012d917..c74a2042 100644 --- a/tests/authorization/cedar_authorizer_test.rs +++ b/tests/authorization/cedar_authorizer_test.rs @@ -1,5 +1,6 @@ #[cfg(test)] mod tests { + use crate::common::factory_bot::create_request; use crate::common::*; use authzd::Authorizer; use authzd::CedarAuthorizer; diff --git a/tests/authorization/check_service_test.rs b/tests/authorization/check_service_test.rs index 23655ffb..dadb6d1a 100644 --- a/tests/authorization/check_service_test.rs +++ b/tests/authorization/check_service_test.rs @@ -1,7 +1,7 @@ #[cfg(test)] mod tests { - use crate::common::create_request; use crate::common::create_token; + use crate::common::factory_bot::create_request; use authzd::CedarAuthorizer; use authzd::CheckService; use envoy_types::ext_authz::v3::pb::Authorization; diff --git a/tests/common/factories.rs b/tests/common/factories.rs deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/common/factory_bot.rs b/tests/common/factory_bot.rs new file mode 100644 index 00000000..17c4c3d5 --- /dev/null +++ b/tests/common/factory_bot.rs @@ -0,0 +1,13 @@ +use envoy_types::ext_authz::v3::pb::CheckRequest; +use envoy_types::pb::envoy::service::auth::v3::AttributeContext; +use envoy_types::pb::envoy::service::auth::v3::attribute_context::{HttpRequest, Request}; + +pub fn create_request(f: impl std::ops::FnOnce(&mut HttpRequest)) -> CheckRequest { + crate::common::build_with(|item: &mut CheckRequest| { + item.attributes = Some(please::build_with(|item: &mut AttributeContext| { + item.request = Some(please::build_with(|item: &mut Request| { + item.http = Some(please::build_with(|item: &mut HttpRequest| f(item))); + })); + })); + }) +} diff --git a/tests/common/mod.rs b/tests/common/mod.rs index aab3a412..9b089f16 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,8 +1,8 @@ -mod factories; +pub mod factory_bot; use envoy_types::ext_authz::v3::pb::CheckRequest; -use envoy_types::pb::envoy::service::auth::v3::AttributeContext; -use envoy_types::pb::envoy::service::auth::v3::attribute_context::{HttpRequest, Request}; +use envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest; +use factory_bot::*; use std::collections::HashMap; pub fn build() -> T { @@ -17,16 +17,6 @@ where return please::build_with(initializer); } -pub fn create_request(f: impl std::ops::FnOnce(&mut HttpRequest)) -> CheckRequest { - build_with(|item: &mut CheckRequest| { - item.attributes = Some(please::build_with(|item: &mut AttributeContext| { - item.request = Some(please::build_with(|item: &mut Request| { - item.http = Some(please::build_with(|item: &mut HttpRequest| f(item))); - })); - })); - }) -} - pub fn create_test_request_with_headers( headers: HashMap, ) -> tonic::Request { -- cgit v1.2.3 From 0482895d6b34a3a3622979389ae62a40f3f64cf6 Mon Sep 17 00:00:00 2001 From: mo khan Date: Wed, 25 Jun 2025 15:13:03 -0600 Subject: test: move builder functions to factory_bot module --- tests/authorization/cedar_authorizer_test.rs | 3 +-- tests/authorization/check_service_test.rs | 3 +-- tests/common/factory_bot.rs | 31 ++++++++++++++++++++++++++ tests/common/mod.rs | 33 ---------------------------- tests/integration_tests.rs | 8 +++---- 5 files changed, 37 insertions(+), 41 deletions(-) (limited to 'tests/authorization') diff --git a/tests/authorization/cedar_authorizer_test.rs b/tests/authorization/cedar_authorizer_test.rs index c74a2042..b13f48ad 100644 --- a/tests/authorization/cedar_authorizer_test.rs +++ b/tests/authorization/cedar_authorizer_test.rs @@ -1,7 +1,6 @@ #[cfg(test)] mod tests { - use crate::common::factory_bot::create_request; - use crate::common::*; + use crate::common::factory_bot::*; use authzd::Authorizer; use authzd::CedarAuthorizer; use envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest; diff --git a/tests/authorization/check_service_test.rs b/tests/authorization/check_service_test.rs index dadb6d1a..0582417e 100644 --- a/tests/authorization/check_service_test.rs +++ b/tests/authorization/check_service_test.rs @@ -1,7 +1,6 @@ #[cfg(test)] mod tests { - use crate::common::create_token; - use crate::common::factory_bot::create_request; + use crate::common::factory_bot::*; use authzd::CedarAuthorizer; use authzd::CheckService; use envoy_types::ext_authz::v3::pb::Authorization; diff --git a/tests/common/factory_bot.rs b/tests/common/factory_bot.rs index 17c4c3d5..bd2cb163 100644 --- a/tests/common/factory_bot.rs +++ b/tests/common/factory_bot.rs @@ -1,6 +1,19 @@ use envoy_types::ext_authz::v3::pb::CheckRequest; use envoy_types::pb::envoy::service::auth::v3::AttributeContext; use envoy_types::pb::envoy::service::auth::v3::attribute_context::{HttpRequest, Request}; +use std::collections::HashMap; + +pub fn build() -> T { + return please::build(); +} + +pub fn build_with(initializer: F) -> T +where + T: Default, + F: std::ops::FnOnce(&mut T), +{ + return please::build_with(initializer); +} pub fn create_request(f: impl std::ops::FnOnce(&mut HttpRequest)) -> CheckRequest { crate::common::build_with(|item: &mut CheckRequest| { @@ -11,3 +24,21 @@ pub fn create_request(f: impl std::ops::FnOnce(&mut HttpRequest)) -> CheckReques })); }) } + +pub fn create_test_request_with_headers( + headers: HashMap, +) -> tonic::Request { + tonic::Request::new(create_request(|item: &mut HttpRequest| { + item.headers = headers; + })) +} + +pub fn create_headers_with_auth(auth_value: &str) -> HashMap { + let mut headers = build::>(); + headers.insert(String::from("authorization"), auth_value.to_string()); + headers +} + +pub fn create_token() -> String { + return String::from("valid-token"); +} diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 9b089f16..4db87a2c 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,36 +1,3 @@ pub mod factory_bot; -use envoy_types::ext_authz::v3::pb::CheckRequest; -use envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest; use factory_bot::*; -use std::collections::HashMap; - -pub fn build() -> T { - return please::build(); -} - -pub fn build_with(initializer: F) -> T -where - T: Default, - F: std::ops::FnOnce(&mut T), -{ - return please::build_with(initializer); -} - -pub fn create_test_request_with_headers( - headers: HashMap, -) -> tonic::Request { - tonic::Request::new(create_request(|item: &mut HttpRequest| { - item.headers = headers; - })) -} - -pub fn create_headers_with_auth(auth_value: &str) -> HashMap { - let mut headers = build::>(); - headers.insert(String::from("authorization"), auth_value.to_string()); - headers -} - -pub fn create_token() -> String { - return String::from("valid-token"); -} diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 2269c7f7..fc31a037 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -10,8 +10,8 @@ async fn test_success_response() { let authorizer = Arc::new(CedarAuthorizer::new()); let server = CheckService::new(authorizer); - let headers = common::create_headers_with_auth("Bearer valid-token"); - let request = common::create_test_request_with_headers(headers); + let headers = common::factory_bot::create_headers_with_auth("Bearer valid-token"); + let request = common::factory_bot::create_test_request_with_headers(headers); let response = server.check(request).await; assert!(response.is_ok()); @@ -36,8 +36,8 @@ async fn test_multiple() { ]; for (auth_value, should_succeed) in test_cases { - let headers = common::create_headers_with_auth(auth_value); - let request = common::create_test_request_with_headers(headers); + let headers = common::factory_bot::create_headers_with_auth(auth_value); + let request = common::factory_bot::create_test_request_with_headers(headers); let response = server.check(request).await; assert!(response.is_ok()); -- cgit v1.2.3 From 187c02e9bf32f152cbca9fd5790f4a6070dbb37d Mon Sep 17 00:00:00 2001 From: mo khan Date: Thu, 26 Jun 2025 15:30:41 -0600 Subject: refactor: try to move policy files to /etc/authzd/ --- Dockerfile | 2 +- etc/authzd/policy0.cedar | 19 +++++++++++++++++++ policies/auth_policy.cedar | 23 ----------------------- src/authorization/cedar_authorizer.rs | 11 +++-------- src/main.rs | 2 +- tests/authorization/cedar_authorizer_test.rs | 10 +++++----- tests/authorization/check_service_test.rs | 4 ++-- tests/integration_tests.rs | 4 ++-- 8 files changed, 33 insertions(+), 42 deletions(-) create mode 100644 etc/authzd/policy0.cedar delete mode 100644 policies/auth_policy.cedar (limited to 'tests/authorization') diff --git a/Dockerfile b/Dockerfile index 0faffb8e..744b4f3d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,5 +10,5 @@ FROM gcr.io/distroless/static-debian12:nonroot EXPOSE 50051 WORKDIR /var/www COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/authzd /bin/authzd -COPY --from=builder /app/policies /etc/authzd/policies +COPY --from=builder /app/etc/authzd /etc/authzd ENTRYPOINT ["/bin/authzd"] diff --git a/etc/authzd/policy0.cedar b/etc/authzd/policy0.cedar new file mode 100644 index 00000000..e01182c5 --- /dev/null +++ b/etc/authzd/policy0.cedar @@ -0,0 +1,19 @@ +permit(principal, action == Action::"check", resource) +when { + context has bearer_token && + context.bearer_token == "valid-token" +}; + +permit(principal, action == Action::"check", resource) +when { + context has path && + (context.path like "*.css" || + context.path like "*.js" || + context.path like "*.ico" || + context.path like "*.png" || + context.path like "*.jpg" || + context.path like "*.jpeg" || + context.path like "*.gif" || + context.path like "*.bmp" || + context.path like "*.html") +}; diff --git a/policies/auth_policy.cedar b/policies/auth_policy.cedar deleted file mode 100644 index c7eb6ce5..00000000 --- a/policies/auth_policy.cedar +++ /dev/null @@ -1,23 +0,0 @@ -// Authorization policies for the authzd service - -// Allow requests with valid Bearer tokens -permit(principal, action == Action::"check", resource) -when { - context has bearer_token && - context.bearer_token == "valid-token" -}; - -// Allow static assets to pass through without authentication -permit(principal, action == Action::"check", resource) -when { - context has path && - (context.path like "*.css" || - context.path like "*.js" || - context.path like "*.ico" || - context.path like "*.png" || - context.path like "*.jpg" || - context.path like "*.jpeg" || - context.path like "*.gif" || - context.path like "*.bmp" || - context.path like "*.html") -}; diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index fb85012e..568bafbc 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -14,21 +14,16 @@ pub struct CedarAuthorizer { } impl CedarAuthorizer { - pub fn new() -> CedarAuthorizer { - let policy_src = include_str!("../../policies/auth_policy.cedar"); - let policies = policy_src.parse().expect("Failed to parse Cedar policies"); - let authorizer = CedarAuth::new(); - + pub fn new(policies: cedar_policy::PolicySet) -> CedarAuthorizer { CedarAuthorizer { policies, - authorizer, + authorizer: CedarAuth::new(), } } } - impl Default for CedarAuthorizer { fn default() -> Self { - Self::new() + Self::new(PolicySet::default()) } } diff --git a/src/main.rs b/src/main.rs index d847a2ee..1a3ff00c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,7 @@ async fn main() -> Result<(), Box> { let (_health_reporter, health_service) = tonic_health::server::health_reporter(); - let authorizer = Arc::new(authorization::CedarAuthorizer::new()); + let authorizer = Arc::new(authorization::CedarAuthorizer::default()); let check_service = authorization::CheckService::new(authorizer); let server = Server::builder() diff --git a/tests/authorization/cedar_authorizer_test.rs b/tests/authorization/cedar_authorizer_test.rs index b13f48ad..6e1591eb 100644 --- a/tests/authorization/cedar_authorizer_test.rs +++ b/tests/authorization/cedar_authorizer_test.rs @@ -8,7 +8,7 @@ mod tests { #[test] fn test_cedar_authorizer_allows_valid_token() { - let authorizer = CedarAuthorizer::new(); + let authorizer = CedarAuthorizer::default(); let request = create_request(|item: &mut HttpRequest| { item.headers = build_with(|item: &mut HashMap| { item.insert( @@ -23,7 +23,7 @@ mod tests { #[test] fn test_cedar_authorizer_denies_invalid_token() { - let authorizer = CedarAuthorizer::new(); + let authorizer = CedarAuthorizer::default(); let mut headers = HashMap::new(); headers.insert( "authorization".to_string(), @@ -39,7 +39,7 @@ mod tests { #[test] fn test_cedar_authorizer_denies_missing_header() { - let authorizer = CedarAuthorizer::new(); + let authorizer = CedarAuthorizer::default(); let headers = HashMap::new(); let request = create_request(|item: &mut HttpRequest| { item.headers = headers; @@ -51,7 +51,7 @@ mod tests { #[test] fn test_cedar_authorizer_allows_static_assets() { - let authorizer = CedarAuthorizer::new(); + let authorizer = CedarAuthorizer::default(); let mut headers = HashMap::new(); headers.insert(":path".to_string(), "/public/style.css".to_string()); let request = create_request(|item: &mut HttpRequest| { @@ -64,7 +64,7 @@ mod tests { #[test] fn test_cedar_authorizer_allows_js_assets() { - let authorizer = CedarAuthorizer::new(); + let authorizer = CedarAuthorizer::default(); let mut headers = HashMap::new(); headers.insert(":path".to_string(), "/app.js".to_string()); let request = create_request(|item: &mut HttpRequest| { diff --git a/tests/authorization/check_service_test.rs b/tests/authorization/check_service_test.rs index 0582417e..a739b16a 100644 --- a/tests/authorization/check_service_test.rs +++ b/tests/authorization/check_service_test.rs @@ -11,7 +11,7 @@ mod tests { #[tokio::test] async fn test_check_allows_valid_bearer_token() { let token = create_token(); - let server = CheckService::new(Arc::new(CedarAuthorizer::new())); + let server = CheckService::new(Arc::new(CedarAuthorizer::default())); let mut headers = HashMap::new(); headers.insert("authorization".to_string(), format!("Bearer {}", token)); @@ -30,7 +30,7 @@ mod tests { #[tokio::test] async fn test_check_denies_invalid_bearer_token() { - let authorizer = Arc::new(CedarAuthorizer::new()); + let authorizer = Arc::new(CedarAuthorizer::default()); let server = CheckService::new(authorizer); let request = tonic::Request::new(create_request(|item: &mut HttpRequest| { item.headers = HashMap::new(); diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 56321acb..a265c2be 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -9,7 +9,7 @@ mod common; #[tokio::test] async fn test_success_response() { - let authorizer = Arc::new(CedarAuthorizer::new()); + let authorizer = Arc::new(CedarAuthorizer::default()); let server = CheckService::new(authorizer); let request = tonic::Request::new(factory_bot::create_request(|item: &mut HttpRequest| { item.headers = factory_bot::build_headers(vec![( @@ -30,7 +30,7 @@ async fn test_success_response() { #[tokio::test] async fn test_multiple() { - let authorizer = Arc::new(CedarAuthorizer::new()); + let authorizer = Arc::new(CedarAuthorizer::default()); let server = CheckService::new(authorizer); let test_cases = vec![ -- cgit v1.2.3 From 9f4bf84825c5a725b0ea36d4474d4fa2cec916fd Mon Sep 17 00:00:00 2001 From: mo khan Date: Thu, 26 Jun 2025 15:46:00 -0600 Subject: test: tidy up the tests --- src/authorization/check_service.rs | 2 +- tests/authorization/cedar_authorizer_test.rs | 33 ++++++++++++---------------- 2 files changed, 15 insertions(+), 20 deletions(-) (limited to 'tests/authorization') diff --git a/src/authorization/check_service.rs b/src/authorization/check_service.rs index d2dd1e17..b6809339 100644 --- a/src/authorization/check_service.rs +++ b/src/authorization/check_service.rs @@ -24,7 +24,7 @@ impl envoy_types::ext_authz::v3::pb::Authorization for CheckService { ) -> Result, Status> { let request = request.into_inner(); - if dbg!(self.authorizer.authorize(dbg!(request))) { + if self.authorizer.authorize(request) { log::info!("OK"); Ok(Response::new(CheckResponse::with_status(Status::ok("OK")))) } else { diff --git a/tests/authorization/cedar_authorizer_test.rs b/tests/authorization/cedar_authorizer_test.rs index 6e1591eb..d6742995 100644 --- a/tests/authorization/cedar_authorizer_test.rs +++ b/tests/authorization/cedar_authorizer_test.rs @@ -24,42 +24,38 @@ mod tests { #[test] fn test_cedar_authorizer_denies_invalid_token() { let authorizer = CedarAuthorizer::default(); - let mut headers = HashMap::new(); - headers.insert( - "authorization".to_string(), - "Bearer invalid-token".to_string(), - ); let request = create_request(|item: &mut HttpRequest| { - item.headers = headers; + item.headers = build_with(|item: &mut HashMap| { + item.insert( + String::from("authorization"), + String::from("Bearer invalid-token"), + ); + }); }); - let result = authorizer.authorize(request); - assert!(!result); + assert!(!authorizer.authorize(request)); } #[test] fn test_cedar_authorizer_denies_missing_header() { let authorizer = CedarAuthorizer::default(); - let headers = HashMap::new(); let request = create_request(|item: &mut HttpRequest| { - item.headers = headers; + item.headers = HashMap::new(); }); - let result = authorizer.authorize(request); - assert!(!result); + assert!(!authorizer.authorize(request)); } #[test] fn test_cedar_authorizer_allows_static_assets() { let authorizer = CedarAuthorizer::default(); - let mut headers = HashMap::new(); - headers.insert(":path".to_string(), "/public/style.css".to_string()); let request = create_request(|item: &mut HttpRequest| { - item.headers = headers; + item.headers = build_with(|item: &mut HashMap| { + item.insert(String::from(":path"), String::from("/public/style.css")); + }); }); - let result = authorizer.authorize(request); - assert!(result); + assert!(authorizer.authorize(request)); } #[test] @@ -71,7 +67,6 @@ mod tests { item.headers = headers; }); - let result = authorizer.authorize(request); - assert!(result); + assert!(authorizer.authorize(request)); } } -- cgit v1.2.3 From afd9729146a7e90bd97bf36f9d2081e29de9da35 Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 10:40:44 -0600 Subject: feat: scan directory for all policy files --- src/authorization/cedar_authorizer.rs | 34 +++++++++++++++++++++++++++- tests/authorization/cedar_authorizer_test.rs | 21 +++++++++-------- tests/authorization/check_service_test.rs | 11 ++++++--- tests/integration_tests.rs | 12 ++++++---- 4 files changed, 60 insertions(+), 18 deletions(-) (limited to 'tests/authorization') diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index 568bafbc..4ec3b34d 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -5,6 +5,8 @@ use cedar_policy::{ }; use envoy_types::ext_authz::v3::pb::CheckRequest; use std::collections::HashMap; +use std::fs; +use std::path::Path; use std::str::FromStr; #[derive(Debug)] @@ -20,10 +22,40 @@ impl CedarAuthorizer { authorizer: CedarAuth::new(), } } + + pub fn new_from(dir_path: &str) -> CedarAuthorizer { + Self::new(Self::load_from(dir_path).unwrap_or_else(|_| PolicySet::default())) + } + + fn load_from(dir_path: &str) -> Result> { + let path = Path::new(dir_path); + if !path.exists() || !path.is_dir() { + return Ok(PolicySet::default()); + } + + let mut policies = PolicySet::new(); + + for entry in fs::read_dir(path)? { + let file_path = entry?.path(); + + if let Some(extension) = file_path.extension() { + if extension == "cedar" { + let content = fs::read_to_string(&file_path)?; + let file_policies = PolicySet::from_str(&content)?; + + for policy in file_policies.policies() { + policies.add(policy.clone())?; + } + } + } + } + + Ok(policies) + } } impl Default for CedarAuthorizer { fn default() -> Self { - Self::new(PolicySet::default()) + Self::new_from("/etc/authzd") } } diff --git a/tests/authorization/cedar_authorizer_test.rs b/tests/authorization/cedar_authorizer_test.rs index d6742995..3073417d 100644 --- a/tests/authorization/cedar_authorizer_test.rs +++ b/tests/authorization/cedar_authorizer_test.rs @@ -6,9 +6,14 @@ mod tests { use envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest; use std::collections::HashMap; + fn authorizer() -> CedarAuthorizer { + CedarAuthorizer::new_from( + "/home/mokhax/src/gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd/etc/authzd", + ) + } + #[test] fn test_cedar_authorizer_allows_valid_token() { - let authorizer = CedarAuthorizer::default(); let request = create_request(|item: &mut HttpRequest| { item.headers = build_with(|item: &mut HashMap| { item.insert( @@ -18,12 +23,11 @@ mod tests { }); }); - assert!(authorizer.authorize(request)); + assert!(authorizer().authorize(request)); } #[test] fn test_cedar_authorizer_denies_invalid_token() { - let authorizer = CedarAuthorizer::default(); let request = create_request(|item: &mut HttpRequest| { item.headers = build_with(|item: &mut HashMap| { item.insert( @@ -33,40 +37,37 @@ mod tests { }); }); - assert!(!authorizer.authorize(request)); + assert!(!authorizer().authorize(request)); } #[test] fn test_cedar_authorizer_denies_missing_header() { - let authorizer = CedarAuthorizer::default(); let request = create_request(|item: &mut HttpRequest| { item.headers = HashMap::new(); }); - assert!(!authorizer.authorize(request)); + assert!(!authorizer().authorize(request)); } #[test] fn test_cedar_authorizer_allows_static_assets() { - let authorizer = CedarAuthorizer::default(); let request = create_request(|item: &mut HttpRequest| { item.headers = build_with(|item: &mut HashMap| { item.insert(String::from(":path"), String::from("/public/style.css")); }); }); - assert!(authorizer.authorize(request)); + assert!(authorizer().authorize(request)); } #[test] fn test_cedar_authorizer_allows_js_assets() { - let authorizer = CedarAuthorizer::default(); let mut headers = HashMap::new(); headers.insert(":path".to_string(), "/app.js".to_string()); let request = create_request(|item: &mut HttpRequest| { item.headers = headers; }); - assert!(authorizer.authorize(request)); + assert!(authorizer().authorize(request)); } } diff --git a/tests/authorization/check_service_test.rs b/tests/authorization/check_service_test.rs index a739b16a..c101850c 100644 --- a/tests/authorization/check_service_test.rs +++ b/tests/authorization/check_service_test.rs @@ -8,10 +8,16 @@ mod tests { use std::collections::HashMap; use std::sync::Arc; + fn authorizer() -> Arc { + Arc::new(CedarAuthorizer::new_from( + "/home/mokhax/src/gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd/etc/authzd", + )) + } + #[tokio::test] async fn test_check_allows_valid_bearer_token() { let token = create_token(); - let server = CheckService::new(Arc::new(CedarAuthorizer::default())); + let server = CheckService::new(authorizer()); let mut headers = HashMap::new(); headers.insert("authorization".to_string(), format!("Bearer {}", token)); @@ -30,8 +36,7 @@ mod tests { #[tokio::test] async fn test_check_denies_invalid_bearer_token() { - let authorizer = Arc::new(CedarAuthorizer::default()); - let server = CheckService::new(authorizer); + let server = CheckService::new(authorizer()); let request = tonic::Request::new(create_request(|item: &mut HttpRequest| { item.headers = HashMap::new(); })); diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index a265c2be..8bf433d1 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -7,10 +7,15 @@ use std::sync::Arc; mod authorization; mod common; +fn authorizer() -> Arc { + Arc::new(CedarAuthorizer::new_from( + "/home/mokhax/src/gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd/etc/authzd", + )) +} + #[tokio::test] async fn test_success_response() { - let authorizer = Arc::new(CedarAuthorizer::default()); - let server = CheckService::new(authorizer); + let server = CheckService::new(authorizer()); let request = tonic::Request::new(factory_bot::create_request(|item: &mut HttpRequest| { item.headers = factory_bot::build_headers(vec![( "authorization".to_string(), @@ -30,8 +35,7 @@ async fn test_success_response() { #[tokio::test] async fn test_multiple() { - let authorizer = Arc::new(CedarAuthorizer::default()); - let server = CheckService::new(authorizer); + let server = CheckService::new(authorizer()); let test_cases = vec![ ("Bearer valid-token", true), -- cgit v1.2.3 From f59c24589af439e0e22f43a2e42595cf88973ccf Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 12:45:13 -0600 Subject: test: extract factory_bot factory for cedar authorizer --- tests/authorization/cedar_authorizer_test.rs | 17 +++++------------ tests/authorization/check_service_test.rs | 5 +---- tests/common/factory_bot.rs | 6 ++++++ tests/integration_tests.rs | 4 +--- 4 files changed, 13 insertions(+), 19 deletions(-) (limited to 'tests/authorization') diff --git a/tests/authorization/cedar_authorizer_test.rs b/tests/authorization/cedar_authorizer_test.rs index 3073417d..656e0060 100644 --- a/tests/authorization/cedar_authorizer_test.rs +++ b/tests/authorization/cedar_authorizer_test.rs @@ -2,16 +2,9 @@ mod tests { use crate::common::factory_bot::*; use authzd::Authorizer; - use authzd::CedarAuthorizer; use envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest; use std::collections::HashMap; - fn authorizer() -> CedarAuthorizer { - CedarAuthorizer::new_from( - "/home/mokhax/src/gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd/etc/authzd", - ) - } - #[test] fn test_cedar_authorizer_allows_valid_token() { let request = create_request(|item: &mut HttpRequest| { @@ -23,7 +16,7 @@ mod tests { }); }); - assert!(authorizer().authorize(request)); + assert!(build_cedar_authorizer().authorize(request)); } #[test] @@ -37,7 +30,7 @@ mod tests { }); }); - assert!(!authorizer().authorize(request)); + assert!(!build_cedar_authorizer().authorize(request)); } #[test] @@ -46,7 +39,7 @@ mod tests { item.headers = HashMap::new(); }); - assert!(!authorizer().authorize(request)); + assert!(!build_cedar_authorizer().authorize(request)); } #[test] @@ -57,7 +50,7 @@ mod tests { }); }); - assert!(authorizer().authorize(request)); + assert!(build_cedar_authorizer().authorize(request)); } #[test] @@ -68,6 +61,6 @@ mod tests { item.headers = headers; }); - assert!(authorizer().authorize(request)); + assert!(build_cedar_authorizer().authorize(request)); } } diff --git a/tests/authorization/check_service_test.rs b/tests/authorization/check_service_test.rs index c101850c..cddbb6b0 100644 --- a/tests/authorization/check_service_test.rs +++ b/tests/authorization/check_service_test.rs @@ -1,7 +1,6 @@ #[cfg(test)] mod tests { use crate::common::factory_bot::*; - use authzd::CedarAuthorizer; use authzd::CheckService; use envoy_types::ext_authz::v3::pb::Authorization; use envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest; @@ -9,9 +8,7 @@ mod tests { use std::sync::Arc; fn authorizer() -> Arc { - Arc::new(CedarAuthorizer::new_from( - "/home/mokhax/src/gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd/etc/authzd", - )) + Arc::new(build_cedar_authorizer()) } #[tokio::test] diff --git a/tests/common/factory_bot.rs b/tests/common/factory_bot.rs index 2389c858..3c3810a7 100644 --- a/tests/common/factory_bot.rs +++ b/tests/common/factory_bot.rs @@ -37,3 +37,9 @@ pub fn build_headers(headers: Vec<(String, String)>) -> HashMap pub fn create_token() -> String { return String::from("valid-token"); } + +pub fn build_cedar_authorizer() -> authzd::CedarAuthorizer { + authzd::CedarAuthorizer::new_from( + "/home/mokhax/src/gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd/etc/authzd", + ) +} diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 8bf433d1..63aaaadc 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -8,9 +8,7 @@ mod authorization; mod common; fn authorizer() -> Arc { - Arc::new(CedarAuthorizer::new_from( - "/home/mokhax/src/gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd/etc/authzd", - )) + Arc::new(factory_bot::build_cedar_authorizer()) } #[tokio::test] -- cgit v1.2.3 From 4230cb44a1212e62c54b3d4f1f7304e5fd02ef81 Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 13:08:45 -0600 Subject: test: rename create_request -> build_request --- tests/authorization/cedar_authorizer_test.rs | 10 +++++----- tests/authorization/check_service_test.rs | 6 +++--- tests/common/factory_bot.rs | 6 +----- tests/integration_tests.rs | 4 ++-- 4 files changed, 11 insertions(+), 15 deletions(-) (limited to 'tests/authorization') diff --git a/tests/authorization/cedar_authorizer_test.rs b/tests/authorization/cedar_authorizer_test.rs index 656e0060..e7e6eb2c 100644 --- a/tests/authorization/cedar_authorizer_test.rs +++ b/tests/authorization/cedar_authorizer_test.rs @@ -7,7 +7,7 @@ mod tests { #[test] fn test_cedar_authorizer_allows_valid_token() { - let request = create_request(|item: &mut HttpRequest| { + let request = build_request(|item: &mut HttpRequest| { item.headers = build_with(|item: &mut HashMap| { item.insert( String::from("authorization"), @@ -21,7 +21,7 @@ mod tests { #[test] fn test_cedar_authorizer_denies_invalid_token() { - let request = create_request(|item: &mut HttpRequest| { + let request = build_request(|item: &mut HttpRequest| { item.headers = build_with(|item: &mut HashMap| { item.insert( String::from("authorization"), @@ -35,7 +35,7 @@ mod tests { #[test] fn test_cedar_authorizer_denies_missing_header() { - let request = create_request(|item: &mut HttpRequest| { + let request = build_request(|item: &mut HttpRequest| { item.headers = HashMap::new(); }); @@ -44,7 +44,7 @@ mod tests { #[test] fn test_cedar_authorizer_allows_static_assets() { - let request = create_request(|item: &mut HttpRequest| { + let request = build_request(|item: &mut HttpRequest| { item.headers = build_with(|item: &mut HashMap| { item.insert(String::from(":path"), String::from("/public/style.css")); }); @@ -57,7 +57,7 @@ mod tests { fn test_cedar_authorizer_allows_js_assets() { let mut headers = HashMap::new(); headers.insert(":path".to_string(), "/app.js".to_string()); - let request = create_request(|item: &mut HttpRequest| { + let request = build_request(|item: &mut HttpRequest| { item.headers = headers; }); diff --git a/tests/authorization/check_service_test.rs b/tests/authorization/check_service_test.rs index cddbb6b0..65b2d120 100644 --- a/tests/authorization/check_service_test.rs +++ b/tests/authorization/check_service_test.rs @@ -13,12 +13,12 @@ mod tests { #[tokio::test] async fn test_check_allows_valid_bearer_token() { - let token = create_token(); + let token = String::from("valid-token"); let server = CheckService::new(authorizer()); let mut headers = HashMap::new(); headers.insert("authorization".to_string(), format!("Bearer {}", token)); - let request = tonic::Request::new(create_request(|item: &mut HttpRequest| { + let request = tonic::Request::new(build_request(|item: &mut HttpRequest| { item.headers = headers; })); @@ -34,7 +34,7 @@ mod tests { #[tokio::test] async fn test_check_denies_invalid_bearer_token() { let server = CheckService::new(authorizer()); - let request = tonic::Request::new(create_request(|item: &mut HttpRequest| { + let request = tonic::Request::new(build_request(|item: &mut HttpRequest| { item.headers = HashMap::new(); })); diff --git a/tests/common/factory_bot.rs b/tests/common/factory_bot.rs index 6e45a01a..ea3a7da1 100644 --- a/tests/common/factory_bot.rs +++ b/tests/common/factory_bot.rs @@ -16,7 +16,7 @@ where return please::build_with(initializer); } -pub fn create_request(f: impl std::ops::FnOnce(&mut HttpRequest)) -> CheckRequest { +pub fn build_request(f: impl std::ops::FnOnce(&mut HttpRequest)) -> CheckRequest { crate::common::build_with(|item: &mut CheckRequest| { item.attributes = Some(please::build_with(|item: &mut AttributeContext| { item.request = Some(please::build_with(|item: &mut Request| { @@ -34,10 +34,6 @@ pub fn build_headers(headers: Vec<(String, String)>) -> HashMap }); } -pub fn create_token() -> String { - return String::from("valid-token"); -} - pub fn build_cedar_authorizer() -> authzd::CedarAuthorizer { let realpath = std::fs::canonicalize("./etc/authzd").unwrap(); let path = realpath.as_path(); diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 6e181f26..f7093600 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -14,7 +14,7 @@ fn authorizer() -> Arc { #[tokio::test] async fn test_success_response() { let server = CheckService::new(authorizer()); - let request = tonic::Request::new(factory_bot::create_request(|item: &mut HttpRequest| { + let request = tonic::Request::new(factory_bot::build_request(|item: &mut HttpRequest| { item.headers = factory_bot::build_headers(vec![( "authorization".to_string(), "Bearer valid-token".to_string(), @@ -43,7 +43,7 @@ async fn test_multiple() { ]; for (auth_value, should_succeed) in test_cases { - let request = tonic::Request::new(factory_bot::create_request(|item: &mut HttpRequest| { + let request = tonic::Request::new(factory_bot::build_request(|item: &mut HttpRequest| { item.headers = factory_bot::build_headers(vec![( "authorization".to_string(), auth_value.to_string(), -- cgit v1.2.3 From e970d1e29aa9a4e1a4ac6419079928b803536825 Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 13:15:47 -0600 Subject: test: refactor duplicate tests and start to build test harness for rpc server --- tests/authorization/check_service_test.rs | 54 +++++++++++++++++++------ tests/integration_tests.rs | 65 ------------------------------- tests/main_test.rs | 2 + 3 files changed, 45 insertions(+), 76 deletions(-) delete mode 100644 tests/integration_tests.rs create mode 100644 tests/main_test.rs (limited to 'tests/authorization') diff --git a/tests/authorization/check_service_test.rs b/tests/authorization/check_service_test.rs index 65b2d120..4a8f1426 100644 --- a/tests/authorization/check_service_test.rs +++ b/tests/authorization/check_service_test.rs @@ -11,39 +11,71 @@ mod tests { Arc::new(build_cedar_authorizer()) } + fn subject() -> CheckService { + CheckService::new(authorizer()) + } + #[tokio::test] async fn test_check_allows_valid_bearer_token() { - let token = String::from("valid-token"); - let server = CheckService::new(authorizer()); - - let mut headers = HashMap::new(); - headers.insert("authorization".to_string(), format!("Bearer {}", token)); let request = tonic::Request::new(build_request(|item: &mut HttpRequest| { - item.headers = headers; + item.headers = build_headers(vec![( + "authorization".to_string(), + format!("Bearer {}", String::from("valid-token")), + )]) })); - let response = server.check(request).await; - + 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 server = CheckService::new(authorizer()); let request = tonic::Request::new(build_request(|item: &mut HttpRequest| { item.headers = HashMap::new(); })); - let response = server.check(request).await; - + 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/integration_tests.rs b/tests/integration_tests.rs deleted file mode 100644 index f7093600..00000000 --- a/tests/integration_tests.rs +++ /dev/null @@ -1,65 +0,0 @@ -use authzd::CheckService; -use common::*; -use envoy_types::ext_authz::v3::pb::Authorization; -use envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest; -use std::sync::Arc; - -mod authorization; -mod common; - -fn authorizer() -> Arc { - Arc::new(factory_bot::build_cedar_authorizer()) -} - -#[tokio::test] -async fn test_success_response() { - let server = CheckService::new(authorizer()); - let request = tonic::Request::new(factory_bot::build_request(|item: &mut HttpRequest| { - item.headers = factory_bot::build_headers(vec![( - "authorization".to_string(), - "Bearer valid-token".to_string(), - )]) - })); - - let response = server.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_multiple() { - let server = CheckService::new(authorizer()); - - 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(factory_bot::build_request(|item: &mut HttpRequest| { - item.headers = factory_bot::build_headers(vec![( - "authorization".to_string(), - auth_value.to_string(), - )]); - })); - - let response = server.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/main_test.rs b/tests/main_test.rs new file mode 100644 index 00000000..5c6016f6 --- /dev/null +++ b/tests/main_test.rs @@ -0,0 +1,2 @@ +#[cfg(test)] +mod tests {} -- cgit v1.2.3 From 2f895218df8115d90ba03253024f6974a1c4f21b Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 14:50:34 -0600 Subject: test: add tests for grpc server --- Cargo.lock | 1 + Cargo.toml | 1 + tests/authorization/check_service_test.rs | 47 +++++++++++++++++++++--- tests/authorization/mod.rs | 1 + tests/authorization/server_test.rs | 7 ++++ tests/common/factory_bot.rs | 2 +- tests/common/mod.rs | 2 - tests/grpc_server_test.rs | 61 +++++++++++++++++++++++++++++++ tests/integration_test.rs | 2 + tests/main_test.rs | 8 ---- 10 files changed, 116 insertions(+), 16 deletions(-) create mode 100644 tests/authorization/server_test.rs create mode 100644 tests/grpc_server_test.rs create mode 100644 tests/integration_test.rs delete mode 100644 tests/main_test.rs (limited to 'tests/authorization') diff --git a/Cargo.lock b/Cargo.lock index a1c069e6..4c657df8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -110,6 +110,7 @@ dependencies = [ "log", "please", "tokio", + "tokio-stream", "tokio-test", "tonic", "tonic-build", diff --git a/Cargo.toml b/Cargo.toml index 2ac42209..ebacce3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,5 +24,6 @@ tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["json"] } [dev-dependencies] +tokio-stream = "0.1" tokio-test = "0.4.0" tonic-build = "0.10.0" diff --git a/tests/authorization/check_service_test.rs b/tests/authorization/check_service_test.rs index 4a8f1426..3bdf30c2 100644 --- a/tests/authorization/check_service_test.rs +++ b/tests/authorization/check_service_test.rs @@ -7,12 +7,8 @@ mod tests { use std::collections::HashMap; use std::sync::Arc; - fn authorizer() -> Arc { - Arc::new(build_cedar_authorizer()) - } - fn subject() -> CheckService { - CheckService::new(authorizer()) + CheckService::new(Arc::new(build_cedar_authorizer())) } #[tokio::test] @@ -50,6 +46,47 @@ mod tests { 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![ diff --git a/tests/authorization/mod.rs b/tests/authorization/mod.rs index a4ece924..675247d4 100644 --- a/tests/authorization/mod.rs +++ b/tests/authorization/mod.rs @@ -1,2 +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..6001e978 --- /dev/null +++ b/tests/authorization/server_test.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn test_create_server() { + assert!(authzd::create_server().is_ok()); + } +} diff --git a/tests/common/factory_bot.rs b/tests/common/factory_bot.rs index ea3a7da1..c64b53a2 100644 --- a/tests/common/factory_bot.rs +++ b/tests/common/factory_bot.rs @@ -17,7 +17,7 @@ where } pub fn build_request(f: impl std::ops::FnOnce(&mut HttpRequest)) -> CheckRequest { - crate::common::build_with(|item: &mut CheckRequest| { + build_with(|item: &mut CheckRequest| { item.attributes = Some(please::build_with(|item: &mut AttributeContext| { item.request = Some(please::build_with(|item: &mut Request| { item.http = Some(please::build_with(|item: &mut HttpRequest| f(item))); diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 4db87a2c..5e2a6d78 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,3 +1 @@ pub mod factory_bot; - -use factory_bot::*; diff --git a/tests/grpc_server_test.rs b/tests/grpc_server_test.rs new file mode 100644 index 00000000..ec471799 --- /dev/null +++ b/tests/grpc_server_test.rs @@ -0,0 +1,61 @@ +#[cfg(test)] +mod tests { + use authzd::create_server; + use std::net::SocketAddr; + use tokio::net::TcpListener; + use tonic::transport::Channel; + + 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 = create_server().expect("Failed to create server"); + + 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) + } + + async fn build_channel(addr: SocketAddr) -> Channel { + Channel::from_shared(format!("http://{}", addr)) + .expect("Failed to create channel") + .connect() + .await + .expect("Failed to connect to server") + } + + async fn build_client( + addr: SocketAddr, + ) -> tonic_health::pb::health_client::HealthClient { + tonic_health::pb::health_client::HealthClient::new(build_channel(addr).await) + } + + #[tokio::test] + async fn test_health_check_service() { + let (addr, server) = start_server().await; + let mut client = build_client(addr).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(); + } +} diff --git a/tests/integration_test.rs b/tests/integration_test.rs new file mode 100644 index 00000000..c1edf36e --- /dev/null +++ b/tests/integration_test.rs @@ -0,0 +1,2 @@ +mod authorization; +mod common; diff --git a/tests/main_test.rs b/tests/main_test.rs deleted file mode 100644 index 69c6eda1..00000000 --- a/tests/main_test.rs +++ /dev/null @@ -1,8 +0,0 @@ -#[cfg(test)] -mod tests { - #[test] - fn test_create_server() { - let result = authzd::create_server(); - assert!(result.is_ok()); - } -} -- cgit v1.2.3 From f2e1cc278bedb63ba0b0b8d9a82e28f0e10fe048 Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 14:52:38 -0600 Subject: test: merge server tests --- tests/authorization/server_test.rs | 59 ++++++++++++++++++++++++++++++++++-- tests/grpc_server_test.rs | 61 -------------------------------------- 2 files changed, 56 insertions(+), 64 deletions(-) delete mode 100644 tests/grpc_server_test.rs (limited to 'tests/authorization') diff --git a/tests/authorization/server_test.rs b/tests/authorization/server_test.rs index 6001e978..5e99fdac 100644 --- a/tests/authorization/server_test.rs +++ b/tests/authorization/server_test.rs @@ -1,7 +1,60 @@ #[cfg(test)] mod tests { - #[test] - fn test_create_server() { - assert!(authzd::create_server().is_ok()); + use std::net::SocketAddr; + use tokio::net::TcpListener; + use tonic::transport::Channel; + + 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::create_server().expect("Failed to create server"); + + 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) + } + + async fn build_channel(addr: SocketAddr) -> Channel { + Channel::from_shared(format!("http://{}", addr)) + .expect("Failed to create channel") + .connect() + .await + .expect("Failed to connect to server") + } + + async fn build_client( + addr: SocketAddr, + ) -> tonic_health::pb::health_client::HealthClient { + tonic_health::pb::health_client::HealthClient::new(build_channel(addr).await) + } + + #[tokio::test] + async fn test_health_check_service() { + let (addr, server) = start_server().await; + let mut client = build_client(addr).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(); } } diff --git a/tests/grpc_server_test.rs b/tests/grpc_server_test.rs deleted file mode 100644 index ec471799..00000000 --- a/tests/grpc_server_test.rs +++ /dev/null @@ -1,61 +0,0 @@ -#[cfg(test)] -mod tests { - use authzd::create_server; - use std::net::SocketAddr; - use tokio::net::TcpListener; - use tonic::transport::Channel; - - 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 = create_server().expect("Failed to create server"); - - 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) - } - - async fn build_channel(addr: SocketAddr) -> Channel { - Channel::from_shared(format!("http://{}", addr)) - .expect("Failed to create channel") - .connect() - .await - .expect("Failed to connect to server") - } - - async fn build_client( - addr: SocketAddr, - ) -> tonic_health::pb::health_client::HealthClient { - tonic_health::pb::health_client::HealthClient::new(build_channel(addr).await) - } - - #[tokio::test] - async fn test_health_check_service() { - let (addr, server) = start_server().await; - let mut client = build_client(addr).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(); - } -} -- cgit v1.2.3 From 2309a49fddd189e5dc9da1e7bf979864f02701e0 Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 14:53:48 -0600 Subject: test: rename common module to support --- tests/authorization/cedar_authorizer_test.rs | 2 +- tests/authorization/check_service_test.rs | 2 +- tests/common/factory_bot.rs | 41 ---------------------------- tests/common/mod.rs | 1 - tests/integration_test.rs | 2 +- tests/support/factory_bot.rs | 41 ++++++++++++++++++++++++++++ tests/support/mod.rs | 1 + 7 files changed, 45 insertions(+), 45 deletions(-) delete mode 100644 tests/common/factory_bot.rs delete mode 100644 tests/common/mod.rs create mode 100644 tests/support/factory_bot.rs create mode 100644 tests/support/mod.rs (limited to 'tests/authorization') diff --git a/tests/authorization/cedar_authorizer_test.rs b/tests/authorization/cedar_authorizer_test.rs index e7e6eb2c..76bf06df 100644 --- a/tests/authorization/cedar_authorizer_test.rs +++ b/tests/authorization/cedar_authorizer_test.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod tests { - use crate::common::factory_bot::*; + use crate::support::factory_bot::*; use authzd::Authorizer; use envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest; use std::collections::HashMap; diff --git a/tests/authorization/check_service_test.rs b/tests/authorization/check_service_test.rs index 3bdf30c2..3a225974 100644 --- a/tests/authorization/check_service_test.rs +++ b/tests/authorization/check_service_test.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod tests { - use crate::common::factory_bot::*; + 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; diff --git a/tests/common/factory_bot.rs b/tests/common/factory_bot.rs deleted file mode 100644 index c64b53a2..00000000 --- a/tests/common/factory_bot.rs +++ /dev/null @@ -1,41 +0,0 @@ -use envoy_types::ext_authz::v3::pb::CheckRequest; -use envoy_types::pb::envoy::service::auth::v3::AttributeContext; -use envoy_types::pb::envoy::service::auth::v3::attribute_context::{HttpRequest, Request}; -use std::collections::HashMap; - -#[allow(dead_code)] -pub fn build() -> T { - return please::build(); -} - -pub fn build_with(initializer: F) -> T -where - T: Default, - F: std::ops::FnOnce(&mut T), -{ - return please::build_with(initializer); -} - -pub fn build_request(f: impl std::ops::FnOnce(&mut HttpRequest)) -> CheckRequest { - build_with(|item: &mut CheckRequest| { - item.attributes = Some(please::build_with(|item: &mut AttributeContext| { - item.request = Some(please::build_with(|item: &mut Request| { - item.http = Some(please::build_with(|item: &mut HttpRequest| f(item))); - })); - })); - }) -} - -pub fn build_headers(headers: Vec<(String, String)>) -> HashMap { - return build_with(|item: &mut HashMap| { - for (key, value) in headers { - item.insert(key, value); - } - }); -} - -pub fn build_cedar_authorizer() -> authzd::CedarAuthorizer { - let realpath = std::fs::canonicalize("./etc/authzd").unwrap(); - let path = realpath.as_path(); - authzd::CedarAuthorizer::new_from(path) -} diff --git a/tests/common/mod.rs b/tests/common/mod.rs deleted file mode 100644 index 5e2a6d78..00000000 --- a/tests/common/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod factory_bot; diff --git a/tests/integration_test.rs b/tests/integration_test.rs index c1edf36e..c17d8e65 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -1,2 +1,2 @@ mod authorization; -mod common; +mod support; diff --git a/tests/support/factory_bot.rs b/tests/support/factory_bot.rs new file mode 100644 index 00000000..c64b53a2 --- /dev/null +++ b/tests/support/factory_bot.rs @@ -0,0 +1,41 @@ +use envoy_types::ext_authz::v3::pb::CheckRequest; +use envoy_types::pb::envoy::service::auth::v3::AttributeContext; +use envoy_types::pb::envoy::service::auth::v3::attribute_context::{HttpRequest, Request}; +use std::collections::HashMap; + +#[allow(dead_code)] +pub fn build() -> T { + return please::build(); +} + +pub fn build_with(initializer: F) -> T +where + T: Default, + F: std::ops::FnOnce(&mut T), +{ + return please::build_with(initializer); +} + +pub fn build_request(f: impl std::ops::FnOnce(&mut HttpRequest)) -> CheckRequest { + build_with(|item: &mut CheckRequest| { + item.attributes = Some(please::build_with(|item: &mut AttributeContext| { + item.request = Some(please::build_with(|item: &mut Request| { + item.http = Some(please::build_with(|item: &mut HttpRequest| f(item))); + })); + })); + }) +} + +pub fn build_headers(headers: Vec<(String, String)>) -> HashMap { + return build_with(|item: &mut HashMap| { + for (key, value) in headers { + item.insert(key, value); + } + }); +} + +pub fn build_cedar_authorizer() -> authzd::CedarAuthorizer { + let realpath = std::fs::canonicalize("./etc/authzd").unwrap(); + let path = realpath.as_path(); + authzd::CedarAuthorizer::new_from(path) +} diff --git a/tests/support/mod.rs b/tests/support/mod.rs new file mode 100644 index 00000000..5e2a6d78 --- /dev/null +++ b/tests/support/mod.rs @@ -0,0 +1 @@ +pub mod factory_bot; -- cgit v1.2.3 From 22bd71354eafd9e7ef4d4579f9bf5e6181d44604 Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 14:58:14 -0600 Subject: test: convert build_client to a generic function --- tests/authorization/server_test.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'tests/authorization') diff --git a/tests/authorization/server_test.rs b/tests/authorization/server_test.rs index 5e99fdac..40cc270f 100644 --- a/tests/authorization/server_test.rs +++ b/tests/authorization/server_test.rs @@ -34,21 +34,23 @@ mod tests { .expect("Failed to connect to server") } - async fn build_client( - addr: SocketAddr, - ) -> tonic_health::pb::health_client::HealthClient { - tonic_health::pb::health_client::HealthClient::new(build_channel(addr).await) + async fn build_client(addr: SocketAddr, f: F) -> T + where + F: FnOnce(Channel) -> T, + { + f(build_channel(addr).await) } #[tokio::test] async fn test_health_check_service() { let (addr, server) = start_server().await; - let mut client = build_client(addr).await; + let mut client = build_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(), -- cgit v1.2.3 From 7bda8947c80fc507b722f321977522bd50377c17 Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 15:02:17 -0600 Subject: test: move helpers to factory_bot module --- tests/authorization/server_test.rs | 20 +++----------------- tests/support/factory_bot.rs | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 17 deletions(-) (limited to 'tests/authorization') diff --git a/tests/authorization/server_test.rs b/tests/authorization/server_test.rs index 40cc270f..55645dd4 100644 --- a/tests/authorization/server_test.rs +++ b/tests/authorization/server_test.rs @@ -1,8 +1,8 @@ #[cfg(test)] mod tests { + use crate::support::factory_bot::*; use std::net::SocketAddr; use tokio::net::TcpListener; - use tonic::transport::Channel; async fn available_port() -> SocketAddr { let listener = TcpListener::bind("127.0.0.1:0") @@ -26,25 +26,11 @@ mod tests { (addr, handle) } - async fn build_channel(addr: SocketAddr) -> Channel { - Channel::from_shared(format!("http://{}", addr)) - .expect("Failed to create channel") - .connect() - .await - .expect("Failed to connect to server") - } - - async fn build_client(addr: SocketAddr, f: F) -> T - where - F: FnOnce(Channel) -> T, - { - f(build_channel(addr).await) - } - #[tokio::test] async fn test_health_check_service() { let (addr, server) = start_server().await; - let mut client = build_client(addr, tonic_health::pb::health_client::HealthClient::new).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(), diff --git a/tests/support/factory_bot.rs b/tests/support/factory_bot.rs index c64b53a2..15c6f1f3 100644 --- a/tests/support/factory_bot.rs +++ b/tests/support/factory_bot.rs @@ -2,6 +2,8 @@ use envoy_types::ext_authz::v3::pb::CheckRequest; use envoy_types::pb::envoy::service::auth::v3::AttributeContext; use envoy_types::pb::envoy::service::auth::v3::attribute_context::{HttpRequest, Request}; use std::collections::HashMap; +use std::net::SocketAddr; +use tonic::transport::Channel; #[allow(dead_code)] pub fn build() -> T { @@ -39,3 +41,18 @@ pub fn build_cedar_authorizer() -> authzd::CedarAuthorizer { let path = realpath.as_path(); authzd::CedarAuthorizer::new_from(path) } + +pub async fn build_channel(addr: SocketAddr) -> Channel { + Channel::from_shared(format!("http://{}", addr)) + .expect("Failed to create channel") + .connect() + .await + .expect("Failed to connect to server") +} + +pub async fn build_rpc_client(addr: SocketAddr, f: F) -> T +where + F: FnOnce(Channel) -> T, +{ + f(build_channel(addr).await) +} -- cgit v1.2.3 From cce3e0f170dfacb6b626a8777255c3183c5c5eb3 Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 16:45:17 -0600 Subject: refactor: extract authorization::Server type --- src/authorization/cedar_authorizer.rs | 1 + src/authorization/mod.rs | 2 ++ src/authorization/server.rs | 41 +++++++++++++++++++++++++++++++++++ src/lib.rs | 22 +------------------ src/main.rs | 5 +---- tests/authorization/server_test.rs | 2 +- 6 files changed, 47 insertions(+), 26 deletions(-) create mode 100644 src/authorization/server.rs (limited to 'tests/authorization') diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index 658de7a6..a877cf87 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -51,6 +51,7 @@ impl CedarAuthorizer { Ok(policies) } } + impl Default for CedarAuthorizer { fn default() -> Self { Self::new_from(std::path::Path::new("/etc/authzd")) diff --git a/src/authorization/mod.rs b/src/authorization/mod.rs index 7d3856a5..d664815b 100644 --- a/src/authorization/mod.rs +++ b/src/authorization/mod.rs @@ -1,7 +1,9 @@ pub mod authorizer; pub mod cedar_authorizer; pub mod check_service; +pub mod server; pub use authorizer::Authorizer; pub use cedar_authorizer::CedarAuthorizer; pub use check_service::CheckService; +pub use server::Server; diff --git a/src/authorization/server.rs b/src/authorization/server.rs new file mode 100644 index 00000000..f11d0465 --- /dev/null +++ b/src/authorization/server.rs @@ -0,0 +1,41 @@ +use super::cedar_authorizer::CedarAuthorizer; +use super::check_service::CheckService; +use envoy_types::ext_authz::v3::pb::AuthorizationServer; +use std::sync::Arc; + +pub fn create_router() -> Result> { + let (_health_reporter, health_service) = tonic_health::server::health_reporter(); + let authorizer = Arc::new(CedarAuthorizer::default()); + let check_service = CheckService::new(authorizer); + let server = tonic::transport::Server::builder() + .add_service(AuthorizationServer::new(check_service)) + .add_service(health_service) + .add_service( + tonic_reflection::server::Builder::configure() + .register_encoded_file_descriptor_set(tonic_health::pb::FILE_DESCRIPTOR_SET) + .build_v1() + .unwrap(), + ); + Ok(server) +} + +pub struct Server { + router: tonic::transport::server::Router, +} + +impl Server { + pub fn new() -> Result> { + let router = create_router()?; + Ok(Server { router: router }) + } + + pub async fn serve(self, addr: std::net::SocketAddr) -> Result<(), tonic::transport::Error> { + self.router.serve(addr).await + } +} + +impl Default for Server { + fn default() -> Self { + Self::new().unwrap() + } +} diff --git a/src/lib.rs b/src/lib.rs index a82c2ace..3bd8fbd1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,22 +1,2 @@ pub mod authorization; -pub use authorization::{Authorizer, CedarAuthorizer, CheckService}; - -use envoy_types::ext_authz::v3::pb::AuthorizationServer; -use std::sync::Arc; -use tonic::transport::Server; - -pub fn create_server() -> Result> { - let (_health_reporter, health_service) = tonic_health::server::health_reporter(); - let authorizer = Arc::new(authorization::CedarAuthorizer::default()); - let check_service = authorization::CheckService::new(authorizer); - let server = Server::builder() - .add_service(AuthorizationServer::new(check_service)) - .add_service(health_service) - .add_service( - tonic_reflection::server::Builder::configure() - .register_encoded_file_descriptor_set(tonic_health::pb::FILE_DESCRIPTOR_SET) - .build_v1() - .unwrap(), - ); - Ok(server) -} +pub use authorization::{Authorizer, CedarAuthorizer, CheckService, Server}; diff --git a/src/main.rs b/src/main.rs index 13d313d7..8638e14b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,3 @@ -use authzd::create_server; - #[tokio::main] async fn main() -> Result<(), Box> { tracing_subscriber::fmt().json().init(); @@ -8,9 +6,8 @@ async fn main() -> Result<(), Box> { .unwrap_or_else(|_| "[::1]:50051".to_string()) .parse()?; - let server = create_server()?; - log::info!("Listening on... {addr}"); + let server = authzd::authorization::Server::new()?; server.serve(addr).await?; Ok(()) diff --git a/tests/authorization/server_test.rs b/tests/authorization/server_test.rs index 55645dd4..fe8c8a73 100644 --- a/tests/authorization/server_test.rs +++ b/tests/authorization/server_test.rs @@ -15,7 +15,7 @@ mod tests { async fn start_server() -> (SocketAddr, tokio::task::JoinHandle<()>) { let addr = available_port().await; - let server = authzd::create_server().expect("Failed to create server"); + let server = authzd::authorization::Server::default(); let handle = tokio::spawn(async move { server.serve(addr).await.expect("Failed to start server"); -- cgit v1.2.3