fix(health): FHIR allowed_patient_ids=None 拒绝所有访问
This commit is contained in:
@@ -70,14 +70,19 @@ pub struct FhirSearchParams {
|
|||||||
|
|
||||||
/// 检查单个 patient_id 是否在 OAuth 客户端的允许范围内
|
/// 检查单个 patient_id 是否在 OAuth 客户端的允许范围内
|
||||||
fn enforce_patient_scope(fhir_ctx: &FhirAuthContext, patient_id: Uuid) -> Result<(), AppError> {
|
fn enforce_patient_scope(fhir_ctx: &FhirAuthContext, patient_id: Uuid) -> Result<(), AppError> {
|
||||||
if let Some(ref allowed) = fhir_ctx.allowed_patient_ids {
|
match &fhir_ctx.allowed_patient_ids {
|
||||||
if !allowed.iter().any(|id| id == &patient_id.to_string()) {
|
Some(allowed) if !allowed.is_empty() => {
|
||||||
tracing::warn!(
|
if !allowed.iter().any(|id| id == &patient_id.to_string()) {
|
||||||
client_id = %fhir_ctx.client_id,
|
tracing::warn!(
|
||||||
requested_patient = %patient_id,
|
client_id = %fhir_ctx.client_id,
|
||||||
"FHIR 客户端尝试访问授权范围外的患者"
|
requested_patient = %patient_id,
|
||||||
);
|
"FHIR 客户端尝试访问授权范围外的患者"
|
||||||
return Err(AppError::Forbidden("Access denied: patient not in allowed scope".into()));
|
);
|
||||||
|
return Err(AppError::Forbidden("Access denied: patient not in allowed scope".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
return Err(AppError::Forbidden("OAuth client has no patient access configured".into()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -751,3 +756,59 @@ pub async fn patient_everything(
|
|||||||
"entry": entries,
|
"entry": entries,
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::oauth::middleware::FhirAuthContext;
|
||||||
|
|
||||||
|
fn default_fhir_ctx() -> FhirAuthContext {
|
||||||
|
FhirAuthContext {
|
||||||
|
client_id: Uuid::now_v7(),
|
||||||
|
tenant_id: Uuid::now_v7(),
|
||||||
|
scopes: vec!["patient/*.read".to_string()],
|
||||||
|
allowed_patient_ids: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_enforce_patient_scope_none_is_denied() {
|
||||||
|
let fhir_ctx = FhirAuthContext {
|
||||||
|
allowed_patient_ids: None,
|
||||||
|
..default_fhir_ctx()
|
||||||
|
};
|
||||||
|
let result = enforce_patient_scope(&fhir_ctx, Uuid::now_v7());
|
||||||
|
assert!(result.is_err(), "None should deny all access");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_enforce_patient_scope_empty_vec_is_denied() {
|
||||||
|
let fhir_ctx = FhirAuthContext {
|
||||||
|
allowed_patient_ids: Some(vec![]),
|
||||||
|
..default_fhir_ctx()
|
||||||
|
};
|
||||||
|
let result = enforce_patient_scope(&fhir_ctx, Uuid::now_v7());
|
||||||
|
assert!(result.is_err(), "Empty list should deny all access");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_enforce_patient_scope_allowed_access() {
|
||||||
|
let patient_id = Uuid::now_v7();
|
||||||
|
let fhir_ctx = FhirAuthContext {
|
||||||
|
allowed_patient_ids: Some(vec![patient_id.to_string()]),
|
||||||
|
..default_fhir_ctx()
|
||||||
|
};
|
||||||
|
let result = enforce_patient_scope(&fhir_ctx, patient_id);
|
||||||
|
assert!(result.is_ok(), "Patient in allowed list should succeed");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_enforce_patient_scope_wrong_patient_denied() {
|
||||||
|
let fhir_ctx = FhirAuthContext {
|
||||||
|
allowed_patient_ids: Some(vec![Uuid::now_v7().to_string()]),
|
||||||
|
..default_fhir_ctx()
|
||||||
|
};
|
||||||
|
let result = enforce_patient_scope(&fhir_ctx, Uuid::now_v7());
|
||||||
|
assert!(result.is_err(), "Patient not in allowed list should be denied");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user