Skip to content

Commit

Permalink
feat: refactored cloud auth
Browse files Browse the repository at this point in the history
  • Loading branch information
chris13524 committed Apr 16, 2024
1 parent 4d2d090 commit 8294492
Show file tree
Hide file tree
Showing 23 changed files with 70 additions and 250 deletions.
4 changes: 0 additions & 4 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ TENANT_DATABASE_URL=
DEFAULT_TENANT_ID= # This has a default value and dosen't hold much impact to the running of echo-server
JWT_SECRET=

# Cloud App
CLOUD_API_URL=
CLOUD_API_KEY=

# CORS
CORS_ALLOWED_ORIGINS=*

Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ jobs:
env:
GRAFANA_AUTH: ${{ steps.grafana-get-key.outputs.key }}
TF_VAR_grafana_endpoint: ${{ steps.grafana-get-details.outputs.endpoint }}
TF_VAR_cloud_api_key: ${{ secrets.CLOUD_API_KEY }}
TF_VAR_jwt_secret: ${{ secrets.JWT_SECRET }}
TF_VAR_image_version: ${{ inputs.image_tag }}
TF_VAR_relay_public_key: ${{ secrets.RELAY_PUBLIC_KEY }}
Expand Down Expand Up @@ -154,7 +153,6 @@ jobs:
env:
GRAFANA_AUTH: ${{ steps.grafana-get-key.outputs.key }}
TF_VAR_grafana_endpoint: ${{ steps.grafana-get-details.outputs.endpoint }}
TF_VAR_cloud_api_key: ${{ secrets.CLOUD_API_KEY }}
TF_VAR_jwt_secret: ${{ secrets.JWT_SECRET }}
TF_VAR_image_version: ${{ inputs.image_tag }}
TF_VAR_relay_public_key: ${{ secrets.RELAY_PUBLIC_KEY }}
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/ci_terraform.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ jobs:
env:
GRAFANA_AUTH: ${{ steps.grafana-get-key.outputs.key }}
TF_VAR_grafana_endpoint: ${{ steps.grafana-get-details.outputs.endpoint }}
TF_VAR_cloud_api_key: ${{ secrets.CLOUD_API_KEY }}
TF_VAR_jwt_secret: ${{ secrets.JWT_SECRET }}
TF_VAR_relay_public_key: ${{ secrets.RELAY_PUBLIC_KEY }}
with:
Expand Down
26 changes: 0 additions & 26 deletions Cargo.lock

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

2 changes: 0 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,6 @@ is-variant-derive = { path = "crates/is-variant-derive" }
once_cell = "1.15"
pnet_datalink = "0.31"
ipnet = "2.5"
cerberus = { git = "https://github.com/WalletConnect/cerberus.git", tag = "v0.5.0" }
async-recursion = "1.0.4"
tap = "1.0.1"
wiremock = "0.5.21"

Expand Down
6 changes: 0 additions & 6 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,6 @@ pub struct Config {

#[cfg(feature = "geoblock")]
pub blocked_countries: Vec<String>,

// Cloud
#[cfg(feature = "cloud")]
pub cloud_api_url: String,
#[cfg(feature = "cloud")]
pub cloud_api_key: String,
}

