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");
Server::builder()
.add_service(WorkspaceService::server(state.clone()))
.add_service(BufferService::server(state.clone()))
.add_service(WorkspaceService::new(state.clone()).server())
.add_service(BufferService::new(state.clone()).server())
.serve(addr)
.await?;

View file

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

View file

@ -1,6 +1,8 @@
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 tonic::{Request, Response, Status};
@ -15,7 +17,47 @@ use tokio_stream::Stream; // TODO example used this?
use proto::workspace_server::{Workspace, WorkspaceServer};
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>>;
@ -33,9 +75,11 @@ impl Workspace for WorkspaceService {
request: Request<WorkspaceRequest>,
) -> Result<Response<WorkspaceResponse>, Status> {
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 _w = WorkspaceInstance::new(r.session_key.clone());
let _w = WorkspaceInstance::new(ext.id);
let reply = WorkspaceResponse {
// session_key: r.session_key.clone(),
@ -137,13 +181,31 @@ impl Workspace for WorkspaceService {
&self,
req: Request<WorkspaceRequest>,
) -> 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 {
pub fn server(state: Arc<StateManager>) -> WorkspaceServer<WorkspaceService> {
WorkspaceServer::new(WorkspaceService { state })
pub fn new(state: Arc<StateManager>) -> WorkspaceService {
WorkspaceService { state }
}
pub fn server(self) -> InterceptedService<WorkspaceServer<WorkspaceService>, WorkspaceInterceptor> {
let state = self.state.clone();
WorkspaceServer::with_interceptor(self, WorkspaceInterceptor { state })
}
}