use crate::control::security::auth_context::{AuthContext, generate_session_id};
use crate::control::security::identity::AuthenticatedIdentity;
use crate::control::security::util::base64_url_decode;
pub fn build_auth_context(identity: &AuthenticatedIdentity) -> AuthContext {
let mut ctx = AuthContext::from_identity(identity, generate_session_id());
ctx.database_id = identity.default_database;
ctx
}
pub fn enrich_auth_context_with_scopes(
ctx: &mut AuthContext,
scope_grants: &crate::control::security::scope::grant::ScopeGrantStore,
org_ids: &[String],
) {
let effective = scope_grants.effective_scopes(&ctx.id, org_ids);
for scope_name in &effective {
let status = scope_grants.scope_status(scope_name, "user", &ctx.id);
ctx.metadata
.insert(format!("scope_status.{scope_name}"), status.to_string());
let expires_at = scope_grants.scope_expires_at(scope_name, "user", &ctx.id);
if expires_at > 0 {
ctx.metadata.insert(
format!("scope_expires_at.{scope_name}"),
expires_at.to_string(),
);
}
}
let scope_list: Vec<String> = effective.into_iter().collect();
if !scope_list.is_empty() {
ctx.metadata.insert("scopes".into(), scope_list.join(","));
}
}
pub fn build_auth_context_with_session(
identity: &AuthenticatedIdentity,
sessions: &crate::control::server::pgwire::session::SessionStore,
addr: &std::net::SocketAddr,
) -> AuthContext {
if let Some(token) = sessions.get_parameter(addr, "nodedb.auth_token") {
if token.matches('.').count() == 2 {
if let Some(payload_b64) = token.split('.').nth(1)
&& let Some(payload_bytes) = base64_url_decode(payload_b64)
&& let Ok(claims) =
sonic_rs::from_slice::<crate::control::security::jwt::JwtClaims>(&payload_bytes)
{
let mut ctx = AuthContext::from_jwt(&claims, generate_session_id());
if let Some(on_deny_val) = sessions.get_parameter(addr, "nodedb.on_deny")
&& let Ok(mode) = crate::control::security::deny::parse_on_deny(&[&on_deny_val])
{
ctx.on_deny_override = Some(mode);
}
return ctx;
}
}
}
let mut ctx = build_auth_context(identity);
if let Some(on_deny_val) = sessions.get_parameter(addr, "nodedb.on_deny")
&& let Ok(mode) = crate::control::security::deny::parse_on_deny(&[&on_deny_val])
{
ctx.on_deny_override = Some(mode);
}
if let Some(db) = sessions.get_current_database(addr) {
ctx.database_id = Some(db);
}
ctx
}
pub fn extract_and_apply_on_deny(
sql: &str,
auth_ctx: &mut crate::control::security::auth_context::AuthContext,
) -> String {
let lower = sql.to_lowercase();
let Some(idx) = lower.rfind("on deny ") else {
return sql.to_string();
};
let trimmed = lower.trim_start();
if !trimmed.starts_with("select") && !trimmed.starts_with("with") {
return sql.to_string();
}
let on_deny_part = &sql[idx + "on deny ".len()..];
let parts: Vec<&str> = on_deny_part.split_whitespace().collect();
match crate::control::security::deny::parse_on_deny(&parts) {
Ok(mode) => {
auth_ctx.on_deny_override = Some(mode);
sql[..idx].trim_end().to_string()
}
Err(_) => sql.to_string(),
}
}