diff options
Diffstat (limited to 'crates/auth')
-rw-r--r-- | crates/auth/Cargo.toml | 5 | ||||
-rw-r--r-- | crates/auth/src/auth.rs | 12 | ||||
-rw-r--r-- | crates/auth/src/main.rs | 41 | ||||
-rw-r--r-- | crates/auth/src/server.rs | 1 | ||||
-rw-r--r-- | crates/auth/src/server/grpc.rs | 2 | ||||
-rw-r--r-- | crates/auth/src/server/grpc/auth.rs | 50 | ||||
-rw-r--r-- | crates/auth/src/server/grpc/interceptor.rs | 11 | ||||
-rw-r--r-- | crates/auth/src/server/routes/authorised.rs | 11 |
8 files changed, 120 insertions, 13 deletions
diff --git a/crates/auth/Cargo.toml b/crates/auth/Cargo.toml index 410c51e..cc6d676 100644 --- a/crates/auth/Cargo.toml +++ b/crates/auth/Cargo.toml @@ -19,12 +19,15 @@ jsonwebtoken = "9.3.1" nanoid.workspace = true oauth2 = "5.0.0" reqwest = { workspace = true, features = ["json", "rustls-tls"] } +sellershut-core = { workspace = true, features = ["auth", "serde"] } serde = { workspace = true, features = ["derive"] } serde_json.workspace = true sqlx = { workspace = true, features = ["macros", "migrate", "runtime-tokio", "time", "tls-rustls", "uuid"] } time = { workspace = true, features = ["parsing", "serde"] } tokio = { workspace = true, features = ["macros", "rt-multi-thread", "signal"] } -tower = { workspace = true, features = ["util"] } +tonic.workspace = true +tonic-reflection = "0.13.0" +tower = { workspace = true, features = ["steer", "util"] } tower-http = { workspace = true, features = ["map-request-body", "trace", "util"] } tower-sessions = "0.14.0" tower-sessions-core = { version = "0.14.0", features = ["deletion-task"] } diff --git a/crates/auth/src/auth.rs b/crates/auth/src/auth.rs new file mode 100644 index 0000000..04cb60a --- /dev/null +++ b/crates/auth/src/auth.rs @@ -0,0 +1,12 @@ +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Claims { + pub iss: String, + pub sub: Uuid, + pub exp: i64, + pub iat: i64, + pub sid: String, + pub aud: String, +} diff --git a/crates/auth/src/main.rs b/crates/auth/src/main.rs index a1883ad..72f991f 100644 --- a/crates/auth/src/main.rs +++ b/crates/auth/src/main.rs @@ -1,3 +1,4 @@ +mod auth; mod client; mod cnfg; mod error; @@ -7,11 +8,19 @@ mod state; use std::net::{Ipv6Addr, SocketAddr}; use clap::Parser; +use reqwest::header::CONTENT_TYPE; +use sellershut_core::auth::{AUTH_FILE_DESCRIPTOR_SET, auth_server::AuthServer}; use stack_up::{Configuration, Services, tracing::Tracing}; use tokio::{signal, task::AbortHandle}; +use tonic::service::Routes; +use tower::{make::Shared, steer::Steer}; use tracing::{info, trace}; -use crate::{error::AppError, state::AppState}; +use crate::{ + error::AppError, + server::{grpc::interceptor::MyInterceptor, routes::authorised::AuthRequest}, + state::AppState, +}; /// auth-service #[derive(Parser, Debug)] @@ -63,7 +72,35 @@ async fn main() -> Result<(), AppError> { let listener = tokio::net::TcpListener::bind(addr).await?; info!(port = addr.port(), "serving api"); - axum::serve(listener, server::router(state)) + let service = AuthServer::with_interceptor(state.clone(), MyInterceptor); + let auth_reflector = tonic_reflection::server::Builder::configure() + .register_encoded_file_descriptor_set(AUTH_FILE_DESCRIPTOR_SET) + .build_v1()?; + + let grpc_server = Routes::new(service) + .add_service(auth_reflector) + .into_axum_router(); + + let service = Steer::new( + vec![server::router(state), grpc_server], + |req: &axum::extract::Request, _services: &[_]| { + if req + .headers() + .get(CONTENT_TYPE) + .map(|content_type| content_type.as_bytes()) + .filter(|content_type| content_type.starts_with(b"application/grpc")) + .is_some() + { + // grpc service + 1 + } else { + // http service + 0 + } + }, + ); + + axum::serve(listener, Shared::new(service)) .with_graceful_shutdown(shutdown_signal(deletion_task.abort_handle())) .await?; diff --git a/crates/auth/src/server.rs b/crates/auth/src/server.rs index 2892412..7b66c42 100644 --- a/crates/auth/src/server.rs +++ b/crates/auth/src/server.rs @@ -7,6 +7,7 @@ use crate::{ }; pub mod csrf_token_validation; +pub mod grpc; pub mod routes; const CSRF_TOKEN: &str = "csrf_token"; diff --git a/crates/auth/src/server/grpc.rs b/crates/auth/src/server/grpc.rs new file mode 100644 index 0000000..0fd775b --- /dev/null +++ b/crates/auth/src/server/grpc.rs @@ -0,0 +1,2 @@ +pub mod auth; +pub mod interceptor; diff --git a/crates/auth/src/server/grpc/auth.rs b/crates/auth/src/server/grpc/auth.rs new file mode 100644 index 0000000..fb00291 --- /dev/null +++ b/crates/auth/src/server/grpc/auth.rs @@ -0,0 +1,50 @@ +use std::str::FromStr; + +use jsonwebtoken::DecodingKey; +use sellershut_core::auth::{ValidationRequest, ValidationResponse, auth_server::Auth}; +use tonic::{Request, Response, Status, async_trait}; +use tower_sessions::{SessionStore, session::Id}; +use tracing::warn; + +use crate::{auth::Claims, state::AppHandle}; + +#[async_trait] +impl Auth for AppHandle { + async fn validate_auth_token( + &self, + request: Request<ValidationRequest>, + ) -> Result<Response<ValidationResponse>, Status> { + let token = request.into_inner().token; + + let token = jsonwebtoken::decode::<Claims>( + &token, + &DecodingKey::from_secret(self.local_config.oauth.jwt_encoding_key.as_bytes()), + &jsonwebtoken::Validation::default(), + ); + + match token { + Ok(value) => { + let session_id = value.claims.sid; + let store = &self.session_store; + match Id::from_str(&session_id) { + Ok(ref id) => { + if let Ok(Some(_)) = store.load(id).await { + return Ok(Response::new(ValidationResponse { valid: true })); + } else { + return Ok(Response::new(Default::default())); + } + } + Err(e) => { + warn!("{e}"); + + return Ok(Response::new(Default::default())); + } + } + } + Err(e) => { + warn!("{e}"); + Ok(Response::new(ValidationResponse::default())) + } + } + } +} diff --git a/crates/auth/src/server/grpc/interceptor.rs b/crates/auth/src/server/grpc/interceptor.rs new file mode 100644 index 0000000..6fbe7fa --- /dev/null +++ b/crates/auth/src/server/grpc/interceptor.rs @@ -0,0 +1,11 @@ +use tonic::{Status, service::Interceptor}; +use tracing::Span; + +#[derive(Clone, Copy)] +pub struct MyInterceptor; + +impl Interceptor for MyInterceptor { + fn call(&mut self, request: tonic::Request<()>) -> Result<tonic::Request<()>, Status> { + Ok(request) + } +} diff --git a/crates/auth/src/server/routes/authorised.rs b/crates/auth/src/server/routes/authorised.rs index 27f02bc..50fcfc8 100644 --- a/crates/auth/src/server/routes/authorised.rs +++ b/crates/auth/src/server/routes/authorised.rs @@ -19,6 +19,7 @@ use tower_sessions::{ use uuid::Uuid; use crate::{ + auth::Claims, error::AppError, server::{ OAUTH_CSRF_COOKIE, csrf_token_validation::csrf_token_validation_workflow, routes::Provider, @@ -55,16 +56,6 @@ struct DbUser { const SESSION_COOKIE: &str = "info"; const SESSION_DATA_KEY: &str = "data"; -#[derive(Debug, Serialize, Deserialize)] -struct Claims { - iss: String, - sub: Uuid, - exp: i64, - iat: i64, - sid: String, - aud: String, -} - pub async fn login_authorised( Query(query): Query<AuthRequest>, State(state): State<AppHandle>, |