You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesatee.apache.org by ur...@apache.org on 2019/11/20 02:35:30 UTC
[incubator-mesatee] branch acs updated: More acs implementation
This is an automated email from the ASF dual-hosted git repository.
uraj pushed a commit to branch acs
in repository https://gitbox.apache.org/repos/asf/incubator-mesatee.git
The following commit(s) were added to refs/heads/acs by this push:
new 99d6f30 More acs implementation
99d6f30 is described below
commit 99d6f30501479171cb129c4bc1af6e2975154568
Author: Pei Wang <wa...@baidu.com>
AuthorDate: Thu Nov 7 14:41:49 2019 -0800
More acs implementation
---
CMakeLists.txt | 2 +-
Makefile | 2 +-
mesatee_core/src/error.rs | 7 +-
mesatee_services/acs/client/src/acs_client.rs | 115 +++++++--
mesatee_services/acs/client/src/lib.rs | 2 +-
mesatee_services/acs/model.conf | 41 ++--
mesatee_services/acs/proto/Cargo.toml | 6 +-
mesatee_services/acs/proto/src/lib.rs | 2 +-
mesatee_services/acs/proto/src/proto.rs | 156 +++---------
.../acs/python/{perm.py => acs_engine.py} | 266 ++++++++------------
mesatee_services/acs/python/acs_engine_test.py | 82 +++++++
mesatee_services/acs/python/ffi.py | 8 +-
mesatee_services/acs/sgx_trusted_lib/src/acs.rs | 254 ++++++++++++++------
mesatee_services/acs/sgx_trusted_lib/src/sgx.rs | 32 +--
tests/functional_test.sh | 10 +-
tests/functional_test/sgx_trusted_lib/Cargo.toml | 3 +-
tests/functional_test/sgx_trusted_lib/src/sgx.rs | 1 +
.../sgx_trusted_lib/src/tests/acs_test.rs | 267 +++++++++++++++++++++
.../sgx_trusted_lib/src/tests/common_setup.rs | 7 +
.../sgx_trusted_lib/src/tests/mod.rs | 1 +
20 files changed, 848 insertions(+), 416 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6f8de9a..3d54dcb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,7 +24,7 @@ dbscan neural_net naive_bayes gbdt mesatee_cli)
set(UNIX_LIBS mesatee_sdk protected_fs_rs)
# need relative path for SGX_MODULE_PATHS to find Enclave.config.xml
set(SGX_MODULE_PATHS mesatee_services/kms mesatee_services/tdfs mesatee_services/tms
- mesatee_services/fns tests/functional_test)
+ mesatee_services/fns mesatee_services/acs tests/functional_test)
# SGX_MODULES is generated from SGX_MODULE_PATHS
# set(SGX_MODULES kms tdfs tms fns functional_test)
# ================ VARIABLES FOR MANUAL CHANGE END ================
diff --git a/Makefile b/Makefile
index ee3d9be..7fcca99 100644
--- a/Makefile
+++ b/Makefile
@@ -243,7 +243,7 @@ pycomponent: $(OUT_DIR)/libpycomponent.a
$(OUT_DIR)/libpycomponent.a: $(OUT_DIR)/acs_py_enclave.o
cd $(OUT_DIR) && ar rcs $@ $?
-$(OUT_DIR)/acs_py_enclave.c: mesatee_services/acs/python/ffi.py mesatee_services/acs/python/perm.py prep
+$(OUT_DIR)/acs_py_enclave.c: mesatee_services/acs/python/ffi.py mesatee_services/acs/python/acs_engine.py prep
env PYTHONPATH=$(THIRD_PARTY_DIR)/mesapy/sgx PYPY_FFI_OUTDIR=$(OUT_DIR) pypy $<
$(OUT_DIR)/acs_py_enclave.o: $(OUT_DIR)/acs_py_enclave.c
diff --git a/mesatee_core/src/error.rs b/mesatee_core/src/error.rs
index fb67d9c..6c60630 100644
--- a/mesatee_core/src/error.rs
+++ b/mesatee_core/src/error.rs
@@ -113,8 +113,10 @@ pub enum ErrorKind {
IPCError,
/// IAS client key or cert not available
IASClientKeyCertError,
- /// No valid worker for the task,
+ /// No valid worker for the task
NoValidWorkerError,
+ /// Unhandled MesaPy exception encountered
+ MesaPyError,
/// Others.
Unknown,
}
@@ -186,6 +188,7 @@ impl ErrorKind {
"intel attestation service client key/certificate unavailable error"
}
ErrorKind::NoValidWorkerError => "no valid worker error",
+ ErrorKind::MesaPyError => "unhandled mesapy exception",
ErrorKind::Unknown => "unknown error",
}
}
@@ -236,6 +239,7 @@ impl From<u32> for Error {
0x0000_1010 => ErrorKind::IPCError,
0x0000_1011 => ErrorKind::IASClientKeyCertError,
0x0000_1012 => ErrorKind::NoValidWorkerError,
+ 0x0000_1013 => ErrorKind::MesaPyError,
_ => ErrorKind::Unknown,
};
@@ -282,6 +286,7 @@ impl Into<u32> for Error {
ErrorKind::IPCError => 0x0000_1010,
ErrorKind::IASClientKeyCertError => 0x0000_1011,
ErrorKind::NoValidWorkerError => 0x0000_1012,
+ ErrorKind::MesaPyError => 0x0000_1013,
ErrorKind::Unknown => 0xffff_ffff,
}
}
diff --git a/mesatee_services/acs/client/src/acs_client.rs b/mesatee_services/acs/client/src/acs_client.rs
index 6f41da9..9a1ceff 100644
--- a/mesatee_services/acs/client/src/acs_client.rs
+++ b/mesatee_services/acs/client/src/acs_client.rs
@@ -16,50 +16,135 @@
#[cfg(feature = "mesalock_sgx")]
use std::prelude::v1::*;
-use acs_proto::{CreateKeyResponse, DeleteKeyResponse, GetKeyResponse, KMSRequest, KMSResponse};
+use acs_proto::*;
use mesatee_core::config::{OutboundDesc, TargetDesc};
use mesatee_core::rpc::channel::SgxTrustedChannel;
use mesatee_core::{Error, ErrorKind, Result};
-pub struct KMSClient {
- channel: SgxTrustedChannel<KMSRequest, KMSResponse>,
+use std::collections::HashSet;
+
+pub struct ACSClient {
+ channel: SgxTrustedChannel<ACSRequest, ACSResponse>,
}
-impl KMSClient {
+impl ACSClient {
pub fn new(target: TargetDesc) -> Result<Self> {
let addr = target.addr;
let channel = match target.desc {
OutboundDesc::Sgx(enclave_addr) => {
- SgxTrustedChannel::<KMSRequest, KMSResponse>::new(addr, enclave_addr)?
+ SgxTrustedChannel::<ACSRequest, ACSResponse>::new(addr, enclave_addr)?
}
};
- Ok(KMSClient { channel })
+ Ok(ACSClient { channel })
}
- pub fn request_create_key(&mut self) -> Result<CreateKeyResponse> {
- let req = KMSRequest::new_create_key();
+ pub fn enforce_task_launch(
+ &mut self,
+ task: String,
+ participants: HashSet<String>,
+ ) -> Result<bool> {
+ let req = ACSRequest::Enforce(EnforceRequest::LaunchTask(task, participants));
let resp = self.channel.invoke(req)?;
match resp {
- KMSResponse::Create(resp) => Ok(resp),
+ ACSResponse::Enforce(allow) => Ok(allow),
_ => Err(Error::from(ErrorKind::RPCResponseError)),
}
}
- pub fn request_get_key(&mut self, key_id: &str) -> Result<GetKeyResponse> {
- let req = KMSRequest::new_get_key(key_id);
+ pub fn enforce_data_access(
+ &mut self,
+ task: String,
+ data: String
+ ) -> Result<bool> {
+ let req = ACSRequest::Enforce(EnforceRequest::AccessData(task, data));
let resp = self.channel.invoke(req)?;
match resp {
- KMSResponse::Get(resp) => Ok(resp),
+ ACSResponse::Enforce(allow) => Ok(allow),
_ => Err(Error::from(ErrorKind::RPCResponseError)),
}
}
- pub fn request_del_key(&mut self, key_id: &str) -> Result<DeleteKeyResponse> {
- let req = KMSRequest::new_del_key(key_id);
+ pub fn enforce_data_deletion(
+ &mut self,
+ usr: String,
+ data: String,
+ ) -> Result<bool> {
+ let req = ACSRequest::Enforce(EnforceRequest::DeleteData(usr, data));
let resp = self.channel.invoke(req)?;
match resp {
- KMSResponse::Delete(resp) => Ok(resp),
+ ACSResponse::Enforce(allow) => Ok(allow),
_ => Err(Error::from(ErrorKind::RPCResponseError)),
}
}
+
+ pub fn enforce_script_access(
+ &mut self,
+ task: String,
+ script: String,
+ ) -> Result<bool> {
+ let req = ACSRequest::Enforce(EnforceRequest::AccessScript(task, script));
+ let resp = self.channel.invoke(req)?;
+ match resp {
+ ACSResponse::Enforce(allow) => Ok(allow),
+ _ => Err(Error::from(ErrorKind::RPCResponseError)),
+ }
+ }
+
+ pub fn enforce_script_deletion(
+ &mut self,
+ usr: String,
+ script: String
+ ) -> Result<bool> {
+ let req = ACSRequest::Enforce(EnforceRequest::DeleteScript(usr, script));
+ let resp = self.channel.invoke(req)?;
+ match resp {
+ ACSResponse::Enforce(allow) => Ok(allow),
+ _ => Err(Error::from(ErrorKind::RPCResponseError)),
+ }
+ }
+
+ fn _announce_terms(&mut self, facts: Vec<AccessControlTerms>) -> Result<()> {
+ let req = ACSRequest::Announce(AnnounceRequest { facts });
+ let resp = self.channel.invoke(req)?;
+ match resp {
+ ACSResponse::Announce => Ok(()),
+ _ => Err(Error::from(ErrorKind::RPCResponseError)),
+ }
+ }
+
+ pub fn announce_task_creation(
+ &mut self,
+ task: String,
+ creator: String,
+ participants: &HashSet<String>,
+ ) -> Result<()> {
+ let mut facts = Vec::with_capacity(1 + participants.len());
+ for par in participants {
+ facts.push(AccessControlTerms::TaskParticipant(task.clone(), par.clone()));
+ }
+ facts.push(AccessControlTerms::TaskCreator(task, creator));
+ self._announce_terms(facts)
+ }
+
+ pub fn announce_data_creation(
+ &mut self,
+ data: String,
+ creator: String,
+ ) -> Result<()> {
+ self._announce_terms(std::vec!(AccessControlTerms::DataOwner(data, creator)))
+ }
+
+ pub fn announce_script_creation(
+ &mut self,
+ script: String,
+ creator: String,
+ is_public: bool,
+ ) -> Result<()> {
+ let mut terms = Vec::new();
+ if is_public {
+ terms.push(AccessControlTerms::IsPublicScript(script.clone()))
+ }
+ terms.push(AccessControlTerms::ScriptOwner(script, creator));
+ self._announce_terms(terms)
+ }
}
diff --git a/mesatee_services/acs/client/src/lib.rs b/mesatee_services/acs/client/src/lib.rs
index a5d844c..f774564 100644
--- a/mesatee_services/acs/client/src/lib.rs
+++ b/mesatee_services/acs/client/src/lib.rs
@@ -18,4 +18,4 @@
extern crate sgx_tstd as std;
mod acs_client;
-pub use acs_client::KMSClient;
+pub use acs_client::ACSClient;
diff --git a/mesatee_services/acs/model.conf b/mesatee_services/acs/model.conf
index 2ab31d9..7e30003 100644
--- a/mesatee_services/acs/model.conf
+++ b/mesatee_services/acs/model.conf
@@ -1,21 +1,32 @@
-# request definition
-[request_definition]
-r = sub, obj, act
-r2 = sub, obj
-r3 = task, participants
+[requests]
+launch_task = task, participants
+access_data = task, data
+delete_data = usr, data
+access_script = task, script
+delete_script = usr, script
-[policy_definition]
-p = sub, obj, act
+[terms]
+task_creator = task, usr
+task_participant = task, usr
-[term_definition]
-g = sub, grp
-c = task, usr
+script_owner = script, usr
+is_public_script = script
-[policy_effect]
-allow-and-deny
+data_owner = data, usr
[matchers]
-r = (r.sub == p.sub and r.obj == p.obj and r.act == p.act) or (g(r.sub, 'admin') and not g(r.sub, 'blklist'))
-r2 = r2.sub == r2.obj.Owner
-r3 = all(usr in r3.participants for usr, in c(r3.task, _))
+# All participants must approve task launch
+launch_task = task_participant(launch_task.task, _) <= launch_task.participants
+# All participants must approve data access
+access_data = data_owner(access_data.data, _) <= task_participant(access_data.task, _)
+
+# Any creator of the data can request for deletion
+delete_data = data_owner(delete_data.data, delete_data.usr)
+
+access_script = \
+ is_public_script(access_script.script) or \
+ script_owner(access_script.script, _) <= task_participant(access_script.task, _)
+
+# Only creator of the script can request for deletion
+delete_script = script_owner(delete_script.script, delete_script.usr)
\ No newline at end of file
diff --git a/mesatee_services/acs/proto/Cargo.toml b/mesatee_services/acs/proto/Cargo.toml
index 7676954..55be836 100644
--- a/mesatee_services/acs/proto/Cargo.toml
+++ b/mesatee_services/acs/proto/Cargo.toml
@@ -12,14 +12,12 @@ mesalock_sgx = ["sgx_tstd", "mesatee_core/mesalock_sgx"]
cov = ["sgx_cov"]
[dependencies]
-cfg-if = { version = "0.1.9" }
+mesatee_core = { version = "0.1.0" }
serde = { version = "1.0.39" }
serde_json = { version = "1.0.39" }
serde_derive = { version = "1.0.92" }
-rand = { version = "0.7.0" }
-base64 = { version = "0.10.1" }
+uuid = { version = "0.7.4", features = ["v4"] }
-mesatee_core = { version = "0.1.0" }
sgx_cov = { version = "0.1.0", optional = true }
sgx_tstd = { version = "1.0.9", features = ["net", "backtrace"], optional = true }
sgx_types = { version = "1.0.9" }
diff --git a/mesatee_services/acs/proto/src/lib.rs b/mesatee_services/acs/proto/src/lib.rs
index ddee753..ff8f727 100644
--- a/mesatee_services/acs/proto/src/lib.rs
+++ b/mesatee_services/acs/proto/src/lib.rs
@@ -13,7 +13,7 @@
// limitations under the License.
#![cfg_attr(feature = "mesalock_sgx", no_std)]
#[cfg(feature = "mesalock_sgx")]
-#[macro_use]
+
extern crate sgx_tstd as std;
mod proto;
diff --git a/mesatee_services/acs/proto/src/proto.rs b/mesatee_services/acs/proto/src/proto.rs
index 3cc2bf4..78c63f1 100644
--- a/mesatee_services/acs/proto/src/proto.rs
+++ b/mesatee_services/acs/proto/src/proto.rs
@@ -16,148 +16,60 @@
#[cfg(feature = "mesalock_sgx")]
use std::prelude::v1::*;
-use mesatee_core;
-use mesatee_core::Result;
+use std::collections::HashSet;
+
use serde_derive::*;
#[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(tag = "type")]
-pub enum KMSRequest {
- Create(CreateKeyRequest),
- Get(GetKeyRequest),
- Delete(DeleteKeyRequest),
+pub enum ACSRequest {
+ Enforce(EnforceRequest),
+ Announce(AnnounceRequest),
}
#[derive(Clone, Serialize, Deserialize, Debug)]
-#[serde(tag = "type")]
-pub enum KMSResponse {
- Create(CreateKeyResponse),
- Get(GetKeyResponse),
- Delete(DeleteKeyResponse),
-}
-
-#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
-pub struct AEADKeyConfig {
- #[serde(with = "base64_coder")]
- pub key: Vec<u8>,
- #[serde(with = "base64_coder")]
- pub nonce: Vec<u8>,
- #[serde(with = "base64_coder")]
- pub ad: Vec<u8>,
+pub enum ACSResponse {
+ Enforce(bool),
+ Announce,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
-pub struct CreateKeyRequest {}
+pub enum EnforceRequest {
+ // launch_task = task, participants
+ LaunchTask(String, HashSet<String>),
-#[derive(Clone, Serialize, Deserialize, Debug)]
-pub struct CreateKeyResponse {
- pub key_id: String,
- pub config: AEADKeyConfig,
-}
+ // access_data = task, data
+ AccessData(String, String),
+
+ // delete_data = usr, data
+ DeleteData(String, String),
-#[derive(Clone, Serialize, Deserialize, Debug)]
-pub struct GetKeyRequest {
- pub key_id: String,
-}
+ // access_script = task, script
+ AccessScript(String, String),
-#[derive(Clone, Serialize, Deserialize, Debug)]
-pub struct GetKeyResponse {
- pub config: AEADKeyConfig,
+ // delete_script = usr, script
+ DeleteScript(String, String),
}
#[derive(Clone, Serialize, Deserialize, Debug)]
-pub struct DeleteKeyRequest {
- pub key_id: String,
+pub struct AnnounceRequest {
+ pub facts: Vec<AccessControlTerms>,
}
#[derive(Clone, Serialize, Deserialize, Debug)]
-pub struct DeleteKeyResponse {
- pub config: AEADKeyConfig,
-}
-
-impl KMSRequest {
- pub fn new_create_key() -> KMSRequest {
- KMSRequest::Create(CreateKeyRequest {})
- }
-
- pub fn new_get_key(key_id: &str) -> KMSRequest {
- let req = GetKeyRequest {
- key_id: key_id.to_owned(),
- };
- KMSRequest::Get(req)
- }
-
- pub fn new_del_key(key_id: &str) -> KMSRequest {
- let req = DeleteKeyRequest {
- key_id: key_id.to_owned(),
- };
- KMSRequest::Delete(req)
- }
-}
-
-impl KMSResponse {
- pub fn new_create_key(key_id: &str, key: &AEADKeyConfig) -> KMSResponse {
- let resp = CreateKeyResponse {
- key_id: key_id.to_owned(),
- config: key.clone(),
- };
- KMSResponse::Create(resp)
- }
-
- pub fn new_get_key(config: &AEADKeyConfig) -> KMSResponse {
- let resp = GetKeyResponse {
- config: config.clone(),
- };
- KMSResponse::Get(resp)
- }
-
- pub fn new_del_key(config: &AEADKeyConfig) -> KMSResponse {
- let resp = DeleteKeyResponse {
- config: config.clone(),
- };
- KMSResponse::Delete(resp)
- }
-}
-
-impl AEADKeyConfig {
- pub fn new() -> Result<Self> {
- use rand::prelude::RngCore;
-
- let mut key_config = AEADKeyConfig {
- key: vec![0; 32],
- nonce: vec![0; 12],
- ad: vec![0; 5],
- };
-
- let mut rng = rand::thread_rng();
- rng.fill_bytes(&mut key_config.key);
- rng.fill_bytes(&mut key_config.nonce);
- rng.fill_bytes(&mut key_config.ad);
-
- Ok(key_config)
- }
-}
-
-mod base64_coder {
- // Insert std prelude in the top for the sgx feature
- #[cfg(feature = "mesalock_sgx")]
- use std::prelude::v1::*;
+pub enum AccessControlTerms {
+ // task_creator = task, usr
+ TaskCreator(String, String),
+
+ // task_participant = task, usr
+ TaskParticipant(String, String),
- extern crate base64;
- use serde::{de, Deserialize, Deserializer, Serializer};
+ // data_owner = data, usr
+ DataOwner(String, String),
- pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
- where
- S: Serializer,
- {
- serializer.serialize_str(&base64::encode(bytes))
- }
+ // script_owner = script, usr
+ ScriptOwner(String, String),
- pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
- where
- D: Deserializer<'de>,
- {
- let s = <&str>::deserialize(deserializer)?;
- base64::decode(s).map_err(de::Error::custom)
- }
+ // is_public_script = script
+ IsPublicScript(String),
}
diff --git a/mesatee_services/acs/python/perm.py b/mesatee_services/acs/python/acs_engine.py
similarity index 71%
rename from mesatee_services/acs/python/perm.py
rename to mesatee_services/acs/python/acs_engine.py
index 1d2a915..4a12bf4 100644
--- a/mesatee_services/acs/python/perm.py
+++ b/mesatee_services/acs/python/acs_engine.py
@@ -158,11 +158,8 @@ class Parser(object):
def parse_from(self, stream):
n_state = self(stream)
if not n_state:
- print n_state.stream, n_state.payload
raise ParsingError(n_state.stream, n_state.payload)
elif not n_state.stream.end():
- print n_state.stream, 'trailing unparsable input'
- print n_state.stream.pos()
raise ParsingError(n_state.stream, 'trailing unparsable input')
return n_state
@@ -184,15 +181,22 @@ class Parser(object):
def __invert__(self):
return Rep(self)
+ def __neg__(self):
+ return Optional(self)
+
def __pow__(self, f):
return Apply(self, f)
-class Epsilon(Parser):
- def __init__(self):
- super(Epsilon, self).__init__()
+class Optional(Parser):
+ def __init__(self, opt):
+ super(Optional, self).__init__()
+ self.__opt = opt
def __call__(self, stream):
- return State(stream)
+ n_state = self.__opt(stream)
+ if n_state:
+ return n_state.fmap(lambda x: Left(x))
+ return State(stream, Right(None))
class StrLiteral(Parser):
def __init__(self, string):
@@ -375,18 +379,6 @@ Definition = Identifier + Equal + IdTuple + NewLine
Relation = Identifier + Equal + IdTuple + NewLine
Relation = Relation ** (lambda x: (x[0], 1 + len(x[1][1])))
-POLICY_EFFECT_ALLOW_OVERRIDE = 'allow-override'
-POLICY_EFFECT_DENY_OVERRIDE = 'deny-override'
-POLICY_EFFECT_ALLOW_AND_DENY = 'allow-and-deny'
-
-POLICY_EFFECTS = [
- POLICY_EFFECT_ALLOW_OVERRIDE,
- POLICY_EFFECT_DENY_OVERRIDE,
- POLICY_EFFECT_ALLOW_AND_DENY
-]
-
-PolicyEft = one_of(map(StrLiteral, POLICY_EFFECTS)) + NewLine
-
def pyparser_matcher(text, pos):
"""syntactically correct python code"""
line_end = text.find('\n', pos)
@@ -401,19 +393,15 @@ def pyparser_matcher(text, pos):
PyExpr = CustomMatcher(pyparser_matcher)
Matcher = Identifier + Equal + PyExpr + NewLine
-RequestDefHeader = StrLiteral('[request_definition]') + NewLine
-TermDefHeader = StrLiteral('[term_definition]') + NewLine
-PolicyDefHeader = StrLiteral('[policy_definition]') + NewLine
-PolicyEftHeader = StrLiteral('[policy_effect]') + NewLine
+RequestDefHeader = StrLiteral('[requests]') + NewLine
+TermDefHeader = StrLiteral('[terms]') + NewLine
MatchersHeader = StrLiteral('[matchers]') + NewLine
RequestDefSec = RequestDefHeader.ignore() + ~Definition
TermDefSec = TermDefHeader.ignore() + ~Definition
-PolicyDefSec = PolicyDefHeader.ignore() + ~Definition
-PolicyEftSec = PolicyEftHeader.ignore() + PolicyEft
MatchersSec = MatchersHeader.ignore() + ~Matcher
-ModelDef = (RequestDefSec + PolicyDefSec + TermDefSec + PolicyEftSec + MatchersSec) ** flatten
+ModelDef = (RequestDefSec + TermDefSec + MatchersSec) ** flatten
def preprocess(conf):
# process escaped line breaks
@@ -454,7 +442,7 @@ class InvalidModelDefinition(Exception):
msg = 'matcher(s) defined for unknown request type(s): {}'
return InvalidModelDefinition(msg.format(', '.join(unknown_requests)))
-class Policy(object):
+class Request(object):
def __init__(self, attrs, vals):
assert len(attrs) == len(vals)
self.__named_attrs = attrs
@@ -462,7 +450,7 @@ class Policy(object):
setattr(self, attr, val)
def __repr__(self):
- parts = ['Policy {\n']
+ parts = ['Request {\n']
for attr in self.__named_attrs:
parts.append(' ')
parts.append(attr)
@@ -472,11 +460,31 @@ class Policy(object):
parts.append('}\n')
return ''.join(parts)
+class QueryResult(object):
+ def __init__(self, generator):
+ self.__gen = generator
+
+ def __iter__(self):
+ return self.__gen
+
+ def __le__(self, iterable):
+ return set(self) <= set(iterable)
+
+ def __lt__(self, iterable):
+ return set(self) < set(iterable)
+
+ def __ge__(self, iterable):
+ return set(self) >= set(iterable)
+
+ def __gt__(self, iterable):
+ return set(self) > set(iterable)
+
class Term(object):
- WILDCARD = object()
+ PLACEHOLDER = object()
+ WILDCARD = None
def __init__(self, arity):
self.__arity = arity
- self.__facts = []
+ self.__facts = set()
def add_facts(self, facts):
for fact in facts:
@@ -486,15 +494,16 @@ class Term(object):
assert len(fact) == self.__arity
if not isinstance(fact, tuple):
fact = tuple(fact)
- self.__facts.append(fact)
+ self.__facts.add(fact)
def __call__(self, *args):
assert len(args) == self.__arity
# When all arguments are concrete, calling a term just returns boolean results
# indicating whether the called tuple is part of the known facts
- if not any(arg is Term.WILDCARD for arg in args):
+ n_placeholders = sum(arg is Term.PLACEHOLDER for arg in args)
+ if not n_placeholders:
return any(all(a == b for a, b in zip(fact, args)) for fact in self.__facts)
- # If arguments contain one or more wildcards, calling a term is more like a
+ # If arguments contain one or more placeholders, calling a term is more like a
# query. The call returns a generator that iterates all facts that match with
# the pattern described by the arguments
def gen():
@@ -502,28 +511,29 @@ class Term(object):
rns = []
matched = True
for a, b in zip(fact, args):
- if b is Term.WILDCARD:
+ if b is Term.PLACEHOLDER:
rns.append(a)
else:
if a != b:
matched = False
break
if matched:
- yield rns
- return gen()
+ if n_placeholders == 1:
+ yield rns[0]
+ else:
+ yield tuple(rns)
+ return QueryResult(gen())
class Model(object):
def __init__(self, raw_model):
- request_def, policy_def, term_def, effect, matchers = raw_model
+ request_def, term_def, matchers = raw_model
self.__request_template = { r[0]:r[1] for r in request_def }
- self.__policy_template = { p[0]:p[1] for p in policy_def }
self.__term_template = { t[0]:t[1] for t in term_def }
- self.__effect = effect
self.__matchers = { m[0]:m[1] for m in matchers }
def_sections = zip(
- ['request_definition', '[policy_definition]', '[term_definition]'],
- [self.__request_template, self.__policy_template, self.__term_template],
+ ['[requests]', '[terms]'],
+ [self.__request_template, self.__term_template],
)
n_sec = len(def_sections)
@@ -543,32 +553,17 @@ class Model(object):
if unknown_requests:
raise InvalidModelDefinition.unknown_requests(unknown_requests)
- self.__policy_knowledge_base = {
- policy_name:set() for policy_name in self.__policy_template.keys()
- }
self.__term_knowledge_base = {
term_name:Term(len(term_tpl)) for term_name, term_tpl in self.__term_template.items()
}
- def add_policies(self, policies):
- for p in policies:
- tpl = self.__policy_template[p[0]]
- self.__policy_knowledge_base[p[0]].add(Policy(tpl, p[1:]))
-
- def add_policies_from_csv_text(self, csv):
- self.add_policies([
- [p.strip() for p in line.split(',')] for line in csv.splitlines() if line
- ])
-
def add_term_items(self, term_items):
for ti in term_items:
- term = self.__term_knowledge_base[ti[0]]
- term.add_fact(ti[1:])
+ self.add_term_item(ti[0], ti[1:])
- def add_term_items_from_csv_text(self, csv):
- self.add_term_items([
- [p.strip() for p in line.split(',')] for line in csv.splitlines() if line
- ])
+ def add_term_item(self, term_name, fact):
+ term = self.__term_knowledge_base[term_name]
+ term.add_fact(fact)
def get_matcher_proxy(self, request_type, env):
def matcher_proxy():
@@ -577,119 +572,60 @@ class Model(object):
def enforce(self, request_type, request_content):
tpl = self.__request_template[request_type]
- request_policy = Policy(tpl, request_content)
-
- has_allow = False
-
- def decisions(remaining_policy_keys, env):
- if not remaining_policy_keys:
- yield self.get_matcher_proxy(request_type, env)()
- else:
- next_key = remaining_policy_keys[0]
- remaining_policy_keys = remaining_policy_keys[1:]
- policy_candidates = self.__policy_knowledge_base[next_key]
- for policy in policy_candidates:
- env[next_key] = policy
- for d in decisions(remaining_policy_keys, env):
- yield d
+ request = Request(tpl, request_content)
enforcer_env = {
- request_type: request_policy,
+ request_type: request,
'true': True, 'false': False, 'null': None,
- '_': Term.WILDCARD
+ '_': Term.PLACEHOLDER,
+ 'X': Term.WILDCARD,
}
enforcer_env.update(self.__term_knowledge_base)
- for decision in decisions(self.__policy_knowledge_base.keys(), enforcer_env):
- if decision is True:
- return True
- return False
+ return eval(self.__matchers[request_type], enforcer_env)
global_perm_model = None
-if __name__ != '__main__':
+
+if __name__ == '__builtin__':
from acs_py_enclave import ffi
+else:
+ class ffi:
+ @staticmethod
+ def def_extern():
+ return lambda x: x
+
+ @staticmethod
+ def string(s):
+ return s
- @ffi.def_extern()
- def mesapy_setup_model(conf):
+@ffi.def_extern()
+def acs_setup_model(conf):
+ try:
global global_perm_model
- global_perm_model = Model(parse_model(ffi.string(conf)))
-else:
- test_model = """
-# request definition
-[request_definition]
-r = sub, obj, act
-r2 = sub, obj
-r3 = task, participants
-
-[policy_definition]
-p = sub, obj, act
-
-[term_definition]
-g = sub, grp
-c = task, usr
-
-[policy_effect]
-allow-and-deny
-
-[matchers]
-r = (r.sub == p.sub and r.obj == p.obj and r.act == p.act) or (g(r.sub, 'admin') and not g(r.sub, 'blklist'))
-r2 = r2.sub == r2.obj.Owner
-r3 = all(usr in r3.participants for usr, in c(r3.task, _))
-"""
- policy_csv = """
-p, alice, file1, read
-p, bob, file1, read
-p, alice, file2, write
-p, bob, file1, write
-"""
- term_csv = """
-g, charlie, admin
-g, david, admin
-g, david, blklist
-
-c, task1, usr1
-c, task1, usr2
-c, task1, usr3
-"""
- raw_model = parse_model(test_model)
- model = Model(raw_model)
- model.add_policies_from_csv_text(policy_csv)
- model.add_term_items_from_csv_text(term_csv)
-
- assert model.enforce('r', ['alice', 'file1', 'read']) == True
- assert model.enforce('r', ['alice', 'file1', 'write']) == False
- assert model.enforce('r', ['alice', 'file2', 'read']) == False
- assert model.enforce('r', ['alice', 'file2', 'write']) == True
-
- assert model.enforce('r', ['bob', 'file1', 'read']) == True
- assert model.enforce('r', ['bob', 'file1', 'write']) == True
- assert model.enforce('r', ['bob', 'file2', 'read']) == False
- assert model.enforce('r', ['bob', 'file2', 'write']) == False
-
- assert model.enforce('r', ['charlie', 'file1', 'read']) == True
- assert model.enforce('r', ['charlie', 'file1', 'write']) == True
- assert model.enforce('r', ['charlie', 'file2', 'read']) == True
- assert model.enforce('r', ['charlie', 'file2', 'write']) == True
-
- assert model.enforce('r', ['david', 'file1', 'read']) == False
- assert model.enforce('r', ['david', 'file1', 'write']) == False
- assert model.enforce('r', ['david', 'file2', 'read']) == False
- assert model.enforce('r', ['david', 'file2', 'write']) == False
-
- class ABACObj(object):
- def __init__(self, name, owner):
- self.Name = name
- self.Owner = owner
-
- r2obj = ABACObj('alicedata', 'alice')
-
- assert model.enforce('r2', ['charlie', r2obj]) == False
- assert model.enforce('r2', ['alice', r2obj]) == True
-
- assert model.enforce('r3', ['task1', ['usr1', 'usr2', 'usr3']]) == True
- assert model.enforce('r3', ['task1', ['usr1', 'usr3']]) == False
- assert model.enforce('r3', ['task1', ['usr1', 'usr2']]) == False
- assert model.enforce('r3', ['task1', ['usr1']]) == False
- assert model.enforce('r3', ['task1', []]) == False
-
- print 'all access control checks correct!'
+ conf = ffi.string(conf)
+ global_perm_model = Model(parse_model(conf))
+ except:
+ return -1
+ return 0
+
+@ffi.def_extern()
+def acs_enforce_request(request_type, request_content):
+ try:
+ request_type = ffi.string(request_type)
+ # request_content is a list of ffi c strings which are syntactically valid
+ # python primitive-type objects, including strings, integers, foating point
+ # numbers, and lists/dictionaries of primitive-type objects
+ request_content = eval(ffi.string(request_content))
+ return global_perm_model.enforce(request_type, request_content)
+ except:
+ return -1
+
+@ffi.def_extern()
+def acs_announce_fact(term_type, term_fact):
+ try:
+ term_type = ffi.string(term_type)
+ term_fact = eval(ffi.string(term_fact))
+ global_perm_model.add_term_item(term_type, term_fact)
+ except:
+ return -1
+ return 0
diff --git a/mesatee_services/acs/python/acs_engine_test.py b/mesatee_services/acs/python/acs_engine_test.py
new file mode 100644
index 0000000..b951d41
--- /dev/null
+++ b/mesatee_services/acs/python/acs_engine_test.py
@@ -0,0 +1,82 @@
+if __name__ == '__main__':
+ import sys
+ import os
+ from acs_engine import *
+
+ model_path = os.path.join(os.path.dirname(__file__), '../model.conf')
+ test_model = open(model_path).read()
+ acs_setup_model(test_model)
+
+ FUSION_TASK = "data_fusion"
+ FUSION_TASK_PARTY_1 = "usr_party1"
+ FUSION_TASK_DATA_1 = "data1"
+ FUSION_TASK_PARTY_2 = "usr_party2"
+ FUSION_TASK_DATA_2 = "data2"
+ FUSION_TASK_SCRIPT = "fusion_script"
+ FUSION_TASK_SCRIPT_WRITER = "usr_party3"
+ PUBLIC_SCRIPT = "public_script"
+ PUBLIC_SCRIPT_WRITER = "usr_party4"
+
+ IRRELEVANT_TASK = "task_irrelevant"
+ IRRELEVANT_PARTY = "usr_irrelevant"
+ IRRELEVANT_DATA = "data_irrelevant"
+
+ acs_announce_fact('task_creator', repr([FUSION_TASK, FUSION_TASK_PARTY_1]))
+ acs_announce_fact('task_participant', repr([FUSION_TASK, FUSION_TASK_PARTY_1]))
+ acs_announce_fact('task_participant', repr([FUSION_TASK, FUSION_TASK_PARTY_2]))
+
+ acs_announce_fact('data_owner', repr([FUSION_TASK_DATA_1, FUSION_TASK_PARTY_1]))
+ acs_announce_fact('data_owner', repr([FUSION_TASK_DATA_2, FUSION_TASK_PARTY_2]))
+ acs_announce_fact('data_owner', repr([IRRELEVANT_DATA, IRRELEVANT_PARTY]))
+
+ acs_announce_fact('script_owner', repr([FUSION_TASK_SCRIPT, FUSION_TASK_SCRIPT_WRITER]))
+
+ acs_announce_fact('script_owner', repr([PUBLIC_SCRIPT, PUBLIC_SCRIPT_WRITER]))
+ acs_announce_fact('is_public_script', repr([PUBLIC_SCRIPT]))
+
+
+ assert acs_enforce_request('launch_task', repr([FUSION_TASK, set([FUSION_TASK_PARTY_1, FUSION_TASK_PARTY_2])]))
+ assert not acs_enforce_request('launch_task', repr([FUSION_TASK, set()]))
+ assert not acs_enforce_request('launch_task', repr([FUSION_TASK, set([FUSION_TASK_PARTY_1])]))
+ assert not acs_enforce_request('launch_task', repr([FUSION_TASK, set([FUSION_TASK_PARTY_2])]))
+
+ assert acs_enforce_request('access_data', repr([FUSION_TASK, FUSION_TASK_DATA_1]))
+ assert acs_enforce_request('access_data', repr([FUSION_TASK, FUSION_TASK_DATA_2]))
+ assert not acs_enforce_request('access_data', repr([FUSION_TASK, IRRELEVANT_DATA]))
+
+ assert acs_enforce_request('access_script', repr([FUSION_TASK, PUBLIC_SCRIPT]))
+ assert not acs_enforce_request('access_script', repr([FUSION_TASK, FUSION_TASK_SCRIPT]))
+
+ acs_announce_fact('task_participant', repr([FUSION_TASK, FUSION_TASK_SCRIPT_WRITER]))
+ assert acs_enforce_request('access_script', repr([FUSION_TASK, FUSION_TASK_SCRIPT]))
+
+ acs_announce_fact('task_participant', repr([FUSION_TASK, IRRELEVANT_PARTY]))
+ assert acs_enforce_request('access_script', repr([FUSION_TASK, FUSION_TASK_SCRIPT]))
+
+ acs_announce_fact('task_creator', repr([IRRELEVANT_TASK, IRRELEVANT_PARTY]))
+ acs_announce_fact('task_participant', repr([IRRELEVANT_TASK, IRRELEVANT_PARTY]))
+ acs_announce_fact('task_participant', repr([IRRELEVANT_TASK, FUSION_TASK_PARTY_2]))
+
+ assert acs_enforce_request('launch_task', repr([IRRELEVANT_TASK, set([IRRELEVANT_PARTY, FUSION_TASK_PARTY_2])]))
+ assert not acs_enforce_request('access_data', repr([IRRELEVANT_TASK, FUSION_TASK_DATA_1]))
+ assert acs_enforce_request('access_data', repr([IRRELEVANT_TASK, FUSION_TASK_DATA_2]))
+ assert not acs_enforce_request('access_script', repr([IRRELEVANT_TASK, FUSION_TASK_SCRIPT]))
+ assert acs_enforce_request('access_script', repr([IRRELEVANT_TASK, PUBLIC_SCRIPT]))
+
+ assert acs_enforce_request('delete_data', repr([FUSION_TASK_PARTY_1, FUSION_TASK_DATA_1]))
+ assert not acs_enforce_request('delete_data', repr([FUSION_TASK_PARTY_1, FUSION_TASK_DATA_2]))
+ assert not acs_enforce_request('delete_data', repr([FUSION_TASK_PARTY_1, IRRELEVANT_DATA]))
+ assert not acs_enforce_request('delete_script', repr([FUSION_TASK_PARTY_1, FUSION_TASK_SCRIPT]))
+ assert not acs_enforce_request('delete_script', repr([FUSION_TASK_PARTY_1, PUBLIC_SCRIPT]))
+
+ assert not acs_enforce_request('delete_data', repr([FUSION_TASK_PARTY_2, FUSION_TASK_DATA_1]))
+ assert acs_enforce_request('delete_data', repr([FUSION_TASK_PARTY_2, FUSION_TASK_DATA_2]))
+ assert not acs_enforce_request('delete_data', repr([FUSION_TASK_PARTY_2, IRRELEVANT_DATA]))
+ assert not acs_enforce_request('delete_script', repr([FUSION_TASK_PARTY_2, FUSION_TASK_SCRIPT]))
+ assert not acs_enforce_request('delete_script', repr([FUSION_TASK_PARTY_2, PUBLIC_SCRIPT]))
+
+ assert not acs_enforce_request('delete_data', repr([FUSION_TASK_SCRIPT_WRITER, FUSION_TASK_DATA_1]))
+ assert not acs_enforce_request('delete_data', repr([FUSION_TASK_SCRIPT_WRITER, FUSION_TASK_DATA_2]))
+ assert not acs_enforce_request('delete_data', repr([FUSION_TASK_SCRIPT_WRITER, IRRELEVANT_DATA]))
+ assert acs_enforce_request('delete_script', repr([FUSION_TASK_SCRIPT_WRITER, FUSION_TASK_SCRIPT]))
+ assert not acs_enforce_request('delete_script', repr([FUSION_TASK_SCRIPT_WRITER, PUBLIC_SCRIPT]))
diff --git a/mesatee_services/acs/python/ffi.py b/mesatee_services/acs/python/ffi.py
index 330f4a2..3f56be7 100644
--- a/mesatee_services/acs/python/ffi.py
+++ b/mesatee_services/acs/python/ffi.py
@@ -4,8 +4,12 @@ import _cffi_backend as backend
ffi = sgx_cffi.FFI(backend)
-ffi.embedding_api("void mesapy_setup_model(const char *);")
-with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "perm.py")) as f:
+ffi.embedding_api("int acs_setup_model(const char *configuration);")
+ffi.embedding_api("""int acs_enforce_request(const char *request_type,
+ const char *request_content);""")
+ffi.embedding_api("""int acs_announce_fact(const char *term_type,
+ const char *term_fact);""")
+with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "acs_engine.py")) as f:
ffi.embedding_init_code(f.read())
ffi.set_source('acs_py_enclave', '')
ffi.emit_c_code(os.environ.get('PYPY_FFI_OUTDIR', ".") + "/acs_py_enclave.c")
diff --git a/mesatee_services/acs/sgx_trusted_lib/src/acs.rs b/mesatee_services/acs/sgx_trusted_lib/src/acs.rs
index b59e2cb..4e2c735 100644
--- a/mesatee_services/acs/sgx_trusted_lib/src/acs.rs
+++ b/mesatee_services/acs/sgx_trusted_lib/src/acs.rs
@@ -15,101 +15,217 @@
// Insert std prelude in the top for the sgx feature
#[cfg(feature = "mesalock_sgx")]
use std::prelude::v1::*;
-use std::vec;
-use uuid::Uuid;
-
-use mesatee_core::db::Memdb;
use mesatee_core::rpc::EnclaveService;
-use mesatee_core::{Error, ErrorKind, Result};
-use std::marker::PhantomData;
-
-use acs_proto::AEADKeyConfig;
-use acs_proto::KMSResponse;
-use acs_proto::{CreateKeyRequest, DeleteKeyRequest, GetKeyRequest, KMSRequest};
-
-use lazy_static::lazy_static;
-
-lazy_static! {
- static ref KEY_STORE: Memdb<String, AEADKeyConfig> = {
- let db = Memdb::<String, AEADKeyConfig>::open().expect("cannot open memdb");
- let fake_record = AEADKeyConfig {
- key: vec![65; 32],
- nonce: vec![65; 12],
- ad: vec![65; 5],
- };
- let _ = db.set(&"fake_kms_record".to_string(), &fake_record);
- let _ = db.set(&"fake_kms_record_to_be_deleted".to_string(), &fake_record);
- db
- };
+use mesatee_core::{Result, ErrorKind};
+use std::ffi::CString;
+use std::os::raw::c_char;
+use std::collections::HashSet;
+
+use acs_proto::*;
+
+pub trait PyMarshallable {
+ fn marshal(&self, buffer: &mut String);
}
-pub trait HandleRequest {
- fn handle_request(&self) -> Result<KMSResponse>;
+impl<T> PyMarshallable for (T,)
+where
+ T: PyMarshallable,
+{
+ fn marshal(&self, buffer: &mut String) {
+ buffer.push('[');
+ self.0.marshal(buffer);
+ buffer.push(']');
+ }
+}
+
+impl<U, V> PyMarshallable for (U, V)
+where
+ U: PyMarshallable,
+ V: PyMarshallable,
+{
+ fn marshal(&self, buffer: &mut String) {
+ buffer.push('[');
+ self.0.marshal(buffer);
+ buffer.push(',');
+ self.1.marshal(buffer);
+ buffer.push(']');
+ }
}
-impl HandleRequest for CreateKeyRequest {
- fn handle_request(&self) -> Result<KMSResponse> {
- let key_config = AEADKeyConfig::new()?;
- let key_id = Uuid::new_v4().to_string();
- if KEY_STORE.get(&key_id)?.is_some() {
- return Err(Error::from(ErrorKind::UUIDError));
+impl<X, Y, Z> PyMarshallable for (X, Y, Z)
+where
+ X: PyMarshallable,
+ Y: PyMarshallable,
+ Z: PyMarshallable,
+{
+ fn marshal(&self, buffer: &mut String) {
+ buffer.push('[');
+ self.0.marshal(buffer);
+ buffer.push(',');
+ self.1.marshal(buffer);
+ buffer.push(',');
+ self.2.marshal(buffer);
+ buffer.push(']');
+ }
+}
+
+impl<T> PyMarshallable for [T] where T: PyMarshallable {
+ fn marshal(&self, buffer: &mut String) {
+ buffer.push('[');
+ for t in self.as_ref() {
+ t.marshal(buffer);
+ buffer.push(',');
}
- KEY_STORE.set(&key_id, &key_config)?;
- let resp = KMSResponse::new_create_key(&key_id, &key_config);
- Ok(resp)
+ buffer.push(']');
}
}
-impl HandleRequest for GetKeyRequest {
- fn handle_request(&self) -> Result<KMSResponse> {
- let key_config = KEY_STORE
- .get(&self.key_id)?
- .ok_or_else(|| Error::from(ErrorKind::MissingValue))?;
+impl<T: PyMarshallable> PyMarshallable for &HashSet<T> {
+ fn marshal(&self, buffer: &mut String) {
+ buffer.push_str("set([");
+ for t in *self {
+ t.marshal(buffer);
+ buffer.push(',');
+ }
+ buffer.push_str("])");
+ }
+}
- let resp = KMSResponse::new_get_key(&key_config);
- Ok(resp)
+impl PyMarshallable for String {
+ fn marshal(&self, buffer: &mut String) {
+ buffer.push('\'');
+ buffer.push_str(self);
+ buffer.push('\'');
}
}
-impl HandleRequest for DeleteKeyRequest {
- fn handle_request(&self) -> Result<KMSResponse> {
- let key_config = KEY_STORE
- .del(&self.key_id)?
- .ok_or_else(|| Error::from(ErrorKind::MissingValue))?;
+impl PyMarshallable for &String {
+ fn marshal(&self, buffer: &mut String) {
+ buffer.push('\'');
+ buffer.push_str(self);
+ buffer.push('\'');
+ }
+}
- let resp = KMSResponse::new_del_key(&key_config);
- Ok(resp)
+pub trait HandleRequest {
+ fn handle_request(&self) -> Result<ACSResponse>;
+}
+
+extern "C" {
+ fn acs_enforce_request(request_type: *const c_char, request_content: *const c_char) -> i32;
+ fn acs_announce_fact(fact_type: *const c_char, fact_vals: *const c_char) -> i32;
+}
+
+impl HandleRequest for EnforceRequest {
+ fn handle_request(&self) -> Result<ACSResponse> {
+ let (request_type, request_content) = match self {
+ EnforceRequest::LaunchTask(usr, task) => {
+ let mut buffer = String::new();
+ (usr, task).marshal(&mut buffer);
+ ("launch_task", buffer)
+ }
+ EnforceRequest::AccessData(task, data) => {
+ let mut buffer = String::new();
+ (task, data).marshal(&mut buffer);
+ ("access_data", buffer)
+ }
+ EnforceRequest::DeleteData(usr, data) => {
+ let mut buffer = String::new();
+ (usr, data).marshal(&mut buffer);
+ ("delete_data", buffer)
+ }
+ EnforceRequest::AccessScript(task, script) => {
+ let mut buffer = String::new();
+ (task, script).marshal(&mut buffer);
+ ("access_script", buffer)
+ }
+ EnforceRequest::DeleteScript(usr, script) => {
+ let mut buffer = String::new();
+ (usr, script).marshal(&mut buffer);
+ ("delete_script", buffer)
+ }
+ };
+
+ let c_request_type = CString::new(request_type.to_string()).unwrap();
+ let c_request_content = CString::new(request_content).unwrap();
+ let py_ret = unsafe {
+ acs_enforce_request(c_request_type.as_ptr(), c_request_content.as_ptr())
+ };
+
+ match py_ret {
+ 0 => Ok(ACSResponse::Enforce(false)),
+ 1 => Ok(ACSResponse::Enforce(true)),
+ _ => Err(ErrorKind::MesaPyError.into()),
+ }
}
}
-pub struct KMSEnclave<S, T> {
- state: i32,
- x: PhantomData<S>,
- y: PhantomData<T>,
+impl HandleRequest for AnnounceRequest {
+ fn handle_request(&self) -> Result<ACSResponse> {
+ for fact in &self.facts {
+ use AccessControlTerms::*;
+ let (term_type, term_fact) = match fact {
+ TaskCreator(task, usr) => {
+ let mut buffer = String::new();
+ (task, usr).marshal(&mut buffer);
+ ("task_creator", buffer)
+ }
+ TaskParticipant(task, usr) => {
+ let mut buffer = String::new();
+ (task, usr).marshal(&mut buffer);
+ ("task_participant", buffer)
+ }
+ DataOwner(data, usr) => {
+ let mut buffer = String::new();
+ (data, usr).marshal(&mut buffer);
+ ("data_owner", buffer)
+ }
+ ScriptOwner(script, usr) => {
+ let mut buffer = String::new();
+ (script, usr).marshal(&mut buffer);
+ ("script_owner", buffer)
+ }
+ IsPublicScript(script) => {
+ let mut buffer = String::new();
+ (script,).marshal(&mut buffer);
+ ("is_public_script", buffer)
+ }
+ };
+
+ let c_term_type = CString::new(term_type.to_string()).unwrap();
+ let c_term_fact = CString::new(term_fact).unwrap();
+
+ let py_ret = unsafe {
+ acs_announce_fact(c_term_type.as_ptr(), c_term_fact.as_ptr())
+ };
+
+ if py_ret != 0 {
+ return Err(ErrorKind::MesaPyError.into());
+ }
+ }
+ Ok(ACSResponse::Announce)
+ }
}
-impl<S, T> Default for KMSEnclave<S, T> {
+pub struct ACSEnclave;
+
+impl Default for ACSEnclave {
fn default() -> Self {
- KMSEnclave {
- state: 0,
- x: PhantomData::<S>,
- y: PhantomData::<T>,
- }
+ ACSEnclave {}
}
}
-impl EnclaveService<KMSRequest, KMSResponse> for KMSEnclave<KMSRequest, KMSResponse> {
- fn handle_invoke(&mut self, input: KMSRequest) -> Result<KMSResponse> {
- trace!("handle_invoke invoked!");
- trace!("incoming payload = {:?}", input);
- self.state += 1;
+impl EnclaveService<ACSRequest, ACSResponse> for ACSEnclave {
+ fn handle_invoke(&mut self, input: ACSRequest) -> Result<ACSResponse> {
+ debug!("handle_invoke invoked!");
+ debug!("incoming payload = {:?}", input);
+
let response = match input {
- KMSRequest::Create(req) => req.handle_request()?,
- KMSRequest::Get(req) => req.handle_request()?,
- KMSRequest::Delete(req) => req.handle_request()?,
+ ACSRequest::Enforce(req) => req.handle_request()?,
+ ACSRequest::Announce(req) => req.handle_request()?,
};
- trace!("{}th round complete!", self.state);
+
Ok(response)
}
}
diff --git a/mesatee_services/acs/sgx_trusted_lib/src/sgx.rs b/mesatee_services/acs/sgx_trusted_lib/src/sgx.rs
index e4f1a4a..85266e6 100644
--- a/mesatee_services/acs/sgx_trusted_lib/src/sgx.rs
+++ b/mesatee_services/acs/sgx_trusted_lib/src/sgx.rs
@@ -21,12 +21,12 @@ use std::os::raw::c_char;
use mesatee_core::config;
use mesatee_core::prelude::*;
-use mesatee_core::Result;
+use mesatee_core::{Result, Error, ErrorKind};
use env_logger;
use std::backtrace::{self, PrintFormat};
-use crate::acs::KMSEnclave;
+use crate::acs::ACSEnclave;
register_ecall_handler!(
type ECallCommand,
@@ -36,18 +36,18 @@ register_ecall_handler!(
);
extern "C" {
- fn mesapy_setup_model(model_text: *const c_char);
+ fn acs_setup_model(model_text: *const c_char) -> i32;
}
#[handle_ecall]
fn handle_serve_connection(args: &ServeConnectionInput) -> Result<ServeConnectionOutput> {
- debug!("Enclave [KMS]: Serve Connection.");
+ debug!("Enclave [ACS]: Serve Connection.");
- let server_instance = KMSEnclave::default();
- let kms_config = config::Internal::kms();
- assert_eq!(args.port, kms_config.addr.port());
+ let server_instance = ACSEnclave::default();
+ let acs_config = config::Internal::acs();
+ assert_eq!(args.port, acs_config.addr.port());
- let enclave_attr = match kms_config.inbound_desc {
+ let enclave_attr = match acs_config.inbound_desc {
config::InboundDesc::Sgx(enclave_attr) => enclave_attr,
_ => unreachable!(),
};
@@ -76,7 +76,7 @@ const MODEL_TEXT: &'static str = include_str!("../../model.conf");
#[handle_ecall]
fn handle_init_enclave(_args: &InitEnclaveInput) -> Result<InitEnclaveOutput> {
- debug!("Enclave [KMS]: Initializing...");
+ debug!("Enclave [ACS]: Initializing...");
env_logger::init();
let _ = backtrace::enable_backtrace(
@@ -85,11 +85,15 @@ fn handle_init_enclave(_args: &InitEnclaveInput) -> Result<InitEnclaveOutput> {
);
mesatee_core::rpc::sgx::prelude();
- unsafe {
- mesapy_setup_model(CString::new(MODEL_TEXT).unwrap().as_ptr());
- }
+ eprintln!("setting up acs model");
+
+ let ec = unsafe { acs_setup_model(CString::new(MODEL_TEXT).unwrap().as_ptr()) };
- Ok(InitEnclaveOutput::default())
+ if ec != 0 {
+ Err(Error::from(ErrorKind::MesaPyError))
+ } else {
+ Ok(InitEnclaveOutput::default())
+ }
}
#[handle_ecall]
@@ -97,6 +101,6 @@ fn handle_finalize_enclave(_args: &FinalizeEnclaveInput) -> Result<FinalizeEncla
#[cfg(feature = "cov")]
sgx_cov::cov_writeout();
- debug!("Enclave [KMS]: Finalized.");
+ debug!("Enclave [ACS]: Finalized.");
Ok(FinalizeEnclaveOutput::default())
}
diff --git a/tests/functional_test.sh b/tests/functional_test.sh
index a825c23..963c60f 100755
--- a/tests/functional_test.sh
+++ b/tests/functional_test.sh
@@ -15,6 +15,10 @@ if lsof -i :5066; then
echo "[-] port 5066 is in use"
exit 1
fi
+if lsof -i :5077; then
+ echo "[-] port 5066 is in use"
+ exit 1
+fi
if lsof -i :5065; then
echo "[-] port 5065 is in use"
exit 1
@@ -27,10 +31,6 @@ if lsof -i :5555; then
echo "[-] port 5555 is in use"
exit 1
fi
-if lsof -i :5555; then
- echo "[-] port 5555 is in use"
- exit 1
-fi
if lsof -i :3444; then
echo "[-] port 3444 is in use"
exit 1
@@ -41,6 +41,7 @@ fi
./tdfs 2>&1 | tee tdfs.log &
./tms 2>&1 | tee tms.log &
./fns 2>&1 | tee fns.log &
+./acs 2>&1 | tee acs.log &
wait_service() {
name=$1
@@ -61,6 +62,7 @@ wait_service tdfs 5065 30
wait_service tms 5554 30
wait_service tms 5555 30
wait_service fns 3444 30
+wait_service acs 5077 30
./functional_test 2>&1 | tee functional_test.log
exit ${PIPESTATUS[0]}
diff --git a/tests/functional_test/sgx_trusted_lib/Cargo.toml b/tests/functional_test/sgx_trusted_lib/Cargo.toml
index 24de3aa..866a392 100644
--- a/tests/functional_test/sgx_trusted_lib/Cargo.toml
+++ b/tests/functional_test/sgx_trusted_lib/Cargo.toml
@@ -12,7 +12,7 @@ crate-type = ["staticlib"]
[features]
default = []
-mesalock_sgx = ["sgx_tstd", "sgx_tunittest", "mesatee_core/mesalock_sgx", "kms_client/mesalock_sgx", "tdfs_internal_client/mesalock_sgx", "tms_internal_client/mesalock_sgx", "tms_internal_proto/mesalock_sgx", "protected_fs_rs/mesalock_sgx"]
+mesalock_sgx = ["sgx_tstd", "sgx_tunittest", "mesatee_core/mesalock_sgx", "kms_client/mesalock_sgx", "acs_client/mesalock_sgx", "tdfs_internal_client/mesalock_sgx", "tms_internal_client/mesalock_sgx", "tms_internal_proto/mesalock_sgx", "protected_fs_rs/mesalock_sgx"]
cov = ["sgx_cov"]
[dependencies]
@@ -22,6 +22,7 @@ env_logger = { version = "0.6.1" }
rand = { version = "0.7" }
kms_client = { path = "../../../mesatee_services/kms/client", optional = true }
+acs_client = { path = "../../../mesatee_services/acs/client", optional = true }
tdfs_internal_client = { path = "../../../mesatee_services/tdfs/internal/client", optional = true }
tms_internal_client = { path = "../../../mesatee_services/tms/internal/client", optional = true }
tms_internal_proto = { path = "../../../mesatee_services/tms/internal/proto", optional = true }
diff --git a/tests/functional_test/sgx_trusted_lib/src/sgx.rs b/tests/functional_test/sgx_trusted_lib/src/sgx.rs
index 1fc2faa..3069e7e 100644
--- a/tests/functional_test/sgx_trusted_lib/src/sgx.rs
+++ b/tests/functional_test/sgx_trusted_lib/src/sgx.rs
@@ -47,6 +47,7 @@ fn handle_run_functional_test(_args: &RunFunctionalTestInput) -> Result<RunFunct
tests::tms_test::update_task_result,
tests::tms_test::update_private_result,
tests::tms_test::update_status,
+ tests::acs_test::access_control_model,
);
Ok(RunFunctionalTestOutput::new(nfailed))
diff --git a/tests/functional_test/sgx_trusted_lib/src/tests/acs_test.rs b/tests/functional_test/sgx_trusted_lib/src/tests/acs_test.rs
new file mode 100644
index 0000000..51d2d5c
--- /dev/null
+++ b/tests/functional_test/sgx_trusted_lib/src/tests/acs_test.rs
@@ -0,0 +1,267 @@
+// Copyright 2019 MesaTEE Authors
+//
+// Licensed 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 super::common_setup::setup_acs_internal_client;
+
+use std::collections::HashSet;
+use std::string::ToString;
+
+const FUSION_TASK: &'static str = "data_fusion";
+
+const FUSION_TASK_PARTY_1: &'static str = "usr1";
+const FUSION_TASK_PARTY_2: &'static str = "usr2";
+
+const FUSION_TASK_DATA_1: &'static str = "data1";
+const FUSION_TASK_DATA_2: &'static str = "data2";
+
+const FUSION_TASK_SCRIPT: &'static str = "fusion_script";
+const FUSION_TASK_SCRIPT_WRITER: &'static str = "usr3";
+const PUBLIC_SCRIPT: &'static str = "public_script";
+const PUBLIC_SCRIPT_WRITER: &'static str = "usr4";
+
+const IRRELEVANT_TASK: &'static str = "task_irrelevant";
+const IRRELEVANT_PARTY: &'static str = "usr_irrelevant";
+const IRRELEVANT_DATA: &'static str = "data_irrelevant";
+
+pub fn access_control_model() {
+ trace!("Test ACS: access control model.");
+ let mut client = setup_acs_internal_client();
+
+ let mut participants = HashSet::new();
+ participants.insert(FUSION_TASK_PARTY_1.to_string());
+ participants.insert(FUSION_TASK_PARTY_2.to_string());
+ participants.insert(FUSION_TASK_SCRIPT_WRITER.to_string());
+
+ client.announce_task_creation(
+ FUSION_TASK.to_string(),
+ FUSION_TASK_PARTY_1.to_string(),
+ &participants,
+ ).expect("fusion task creation announcement failed");
+
+ client.announce_data_creation(
+ FUSION_TASK_DATA_1.to_string(),
+ FUSION_TASK_PARTY_1.to_string(),
+ ).expect("fusion data n1 creation announcement failed");
+
+ client.announce_data_creation(
+ FUSION_TASK_DATA_2.to_string(),
+ FUSION_TASK_PARTY_2.to_string(),
+ ).expect("fusion data 2 creation announcement failed");
+
+ client.announce_data_creation(
+ IRRELEVANT_DATA.to_string(),
+ IRRELEVANT_PARTY.to_string(),
+ ).expect("irrelevant data creation announcement failed");
+
+ client.announce_script_creation(
+ FUSION_TASK_SCRIPT.to_string(),
+ FUSION_TASK_SCRIPT_WRITER.to_string(),
+ false,
+ ).expect("fusion script creation announcement failed");
+
+ client.announce_script_creation(
+ PUBLIC_SCRIPT.to_string(),
+ PUBLIC_SCRIPT_WRITER.to_string(),
+ true,
+ ).expect("public script creation announcement failed");
+
+ let mut participants = HashSet::new();
+
+ assert_eq!(
+ client.enforce_task_launch(
+ FUSION_TASK.to_string(),
+ participants.clone(),
+ ).unwrap(),
+ false,
+ );
+
+ participants.insert(FUSION_TASK_PARTY_1.to_string());
+
+ assert_eq!(
+ client.enforce_task_launch(
+ FUSION_TASK.to_string(),
+ participants.clone(),
+ ).unwrap(),
+ false,
+ );
+
+ participants.insert(FUSION_TASK_PARTY_2.to_string());
+
+ assert_eq!(
+ client.enforce_task_launch(
+ FUSION_TASK.to_string(),
+ participants.clone(),
+ ).unwrap(),
+ false,
+ );
+
+ participants.insert(FUSION_TASK_SCRIPT_WRITER.to_string());
+
+ assert_eq!(
+ client.enforce_task_launch(
+ FUSION_TASK.to_string(),
+ participants.clone(),
+ ).unwrap(),
+ true,
+ );
+
+ // Load fusion script
+ assert_eq!(
+ client.enforce_script_access(
+ FUSION_TASK.to_string(),
+ FUSION_TASK_SCRIPT.to_string(),
+ ).unwrap(),
+ true,
+ );
+
+ // Load public script
+ assert_eq!(
+ client.enforce_script_access(
+ FUSION_TASK.to_string(),
+ PUBLIC_SCRIPT.to_string(),
+ ).unwrap(),
+ true,
+ );
+
+ // Read data1
+ assert_eq!(
+ client.enforce_data_access(
+ FUSION_TASK.to_string(),
+ FUSION_TASK_DATA_1.to_string(),
+ ).unwrap(),
+ true,
+ );
+
+ // Read data2
+ assert_eq!(
+ client.enforce_data_access(
+ FUSION_TASK.to_string(),
+ FUSION_TASK_DATA_2.to_string(),
+ ).unwrap(),
+ true,
+ );
+
+ let mut participants = HashSet::new();
+
+ participants.insert(IRRELEVANT_PARTY.to_string());
+ participants.insert(FUSION_TASK_PARTY_2.to_string());
+
+ client.announce_task_creation(
+ IRRELEVANT_TASK.to_string(),
+ IRRELEVANT_PARTY.to_string(),
+ &participants,
+ ).expect("irrelevant task creation announcement failed");
+
+ // Launch irrelevant task
+ assert_eq!(
+ client.enforce_task_launch(
+ IRRELEVANT_TASK.to_string(),
+ participants,
+ ).unwrap(),
+ true,
+ );
+
+ // Load fusion script; deny
+ assert_eq!(
+ client.enforce_script_access(
+ IRRELEVANT_TASK.to_string(),
+ FUSION_TASK_SCRIPT.to_string(),
+ ).unwrap(),
+ false,
+ );
+
+ // Load public script; allow
+ assert_eq!(
+ client.enforce_script_access(
+ IRRELEVANT_TASK.to_string(),
+ PUBLIC_SCRIPT.to_string(),
+ ).unwrap(),
+ true,
+ );
+
+ // Read data1; deny
+ assert_eq!(
+ client.enforce_data_access(
+ IRRELEVANT_TASK.to_string(),
+ FUSION_TASK_DATA_1.to_string(),
+ ).unwrap(),
+ false,
+ );
+
+ // Read data2; allow
+ assert_eq!(
+ client.enforce_data_access(
+ IRRELEVANT_TASK.to_string(),
+ FUSION_TASK_DATA_2.to_string(),
+ ).unwrap(),
+ true,
+ );
+
+ assert_eq!(
+ client.enforce_data_deletion(
+ FUSION_TASK_PARTY_1.to_string(),
+ FUSION_TASK_DATA_1.to_string(),
+ ).unwrap(),
+ true,
+ );
+
+ assert_eq!(
+ client.enforce_data_deletion(
+ FUSION_TASK_PARTY_2.to_string(),
+ FUSION_TASK_DATA_2.to_string(),
+ ).unwrap(),
+ true,
+ );
+
+ assert_eq!(
+ client.enforce_data_deletion(
+ FUSION_TASK_PARTY_1.to_string(),
+ FUSION_TASK_DATA_2.to_string(),
+ ).unwrap(),
+ false,
+ );
+
+ assert_eq!(
+ client.enforce_script_deletion(
+ FUSION_TASK_PARTY_1.to_string(),
+ FUSION_TASK_SCRIPT.to_string(),
+ ).unwrap(),
+ false,
+ );
+
+ assert_eq!(
+ client.enforce_script_deletion(
+ FUSION_TASK_SCRIPT_WRITER.to_string(),
+ FUSION_TASK_SCRIPT.to_string(),
+ ).unwrap(),
+ true,
+ );
+
+ assert_eq!(
+ client.enforce_script_deletion(
+ IRRELEVANT_PARTY.to_string(),
+ PUBLIC_SCRIPT.to_string(),
+ ).unwrap(),
+ false,
+ );
+
+ assert_eq!(
+ client.enforce_script_deletion(
+ PUBLIC_SCRIPT_WRITER.to_string(),
+ PUBLIC_SCRIPT.to_string(),
+ ).unwrap(),
+ true,
+ );
+
+}
diff --git a/tests/functional_test/sgx_trusted_lib/src/tests/common_setup.rs b/tests/functional_test/sgx_trusted_lib/src/tests/common_setup.rs
index b6fa952..92244f3 100644
--- a/tests/functional_test/sgx_trusted_lib/src/tests/common_setup.rs
+++ b/tests/functional_test/sgx_trusted_lib/src/tests/common_setup.rs
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use kms_client::KMSClient;
+use acs_client::ACSClient;
use mesatee_core::config;
use tdfs_internal_client::TDFSClient;
use tms_internal_client::TMSClient;
@@ -21,6 +22,11 @@ pub(crate) fn setup_kms_internal_client() -> KMSClient {
KMSClient::new(target).unwrap()
}
+pub(crate) fn setup_acs_internal_client() -> ACSClient {
+ let target = config::Internal::target_acs();
+ ACSClient::new(target).unwrap()
+}
+
pub(crate) fn setup_tdfs_internal_client() -> TDFSClient {
let target = config::Internal::target_tdfs();
TDFSClient::new(target).unwrap()
@@ -30,3 +36,4 @@ pub(crate) fn setup_tms_internal_client() -> TMSClient {
let target = config::Internal::target_tms();
TMSClient::new(target).unwrap()
}
+
diff --git a/tests/functional_test/sgx_trusted_lib/src/tests/mod.rs b/tests/functional_test/sgx_trusted_lib/src/tests/mod.rs
index dde9bb0..d8b9735 100644
--- a/tests/functional_test/sgx_trusted_lib/src/tests/mod.rs
+++ b/tests/functional_test/sgx_trusted_lib/src/tests/mod.rs
@@ -17,3 +17,4 @@ pub mod kms_test;
pub mod protected_fs_test;
pub mod tdfs_test;
pub mod tms_test;
+pub mod acs_test;
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@mesatee.apache.org
For additional commands, e-mail: commits-help@mesatee.apache.org