-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add initial implementation of auth service
Signed-off-by: Adam Cattermole <[email protected]>
- Loading branch information
1 parent
b5b3b1b
commit c752365
Showing
4 changed files
with
130 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
pub(crate) mod auth; | ||
pub(crate) mod rate_limit; | ||
|
||
use protobuf::Message; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
use crate::attribute::get_attribute; | ||
use crate::envoy::{ | ||
Address, AttributeContext, AttributeContext_HttpRequest, AttributeContext_Peer, | ||
AttributeContext_Request, CheckRequest, Metadata, SocketAddress, | ||
}; | ||
use crate::service::Service; | ||
use chrono::{DateTime, FixedOffset, Timelike}; | ||
use protobuf::well_known_types::Timestamp; | ||
use protobuf::Message; | ||
use proxy_wasm::hostcalls; | ||
use proxy_wasm::hostcalls::dispatch_grpc_call; | ||
use proxy_wasm::types::{MapType, Status}; | ||
use std::collections::HashMap; | ||
use std::time::Duration; | ||
|
||
const AUTH_SERVICE_NAME: &str = "envoy.service.auth.v3.Authorization"; | ||
const AUTH_METHOD_NAME: &str = "Check"; | ||
|
||
pub struct AuthService { | ||
endpoint: String, | ||
metadata: Vec<(String, Vec<u8>)>, | ||
} | ||
|
||
impl AuthService { | ||
pub fn new(endpoint: &str, metadata: Vec<(&str, &[u8])>) -> Self { | ||
Check warning on line 25 in src/service/auth.rs GitHub Actions / Test Suite
Check warning on line 25 in src/service/auth.rs GitHub Actions / Test Suite
Check warning on line 25 in src/service/auth.rs GitHub Actions / Check
Check warning on line 25 in src/service/auth.rs GitHub Actions / Rustfmt
|
||
let m = metadata | ||
.into_iter() | ||
.map(|(header, value)| (header.to_owned(), value.to_owned())) | ||
.collect(); | ||
Self { | ||
endpoint: endpoint.to_owned(), | ||
metadata: m, | ||
} | ||
} | ||
|
||
pub fn message() -> CheckRequest { | ||
AuthService::build_check_req() | ||
} | ||
|
||
fn build_check_req() -> CheckRequest { | ||
let mut auth_req = CheckRequest::default(); | ||
let mut attr = AttributeContext::default(); | ||
attr.set_request(AuthService::build_request()); | ||
attr.set_destination(AuthService::build_peer( | ||
get_attribute::<String>("destination.address").unwrap_or_default(), | ||
get_attribute::<i64>("destination.port").unwrap_or_default() as u32, | ||
)); | ||
attr.set_source(AuthService::build_peer( | ||
get_attribute::<String>("source.address").unwrap_or_default(), | ||
get_attribute::<i64>("source.port").unwrap_or_default() as u32, | ||
)); | ||
// todo(adam-cattermole): for now we set the context_extensions to the request host | ||
// but this should take other info into account | ||
let context_extensions = HashMap::from([( | ||
"host".to_string(), | ||
attr.get_request().get_http().host.to_owned(), | ||
)]); | ||
attr.set_context_extensions(context_extensions); | ||
attr.set_metadata_context(Metadata::default()); | ||
auth_req.set_attributes(attr); | ||
auth_req | ||
} | ||
|
||
fn build_request() -> AttributeContext_Request { | ||
let mut request = AttributeContext_Request::default(); | ||
let mut http = AttributeContext_HttpRequest::default(); | ||
let headers: HashMap<String, String> = hostcalls::get_map(MapType::HttpRequestHeaders) | ||
.unwrap() | ||
.into_iter() | ||
.collect(); | ||
|
||
http.set_host(get_attribute::<String>("request.host").unwrap_or_default()); | ||
http.set_method(get_attribute::<String>("request.method").unwrap_or_default()); | ||
http.set_scheme(get_attribute::<String>("request.scheme").unwrap_or_default()); | ||
http.set_path(get_attribute::<String>("request.path").unwrap_or_default()); | ||
http.set_protocol(get_attribute::<String>("request.protocol").unwrap_or_default()); | ||
|
||
http.set_headers(headers); | ||
request.set_time(get_attribute("request.time").map_or( | ||
Timestamp::new(), | ||
|date_time: DateTime<FixedOffset>| Timestamp { | ||
nanos: date_time.nanosecond() as i32, | ||
seconds: date_time.second() as i64, | ||
unknown_fields: Default::default(), | ||
cached_size: Default::default(), | ||
}, | ||
)); | ||
request.set_http(http); | ||
request | ||
} | ||
|
||
fn build_peer(host: String, port: u32) -> AttributeContext_Peer { | ||
let mut peer = AttributeContext_Peer::default(); | ||
let mut address = Address::default(); | ||
let mut socket_address = SocketAddress::default(); | ||
socket_address.set_address(host); | ||
socket_address.set_port_value(port); | ||
address.set_socket_address(socket_address); | ||
peer.set_address(address); | ||
peer | ||
} | ||
} | ||
|
||
impl Service<CheckRequest> for AuthService { | ||
fn send(&self, message: CheckRequest) -> Result<u32, Status> { | ||
let msg = Message::write_to_bytes(&message).unwrap(); // TODO(adam-cattermole): Error Handling | ||
let metadata = self | ||
.metadata | ||
.iter() | ||
.map(|(header, value)| (header.as_str(), value.as_slice())) | ||
.collect(); | ||
|
||
dispatch_grpc_call( | ||
self.endpoint.as_str(), | ||
AUTH_SERVICE_NAME, | ||
AUTH_METHOD_NAME, | ||
metadata, | ||
Some(&msg), | ||
Duration::from_secs(5), | ||
) | ||
} | ||
} |