From 734327a957c216511b182151a2f0b27819e7e3bb Mon Sep 17 00:00:00 2001
From: Mani Chandra <84711804+ThisIsMani@users.noreply.github.com>
Date: Fri, 23 Feb 2024 16:25:36 +0530
Subject: [PATCH] feat(roles): Add blacklist for roles (#3794)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
---
crates/router/src/consts.rs | 2 +
crates/router/src/core/user_role/role.rs | 4 +-
crates/router/src/services/authentication.rs | 17 ++---
.../src/services/authentication/blacklist.rs | 64 ++++++++++++++++++-
4 files changed, 77 insertions(+), 10 deletions(-)
diff --git a/crates/router/src/consts.rs b/crates/router/src/consts.rs
index 3c3f01dc5f97..72f160990e58 100644
--- a/crates/router/src/consts.rs
+++ b/crates/router/src/consts.rs
@@ -70,6 +70,8 @@ pub const JWT_TOKEN_TIME_IN_SECS: u64 = 60 * 60 * 24 * 2; // 2 days
pub const USER_BLACKLIST_PREFIX: &str = "BU_";
+pub const ROLE_BLACKLIST_PREFIX: &str = "BR_";
+
#[cfg(feature = "email")]
pub const EMAIL_TOKEN_TIME_IN_SECS: u64 = 60 * 60 * 24; // 1 day
diff --git a/crates/router/src/core/user_role/role.rs b/crates/router/src/core/user_role/role.rs
index 7ce72779bbb5..6edbda85bfd6 100644
--- a/crates/router/src/core/user_role/role.rs
+++ b/crates/router/src/core/user_role/role.rs
@@ -12,7 +12,7 @@ use crate::{
core::errors::{StorageErrorExt, UserErrors, UserResponse},
routes::AppState,
services::{
- authentication::UserFromToken,
+ authentication::{blacklist, UserFromToken},
authorization::roles::{self, predefined_roles::PREDEFINED_ROLES},
ApplicationResponse,
},
@@ -219,5 +219,7 @@ pub async fn update_role(
.await
.to_duplicate_response(UserErrors::RoleNameAlreadyExists)?;
+ blacklist::insert_role_in_blacklist(&state, role_id).await?;
+
Ok(ApplicationResponse::StatusOk)
}
diff --git a/crates/router/src/services/authentication.rs b/crates/router/src/services/authentication.rs
index 34153ef6e8f4..455dc97d03e4 100644
--- a/crates/router/src/services/authentication.rs
+++ b/crates/router/src/services/authentication.rs
@@ -13,6 +13,7 @@ use masking::ExposeInterface;
use masking::{PeekInterface, StrongSecret};
use serde::Serialize;
+use self::blacklist::BlackList;
use super::authorization::{self, permissions::Permission};
#[cfg(feature = "olap")]
use super::jwt;
@@ -334,7 +335,7 @@ where
state: &A,
) -> RouterResult<(UserWithoutMerchantFromToken, AuthenticationType)> {
let payload = parse_jwt_payload::(request_headers, state).await?;
- if blacklist::check_user_in_blacklist(state, &payload.user_id, payload.exp).await? {
+ if payload.check_in_blacklist(state).await? {
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
}
@@ -499,7 +500,7 @@ where
state: &A,
) -> RouterResult<((), AuthenticationType)> {
let payload = parse_jwt_payload::(request_headers, state).await?;
- if blacklist::check_user_in_blacklist(state, &payload.user_id, payload.exp).await? {
+ if payload.check_in_blacklist(state).await? {
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
}
@@ -528,7 +529,7 @@ where
state: &A,
) -> RouterResult<(UserFromToken, AuthenticationType)> {
let payload = parse_jwt_payload::(request_headers, state).await?;
- if blacklist::check_user_in_blacklist(state, &payload.user_id, payload.exp).await? {
+ if payload.check_in_blacklist(state).await? {
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
}
@@ -566,7 +567,7 @@ where
state: &A,
) -> RouterResult<((), AuthenticationType)> {
let payload = parse_jwt_payload::(request_headers, state).await?;
- if blacklist::check_user_in_blacklist(state, &payload.user_id, payload.exp).await? {
+ if payload.check_in_blacklist(state).await? {
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
}
@@ -609,7 +610,7 @@ where
state: &A,
) -> RouterResult<(AuthenticationData, AuthenticationType)> {
let payload = parse_jwt_payload::(request_headers, state).await?;
- if blacklist::check_user_in_blacklist(state, &payload.user_id, payload.exp).await? {
+ if payload.check_in_blacklist(state).await? {
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
}
@@ -659,7 +660,7 @@ where
state: &A,
) -> RouterResult<(AuthenticationDataWithUserId, AuthenticationType)> {
let payload = parse_jwt_payload::(request_headers, state).await?;
- if blacklist::check_user_in_blacklist(state, &payload.user_id, payload.exp).await? {
+ if payload.check_in_blacklist(state).await? {
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
}
@@ -710,7 +711,7 @@ where
state: &A,
) -> RouterResult<(UserFromToken, AuthenticationType)> {
let payload = parse_jwt_payload::(request_headers, state).await?;
- if blacklist::check_user_in_blacklist(state, &payload.user_id, payload.exp).await? {
+ if payload.check_in_blacklist(state).await? {
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
}
@@ -741,7 +742,7 @@ where
state: &A,
) -> RouterResult<((), AuthenticationType)> {
let payload = parse_jwt_payload::(request_headers, state).await?;
- if blacklist::check_user_in_blacklist(state, &payload.user_id, payload.exp).await? {
+ if payload.check_in_blacklist(state).await? {
return Err(errors::ApiErrorResponse::InvalidJwtToken.into());
}
diff --git a/crates/router/src/services/authentication/blacklist.rs b/crates/router/src/services/authentication/blacklist.rs
index 325ef29bad3e..346e563ee327 100644
--- a/crates/router/src/services/authentication/blacklist.rs
+++ b/crates/router/src/services/authentication/blacklist.rs
@@ -5,10 +5,11 @@ use common_utils::date_time;
use error_stack::{IntoReport, ResultExt};
use redis_interface::RedisConnectionPool;
+use super::{AuthToken, UserAuthToken};
#[cfg(feature = "email")]
use crate::consts::{EMAIL_TOKEN_BLACKLIST_PREFIX, EMAIL_TOKEN_TIME_IN_SECS};
use crate::{
- consts::{JWT_TOKEN_TIME_IN_SECS, USER_BLACKLIST_PREFIX},
+ consts::{JWT_TOKEN_TIME_IN_SECS, ROLE_BLACKLIST_PREFIX, USER_BLACKLIST_PREFIX},
core::errors::{ApiErrorResponse, RouterResult},
routes::app::AppStateInfo,
};
@@ -34,6 +35,22 @@ pub async fn insert_user_in_blacklist(state: &AppState, user_id: &str) -> UserRe
.change_context(UserErrors::InternalServerError)
}
+#[cfg(feature = "olap")]
+pub async fn insert_role_in_blacklist(state: &AppState, role_id: &str) -> UserResult<()> {
+ let role_blacklist_key = format!("{}{}", ROLE_BLACKLIST_PREFIX, role_id);
+ let expiry =
+ expiry_to_i64(JWT_TOKEN_TIME_IN_SECS).change_context(UserErrors::InternalServerError)?;
+ let redis_conn = get_redis_connection(state).change_context(UserErrors::InternalServerError)?;
+ redis_conn
+ .set_key_with_expiry(
+ role_blacklist_key.as_str(),
+ date_time::now_unix_timestamp(),
+ expiry,
+ )
+ .await
+ .change_context(UserErrors::InternalServerError)
+}
+
pub async fn check_user_in_blacklist(
state: &A,
user_id: &str,
@@ -49,6 +66,21 @@ pub async fn check_user_in_blacklist(
.map(|timestamp| timestamp.map_or(false, |timestamp| timestamp > token_issued_at))
}
+pub async fn check_role_in_blacklist(
+ state: &A,
+ role_id: &str,
+ token_expiry: u64,
+) -> RouterResult {
+ let token = format!("{}{}", ROLE_BLACKLIST_PREFIX, role_id);
+ let token_issued_at = expiry_to_i64(token_expiry - JWT_TOKEN_TIME_IN_SECS)?;
+ let redis_conn = get_redis_connection(state)?;
+ redis_conn
+ .get_key::