diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/authorization.rs | 104 | ||||
| -rw-r--r-- | src/lib.rs | 3 | ||||
| -rw-r--r-- | src/main.rs | 35 |
3 files changed, 111 insertions, 31 deletions
diff --git a/src/authorization.rs b/src/authorization.rs new file mode 100644 index 00000000..22cd695c --- /dev/null +++ b/src/authorization.rs @@ -0,0 +1,104 @@ +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 PolicyServer; + +#[tonic::async_trait] +impl envoy_types::ext_authz::v3::pb::Authorization for PolicyServer { + async fn check( + &self, + request: Request<CheckRequest>, + ) -> Result<Response<CheckResponse>, 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<String, String>) -> Request<CheckRequest> { + 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<String, String> { + 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 = PolicyServer::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 = PolicyServer::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()); + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..cb28e34b --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,3 @@ +pub mod authorization; + +pub use authorization::PolicyServer; diff --git a/src/main.rs b/src/main.rs index 05d57719..25e2c88f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,35 +1,8 @@ -use envoy_types::ext_authz::v3::pb::{ - Authorization, AuthorizationServer, CheckRequest, CheckResponse, -}; -use envoy_types::ext_authz::v3::{CheckRequestExt, CheckResponseExt}; -use tonic::{Request, Response, Status, transport::Server}; +use envoy_types::ext_authz::v3::pb::AuthorizationServer; +use tonic::transport::Server; -#[derive(Debug, Default)] -struct PolicyServer; - -#[tonic::async_trait] -impl Authorization for PolicyServer { - async fn check( - &self, - request: Request<CheckRequest>, - ) -> Result<Response<CheckResponse>, Status> { - let request = request.into_inner(); - - let client_headers = request - .get_client_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))) - } -} +pub mod authorization; +use authorization::PolicyServer; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { |
