mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-02 04:04:43 +08:00
139 lines
3.9 KiB
Rust
139 lines
3.9 KiB
Rust
use std::sync::Arc;
|
|
|
|
use common_utils::id_type;
|
|
use error_stack::ResultExt;
|
|
use redis_interface::RedisConnectionPool;
|
|
use router_env::logger;
|
|
|
|
use super::authentication::AuthToken;
|
|
use crate::{
|
|
consts,
|
|
core::errors::{ApiErrorResponse, RouterResult, StorageErrorExt},
|
|
routes::app::SessionStateInfo,
|
|
};
|
|
|
|
#[cfg(feature = "olap")]
|
|
pub mod info;
|
|
pub mod permission_groups;
|
|
pub mod permissions;
|
|
pub mod roles;
|
|
|
|
pub async fn get_role_info<A>(state: &A, token: &AuthToken) -> RouterResult<roles::RoleInfo>
|
|
where
|
|
A: SessionStateInfo + Sync,
|
|
{
|
|
if let Some(role_info) = roles::predefined_roles::PREDEFINED_ROLES.get(token.role_id.as_str()) {
|
|
return Ok(role_info.clone());
|
|
}
|
|
|
|
if let Ok(role_info) = get_role_info_from_cache(state, &token.role_id)
|
|
.await
|
|
.map_err(|e| logger::error!("Failed to get permissions from cache {e:?}"))
|
|
{
|
|
return Ok(role_info.clone());
|
|
}
|
|
|
|
let role_info = get_role_info_from_db(state, &token.role_id, &token.org_id).await?;
|
|
|
|
let token_expiry =
|
|
i64::try_from(token.exp).change_context(ApiErrorResponse::InternalServerError)?;
|
|
let cache_ttl = token_expiry - common_utils::date_time::now_unix_timestamp();
|
|
|
|
if cache_ttl > 0 {
|
|
set_role_info_in_cache(state, &token.role_id, &role_info, cache_ttl)
|
|
.await
|
|
.map_err(|e| logger::error!("Failed to set role info in cache {e:?}"))
|
|
.ok();
|
|
}
|
|
Ok(role_info)
|
|
}
|
|
|
|
async fn get_role_info_from_cache<A>(state: &A, role_id: &str) -> RouterResult<roles::RoleInfo>
|
|
where
|
|
A: SessionStateInfo + Sync,
|
|
{
|
|
let redis_conn = get_redis_connection(state)?;
|
|
|
|
redis_conn
|
|
.get_and_deserialize_key(&get_cache_key_from_role_id(role_id), "RoleInfo")
|
|
.await
|
|
.change_context(ApiErrorResponse::InternalServerError)
|
|
}
|
|
|
|
pub fn get_cache_key_from_role_id(role_id: &str) -> String {
|
|
format!("{}{}", consts::ROLE_INFO_CACHE_PREFIX, role_id)
|
|
}
|
|
|
|
async fn get_role_info_from_db<A>(
|
|
state: &A,
|
|
role_id: &str,
|
|
org_id: &id_type::OrganizationId,
|
|
) -> RouterResult<roles::RoleInfo>
|
|
where
|
|
A: SessionStateInfo + Sync,
|
|
{
|
|
state
|
|
.session_state()
|
|
.global_store
|
|
.find_by_role_id_and_org_id(role_id, org_id)
|
|
.await
|
|
.map(roles::RoleInfo::from)
|
|
.to_not_found_response(ApiErrorResponse::InvalidJwtToken)
|
|
}
|
|
|
|
pub async fn set_role_info_in_cache<A>(
|
|
state: &A,
|
|
role_id: &str,
|
|
role_info: &roles::RoleInfo,
|
|
expiry: i64,
|
|
) -> RouterResult<()>
|
|
where
|
|
A: SessionStateInfo + Sync,
|
|
{
|
|
let redis_conn = get_redis_connection(state)?;
|
|
|
|
redis_conn
|
|
.serialize_and_set_key_with_expiry(&get_cache_key_from_role_id(role_id), role_info, expiry)
|
|
.await
|
|
.change_context(ApiErrorResponse::InternalServerError)
|
|
}
|
|
|
|
pub fn check_permission(
|
|
required_permission: permissions::Permission,
|
|
role_info: &roles::RoleInfo,
|
|
) -> RouterResult<()> {
|
|
role_info
|
|
.check_permission_exists(required_permission)
|
|
.then_some(())
|
|
.ok_or(
|
|
ApiErrorResponse::AccessForbidden {
|
|
resource: required_permission.to_string(),
|
|
}
|
|
.into(),
|
|
)
|
|
}
|
|
|
|
pub fn check_tenant(
|
|
token_tenant_id: Option<id_type::TenantId>,
|
|
header_tenant_id: &id_type::TenantId,
|
|
) -> RouterResult<()> {
|
|
if let Some(tenant_id) = token_tenant_id {
|
|
if tenant_id != *header_tenant_id {
|
|
return Err(ApiErrorResponse::InvalidJwtToken).attach_printable(format!(
|
|
"Token tenant ID: '{}' does not match Header tenant ID: '{}'",
|
|
tenant_id.get_string_repr().to_owned(),
|
|
header_tenant_id.get_string_repr().to_owned()
|
|
));
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn get_redis_connection<A: SessionStateInfo>(state: &A) -> RouterResult<Arc<RedisConnectionPool>> {
|
|
state
|
|
.store()
|
|
.get_redis_conn()
|
|
.change_context(ApiErrorResponse::InternalServerError)
|
|
.attach_printable("Failed to get redis connection")
|
|
}
|