impl Config {
Expand Down
9 changes: 0 additions & 9 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,6 @@ pub enum Error {
#[error("BatchCollector Error: {0}")]
BatchCollector(String),

#[error(transparent)]
Registry(#[from] cerberus::registry::RegistryError),

#[error("Invalid Project ID: {0}")]
InvalidProjectId(String),

Expand Down Expand Up @@ -513,12 +510,6 @@ impl IntoResponse for Error {
message: "Internal error monitoring the request".to_string(),
},
], vec![]),
Error::Registry(_) => crate::handlers::Response::new_failure(StatusCode::INTERNAL_SERVER_ERROR, vec![
ResponseError {
name: "internal_api_failed".to_string(),
message: "Please check https://status.walletconnect.com as an internal API failed to resolve this request".to_string(),
},
], vec![]),
Error::JWT(_) => crate::handlers::Response::new_failure(StatusCode::UNAUTHORIZED, vec![
ResponseError {
name: "invalid_auth".to_string(),
Expand Down
63 changes: 12 additions & 51 deletions src/handlers/create_tenant.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
#[cfg(feature = "cloud")]
use cerberus::registry::RegistryClient;
use {
crate::{
error::{Error, Error::InvalidProjectId},
handlers::validate_tenant_request,
increment_counter,
log::prelude::*,
state::AppState,
stores::tenant::TenantUpdateParams,
error::Error, handlers::validate_tenant_request, increment_counter, log::prelude::*,
state::AppState, stores::tenant::TenantUpdateParams,
},
axum::{extract::State, http::HeaderMap, Json},
serde::{Deserialize, Serialize},
Expand All @@ -34,52 +28,19 @@ pub async fn handler(
Json(body): Json<TenantRegisterBody>,
) -> Result<Json<TenantRegisterResponse>, Error> {
#[cfg(feature = "cloud")]
let (valid_id, project) = {
let project_id = body.id.clone();

let response = state.registry_client.project_data(&project_id).await?;

if let Some(project) = response {
// TODO potentially more validation in future
// Project passed forwards for JWT verification later
(project.is_enabled, Some(project))
} else {
(false, None)
}
};

// When not using the cloud app all Ids are valid
#[cfg(not(feature = "cloud"))]
let valid_id = true;

if !valid_id {
return Err(InvalidProjectId(body.id));
}

#[cfg(feature = "cloud")]
if let Some(project) = project {
if let Err(e) = validate_tenant_request(
&state.registry_client,
&state.gotrue_client,
&headers,
body.id.clone(),
Some(project),
)
.await
{
error!(
tenant_id = %body.id,
err = ?e,
"JWT verification failed"
);
return Err(e);
}
} else {
return Err(InvalidProjectId(body.id));
if let Err(e) =
validate_tenant_request(&state.jwt_validation_client, &headers, body.id.clone()).await
{
error!(
tenant_id = %body.id,
err = ?e,
"JWT verification failed"
);
return Err(e);
}

#[cfg(not(feature = "cloud"))]
if let Err(e) = validate_tenant_request(&state.gotrue_client, &headers) {
if let Err(e) = validate_tenant_request(&state.jwt_validation_client, &headers) {
error!(
tenant_id = %body.id,
err = ?e,
Expand Down
12 changes: 3 additions & 9 deletions src/handlers/delete_tenant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,11 @@ pub async fn handler(
headers: HeaderMap,
) -> Result<Json<DeleteTenantResponse>, Error> {
#[cfg(feature = "cloud")]
let verification_res = validate_tenant_request(
&state.registry_client,
&state.gotrue_client,
&headers,
id.clone(),
None,
)
.await;
let verification_res =
validate_tenant_request(&state.jwt_validation_client, &headers, id.clone()).await;

#[cfg(not(feature = "cloud"))]
let verification_res = validate_tenant_request(&state.gotrue_client, &headers);
let verification_res = validate_tenant_request(&state.jwt_validation_client, &headers);

if let Err(e) = verification_res {
error!(
Expand Down
12 changes: 3 additions & 9 deletions src/handlers/get_tenant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,11 @@ pub async fn handler(
headers: HeaderMap,
) -> Result<Json<GetTenantResponse>, Error> {
#[cfg(feature = "cloud")]
let verification_res = validate_tenant_request(
&state.registry_client,
&state.gotrue_client,
&headers,
id.clone(),
None,
)
.await;
let verification_res =
validate_tenant_request(&state.jwt_validation_client, &headers, id.clone()).await;

#[cfg(not(feature = "cloud"))]
let verification_res = validate_tenant_request(&state.gotrue_client, &headers);
let verification_res = validate_tenant_request(&state.jwt_validation_client, &headers);

if let Err(e) = verification_res {
error!(
Expand Down
76 changes: 27 additions & 49 deletions src/handlers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
#[cfg(feature = "cloud")]
use {
crate::error::Error::InvalidProjectId,
async_recursion::async_recursion,
cerberus::{
project::ProjectData,
registry::{RegistryClient, RegistryHttpClient},
},
};
use {
crate::{
error::{Error::InvalidAuthentication, Result},
supabase::GoTrueClient,
jwt_validation::JwtValidationClient,
},
axum::{
http::{header::AUTHORIZATION, HeaderMap},
Expand Down Expand Up @@ -162,58 +153,45 @@ impl Default for Response {
}
}

#[async_recursion]
#[cfg(feature = "cloud")]
#[instrument(skip_all, fields(project_id = %project_id, project = ?project))]
#[instrument(skip_all, fields(project_id = %project_id))]
pub async fn validate_tenant_request(
registry_client: &RegistryHttpClient,
gotrue_client: &GoTrueClient,
jwt_validation_client: &JwtValidationClient,
headers: &HeaderMap,
project_id: String,
project: Option<ProjectData>,
) -> Result<bool> {
if let Some(project) = project {
if let Some(token_value) = headers.get(AUTHORIZATION) {
Ok(match gotrue_client
.is_valid_token(token_value.to_str()?.to_string().replace("Bearer ", ""))
{
Ok(token_data) => {
#[cfg(feature = "cloud")]
let valid_token = token_data.claims.sub == project.creator;

#[cfg(not(feature = "cloud"))]
let valid_token = true;

if !valid_token {
Err(InvalidAuthentication)
} else {
Ok(true)
}
if let Some(token_value) = headers.get(AUTHORIZATION) {
Ok(match jwt_validation_client
.is_valid_token(token_value.to_str()?.to_string().replace("Bearer ", ""))
{
Ok(token_data) => {
#[cfg(feature = "cloud")]
let valid_token = token_data.claims.sub == project_id;

#[cfg(not(feature = "cloud"))]
let valid_token = true;

if !valid_token {
Err(InvalidAuthentication)
} else {
Ok(true)
}
Err(_) => Err(InvalidAuthentication),
}?)
} else {
Err(InvalidAuthentication)
}
} else if let Some(project_fetched) = registry_client.project_data(&project_id).await? {
validate_tenant_request(
registry_client,
gotrue_client,
headers,
project_id,
Some(project_fetched),
)
.await
}
Err(_) => Err(InvalidAuthentication),
}?)
} else {
Err(InvalidProjectId(project_id.to_string()))
Err(InvalidAuthentication)
}
}

#[cfg(not(feature = "cloud"))]
#[instrument(skip_all)]
pub fn validate_tenant_request(gotrue_client: &GoTrueClient, headers: &HeaderMap) -> Result<bool> {
pub fn validate_tenant_request(
jwt_validation_client: &JwtValidationClient,
headers: &HeaderMap,
) -> Result<bool> {
if let Some(token_data) = headers.get(AUTHORIZATION) {
if gotrue_client
if jwt_validation_client
.is_valid_token(token_data.to_str()?.to_string().replace("Bearer ", ""))
.is_ok()
{
Expand Down
18 changes: 6 additions & 12 deletions src/handlers/update_apns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,22 +123,13 @@ pub async fn handler(
headers: HeaderMap,
mut form_body: Multipart,
) -> Result<Json<UpdateTenantApnsResponse>, Error> {
// Ensure tenant real
let _existing_tenant = state.tenant_store.get_tenant(&id).await?;

// JWT verification
#[cfg(feature = "cloud")]
let jwt_verification_result = validate_tenant_request(
&state.registry_client,
&state.gotrue_client,
&headers,
id.clone(),
None,
)
.await;
let jwt_verification_result =
validate_tenant_request(&state.jwt_validation_client, &headers, id.clone()).await;

#[cfg(not(feature = "cloud"))]
let jwt_verification_result = validate_tenant_request(&state.gotrue_client, &headers);
let jwt_verification_result = validate_tenant_request(&state.jwt_validation_client, &headers);

if let Err(e) = jwt_verification_result {
error!(
Expand All @@ -149,6 +140,9 @@ pub async fn handler(
return Err(e);
}

// Ensure tenant real
let _existing_tenant = state.tenant_store.get_tenant(&id).await?;

// ---- retrieve body from form
let mut body = ApnsUpdateBody {
apns_topic: None,
Expand Down
Loading

0 comments on commit 8294492

Please sign in to comment.