use envoy_types::ext_authz::v3::CheckResponseExt; use envoy_types::ext_authz::v3::pb::{CheckRequest, CheckResponse}; use tonic::{Request, Response, Status}; #[derive(Debug, Default)] pub struct CheckService; #[tonic::async_trait] impl envoy_types::ext_authz::v3::pb::Authorization for CheckService { async fn check( &self, request: Request, ) -> Result, Status> { let request = request.into_inner(); let client_headers = request .attributes .as_ref() .and_then(|attr| attr.request.as_ref()) .and_then(|req| req.http.as_ref()) .map(|http| &http.headers) .ok_or_else(|| Status::invalid_argument("client headers not populated by envoy"))?; let mut request_status = Status::unauthenticated("not authorized"); if let Some(authorization) = client_headers.get("authorization") { if authorization == "Bearer valid-token" { request_status = Status::ok("request is valid"); } } Ok(Response::new(CheckResponse::with_status(request_status))) } } #[cfg(test)] mod tests { use super::*; use envoy_types::ext_authz::v3::pb::{Authorization, CheckRequest}; use std::collections::HashMap; use tonic::Request; fn create_test_request_with_headers(headers: HashMap) -> Request { use envoy_types::pb::envoy::service::auth::v3::{AttributeContext, attribute_context}; let http_request = attribute_context::HttpRequest { headers, ..Default::default() }; let request_context = attribute_context::Request { http: Some(http_request), ..Default::default() }; let attributes = AttributeContext { request: Some(request_context), ..Default::default() }; let check_request = CheckRequest { attributes: Some(attributes), ..Default::default() }; Request::new(check_request) } fn create_headers_with_auth(auth_value: &str) -> HashMap { let mut headers = HashMap::new(); headers.insert("authorization".to_string(), auth_value.to_string()); headers } #[tokio::test] async fn test_check_allows_valid_bearer_token() { let token = String::from("valid-token"); let server = CheckService::default(); let headers = create_headers_with_auth(&format!("Bearer {}", token)); let request = create_test_request_with_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.into()); } #[tokio::test] async fn test_check_denies_invalid_bearer_token() { let server = CheckService::default(); let request = create_test_request_with_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.into()); } }