blob: b733dddc5123493d954554eba187c895c1b27be0 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use crate::acs::{AccessControlModule, EnforceRequest};
use crate::error::TeaclavAccessControlError;
use teaclave_proto::teaclave_access_control_service::{
AuthorizeDataRequest, AuthorizeDataResponse, AuthorizeFunctionRequest,
AuthorizeFunctionResponse, AuthorizeStagedTaskRequest, AuthorizeStagedTaskResponse,
AuthorizeTaskRequest, AuthorizeTaskResponse, TeaclaveAccessControl,
};
use teaclave_rpc::{Request, Response};
use teaclave_service_enclave_utils::bail;
use teaclave_types::TeaclaveServiceResponseResult;
#[derive(Clone)]
pub(crate) struct TeaclaveAccessControlService {
access_control_module: AccessControlModule,
}
impl TeaclaveAccessControlService {
pub(crate) fn new() -> Self {
TeaclaveAccessControlService {
access_control_module: AccessControlModule::new(),
}
}
}
#[teaclave_rpc::async_trait]
impl TeaclaveAccessControl for TeaclaveAccessControlService {
async fn authorize_data(
&self,
request: Request<AuthorizeDataRequest>,
) -> TeaclaveServiceResponseResult<AuthorizeDataResponse> {
let request = request.into_inner();
let request =
EnforceRequest::UserAccessData(request.subject_user_id, request.object_data_id);
match self.access_control_module.enforce_request(request) {
Ok(accept) => {
let response = AuthorizeDataResponse::new(accept);
Ok(Response::new(response))
}
Err(_) => Err(TeaclavAccessControlError::AccessControlError.into()),
}
}
async fn authorize_function(
&self,
request: Request<AuthorizeFunctionRequest>,
) -> TeaclaveServiceResponseResult<AuthorizeFunctionResponse> {
let request = request.into_inner();
let request =
EnforceRequest::UserAccessFunction(request.subject_user_id, request.object_function_id);
match self.access_control_module.enforce_request(request) {
Ok(accept) => {
let response = AuthorizeFunctionResponse::new(accept);
Ok(Response::new(response))
}
Err(_) => Err(TeaclavAccessControlError::AccessControlError.into()),
}
}
async fn authorize_task(
&self,
request: Request<AuthorizeTaskRequest>,
) -> TeaclaveServiceResponseResult<AuthorizeTaskResponse> {
let request = request.into_inner();
let request =
EnforceRequest::UserAccessTask(request.subject_user_id, request.object_task_id);
match self.access_control_module.enforce_request(request) {
Ok(accept) => {
let response = AuthorizeTaskResponse::new(accept);
Ok(Response::new(response))
}
Err(_) => Err(TeaclavAccessControlError::AccessControlError.into()),
}
}
async fn authorize_staged_task(
&self,
request: Request<AuthorizeStagedTaskRequest>,
) -> TeaclaveServiceResponseResult<AuthorizeStagedTaskResponse> {
let request = request.into_inner();
let enforce_access_function_request = EnforceRequest::TaskAccessFunction(
request.subject_task_id.clone(),
request.object_function_id,
);
match self
.access_control_module
.enforce_request(enforce_access_function_request)
{
Ok(accept) => {
if !accept {
return Ok(Response::new(AuthorizeStagedTaskResponse::new(false)));
}
}
Err(_) => bail!(TeaclavAccessControlError::AccessControlError),
}
for object_data_id in request.object_input_data_id_list.iter() {
let enforce_access_data_request = EnforceRequest::TaskAccessData(
request.subject_task_id.clone(),
object_data_id.to_string(),
);
match self
.access_control_module
.enforce_request(enforce_access_data_request)
{
Ok(accept) => {
if !accept {
return Ok(Response::new(AuthorizeStagedTaskResponse::new(false)));
}
}
Err(_) => bail!(TeaclavAccessControlError::AccessControlError),
}
}
for object_data_id in request.object_output_data_id_list.iter() {
let enforce_access_data_request = EnforceRequest::TaskAccessData(
request.subject_task_id.clone(),
object_data_id.to_string(),
);
match self
.access_control_module
.enforce_request(enforce_access_data_request)
{
Ok(accept) => {
if !accept {
return Ok(Response::new(AuthorizeStagedTaskResponse::new(false)));
}
}
Err(_) => bail!(TeaclavAccessControlError::AccessControlError),
}
}
Ok(Response::new(AuthorizeStagedTaskResponse { accept: true }))
}
}
#[cfg(feature = "enclave_unit_test")]
pub mod tests {
use super::*;
use teaclave_rpc::IntoRequest;
pub async fn user_access_data() {
let service = TeaclaveAccessControlService::new();
let request = AuthorizeDataRequest::new("mock_user_a", "mock_data").into_request();
let response = service.authorize_data(request).await;
assert!(response.is_ok());
assert!(response.unwrap().into_inner().accept);
let request = AuthorizeDataRequest::new("mock_user_b", "mock_data").into_request();
let response = service.authorize_data(request).await;
assert!(response.is_ok());
assert!(response.unwrap().into_inner().accept);
let request = AuthorizeDataRequest::new("mock_user_c", "mock_data").into_request();
let response = service.authorize_data(request).await;
assert!(response.is_ok());
assert!(response.unwrap().into_inner().accept);
let request = AuthorizeDataRequest::new("mock_user_d", "mock_data").into_request();
let response = service.authorize_data(request).await;
assert!(response.is_ok());
assert!(!response.unwrap().into_inner().accept);
let request = AuthorizeDataRequest::new("mock_user_a", "mock_data_b").into_request();
let response = service.authorize_data(request).await;
assert!(response.is_ok());
assert!(!response.unwrap().into_inner().accept);
}
pub async fn user_access_function() {
let service = TeaclaveAccessControlService::new();
let request =
AuthorizeFunctionRequest::new("mock_public_function_owner", "mock_public_function")
.into_request();
let response = service.authorize_function(request).await;
assert!(response.is_ok());
assert!(response.unwrap().into_inner().accept);
let request =
AuthorizeFunctionRequest::new("mock_private_function_owner", "mock_private_function")
.into_request();
let response = service.authorize_function(request).await;
assert!(response.is_ok());
assert!(response.unwrap().into_inner().accept);
let request =
AuthorizeFunctionRequest::new("mock_private_function_owner", "mock_public_function")
.into_request();
let response = service.authorize_function(request).await;
assert!(response.is_ok());
assert!(response.unwrap().into_inner().accept);
let request =
AuthorizeFunctionRequest::new("mock_public_function_owner", "mock_private_function")
.into_request();
let response = service.authorize_function(request).await;
assert!(response.is_ok());
assert!(!response.unwrap().into_inner().accept);
}
pub async fn user_access_task() {
let service = TeaclaveAccessControlService::new();
let request = AuthorizeTaskRequest::new("mock_participant_a", "mock_task").into_request();
let response = service.authorize_task(request).await;
assert!(response.is_ok());
assert!(response.unwrap().into_inner().accept);
let request = AuthorizeTaskRequest::new("mock_participant_b", "mock_task").into_request();
let response = service.authorize_task(request).await;
assert!(response.is_ok());
assert!(response.unwrap().into_inner().accept);
let request = AuthorizeTaskRequest::new("mock_participant_c", "mock_task").into_request();
let response = service.authorize_task(request).await;
assert!(response.is_ok());
assert!(!response.unwrap().into_inner().accept);
}
pub async fn task_access_function() {
let service = TeaclaveAccessControlService::new();
let mut request = get_correct_authorized_stage_task_req();
request.object_function_id = "mock_staged_allowed_private_function".to_string();
let response = service.authorize_staged_task(request.into_request()).await;
assert!(response.is_ok());
assert!(response.unwrap().into_inner().accept);
let mut request = get_correct_authorized_stage_task_req();
request.object_function_id = "mock_staged_public_function".to_string();
let response = service.authorize_staged_task(request.into_request()).await;
assert!(response.is_ok());
assert!(response.unwrap().into_inner().accept);
let mut request = get_correct_authorized_stage_task_req();
request.object_function_id = "mock_staged_disallowed_private_function".to_string();
let response = service.authorize_staged_task(request.into_request()).await;
assert!(response.is_ok());
assert!(!response.unwrap().into_inner().accept);
}
fn get_correct_authorized_stage_task_req() -> AuthorizeStagedTaskRequest {
AuthorizeStagedTaskRequest {
subject_task_id: "mock_staged_task".to_string(),
object_function_id: "mock_staged_allowed_private_function".to_string(),
object_input_data_id_list: vec![
"mock_staged_allowed_data1".to_string(),
"mock_staged_allowed_data2".to_string(),
"mock_staged_allowed_data3".to_string(),
],
object_output_data_id_list: vec![
"mock_staged_allowed_data1".to_string(),
"mock_staged_allowed_data2".to_string(),
"mock_staged_allowed_data3".to_string(),
],
}
}
pub async fn task_access_data() {
let service = TeaclaveAccessControlService::new();
let request = get_correct_authorized_stage_task_req().into_request();
let response = service.authorize_staged_task(request).await;
assert!(response.is_ok());
assert!(response.unwrap().into_inner().accept);
let mut request = get_correct_authorized_stage_task_req();
request
.object_input_data_id_list
.push("mock_staged_disallowed_data1".to_string());
let response = service.authorize_staged_task(request.into_request()).await;
assert!(response.is_ok());
assert!(!response.unwrap().into_inner().accept);
let mut request = get_correct_authorized_stage_task_req();
request
.object_input_data_id_list
.push("mock_staged_disallowed_data2".to_string());
let response = service.authorize_staged_task(request.into_request()).await;
assert!(response.is_ok());
assert!(!response.unwrap().into_inner().accept);
let mut request = get_correct_authorized_stage_task_req();
request
.object_output_data_id_list
.push("mock_staged_disallowed_data1".to_string());
let response = service.authorize_staged_task(request.into_request()).await;
assert!(response.is_ok());
assert!(!response.unwrap().into_inner().accept);
let mut request = get_correct_authorized_stage_task_req();
request
.object_output_data_id_list
.push("mock_staged_disallowed_data2".to_string());
let response = service.authorize_staged_task(request.into_request()).await;
assert!(response.is_ok());
assert!(!response.unwrap().into_inner().accept);
}
}