Skip to content

Commit

Permalink
Adding support for oauth2 trusted call authentication (#3189)
Browse files Browse the repository at this point in the history
  • Loading branch information
silva-fj authored Dec 9, 2024
1 parent d68ffef commit 06f0c71
Show file tree
Hide file tree
Showing 18 changed files with 549 additions and 92 deletions.
29 changes: 27 additions & 2 deletions common/primitives/core/src/identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -524,11 +524,36 @@ impl Identity {
self.using_encoded(blake2_256).into()
}

pub fn from_email(email: &str) -> Self {
Identity::Email(IdentityString::new(email.as_bytes().to_vec()))
pub fn from_web2_account(handle: &str, identity_type: Web2IdentityType) -> Self {
match identity_type {
Web2IdentityType::Twitter => {
Identity::Twitter(IdentityString::new(handle.as_bytes().to_vec()))
}
Web2IdentityType::Discord => {
Identity::Discord(IdentityString::new(handle.as_bytes().to_vec()))
}
Web2IdentityType::Github => {
Identity::Github(IdentityString::new(handle.as_bytes().to_vec()))
}
Web2IdentityType::Email => {
Identity::Email(IdentityString::new(handle.as_bytes().to_vec()))
}
Web2IdentityType::Google => {
Identity::Google(IdentityString::new(handle.as_bytes().to_vec()))
}
}
}
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Web2IdentityType {
Twitter,
Discord,
Github,
Email,
Google,
}

impl From<ed25519::Public> for Identity {
fn from(value: ed25519::Public) -> Self {
Identity::Substrate(value.into())
Expand Down
4 changes: 3 additions & 1 deletion local-setup/.env.dev
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ NODE_ENV=local
## -----------------------------------

# The following key/token are MANDATORY to give when running worker.
# Otherwise request-vc might suffering from data provider error.
# Otherwise request-vc might suffering from data provider error and OAuth2 verification will not work.
TWITTER_AUTH_TOKEN_V2=
TWITTER_CLIENT_ID=
TWITTER_CLIENT_SECRET=
Expand All @@ -34,6 +34,8 @@ NODEREAL_API_KEY=
GENIIDATA_API_KEY=
MORALIS_API_KEY=
MAGIC_CRAFT_API_KEY=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=

# The followings are default value.
# Can be skipped; or overwrite within non-production mode.
Expand Down
3 changes: 3 additions & 0 deletions tee-worker/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions tee-worker/identity/enclave-runtime/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 39 additions & 5 deletions tee-worker/identity/enclave-runtime/src/rpc/common_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ use jsonrpc_core::{serde_json::json, IoHandler, Params, Value};
use lc_data_providers::DataProviderConfig;
use lc_identity_verification::{
generate_verification_code,
web2::{email, twitter},
VerificationCodeStore,
web2::{email, google, twitter},
};
use litentry_macros::{if_development, if_development_or};
use litentry_primitives::{aes_decrypt, AesRequest, DecryptableRequest, Identity};
use litentry_primitives::{
aes_decrypt, AesRequest, DecryptableRequest, Identity, Web2IdentityType,
};
use log::debug;
use sgx_crypto_helper::rsa3072::Rsa3072PubKey;
use sp_core::Pair;
Expand Down Expand Up @@ -466,6 +467,39 @@ pub fn add_common_api<Author, GetterExecutor, AccessShieldingKey, OcallApi, Stat
}
});

let google_client_id = data_provider_config.google_client_id.clone();

io_handler.add_sync_method("omni_getOAuth2GoogleAuthorizationUrl", move |params: Params| {
match params.parse::<(String, String, String)>() {
Ok((encoded_omni_account, google_account, redirect_uri)) => {
let omni_account = match AccountId::from_hex(encoded_omni_account.as_str()) {
Ok(account_id) => account_id,
Err(_) =>
return Ok(json!(compute_hex_encoded_return_error(
"Could not parse omni account"
))),
};
let google_identity =
Identity::from_web2_account(&google_account, Web2IdentityType::Google);
let state = generate_verification_code();
let authorize_data = google::get_authorize_data(&google_client_id, &redirect_uri);

match google::OAuthStateStore::insert(omni_account, google_identity.hash(), state) {
Ok(_) => {
let json_value = RpcReturnValue::new(
authorize_data.authorize_url.encode(),
false,
DirectRequestStatus::Ok,
);
Ok(json!(json_value.to_hex()))
},
Err(_) => Ok(json!(compute_hex_encoded_return_error("Could not save state"))),
}
},
Err(_) => Ok(json!(compute_hex_encoded_return_error("Could not parse params"))),
}
});

io_handler.add_sync_method("omni_requestEmailVerificationCode", move |params: Params| {
match params.parse::<(String, String)>() {
Ok((encoded_omni_account, email)) => {
Expand All @@ -481,9 +515,9 @@ pub fn add_common_api<Author, GetterExecutor, AccessShieldingKey, OcallApi, Stat
data_provider_config.sendgrid_from_email.clone(),
);
let verification_code = generate_verification_code();
let email_identity = Identity::from_email(&email);
let email_identity = Identity::from_web2_account(&email, Web2IdentityType::Email);

match VerificationCodeStore::insert(
match email::VerificationCodeStore::insert(
omni_account,
email_identity.hash(),
verification_code.clone(),
Expand Down
76 changes: 76 additions & 0 deletions tee-worker/identity/litentry/core/data-providers/src/google.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright 2020-2024 Trust Computing GmbH.
// This file is part of Litentry.
//
// Litentry is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Litentry is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Litentry. If not, see <https://www.gnu.org/licenses/>.

use crate::{build_client_with_cert, format, Error, Headers, HttpError, String, ToString};
use itc_rest_client::{
http_client::{HttpClient, SendWithCertificateVerification},
rest_client::RestClient,
RestPath,
};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

const OAUTH2_BASE_URL: &str = "https://oauth2.googleapis.com";

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct GoogleOAuth2TokenResponse {
access_token: String,
expires_in: u64,
id_token: String,
scope: String,
token_type: String,
}

impl RestPath<String> for GoogleOAuth2TokenResponse {
fn get_path(path: String) -> Result<String, HttpError> {
Ok(path)
}
}

pub struct GoogleOAuth2Client {
client: RestClient<HttpClient<SendWithCertificateVerification>>,
client_id: String,
client_secret: String,
}

impl GoogleOAuth2Client {
pub fn new(client_id: String, client_secret: String) -> Self {
let client = build_client_with_cert(OAUTH2_BASE_URL, Headers::new());
Self { client, client_id, client_secret }
}

pub fn exchange_code_for_token(
&mut self,
code: String,
redirect_uri: String,
) -> Result<String, Error> {
let path = String::from("/token");

let mut body = HashMap::new();
body.insert("code".to_string(), code);
body.insert("client_id".to_string(), self.client_id.clone());
body.insert("client_secret".to_string(), self.client_secret.clone());
body.insert("redirect_uri".to_string(), redirect_uri);
body.insert("grant_type".to_string(), "authorization_code".to_string());

let response = self
.client
.post_form_urlencoded_capture::<String, GoogleOAuth2TokenResponse>(path, body)
.map_err(|e| Error::RequestError(format!("{:?}", e)))?;

Ok(response.id_token)
}
}
38 changes: 29 additions & 9 deletions tee-worker/identity/litentry/core/data-providers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#![allow(clippy::large_enum_variant)]
#![allow(clippy::result_large_err)]

extern crate alloc;
extern crate core;
#[cfg(all(not(feature = "std"), feature = "sgx"))]
extern crate sgx_tstd as std;
Expand All @@ -34,6 +35,12 @@ pub mod sgx_reexport_prelude {
#[cfg(all(not(feature = "std"), feature = "sgx"))]
use crate::sgx_reexport_prelude::*;

use alloc::{
format,
string::{String, ToString},
vec,
vec::Vec,
};
use codec::{Decode, Encode};
use core::time::Duration;
use http_req::response::Headers;
Expand All @@ -43,19 +50,13 @@ use itc_rest_client::{
rest_client::RestClient,
Query, RestGet, RestPath, RestPost,
};
use log::debug;
use serde::{Deserialize, Serialize};
use std::{thread, vec};

use litentry_primitives::{
AchainableParams, Assertion, ErrorDetail, ErrorString, IntoErrorDetail, ParameterString,
VCMPError,
};
use std::{
env, format,
string::{String, ToString},
vec::Vec,
};
use log::debug;
use serde::{Deserialize, Serialize};
use std::{env, thread};
use url::Url;

#[cfg(all(feature = "std", feature = "sgx"))]
Expand All @@ -68,6 +69,7 @@ pub mod daren_market;
pub mod discord_litentry;
pub mod discord_official;
pub mod geniidata;
pub mod google;
pub mod karat_dao;
pub mod magic_craft;
pub mod moralis;
Expand Down Expand Up @@ -174,6 +176,8 @@ pub struct DataProviderConfig {
pub discord_official_url: String,
pub discord_client_id: String,
pub discord_client_secret: String,
pub google_client_id: String,
pub google_client_secret: String,
pub litentry_discord_microservice_url: String,
pub discord_auth_token: String,
pub achainable_url: String,
Expand Down Expand Up @@ -230,6 +234,8 @@ impl DataProviderConfig {
discord_official_url: "https://discordapp.com".to_string(),
discord_client_id: "".to_string(),
discord_client_secret: "".to_string(),
google_client_id: "".to_string(),
google_client_secret: "".to_string(),
litentry_discord_microservice_url: "https://tee-microservice.litentry.io:9528"
.to_string(),
discord_auth_token: "".to_string(),
Expand Down Expand Up @@ -399,6 +405,12 @@ impl DataProviderConfig {
if let Ok(v) = env::var("DISCORD_CLIENT_SECRET") {
config.set_discord_client_secret(v);
}
if let Ok(v) = env::var("GOOGLE_CLIENT_ID") {
config.set_google_client_id(v);
}
if let Ok(v) = env::var("GOOGLE_CLIENT_SECRET") {
config.set_google_client_secret(v);
}
if let Ok(v) = env::var("ACHAINABLE_AUTH_KEY") {
config.set_achainable_auth_key(v);
}
Expand Down Expand Up @@ -458,6 +470,14 @@ impl DataProviderConfig {
debug!("set_discord_client_secret: {:?}", v);
self.discord_client_secret = v;
}
pub fn set_google_client_id(&mut self, v: String) {
debug!("set_google_client_id: {:?}", v);
self.google_client_id = v;
}
pub fn set_google_client_secret(&mut self, v: String) {
debug!("set_google_client_secret: {:?}", v);
self.google_client_secret = v;
}
pub fn set_litentry_discord_microservice_url(&mut self, v: String) -> Result<(), Error> {
check_url(&v)?;
debug!("set_litentry_discord_microservice_url: {:?}", v);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

#![cfg_attr(not(feature = "std"), no_std)]

pub extern crate alloc;
extern crate alloc;

#[cfg(all(not(feature = "std"), feature = "sgx"))]
extern crate sgx_tstd as std;
Expand All @@ -35,9 +35,7 @@ compile_error!("feature \"std\" and feature \"sgx\" cannot be enabled at the sam

mod error;
mod helpers;
mod verification_code_store;
pub mod web2;
pub use verification_code_store::VerificationCodeStore;

use alloc::string::String;
use error::{Error, Result};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod verification_code_store;
pub use verification_code_store::*;
mod mailer;
pub use mailer::*;

Expand Down
Loading

0 comments on commit 06f0c71

Please sign in to comment.