You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@teaclave.apache.org by ms...@apache.org on 2020/01/27 23:45:44 UTC

[incubator-teaclave] branch develop updated: [services] Polish authentication service

This is an automated email from the ASF dual-hosted git repository.

mssun pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/incubator-teaclave.git


The following commit(s) were added to refs/heads/develop by this push:
     new 365b3c0  [services] Polish authentication service
365b3c0 is described below

commit 365b3c07eb82d81378d8af25227e8848c21ed525
Author: Mingshen Sun <bo...@mssun.me>
AuthorDate: Mon Jan 27 15:38:44 2020 -0800

    [services] Polish authentication service
---
 services/authentication/enclave/src/lib.rs       |  12 +--
 services/authentication/enclave/src/service.rs   |  36 ++++----
 services/authentication/enclave/src/user_db.rs   | 106 +++++++++++++----------
 services/authentication/enclave/src/user_info.rs |  79 +++++++----------
 4 files changed, 109 insertions(+), 124 deletions(-)

diff --git a/services/authentication/enclave/src/lib.rs b/services/authentication/enclave/src/lib.rs
index d3a10a5..0f3afe1 100644
--- a/services/authentication/enclave/src/lib.rs
+++ b/services/authentication/enclave/src/lib.rs
@@ -17,31 +17,27 @@
 
 #![cfg_attr(feature = "mesalock_sgx", no_std)]
 #[cfg(feature = "mesalock_sgx")]
+#[macro_use]
 extern crate sgx_tstd as std;
 
 #[macro_use]
 extern crate log;
 
-use std::prelude::v1::*;
-
 use anyhow::Result;
-
+use std::prelude::v1::*;
+use teaclave_attestation::RemoteAttestation;
 use teaclave_ipc::protos::ecall::{
     FinalizeEnclaveInput, FinalizeEnclaveOutput, InitEnclaveInput, InitEnclaveOutput,
     StartServiceInput, StartServiceOutput,
 };
 use teaclave_ipc::protos::ECallCommand;
-
 use teaclave_ipc::{handle_ecall, register_ecall_handler};
-
-use teaclave_service_enclave_utils::ServiceEnclave;
-
-use teaclave_attestation::RemoteAttestation;
 use teaclave_proto::teaclave_authentication_service::{
     TeaclaveAuthenticationRequest, TeaclaveAuthenticationResponse,
 };
 use teaclave_rpc::config::SgxTrustedTlsServerConfig;
 use teaclave_rpc::server::SgxTrustedTlsServer;
+use teaclave_service_enclave_utils::ServiceEnclave;
 
 mod service;
 mod user_db;
diff --git a/services/authentication/enclave/src/service.rs b/services/authentication/enclave/src/service.rs
index c03eed1..d4ea73c 100644
--- a/services/authentication/enclave/src/service.rs
+++ b/services/authentication/enclave/src/service.rs
@@ -1,4 +1,4 @@
-use crate::user_db::{DBClient, DBError, Database};
+use crate::user_db::{Database, DbClient, DbError};
 use crate::user_info::{UserInfo, JWT_SECRET_LEN};
 use rand::prelude::RngCore;
 use std::prelude::v1::*;
