Skip to content

Commit

Permalink
authorization as a layer
Browse files Browse the repository at this point in the history
  • Loading branch information
fulmicoton committed Nov 4, 2024
1 parent afa80fb commit fb2cfcf
Show file tree
Hide file tree
Showing 16 changed files with 168 additions and 197 deletions.
4 changes: 4 additions & 0 deletions quickwit/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions quickwit/quickwit-auth/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@ authors.workspace = true
license.workspace = true

[dependencies]
tower = { workspace = true}
biscuit-auth = { workspace = true, optional=true }
futures = { workspace = true }
http = { workspace = true }
serde = { workspace = true }
thiserror = { workspace = true }
tonic = { workspace = true }
tokio = { workspace = true }
tracing = { workspace = true }
pin-project = { workspace = true }

quickwit-common = { workspace = true }

[features]
enterprise = ["biscuit-auth"]
51 changes: 51 additions & 0 deletions quickwit/quickwit-auth/src/authorization_layer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use std::fmt;
use std::task::{Context, Poll};

use futures::future::Either;
use quickwit_common::tower::RpcName;
use tower::{Layer, Service};

use crate::AuthorizationError;

pub struct AuthorizationLayer;

impl<S: Clone> Layer<S> for AuthorizationLayer {
type Service = AuthorizationService<S>;

fn layer(&self, service: S) -> Self::Service {
AuthorizationService { service }
}
}

#[derive(Clone)]
pub struct AuthorizationService<S> {
service: S,
}

impl<S, Request> Service<Request> for AuthorizationService<S>
where
S: Service<Request>,
S::Future: Send + 'static,
S::Response: Send + 'static,
S::Error: From<AuthorizationError> + Send + 'static,
Request: fmt::Debug + Send + RpcName + crate::Authorization + 'static,
{
type Response = S::Response;
type Error = S::Error;
type Future =
futures::future::Either<futures::future::Ready<Result<S::Response, S::Error>>, S::Future>;

fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}

fn call(&mut self, request: Request) -> Self::Future {
if let Err(authorization_err) = crate::authorize_request(&request) {
let err = S::Error::from(authorization_err);
let result: Result<S::Response, S::Error> = Err(err);
return Either::Left(futures::future::ready(result));
}
let service_fut = self.service.call(request);
Either::Right(service_fut)
}
}
4 changes: 4 additions & 0 deletions quickwit/quickwit-auth/src/community.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,7 @@ pub fn execute_with_authorization<F, O>(_: AuthorizationToken, f: F) -> impl Fut
where F: Future<Output = O> {
f
}

pub fn authorize_request<R: Authorization>(_req: &R) -> Result<(), AuthorizationError> {
Ok(())
}
6 changes: 6 additions & 0 deletions quickwit/quickwit-auth/src/enterprise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,12 @@ pub fn authorize_stream<R: StreamAuthorization>(
Ok(())
}

pub fn authorize_request<R: Authorization>(req: &R) -> Result<(), AuthorizationError> {
AUTHORIZATION_TOKEN
.try_with(|auth_token| authorize(req, auth_token))
.unwrap_or(Err(AuthorizationError::AuthorizationTokenMissing))
}

pub fn execute_with_authorization<F, O>(
token: AuthorizationToken,
f: F,
Expand Down
3 changes: 2 additions & 1 deletion quickwit/quickwit-auth/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

use serde::{Deserialize, Serialize};
mod authorization_layer;

#[cfg(not(feature = "enterprise"))]
#[path = "community.rs"]
Expand All @@ -28,6 +28,7 @@ mod implementation;
mod implementation;

pub use implementation::*;
use serde::{Deserialize, Serialize};

#[derive(thiserror::Error, Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq)]
pub enum AuthorizationError {
Expand Down
30 changes: 18 additions & 12 deletions quickwit/quickwit-codegen/example/src/codegen/hello.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 2 additions & 16 deletions quickwit/quickwit-codegen/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1246,9 +1246,7 @@ fn generate_grpc_server_adapter_methods(context: &CodegenContext) -> TokenStream
}
}
} else {
quote! {
request.into_inner()
}
quote! { request.into_inner() }
};
let response_type = if syn_method.server_streaming {
let associated_type_name = quote::format_ident!("{}Stream", syn_method.proto_name);
Expand All @@ -1271,24 +1269,12 @@ fn generate_grpc_server_adapter_methods(context: &CodegenContext) -> TokenStream
quote! { tonic::Response::new }
};

let authorize_block = if syn_method.client_streaming {
let stream_item = &syn_method.request_type;
quote! {
quickwit_auth::authorize_stream::<#stream_item>(&auth_token)?;
}
} else {
quote! {
quickwit_auth::authorize(&req, &auth_token)?;
}
};
let method = quote! {
#associated_type

async fn #method_name(&self, request: tonic::Request<#request_type>) -> Result<tonic::Response<#response_type>, tonic::Status> {
let auth_token = quickwit_auth::get_auth_token(request.metadata())?;
let req = #method_arg;
#authorize_block;
quickwit_auth::execute_with_authorization(auth_token, self.inner.0.#method_name(req)).await
quickwit_auth::execute_with_authorization(auth_token, self.inner.0.#method_name(#method_arg)).await
.map(#into_response_type)
.map_err(crate::error::grpc_error_to_grpc_status)
}
Expand Down
21 changes: 12 additions & 9 deletions quickwit/quickwit-ingest/src/codegen/ingest_service.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit fb2cfcf

Please sign in to comment.