summaryrefslogtreecommitdiff
path: root/crates/jmap/src
diff options
context:
space:
mode:
authormdecimus <mauro@stalw.art>2024-09-18 18:08:57 +0200
committermdecimus <mauro@stalw.art>2024-09-18 18:08:57 +0200
commite9d12aea44930d5136a67fc9536d55d31d9a1ddc (patch)
tree7f6cb7fdee263ea3d2fdb0ec7eae321cc3de12b0 /crates/jmap/src
parentd0303aefa8f5c0e8700326f979af17669cb8d325 (diff)
Permissions & multi-tenancy test suite
Diffstat (limited to 'crates/jmap/src')
-rw-r--r--crates/jmap/src/api/http.rs16
-rw-r--r--crates/jmap/src/api/management/mod.rs22
-rw-r--r--crates/jmap/src/api/management/principal.rs32
3 files changed, 45 insertions, 25 deletions
diff --git a/crates/jmap/src/api/http.rs b/crates/jmap/src/api/http.rs
index 8988bbd5..16ad3c39 100644
--- a/crates/jmap/src/api/http.rs
+++ b/crates/jmap/src/api/http.rs
@@ -818,11 +818,6 @@ impl ToHttpResponse for &trc::Error {
fn into_http_response(self) -> HttpResponse {
match self.as_ref() {
trc::EventType::Manage(cause) => {
- let details_or_reason = self
- .value(trc::Key::Details)
- .or_else(|| self.value(trc::Key::Reason))
- .and_then(|v| v.as_str());
-
match cause {
trc::ManageEvent::MissingParameter => ManagementApiError::FieldMissing {
field: self.value_as_str(trc::Key::Key).unwrap_or_default(),
@@ -835,11 +830,18 @@ impl ToHttpResponse for &trc::Error {
item: self.value_as_str(trc::Key::Key).unwrap_or_default(),
},
trc::ManageEvent::NotSupported => ManagementApiError::Unsupported {
- details: details_or_reason.unwrap_or("Requested action is unsupported"),
+ details: self
+ .value(trc::Key::Details)
+ .or_else(|| self.value(trc::Key::Reason))
+ .and_then(|v| v.as_str())
+ .unwrap_or("Requested action is unsupported"),
},
trc::ManageEvent::AssertFailed => ManagementApiError::AssertFailed,
trc::ManageEvent::Error => ManagementApiError::Other {
- details: details_or_reason.unwrap_or("An error occurred."),
+ reason: self.value_as_str(trc::Key::Reason),
+ details: self
+ .value_as_str(trc::Key::Details)
+ .unwrap_or("Unknown error"),
},
}
}
diff --git a/crates/jmap/src/api/management/mod.rs b/crates/jmap/src/api/management/mod.rs
index b88f78fa..0a3dc0c2 100644
--- a/crates/jmap/src/api/management/mod.rs
+++ b/crates/jmap/src/api/management/mod.rs
@@ -33,12 +33,24 @@ use crate::JMAP;
#[serde(tag = "error")]
#[serde(rename_all = "camelCase")]
pub enum ManagementApiError<'x> {
- FieldAlreadyExists { field: &'x str, value: &'x str },
- FieldMissing { field: &'x str },
- NotFound { item: &'x str },
- Unsupported { details: &'x str },
+ FieldAlreadyExists {
+ field: &'x str,
+ value: &'x str,
+ },
+ FieldMissing {
+ field: &'x str,
+ },
+ NotFound {
+ item: &'x str,
+ },
+ Unsupported {
+ details: &'x str,
+ },
AssertFailed,
- Other { details: &'x str },
+ Other {
+ details: &'x str,
+ reason: Option<&'x str>,
+ },
}
impl JMAP {
diff --git a/crates/jmap/src/api/management/principal.rs b/crates/jmap/src/api/management/principal.rs
index 9302ccfe..f3944a81 100644
--- a/crates/jmap/src/api/management/principal.rs
+++ b/crates/jmap/src/api/management/principal.rs
@@ -85,7 +85,7 @@ impl JMAP {
}
// Make sure the current directory supports updates
- if matches!(principal.typ(), Type::Individual | Type::Group | Type::List) {
+ if matches!(principal.typ(), Type::Individual) {
self.assert_supported_directory()?;
}
@@ -315,27 +315,27 @@ impl JMAP {
// Validate changes
let mut needs_assert = false;
- let mut is_password_change = false;
+ let mut expire_session = false;
+ let mut expire_token = false;
let mut is_role_change = false;
for change in &changes {
match change.field {
- PrincipalField::Name
- | PrincipalField::Emails
- | PrincipalField::MemberOf
- | PrincipalField::Members
- | PrincipalField::Lists => {
+ PrincipalField::Name | PrincipalField::Emails => {
+ needs_assert = true;
+ }
+ PrincipalField::Secrets => {
+ expire_session = true;
needs_assert = true;
}
PrincipalField::Quota
| PrincipalField::UsedQuota
| PrincipalField::Description
| PrincipalField::Type
- | PrincipalField::Picture => (),
- PrincipalField::Secrets => {
- is_password_change = true;
- needs_assert = true;
- }
+ | PrincipalField::Picture
+ | PrincipalField::MemberOf
+ | PrincipalField::Members
+ | PrincipalField::Lists => (),
PrincipalField::Tenant => {
// Tenants are not allowed to change their tenantId
if access_token.tenant.is_some() {
@@ -353,6 +353,8 @@ impl JMAP {
| PrincipalField::DisabledPermissions => {
if matches!(typ, Type::Role | Type::Tenant) {
is_role_change = true;
+ } else {
+ expire_token = true;
}
if change.field == PrincipalField::Roles {
needs_assert = true;
@@ -376,7 +378,7 @@ impl JMAP {
)
.await?;
- if is_password_change {
+ if expire_session {
// Remove entries from cache
self.inner.sessions.retain(|_, id| id.item != account_id);
}
@@ -390,6 +392,10 @@ impl JMAP {
.fetch_add(1, Ordering::Relaxed);
}
+ if expire_token {
+ self.core.security.access_tokens.remove(&account_id);
+ }
+
Ok(JsonResponse::new(json!({
"data": (),
}))