@@ -17,7 +17,7 @@ pub enum TeaclaveAuthenticationError {
     #[error("permission denied")]
     PermissionDenied,
     #[error("invalid userid")]
-    InvalidUserid,
+    InvalidUserId,
     #[error("invalid password")]
     InvalidPassword,
     #[error("service unavailable")]
@@ -37,20 +37,17 @@ impl From<TeaclaveAuthenticationError> for TeaclaveServiceResponseError {
 )]
 #[derive(Clone)]
 pub(crate) struct TeaclaveAuthenticationService {
-    db_client: DBClient,
-    secret: [u8; JWT_SECRET_LEN],
+    db_client: DbClient,
+    secret: Vec<u8>,
 }
 
 impl TeaclaveAuthenticationService {
-    pub fn init() -> Option<Self> {
-        let database = match Database::open() {
-            Some(db) => db,
-            None => return None,
-        };
-        let mut secret = [0; JWT_SECRET_LEN];
+    pub fn init() -> anyhow::Result<Self> {
+        let database = Database::open()?;
+        let mut secret = vec![0; JWT_SECRET_LEN];
         let mut rng = rand::thread_rng();
         rng.fill_bytes(&mut secret);
-        Some(Self {
+        Ok(Self {
             db_client: database.get_client(),
             secret,
         })
@@ -63,18 +60,15 @@ impl TeaclaveAuthentication for TeaclaveAuthenticationService {
         request: UserRegisterRequest,
     ) -> TeaclaveServiceResponseResult<UserRegisterResponse> {
         if request.id.is_empty() {
-            return Err(TeaclaveAuthenticationError::InvalidUserid.into());
+            return Err(TeaclaveAuthenticationError::InvalidUserId.into());
         }
         if self.db_client.get_user(&request.id).is_ok() {
-            return Err(TeaclaveAuthenticationError::InvalidUserid.into());
+            return Err(TeaclaveAuthenticationError::InvalidUserId.into());
         }
-        let new_user = match UserInfo::new_register_user(&request.id, &request.password) {
-            Some(value) => value,
-            None => return Err(TeaclaveAuthenticationError::ServiceUnavailable.into()),
-        };
+        let new_user = UserInfo::new(&request.id, &request.password);
         match self.db_client.create_user(&new_user) {
             Ok(_) => Ok(UserRegisterResponse {}),
-            Err(DBError::UserExist) => Err(TeaclaveAuthenticationError::InvalidUserid.into()),
+            Err(DbError::UserExist) => Err(TeaclaveAuthenticationError::InvalidUserId.into()),
             Err(_) => Err(TeaclaveAuthenticationError::ServiceUnavailable.into()),
         }
     }
@@ -84,7 +78,7 @@ impl TeaclaveAuthentication for TeaclaveAuthenticationService {
         request: UserLoginRequest,
     ) -> TeaclaveServiceResponseResult<UserLoginResponse> {
         if request.id.is_empty() {
-            return Err(TeaclaveAuthenticationError::InvalidUserid.into());
+            return Err(TeaclaveAuthenticationError::InvalidUserId.into());
         }
         if request.password.is_empty() {
             return Err(TeaclaveAuthenticationError::InvalidPassword.into());
@@ -97,7 +91,7 @@ impl TeaclaveAuthentication for TeaclaveAuthenticationService {
             Err(TeaclaveAuthenticationError::PermissionDenied.into())
         } else {
             let now = match SystemTime::now().duration_since(UNIX_EPOCH) {
-                Ok(timestamp) => timestamp.as_secs() as i64,
+                Ok(timestamp) => timestamp.as_secs(),
                 Err(_) => return Err(TeaclaveAuthenticationError::ServiceUnavailable.into()),
             };
             let exp = now + 24 * 60;
@@ -236,7 +230,7 @@ pub mod tests {
         let now = SystemTime::now()
             .duration_since(UNIX_EPOCH)
             .unwrap()
-            .as_secs() as i64;
+            .as_secs();
         Claims {
             sub: "test_authenticate_id".to_string(),
             iss: ISSUER_NAME.to_string(),
diff --git a/services/authentication/enclave/src/user_db.rs b/services/authentication/enclave/src/user_db.rs
index 6a090b5..2d1a9b8 100644
--- a/services/authentication/enclave/src/user_db.rs
+++ b/services/authentication/enclave/src/user_db.rs
@@ -16,20 +16,20 @@
 // under the License.
 
 use crate::user_info::UserInfo;
-use rusty_leveldb::DB;
+use rusty_leveldb;
 use std::prelude::v1::*;
 use std::sync::mpsc::{channel, Sender};
 use std::thread;
 use thiserror::Error;
 
 #[derive(Error, Debug)]
-pub enum DBError {
+pub enum DbError {
     #[error("user not exist")]
     UserNotExist,
     #[error("user exist")]
     UserExist,
     #[error("mpsc error")]
-    MpscError,
+    ConnectionError,
     #[error("leveldb error")]
     LevelDbError,
     #[error("invalid response")]
@@ -38,6 +38,18 @@ pub enum DBError {
     InvalidRequest,
 }
 
+impl<T> From<std::sync::mpsc::SendError<T>> for DbError {
+    fn from(_error: std::sync::mpsc::SendError<T>) -> Self {
+        DbError::ConnectionError
+    }
+}
+
+impl From<std::sync::mpsc::RecvError> for DbError {
+    fn from(_error: std::sync::mpsc::RecvError) -> Self {
+        DbError::ConnectionError
+    }
+}
+
 #[derive(Clone)]
 struct GetRequest {
     key: Vec<u8>,
@@ -54,14 +66,14 @@ struct CreateRequest {
 }
 
 #[derive(Clone)]
-enum DBRequest {
+enum DbRequest {
     Get(GetRequest),
     Create(CreateRequest),
     Ping,
 }
 
 #[derive(Clone)]
-enum DBResponse {
+enum DbResponse {
     Get(GetResponse),
     Create,
     Ping,
@@ -69,8 +81,8 @@ enum DBResponse {
 
 #[derive(Clone)]
 struct DBCall {
-    pub sender: Sender<Result<DBResponse, DBError>>,
-    pub request: DBRequest,
+    pub sender: Sender<Result<DbResponse, DbError>>,
+    pub request: DbRequest,
 }
 
 pub struct Database {
@@ -78,11 +90,11 @@ pub struct Database {
 }
 
 impl Database {
-    pub fn open() -> Option<Self> {
+    pub fn open() -> Result<Self, DbError> {
         let (sender, receiver) = channel();
         thread::spawn(move || {
             let opt = rusty_leveldb::in_memory();
-            let mut database = DB::open("authentication_db", opt).unwrap();
+            let mut database = rusty_leveldb::DB::open("authentication_db", opt).unwrap();
             loop {
                 let call: DBCall = match receiver.recv() {
                     Ok(req) => req,
@@ -93,18 +105,18 @@ impl Database {
                 };
                 let sender = call.sender;
                 let response = match call.request {
-                    DBRequest::Get(request) => match database.get(&request.key) {
-                        Some(value) => Ok(DBResponse::Get(GetResponse { value })),
-                        None => Err(DBError::UserNotExist),
+                    DbRequest::Get(request) => match database.get(&request.key) {
+                        Some(value) => Ok(DbResponse::Get(GetResponse { value })),
+                        None => Err(DbError::UserNotExist),
                     },
-                    DBRequest::Create(request) => match database.get(&request.key) {
-                        Some(_) => Err(DBError::UserExist),
+                    DbRequest::Create(request) => match database.get(&request.key) {
+                        Some(_) => Err(DbError::UserExist),
                         None => match database.put(&request.key, &request.value) {
-                            Ok(_) => Ok(DBResponse::Create),
-                            Err(_) => Err(DBError::LevelDbError),
+                            Ok(_) => Ok(DbResponse::Create),
+                            Err(_) => Err(DbError::LevelDbError),
                         },
                     },
-                    DBRequest::Ping => Ok(DBResponse::Ping),
+                    DbRequest::Ping => Ok(DbResponse::Ping),
                 };
                 match sender.send(response) {
                     Ok(_) => (),
@@ -115,73 +127,73 @@ impl Database {
 
         let database = Self { sender };
         let client = database.get_client();
-        // check whether the db is opened successfuly
-        match client.ping() {
-            Ok(_) => Some(database),
-            Err(_) => None,
-        }
+
+        // Check whether the user database is successfully opened.
+        client.ping()?;
+
+        Ok(database)
     }
 
-    pub fn get_client(&self) -> DBClient {
-        DBClient {
+    pub fn get_client(&self) -> DbClient {
+        DbClient {
             sender: self.sender.clone(),
         }
     }
 }
 
 #[derive(Clone)]
-pub struct DBClient {
+pub struct DbClient {
     sender: Sender<DBCall>,
 }
 
-impl DBClient {
-    pub fn get_user(&self, id: &str) -> Result<UserInfo, DBError> {
+impl DbClient {
+    pub fn get_user(&self, id: &str) -> Result<UserInfo, DbError> {
         let (sender, receiver) = channel();
-        let request = DBRequest::Get(GetRequest {
+        let request = DbRequest::Get(GetRequest {
             key: id.as_bytes().to_vec(),
         });
         let call = DBCall { sender, request };
-        self.sender.send(call).map_err(|_| DBError::MpscError)?;
-        let result = receiver.recv().map_err(|_| DBError::MpscError)?;
+        self.sender.send(call)?;
+        let result = receiver.recv()?;
         let db_response = result?;
         match db_response {
-            DBResponse::Get(response) => {
+            DbResponse::Get(response) => {
                 let user = serde_json::from_slice(&response.value)
-                    .map_err(|_| DBError::InvalidResponse)?;
+                    .map_err(|_| DbError::InvalidResponse)?;
                 Ok(user)
             }
-            _ => Err(DBError::UserNotExist),
+            _ => Err(DbError::UserNotExist),
         }
     }
 
-    pub fn create_user(&self, user: &UserInfo) -> Result<(), DBError> {
+    pub fn create_user(&self, user: &UserInfo) -> Result<(), DbError> {
         let (sender, receiver) = channel();
-        let user_bytes = serde_json::to_vec(&user).map_err(|_| DBError::InvalidRequest)?;
-        let request = DBRequest::Create(CreateRequest {
+        let user_bytes = serde_json::to_vec(&user).map_err(|_| DbError::InvalidRequest)?;
+        let request = DbRequest::Create(CreateRequest {
             key: user.id.as_bytes().to_vec(),
             value: user_bytes.to_vec(),
         });
         let call = DBCall { sender, request };
-        self.sender.send(call).map_err(|_| DBError::MpscError)?;
-        let result = receiver.recv().map_err(|_| DBError::MpscError)?;
+        self.sender.send(call)?;
+        let result = receiver.recv()?;
         let db_response = result?;
         match db_response {
-            DBResponse::Create => Ok(()),
-            _ => Err(DBError::InvalidResponse),
+            DbResponse::Create => Ok(()),
+            _ => Err(DbError::InvalidResponse),
         }
     }
 
-    // use to check whether the db is opened successfully
-    fn ping(&self) -> Result<(), DBError> {
+    // Check whether the database is opened successfully.
+    fn ping(&self) -> Result<(), DbError> {
         let (sender, receiver) = channel();
-        let request = DBRequest::Ping;
+        let request = DbRequest::Ping;
         let call = DBCall { sender, request };
-        self.sender.send(call).map_err(|_| DBError::MpscError)?;
-        let result = receiver.recv().map_err(|_| DBError::MpscError)?;
+        self.sender.send(call)?;
+        let result = receiver.recv()?;
         let db_response = result?;
         match db_response {
-            DBResponse::Ping => Ok(()),
-            _ => Err(DBError::InvalidResponse),
+            DbResponse::Ping => Ok(()),
+            _ => Err(DbError::InvalidResponse),
         }
     }
 }
diff --git a/services/authentication/enclave/src/user_info.rs b/services/authentication/enclave/src/user_info.rs
index 49e6a41..0c780d1 100644
--- a/services/authentication/enclave/src/user_info.rs
+++ b/services/authentication/enclave/src/user_info.rs
@@ -16,106 +16,89 @@
 // under the License.
 
 use anyhow::Result;
-use jsonwebtoken::{self, Header, Validation};
+use jsonwebtoken as jwt;
 use rand::prelude::RngCore;
 use ring::{digest, pbkdf2};
 use serde::{Deserialize, Serialize};
-use std::num::NonZeroU32;
+use std::num;
 use std::prelude::v1::*;
 use std::vec;
 
 const SALT_LEN: usize = 16;
-const PASS_LEN: usize = digest::SHA512_OUTPUT_LEN;
-static PBKDF2_ALG: ring::pbkdf2::Algorithm = pbkdf2::PBKDF2_HMAC_SHA512;
-const ITER_LEN: u32 = 100_000;
-pub const ISSUER_NAME: &str = "TeaClave";
-pub static JWT_ALG: jsonwebtoken::Algorithm = jsonwebtoken::Algorithm::HS512;
+const PASSWORD_DIGEST_LEN: usize = digest::SHA512_OUTPUT_LEN;
+const PBKDF2_ITERATIONS: u32 = 100_000;
+static PBKDF2_ALG: pbkdf2::Algorithm = pbkdf2::PBKDF2_HMAC_SHA512;
+pub const ISSUER_NAME: &str = "Teaclave";
+pub static JWT_ALG: jwt::Algorithm = jwt::Algorithm::HS512;
 pub const JWT_SECRET_LEN: usize = 512;
 
 #[derive(Clone, Serialize, Deserialize, Debug)]
 pub struct UserInfo {
     pub id: String,
-    pub salt: Vec<u8>,                 // size is SALT_LEN
-    pub salted_password_hash: Vec<u8>, // size is PASS_LEN
+    pub salt: Vec<u8>,
+    pub salted_password_hash: Vec<u8>,
 }
 
 #[derive(Debug, Serialize, Deserialize)]
 pub struct Claims {
     // user id
     pub sub: String,
-    // issuer: ISSUER_NAME
+    // issuer
     pub iss: String,
     // expiration time
-    // (SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64 + some seconds)
-    pub exp: i64,
+    pub exp: u64,
 }
 
 impl UserInfo {
-    pub fn new_register_user(id: &str, password: &str) -> Option<UserInfo> {
+    pub fn new(id: &str, password: &str) -> Self {
         let mut rng = rand::thread_rng();
-        let mut salt: [u8; SALT_LEN] = [0; SALT_LEN];
+        let mut salt = vec![0u8; SALT_LEN];
         rng.fill_bytes(&mut salt);
-        let mut salted_password_hash = [0; PASS_LEN];
-        let iter = match NonZeroU32::new(ITER_LEN) {
-            Some(value) => value,
-            None => return None,
-        };
+        let mut salted_password_hash = vec![0u8; PASSWORD_DIGEST_LEN];
+        let pbkdf2_iterations = num::NonZeroU32::new(PBKDF2_ITERATIONS).unwrap();
         pbkdf2::derive(
             PBKDF2_ALG,
-            iter,
+            pbkdf2_iterations,
             &salt,
             password.as_bytes(),
             &mut salted_password_hash,
         );
-        Some(Self {
+        Self {
             id: id.to_string(),
-            salt: salt.to_vec(),
-            salted_password_hash: salted_password_hash.to_vec(),
-        })
+            salt,
+            salted_password_hash,
+        }
     }
 
     pub fn verify_password(&self, password: &str) -> bool {
-        let mut salt: [u8; SALT_LEN] = [0; SALT_LEN];
-        let mut salted_password_hash: [u8; PASS_LEN] = [0; PASS_LEN];
-        if self.salt.len() != SALT_LEN || self.salted_password_hash.len() != PASS_LEN {
-            return false;
-        }
-        let iter = match NonZeroU32::new(ITER_LEN) {
-            Some(value) => value,
-            None => return false,
-        };
-        salt.copy_from_slice(&self.salt[0..SALT_LEN]);
-        salted_password_hash.copy_from_slice(&self.salted_password_hash[0..PASS_LEN]);
+        let pbkdf2_iterations = num::NonZeroU32::new(PBKDF2_ITERATIONS).unwrap();
         pbkdf2::verify(
             PBKDF2_ALG,
-            iter,
-            &salt,
+            pbkdf2_iterations,
+            &self.salt,
             password.as_bytes(),
-            &salted_password_hash,
+            &self.salted_password_hash,
         )
         .is_ok()
     }
 
-    pub fn get_token(&self, exp: i64, secret: &[u8]) -> Result<String> {
+    pub fn get_token(&self, exp: u64, secret: &[u8]) -> Result<String> {
         let my_claims = Claims {
             sub: self.id.clone(),
             iss: ISSUER_NAME.to_string(),
             exp,
         };
-        let mut header = Header::default();
+        let mut header = jwt::Header::default();
         header.alg = JWT_ALG;
-        let token = jsonwebtoken::encode(&header, &my_claims, secret)?;
+        let token = jwt::encode(&header, &my_claims, secret)?;
         Ok(token)
     }
 
     pub fn validate_token(&self, secret: &[u8], token: &str) -> bool {
-        let validation = Validation {
-            iss: Some(ISSUER_NAME.to_string()),
-            sub: Some(self.id.to_string()),
-            algorithms: vec![JWT_ALG],
-            ..Default::default()
-        };
-        let token_data = jsonwebtoken::decode::<Claims>(token, secret, &validation);
+        let mut validation = jwt::Validation::new(JWT_ALG);
+        validation.iss = Some(ISSUER_NAME.to_string());
+        validation.sub = Some(self.id.to_string());
+        let token_data = jwt::decode::<Claims>(token, secret, &validation);
         token_data.is_ok()
     }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@teaclave.apache.org
For additional commands, e-mail: commits-help@teaclave.apache.org