Skip to content
Clone
main
168 lines 5.6 KB Rust
//! 内部 RPC 的 space 域:把资源 id 解析到目录后复用权限内核(Access/Capability)。
use internal::Gate;
use internal::server::InternalRouter;
use proto::internal::v1::issue_authorization_service_server::{
IssueAuthorizationService as IssueAuthorizationTrait, IssueAuthorizationServiceServer,
};
use proto::internal::v1::pull_authorization_service_server::{
PullAuthorizationService as PullAuthorizationTrait, PullAuthorizationServiceServer,
};
use proto::internal::v1::space_authorization_service_server::{
SpaceAuthorizationService as SpaceAuthorizationTrait, SpaceAuthorizationServiceServer,
};
use proto::internal::v1::{
AuthorizationDecision, AuthorizeIssueRequest, AuthorizePullRequest, AuthorizeResourceRequest,
SpaceMembersRequest, SpaceMembersResponse,
};
use tonic::{Request, Response, Status};
use crate::errors::SpaceError;
use crate::services::service::SpaceService;
mod space_directory;
pub fn register(router: InternalRouter, service: &SpaceService, gate: Gate) -> InternalRouter {
let rpc = SpaceRpc {
service: service.clone(),
};
let router = space_directory::register(router, service, gate.clone());
let router = router.add_service(IssueAuthorizationServiceServer::with_interceptor(
rpc.clone(),
gate.clone(),
));
let router = router.add_service(PullAuthorizationServiceServer::with_interceptor(
rpc.clone(),
gate.clone(),
));
let router = router.add_service(SpaceAuthorizationServiceServer::with_interceptor(
rpc.clone(),
gate.clone(),
));
router
}
#[derive(Clone)]
struct SpaceRpc {
service: SpaceService,
}
fn resource_id(value: &str) -> Result<uuid::Uuid, Status> {
value
.parse()
.map_err(|_| Status::invalid_argument("resource id must be a UUID"))
}
#[tonic::async_trait]
impl IssueAuthorizationTrait for SpaceRpc {
async fn authorize_issue(
&self,
request: Request<AuthorizeIssueRequest>,
) -> Result<Response<AuthorizationDecision>, Status> {
let _meta = internal::interceptor::meta(&request)?;
let request = request.into_inner();
let issue_id = resource_id(&request.issue_id)?;
let allowed = self
.service
.authorize_internal_issue(request.user_id, issue_id)
.await
.map_err(status_of)?;
Ok(Response::new(AuthorizationDecision {
allowed,
reason: String::new(),
resource_id: request.issue_id,
}))
}
}
#[tonic::async_trait]
impl PullAuthorizationTrait for SpaceRpc {
async fn authorize_pull(
&self,
request: Request<AuthorizePullRequest>,
) -> Result<Response<AuthorizationDecision>, Status> {
let _meta = internal::interceptor::meta(&request)?;
let request = request.into_inner();
let pull_id = resource_id(&request.pull_id)?;
let allowed = self
.service
.authorize_internal_pull(request.user_id, pull_id)
.await
.map_err(status_of)?;
Ok(Response::new(AuthorizationDecision {
allowed,
reason: String::new(),
resource_id: request.pull_id,
}))
}
}
#[tonic::async_trait]
impl SpaceAuthorizationTrait for SpaceRpc {
async fn authorize_repo(
&self,
request: Request<AuthorizeResourceRequest>,
) -> Result<Response<AuthorizationDecision>, Status> {
let _meta = internal::interceptor::meta(&request)?;
let request = request.into_inner();
let repo_id = resource_id(&request.repo_id)?;
let allowed = self
.service
.authorize_internal_repo(request.user_id, repo_id)
.await
.map_err(status_of)?;
Ok(Response::new(AuthorizationDecision {
allowed,
reason: String::new(),
resource_id: request.repo_id,
}))
}
async fn authorize_space(
&self,
request: Request<AuthorizeResourceRequest>,
) -> Result<Response<AuthorizationDecision>, Status> {
let _meta = internal::interceptor::meta(&request)?;
let request = request.into_inner();
let space_id = resource_id(&request.space_id)?;
let allowed = self
.service
.authorize_internal_space(request.user_id, space_id)
.await
.map_err(status_of)?;
Ok(Response::new(AuthorizationDecision {
allowed,
reason: String::new(),
resource_id: request.space_id,
}))
}
async fn list_members(
&self,
request: Request<SpaceMembersRequest>,
) -> Result<Response<SpaceMembersResponse>, Status> {
let _meta = internal::interceptor::meta(&request)?;
let request = request.into_inner();
let space_id = resource_id(&request.space_id)?;
let user_ids = self
.service
.internal_space_member_ids(space_id)
.await
.map_err(status_of)?;
Ok(Response::new(SpaceMembersResponse { user_ids }))
}
}
fn status_of(error: SpaceError) -> Status {
match error {
SpaceError::Unauthorized => Status::unauthenticated("space authorization rejected"),
SpaceError::Forbidden | SpaceError::NotFound | SpaceError::SpaceNotFound => {
Status::permission_denied("not allowed")
}
SpaceError::BadRequest(message) => Status::invalid_argument(message),
other => {
tracing::warn!(%other, "internal space authorization failed");
Status::internal("space authorization failed")
}
}
}