Skip to main content
Un seul serveur OxiMail peut héberger plusieurs organisations (des tenants au sens du stockage). L’isolation n’est pas une vérification de permission ajoutée par-dessus : elle est construite dans la couche de stockage. tenant_id est un paramètre obligatoire de chaque méthode du store et chaque requête SQL filtre dessus (ADR-015). Un handler ne peut physiquement pas lire les données d’une autre organisation, même à travers un bug. Le RBAC vient par-dessus, en défense en profondeur, pas comme seule ligne. Une installation mono-organisation n’est que le cas dégénéré : l’assistant provisionne un tenant nommé default et tout ce qui suit s’applique quand même.

Les organisations

L’état par organisation comprend ses comptes, ses domaines, ses quotas, ses clés de chiffrement (la hiérarchie de clés au repos est par organisation, voir chiffrement au repos), ses surcharges de configuration à l’exécution, et des réglages de politique comme :
  • Le fuseau horaire par défaut : le dernier étage de la chaîne de repli du calendrier (travail collaboratif).
  • La persistance hors ligne côté client : l’organisation autorise ou non les applications clientes à persister des données localement pour le hors-ligne (offlinePersistenceAllowed, réglable par la surface d’administration Tenant/set). Une organisation aux règles strictes de résidence des données peut la couper.
  • Les règles de journalisation et la durée du tampon de réversibilité d’effacement : voir conformité.

Comptes et rôles

Les rôles sont admin, member, restricted, readonly, disabled (ADR-028). Un compte désactivé garde ses données mais perd son agence : pas de connexion, pas de soumission SMTP (550), pas de réponses d’absence ; le courrier continue de lui être remis. La suppression est la machine à phases d’effacement, pas un simple delete. Les quotas de stockage par compte se fixent en Mo (0 retire la limite par compte).

Mots de passe d’application

Les clients qui ne peuvent pas suivre le flux de connexion web (clients IMAP, agents DAV) s’authentifient avec des mots de passe d’application par client, générés par compte. Ils sont révocables individuellement, leur vérification est à travail constant (pas d’oracle de temps), et les échecs alimentent fail2ban comme sur chaque écouteur. Chaque mot de passe d’application porte un scope, choisi à la création et obligatoire (pas de plein accès par défaut silencieux) : full, mail, calendar (qui inclut les tâches : un seul credential d’agenda couvre les clients CalDAV VTODO), contacts (le credential de synchronisation CardDAV), drive, ou une liste personnalisée d’URN de capabilities en tableau JSON. Une liste personnalisée est validée à la création sur les deux surfaces : chaque élément doit être une capability que ce serveur sert réellement, et le refus nomme les entrées fautives. Un credential qui revendiquerait un droit que le dispatch n’honorera jamais ne peut pas être créé. La CLI (oximail app-password create) valide contre le vocabulaire intégré et le dit ; pour scoper un credential sur une capability d’extension enregistrée au démarrage, passez par POST /auth/app-password, qui les connaît aussi. Les passkeys (WebAuthn) suivent la même discipline de gestion : GET /auth/passkey et DELETE /auth/passkey/{id} permettent à un utilisateur connecté de lister et révoquer ses credentials, et oximail passkey list|revoke est la porte hors bande de l’opérateur. C’est voulu : quand le credential à révoquer est celui qui ouvre le webmail, le chemin de révocation ne doit pas être le webmail. Le listing inclut pour chaque credential l’indice discoverable (a-t-il été créé utilisable par une connexion sans nom d’utilisateur), enregistré à l’enrôlement.

Comptes d’équipe partagés

Un compte partagé est une identité d’équipe non connectable (comptabilite@, equipe@) qui possède une boîte et des ressources d’équipe sans être une personne :
Personne ne s’y connecte ; les humains l’atteignent par des droits. Trois invariants gardent le modèle honnête :
  • Un compte partagé ne peut jamais être bénéficiaire. Une entrée shareWith dont le principal est adossé à un compte partagé est rejetée à l’écriture sur tous les domaines : une identité non connectable ne peut jamais exercer un droit, l’accepter créerait des entrées d’ACL mortes.
  • Son drive a toujours un gardien. La racine de fichiers du compte partagé n’est pas modifiable en JMAP ; la garde est une surface CLI explicite. oximail account custodian show liste les gardiens actuels et indique si le repli sur les administrateurs humains du tenant tient ; custodian reattach --principal <p> [--replace] accorde à un principal adossé à un humain les pleins droits sur la racine, avec audit (l’état antérieur est conservé dans l’entrée d’audit, un transfert est donc restaurable). Les commandes qui modifient les rôles refusent de retirer le dernier administrateur humain de l’organisation tant qu’un drive partagé n’a pas de gardien explicite.
  • Dans l’annuaire, il est typé honnêtement. Le principal d’un compte partagé est émis en type: "other", pas individual : les sélecteurs de personnes ne le proposent pas comme un humain.

Annuaires de contacts partagés

Une organisation peut publier des jeux de contacts partagés (une liste de clients, une liste du personnel) qui apparaissent dans le carnet d’adresses de chaque membre sans que personne ne recopie de fiche. C’est un objet du plan d’administration : il est créé et nommé par un administrateur de tenant, et les entrées du quotidien sont tenues par les principaux inscrits comme éditeurs, groupes compris. Deux conséquences comptent pour l’exploitation :
  • Les membres reçoivent des contacts, pas un dossier. Les entrées arrivent chez un membre en fiches lisibles seulement, marquées comme provenant de l’organisation, sur le plan même qu’utiliserait un flux LDAP ou SCIM externe. Il n’y a rien qu’un utilisateur puisse renommer, déplacer ou supprimer par mégarde, et rien à départager quand quelqu’un s’en va.
  • Le contenu appartient à l’organisation, pas au membre. Un annuaire se purge en retirant ses entrées ; il ne suit pas l’effacement d’un compte individuel, puisqu’il n’a jamais été la donnée de cette personne.
La surface est servie en JMAP pour les sessions d’administration et d’édition. Il n’existe volontairement aucun verbe en ligne de commande : c’est du contenu d’annuaire, pas de la configuration de serveur. Le détail des méthodes et des propriétés est sur la page contacts.

Plafonds de capacité

La capacité du chat est bornée par organisation via la section TOML [chat], et les valeurs appliquées sont annoncées dans l’objet de capacité du chat, pour que les clients les respectent avant de rencontrer l’erreur : Ces plafonds bornent le produit d’écriture de la diffusion (chaque message de salon écrit une ligne par membre).

Un serveur, plusieurs organisations : les frontières

  • Les domaines de courrier appartiennent aux organisations ; l’adresse d’un compte doit être dans un domaine que son organisation possède.
  • Les blobs sont stockés sous des chemins par organisation et chiffrés avec des hiérarchies de clés par organisation ; la déduplication inter-organisations n’existe pas, à dessein.
  • Les destinations de journalisation, les droits de partage et chaque objet JMAP se résolvent strictement dans l’organisation.
  • L’API d’administration et la CLI opèrent par organisation (--tenant-id) ; il n’existe volontairement pas de vue de données « tous tenants ».