tonic rbac to tower
This commit is contained in:
@@ -1,102 +1,36 @@
|
||||
// src/auth/logic/rbac.rs
|
||||
use tonic::{Request, Status};
|
||||
use crate::auth::logic::jwt;
|
||||
|
||||
// Define roles constants to match database constraints
|
||||
pub const ROLE_VIEWER: &str = "viewer";
|
||||
pub const ROLE_ACCOUNTANT: &str = "accountant";
|
||||
pub const ROLE_MODERATOR: &str = "moderator";
|
||||
pub const ROLE_ADMIN: &str = "admin";
|
||||
use tower::ServiceBuilder;
|
||||
use crate::auth::logic::rbac;
|
||||
|
||||
// Role-check interceptor functions
|
||||
pub fn require_roles<T>(roles: Vec<String>, req: Request<T>) -> Result<Request<T>, Status> {
|
||||
let token = match req.metadata().get("authorization") {
|
||||
Some(token) => match token.to_str() {
|
||||
Ok(t) => t,
|
||||
Err(_) => return Err(Status::unauthenticated("Invalid authorization header")),
|
||||
},
|
||||
None => return Err(Status::unauthenticated("Missing authorization header")),
|
||||
};
|
||||
|
||||
// Strip 'Bearer ' prefix if present
|
||||
let token = token.strip_prefix("Bearer ")
|
||||
.unwrap_or(token);
|
||||
|
||||
// Validate the token and get claims
|
||||
let claims = match jwt::validate_token(token) {
|
||||
Ok(claims) => claims,
|
||||
Err(_) => return Err(Status::unauthenticated("Invalid token")),
|
||||
};
|
||||
|
||||
// Check if user role is allowed
|
||||
if !roles.contains(&claims.role) {
|
||||
tracing::warn!(
|
||||
user_id = %claims.sub,
|
||||
user_role = %claims.role,
|
||||
required_roles = ?roles,
|
||||
"Access denied: insufficient permissions"
|
||||
);
|
||||
return Err(Status::permission_denied("Insufficient permissions"));
|
||||
}
|
||||
|
||||
// Add claims to request extensions for handler access
|
||||
let mut req = req;
|
||||
req.extensions_mut().insert(claims);
|
||||
|
||||
Ok(req)
|
||||
}
|
||||
|
||||
// Convenience function for admin-only endpoints
|
||||
pub fn admin_only<T>(req: Request<T>) -> Result<Request<T>, Status> {
|
||||
require_roles(vec![ROLE_ADMIN.to_string()], req)
|
||||
}
|
||||
|
||||
// Convenience function for admin and moderator endpoints
|
||||
pub fn admin_moderator<T>(req: Request<T>) -> Result<Request<T>, Status> {
|
||||
require_roles(
|
||||
vec![
|
||||
ROLE_MODERATOR.to_string(),
|
||||
ROLE_ADMIN.to_string()
|
||||
],
|
||||
req
|
||||
)
|
||||
}
|
||||
|
||||
// Convenience function for accountants and higher (more privileges)
|
||||
pub fn accountant_and_higher<T>(req: Request<T>) -> Result<Request<T>, Status> {
|
||||
require_roles(
|
||||
vec![
|
||||
ROLE_ACCOUNTANT.to_string(),
|
||||
ROLE_MODERATOR.to_string(),
|
||||
ROLE_ADMIN.to_string()
|
||||
],
|
||||
req
|
||||
)
|
||||
}
|
||||
|
||||
// Convenience function for any authenticated user
|
||||
pub fn any_authenticated_user<T>(req: Request<T>) -> Result<Request<T>, Status> {
|
||||
require_roles(
|
||||
vec![
|
||||
ROLE_VIEWER.to_string(),
|
||||
ROLE_ACCOUNTANT.to_string(),
|
||||
ROLE_MODERATOR.to_string(),
|
||||
ROLE_ADMIN.to_string()
|
||||
],
|
||||
req
|
||||
)
|
||||
}
|
||||
|
||||
// Helper to get a user's role from the request
|
||||
pub fn get_user_role<T>(req: &Request<T>) -> Option<&str> {
|
||||
req.extensions()
|
||||
.get::<jwt::Claims>()
|
||||
.map(|claims| claims.role.as_str())
|
||||
}
|
||||
|
||||
// Helper to get a user's ID from the request
|
||||
pub fn get_user_id<T>(req: &Request<T>) -> Option<uuid::Uuid> {
|
||||
req.extensions()
|
||||
.get::<jwt::Claims>()
|
||||
.map(|claims| claims.sub)
|
||||
pub async fn run_server(db_pool: sqlx::PgPool) -> Result<(), Box<dyn std::error::Error>> {
|
||||
// ... existing setup code ...
|
||||
|
||||
// Create service layers
|
||||
let adresar_layer = ServiceBuilder::new()
|
||||
.layer(rbac::create_adresar_layer())
|
||||
.into_inner();
|
||||
|
||||
let uctovnictvo_layer = ServiceBuilder::new()
|
||||
.layer(rbac::create_uctovnictvo_layer())
|
||||
.into_inner();
|
||||
|
||||
// Create services with layers
|
||||
let adresar_service = AdresarServer::new(AdresarService { db_pool: db_pool.clone() })
|
||||
.layer(adresar_layer);
|
||||
|
||||
let uctovnictvo_service = UctovnictvoServer::new(UctovnictvoService { db_pool: db_pool.clone() })
|
||||
.layer(uctovnictvo_layer);
|
||||
|
||||
// ... repeat for other services ...
|
||||
|
||||
Server::builder()
|
||||
.add_service(auth_server)
|
||||
.add_service(adresar_service)
|
||||
.add_service(uctovnictvo_service)
|
||||
// ... other services ...
|
||||
.serve(addr)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user