diff options
| author | mo khan <mo@mokhan.ca> | 2025-07-05 13:36:41 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-07-05 13:36:41 -0600 |
| commit | 63c5263087c9e282ced0e549b78c7ebd4353b273 (patch) | |
| tree | e408c3aed5e4edf723c72897094bdd2f49077a15 /tests/authorization | |
| parent | 33083559c6d43d266ca77fcd1beb94c6feb4b547 (diff) | |
| parent | c6ec4e63d797c5e6cc01a4f09e723ad781b1034e (diff) | |
Merge branch 'sparkle-policies' into 'main'
Add Cedar policy validation and improve authorization architecture
See merge request gitlab-org/software-supply-chain-security/authorization/authzd!4
Diffstat (limited to 'tests/authorization')
| -rw-r--r-- | tests/authorization/cedar_authorizer_test.rs | 60 | ||||
| -rw-r--r-- | tests/authorization/check_service_test.rs | 127 |
2 files changed, 91 insertions, 96 deletions
diff --git a/tests/authorization/cedar_authorizer_test.rs b/tests/authorization/cedar_authorizer_test.rs index 79f83c00..490a0107 100644 --- a/tests/authorization/cedar_authorizer_test.rs +++ b/tests/authorization/cedar_authorizer_test.rs @@ -5,46 +5,44 @@ mod tests { use envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest; use std::collections::HashMap; + fn subject() -> authzd::CedarAuthorizer { + build_cedar_authorizer() + } + #[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)); + assert!(subject().authorize(build_request(|item: &mut HttpRequest| { + item.headers = build_headers(vec![( + "authorization".to_string(), + "Bearer valid-token".to_string(), + )]); + }))); } #[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)); + assert!( + !subject().authorize(build_request(|item: &mut HttpRequest| { + item.headers = build_headers(vec![( + "authorization".to_string(), + "Bearer invalid-token".to_string(), + )]); + })) + ); } #[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)); + assert!( + !subject().authorize(build_request(|item: &mut HttpRequest| { + item.headers = HashMap::new(); + })) + ); } #[test] fn test_cedar_authorizer_allows_static_assets() { - let request = build_request(|item: &mut HttpRequest| { + assert!(subject().authorize(build_request(|item: &mut HttpRequest| { let method = String::from("GET"); let host = String::from("sparkle.staging.runway.gitlab.net"); let path = "/public/style.css"; @@ -57,14 +55,12 @@ mod tests { (String::from(":method"), method), (String::from(":authority"), host), ]); - }); - - assert!(build_cedar_authorizer().authorize(request)); + }))); } #[test] fn test_cedar_authorizer_allows_js_assets() { - let request = build_request(|item: &mut HttpRequest| { + assert!(subject().authorize(build_request(|item: &mut HttpRequest| { let method = String::from("GET"); let host = String::from("sparkle.staging.runway.gitlab.net"); let path = "/app.js"; @@ -77,8 +73,6 @@ mod tests { (String::from(":method"), method), (String::from(":authority"), host), ]); - }); - - assert!(build_cedar_authorizer().authorize(request)); + }))); } } diff --git a/tests/authorization/check_service_test.rs b/tests/authorization/check_service_test.rs index a4b8f2ee..c5c824fc 100644 --- a/tests/authorization/check_service_test.rs +++ b/tests/authorization/check_service_test.rs @@ -14,6 +14,7 @@ mod tests { #[tokio::test] async fn test_check_allows_valid_bearer_token() { let request = tonic::Request::new(build_request(|item: &mut HttpRequest| { + item.path = String::from("/"); item.headers = build_headers(vec![( "authorization".to_string(), format!("Bearer {}", String::from("valid-token")), @@ -27,7 +28,7 @@ mod tests { assert!(check_response.status.is_some()); let status = check_response.status.unwrap(); - assert_eq!(status.code, tonic::Code::Ok as i32); + assert_eq!(tonic::Code::from_i32(status.code), tonic::Code::Ok); } #[tokio::test] @@ -43,7 +44,10 @@ mod tests { assert!(check_response.status.is_some()); let status = check_response.status.unwrap(); - assert_eq!(status.code, tonic::Code::Unauthenticated as i32); + assert_eq!( + tonic::Code::from_i32(status.code), + tonic::Code::Unauthenticated + ); } #[tokio::test] @@ -79,7 +83,7 @@ mod tests { assert!(check_response.status.is_some()); let status = check_response.status.unwrap(); - assert_eq!(status.code, tonic::Code::Ok as i32); + assert_eq!(tonic::Code::from_i32(status.code), tonic::Code::Ok); } } @@ -94,19 +98,22 @@ mod tests { assert!(check_response.status.is_some()); let status = check_response.status.unwrap(); - assert_eq!(status.code, tonic::Code::Unauthenticated as i32); + assert_eq!( + tonic::Code::from_i32(status.code), + tonic::Code::Unauthenticated + ); } #[tokio::test] async fn test_table() { let test_cases = vec![ - ("Bearer valid-token", true), - ("Bearer invalid-token", false), - ("Basic valid-token", false), - ("", false), + ("Bearer valid-token", tonic::Code::Ok), + ("Bearer invalid-token", tonic::Code::Unauthenticated), + ("Basic valid-token", tonic::Code::Unauthenticated), + ("", tonic::Code::Unauthenticated), ]; - for (auth_value, should_succeed) in test_cases { + for (auth_value, expected_status_code) 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())]); @@ -118,70 +125,64 @@ mod tests { 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); - } + assert_eq!(tonic::Code::from_i32(status.code), expected_status_code); } } #[tokio::test] async fn test_public_sparkle_endpoints() { - // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "GET", Path: "/"}}, - // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "GET", Path: "/application.js"}}, - // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "GET", Path: "/callback"}}, // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "GET", Path: "/dashboard", Headers: loggedInHeaders}}, - // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "GET", Path: "/dashboard/nav"}}, - // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "GET", Path: "/favicon.ico"}}, - // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "GET", Path: "/favicon.png"}}, - // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "GET", Path: "/favicon.png"}}, - // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "GET", Path: "/health"}}, - // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "GET", Path: "/htmx.js"}}, - // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "GET", Path: "/index.html"}}, - // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "GET", Path: "/logo.png"}}, - // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "GET", Path: "/pico.min.css"}}, - // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "GET", Path: "/signout"}}, - // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "GET", Path: "/sparkles"}}, - // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "GET", Path: "/vue.global.js"}}, // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "POST", Path: "/sparkles", Headers: loggedInHeaders}}, - // {status: tonic::Code::Ok, http: &HTTPRequest{Method: "POST", Path: "/sparkles/restore"}}, - // {status: tonic::Code::PermissionDenied, http: &HTTPRequest{Method: "GET", Path: "/dashboard"}}, // {status: tonic::Code::PermissionDenied, http: &HTTPRequest{Method: "GET", Path: "/dashboard", Headers: invalidHeaders}}, - // {status: tonic::Code::PermissionDenied, http: &HTTPRequest{Method: "POST", Path: "/sparkles"}}, - // - // http: - // method: \"GET\", - // headers: { - // \":method\": \"GET\", - // \":authority\": \"localhost:10000\", - // \":path\": \"/sparkles\", - // }, - // path: \"/sparkles\", - // host: \"localhost:10000\", - - let request = tonic::Request::new(build_request(|item: &mut HttpRequest| { - let path = String::from("/"); - let method = String::from("GET"); - let host = String::from("sparkle.staging.runway.gitlab.net"); - - item.method = method.clone(); - item.path = path.clone(); - item.host = host.clone(); - item.headers = build_headers(vec![ - (String::from(":path"), path), - (String::from(":method"), method), - (String::from(":authority"), host), - ]); - })); - let response = subject().check(request).await; - assert!(response.is_ok()); + let hosts = vec![ + "localhost:10000", + "sparkle.runway.gitlab.net", + "sparkle.staging.runway.gitlab.net", + ]; - let check_response = response.unwrap().into_inner(); - assert!(check_response.status.is_some()); + let routes = vec![ + ("GET", "/", tonic::Code::Ok), + ("GET", "/application.js", tonic::Code::Ok), + ("GET", "/callback", tonic::Code::Ok), + ("GET", "/dashboard/nav", tonic::Code::Ok), + ("GET", "/favicon.ico", tonic::Code::Ok), + ("GET", "/favicon.png", tonic::Code::Ok), + ("GET", "/health", tonic::Code::Ok), + ("GET", "/htmx.js", tonic::Code::Ok), + ("GET", "/index.html", tonic::Code::Ok), + ("GET", "/logo.png", tonic::Code::Ok), + ("GET", "/pico.min.css", tonic::Code::Ok), + ("GET", "/signout", tonic::Code::Ok), + ("GET", "/sparkles", tonic::Code::Ok), + ("GET", "/vue.global.js", tonic::Code::Ok), + ("POST", "/sparkles/restore", tonic::Code::Ok), + ("GET", "/dashboard", tonic::Code::Unauthenticated), + ("POST", "/sparkles", tonic::Code::Unauthenticated), + ]; - let status = check_response.status.unwrap(); - assert_eq!(status.code, tonic::Code::Ok as i32); + for host in hosts { + for (method, path, expected_status_code) in &routes { + let request = tonic::Request::new(build_request(|item: &mut HttpRequest| { + item.method = method.to_string(); + item.path = path.to_string(); + item.host = host.to_string(); + item.headers = build_headers(vec![ + (String::from(":path"), path.to_string()), + (String::from(":method"), method.to_string()), + (String::from(":authority"), host.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!(tonic::Code::from_i32(status.code), *expected_status_code); + } + } } } |
