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