caps and delete

This commit is contained in:
2025-11-05 12:32:10 +01:00
parent 4ec19dbd70
commit 480bc20ae7
30 changed files with 2702 additions and 262 deletions
+52 -12
View File
@@ -19,6 +19,8 @@ use uuid::Uuid;
use crate::{
auth::{
api_tokens::{find_active_token_by_secret, touch_api_token},
capability_sets::load_capability_set,
jwt::{AccessTokenContext, PrincipalKind},
passkeys::{
AuthenticationChallengeResponse, PasskeyLoginFinishPayload, PasskeyLoginStartPayload,
PasskeyRegistrationFinishPayload, PasskeySummary, RegistrationChallengeResponse,
@@ -27,8 +29,8 @@ use crate::{
},
error::{AppError, AppResult},
models::{
ApiTokenCapability, MagicToken, MagicTokenKind, NewUser, NewUserSession, TenantStatus,
User, UserSession,
ApiCapability, MagicToken, MagicTokenKind, NewUser, NewUserSession, TenantStatus, User,
UserMembership, UserSession,
},
schema::{
magic_tokens::dsl as magic_dsl, tenants::dsl as tenant_dsl,
@@ -160,7 +162,7 @@ pub enum LoginResponseVariants {
crate::auth::passkeys::PasskeyRegistrationFinishPayload,
crate::auth::passkeys::PasskeyLoginStartPayload,
crate::auth::passkeys::PasskeyLoginFinishPayload,
crate::models::ApiTokenCapability,
crate::models::ApiCapability,
))
)]
pub struct AuthApiDoc;
@@ -230,7 +232,7 @@ pub async fn api_token_exchange(
let mut conn = state.db_unscoped()?;
let token = find_active_token_by_secret(&mut conn, None, secret, ApiTokenCapability::Api)?
let token = find_active_token_by_secret(&mut conn, None, secret, ApiCapability::ProfileRead)?
.ok_or_else(AppError::unauthorized)?;
let user: User = dsl::users.find(token.user_id).first(&mut conn)?;
@@ -239,21 +241,36 @@ pub async fn api_token_exchange(
let membership = memberships_dsl::user_memberships
.filter(memberships_dsl::user_id.eq(user.id))
.filter(memberships_dsl::tenant_id.eq(token.tenant_id))
.select(memberships_dsl::tenant_id)
.first::<Uuid>(&mut conn)
.first::<UserMembership>(&mut conn)
.optional()?;
clear_user_guc(&mut conn)?;
if membership.is_none() {
return Err(AppError::unauthorized());
}
let membership = membership.ok_or_else(AppError::unauthorized)?;
let membership_capability_set = membership.capability_set_id.ok_or_else(|| {
AppError::new(
StatusCode::FORBIDDEN,
"membership has no capability set assigned",
)
})?;
let token_capability_set = load_capability_set(&mut conn, token.capability_set_id)?;
let _membership_set = load_capability_set(&mut conn, membership_capability_set)?;
apply_tenant_guc(&mut conn, token.tenant_id)?;
touch_api_token(&mut conn, token.id)?;
let access_token = state
.jwt
.generate_token(user.id, token.tenant_id, &user.username)
.generate_token(AccessTokenContext {
user_id: user.id,
tenant_id: token.tenant_id,
username: user.username.clone(),
principal_kind: PrincipalKind::ApiToken,
principal_id: token.id,
capability_set_id: token_capability_set.id,
cap_version: token_capability_set.cap_version,
})
.map_err(AppError::from)?;
let tenant_name: String = tenant_dsl::tenants
@@ -856,10 +873,33 @@ fn issue_session(
clear_user_guc(conn)?;
clear_user_session_hash(conn)?;
let membership: UserMembership = memberships_dsl::user_memberships
.filter(memberships_dsl::user_id.eq(user.id))
.filter(memberships_dsl::tenant_id.eq(tenant_id))
.first(conn)?;
let capability_set_id = membership.capability_set_id.ok_or_else(|| {
AppError::new(
StatusCode::FORBIDDEN,
"membership has no capability set assigned",
)
})?;
let capability_set = load_capability_set(conn, capability_set_id)?;
let now = Utc::now();
let session_id = Uuid::new_v4();
let access_token = state
.jwt
.generate_token(user.id, tenant_id, &user.username)
.generate_token(AccessTokenContext {
user_id: user.id,
tenant_id,
username: user.username.clone(),
principal_kind: PrincipalKind::UserSession,
principal_id: session_id,
capability_set_id,
cap_version: capability_set.cap_version,
})
.map_err(AppError::from)?;
let tenant_name: String = tenant_dsl::tenants
@@ -873,7 +913,7 @@ fn issue_session(
let refresh_expires_at = now + ChronoDuration::days(state.config.refresh_token_expiry_days);
let new_session = NewUserSession {
id: Uuid::new_v4(),
id: session_id,
user_id: user.id,
token_hash: session_hash,
issued_at: now.naive_utc(),