feat: enforce RBAC in RPC dispatcher
Check user role against method permissions before dispatch. All current users default to Admin, laying groundwork for multi-user. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
299357e908
commit
ef58b2ad18
@ -242,6 +242,29 @@ impl RpcHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RBAC: check if the user's role allows this method
|
||||||
|
if !is_unauthenticated {
|
||||||
|
if let Ok(Some(user)) = self.auth_manager.get_user().await {
|
||||||
|
if !user.role.can_access(&rpc_req.method) {
|
||||||
|
let rpc_resp = RpcResponse {
|
||||||
|
result: None,
|
||||||
|
error: Some(RpcError {
|
||||||
|
code: 403,
|
||||||
|
message: "Forbidden: insufficient permissions".to_string(),
|
||||||
|
data: None,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
let resp_body = serde_json::to_vec(&rpc_resp)
|
||||||
|
.context("Failed to serialize response")?;
|
||||||
|
return Ok(Response::builder()
|
||||||
|
.status(StatusCode::FORBIDDEN)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.body(hyper::Body::from(resp_body))
|
||||||
|
.unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CSRF protection: validate X-CSRF-Token header for authenticated methods
|
// CSRF protection: validate X-CSRF-Token header for authenticated methods
|
||||||
if !is_unauthenticated {
|
if !is_unauthenticated {
|
||||||
let csrf_cookie = extract_csrf_cookie(&parts.headers);
|
let csrf_cookie = extract_csrf_cookie(&parts.headers);
|
||||||
|
|||||||
@ -74,7 +74,7 @@
|
|||||||
|
|
||||||
- [x] **Fix session TTL clock bug — use SystemTime instead of Instant**: Read `core/archipelago/src/session.rs`. Find where `Instant::now()` is used for session TTL/expiry (around line 97). `Instant` is monotonic but can drift on sleep/hibernate — common on NUC/Pi hardware. Replace with `SystemTime::now()` for absolute time comparison. The `FULL_SESSION_TTL` (24 hours) and `PENDING_TOTP_TTL` (5 minutes) checks should use `SystemTime::elapsed()` or store `SystemTime` timestamps and compare with `SystemTime::now()`. Run `cargo test --all-features` in `core/` on the dev server.
|
- [x] **Fix session TTL clock bug — use SystemTime instead of Instant**: Read `core/archipelago/src/session.rs`. Find where `Instant::now()` is used for session TTL/expiry (around line 97). `Instant` is monotonic but can drift on sleep/hibernate — common on NUC/Pi hardware. Replace with `SystemTime::now()` for absolute time comparison. The `FULL_SESSION_TTL` (24 hours) and `PENDING_TOTP_TTL` (5 minutes) checks should use `SystemTime::elapsed()` or store `SystemTime` timestamps and compare with `SystemTime::now()`. Run `cargo test --all-features` in `core/` on the dev server.
|
||||||
|
|
||||||
- [ ] **Enforce RBAC in RPC handler**: Read `core/archipelago/src/auth.rs` — find the `UserRole` enum and `can_access()` method. Then read `core/archipelago/src/api/rpc/mod.rs` — find where authenticated requests are dispatched to handlers. Add a role check before dispatching: after validating the session, get the user's role, call `role.can_access(method_name)`, and return an authorization error if denied. For now, all users created via onboarding should default to `Admin` role (single-user system), but this lays the groundwork for multi-user. Run `cargo clippy --all-targets --all-features && cargo test --all-features` on the dev server.
|
- [x] **Enforce RBAC in RPC handler**: Read `core/archipelago/src/auth.rs` — find the `UserRole` enum and `can_access()` method. Then read `core/archipelago/src/api/rpc/mod.rs` — find where authenticated requests are dispatched to handlers. Add a role check before dispatching: after validating the session, get the user's role, call `role.can_access(method_name)`, and return an authorization error if denied. For now, all users created via onboarding should default to `Admin` role (single-user system), but this lays the groundwork for multi-user. Run `cargo clippy --all-targets --all-features && cargo test --all-features` on the dev server.
|
||||||
|
|
||||||
- [ ] **Remove dead code and #[allow(dead_code)]**: Search `core/` for all `#[allow(dead_code)]` and `#[allow(unused)]` annotations. For each: (1) if the code is genuinely unused and not part of a planned feature, delete it, (2) if it should be used (like RBAC — now wired up in previous task), remove the allow annotation. Key file: `core/archipelago/src/auth.rs` lines ~70, 83, 88. Run `cargo clippy --all-targets --all-features` to verify no new warnings.
|
- [ ] **Remove dead code and #[allow(dead_code)]**: Search `core/` for all `#[allow(dead_code)]` and `#[allow(unused)]` annotations. For each: (1) if the code is genuinely unused and not part of a planned feature, delete it, (2) if it should be used (like RBAC — now wired up in previous task), remove the allow annotation. Key file: `core/archipelago/src/auth.rs` lines ~70, 83, 88. Run `cargo clippy --all-targets --all-features` to verify no new warnings.
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user