feat: initial work on auth interceptors

This commit is contained in:
əlemi 2022-09-17 21:46:40 +02:00
parent ab432966f9
commit 7f4696f164
3 changed files with 76 additions and 11 deletions

View file

@ -30,8 +30,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
info!("Starting server"); info!("Starting server");
Server::builder() Server::builder()
.add_service(WorkspaceService::server(state.clone())) .add_service(WorkspaceService::new(state.clone()).server())
.add_service(BufferService::server(state.clone())) .add_service(BufferService::new(state.clone()).server())
.serve(addr) .serve(addr)
.await?; .await?;

View file

@ -145,8 +145,11 @@ impl Buffer for BufferService {
} }
impl BufferService { impl BufferService {
// TODO is this smart? Should I let main() instantiate servers? pub fn new(state: Arc<StateManager>) -> BufferService {
pub fn server(state: Arc<StateManager>) -> BufferServer<BufferService> { BufferService { state }
BufferServer::new(BufferService { state }) }
pub fn server(self) -> BufferServer<BufferService> {
BufferServer::new(self)
} }
} }

View file

@ -1,6 +1,8 @@
use std::{pin::Pin, sync::Arc}; use std::{pin::Pin, sync::Arc};
use tracing::{debug, error, info, warn}; use tonic::codegen::InterceptedService;
use tonic::service::Interceptor;
use tracing::debug;
use tokio_stream::wrappers::ReceiverStream; use tokio_stream::wrappers::ReceiverStream;
use tonic::{Request, Response, Status}; use tonic::{Request, Response, Status};
@ -15,7 +17,47 @@ use tokio_stream::Stream; // TODO example used this?
use proto::workspace_server::{Workspace, WorkspaceServer}; use proto::workspace_server::{Workspace, WorkspaceServer};
use proto::{BufferList, Event, WorkspaceRequest, WorkspaceResponse, UsersList, BufferRequest}; use proto::{BufferList, Event, WorkspaceRequest, WorkspaceResponse, UsersList, BufferRequest};
use crate::actor::{buffer::Buffer, state::StateManager, workspace::{Workspace as WorkspaceInstance}}; // TODO fuck x2! use crate::actor::{buffer::Buffer, state::StateManager, workspace::Workspace as WorkspaceInstance}; // TODO fuck x2!
struct WorkspaceExtension {
id: String
}
#[derive(Debug, Clone)]
pub struct WorkspaceInterceptor {
state: Arc<StateManager>,
}
impl Interceptor for WorkspaceInterceptor {
fn call(&mut self, mut req: tonic::Request<()>) -> Result<tonic::Request<()>, Status> {
// Set an extension that can be retrieved by `say_hello`
let id;
// TODO this is kinda spaghetti but I can't borrow immutably and mutably req inside this match
// tree...
match req.metadata().get("workspace") {
Some(value) => {
match value.to_str() {
Ok(w_id) => {
id = w_id.to_string();
},
Err(_) => return Err(Status::invalid_argument("Workspace key is not valid")),
}
},
None => return Err(Status::unauthenticated("No workspace key included in request"))
}
if !self.state.workspaces.borrow().contains_key(&id) {
return Err(Status::not_found(format!("Workspace '{}' could not be found", id)));
}
req.extensions_mut().insert(WorkspaceExtension { id });
Ok(req)
}
}
type EventStream = Pin<Box<dyn Stream<Item = Result<Event, Status>> + Send>>; type EventStream = Pin<Box<dyn Stream<Item = Result<Event, Status>> + Send>>;
@ -33,9 +75,11 @@ impl Workspace for WorkspaceService {
request: Request<WorkspaceRequest>, request: Request<WorkspaceRequest>,
) -> Result<Response<WorkspaceResponse>, Status> { ) -> Result<Response<WorkspaceResponse>, Status> {
debug!("create request: {:?}", request); debug!("create request: {:?}", request);
// We should always have an extension because of the interceptor but maybe don't unwrap?
let ext = request.extensions().get::<WorkspaceExtension>().unwrap();
let r = request.into_inner(); let r = request.into_inner();
let _w = WorkspaceInstance::new(r.session_key.clone()); let _w = WorkspaceInstance::new(ext.id);
let reply = WorkspaceResponse { let reply = WorkspaceResponse {
// session_key: r.session_key.clone(), // session_key: r.session_key.clone(),
@ -137,13 +181,31 @@ impl Workspace for WorkspaceService {
&self, &self,
req: Request<WorkspaceRequest>, req: Request<WorkspaceRequest>,
) -> Result<Response<UsersList>, Status> { ) -> Result<Response<UsersList>, Status> {
todo!() let r = req.into_inner();
match self.state.get(&r.session_key) {
Some(w) => {
let mut out = Vec::new();
for (_k, v) in w.users.borrow().iter() {
out.push(v.name.clone());
}
Ok(Response::new(UsersList { name: out }))
},
None => Err(Status::not_found(format!(
"No active workspace with session_key '{}'",
r.session_key
))),
}
} }
} }
impl WorkspaceService { impl WorkspaceService {
pub fn server(state: Arc<StateManager>) -> WorkspaceServer<WorkspaceService> { pub fn new(state: Arc<StateManager>) -> WorkspaceService {
WorkspaceServer::new(WorkspaceService { state }) WorkspaceService { state }
}
pub fn server(self) -> InterceptedService<WorkspaceServer<WorkspaceService>, WorkspaceInterceptor> {
let state = self.state.clone();
WorkspaceServer::with_interceptor(self, WorkspaceInterceptor { state })
} }
} }