Deputy permissions deprecated
Introduction
Since version v7.10.6 the Open-Xchange Middleware offers the feature to grant deputy permissions to one ore more users from the same context that are supposed to act as representatives (e.g. vacation replacement).
A deputy has configurable access to granting user's primary mail account's Inbox and/or standard Calendar folder. Moreover, a deputy might get the "send on behalf of" permission granted, which allows them to send E-Mails on behalf of the granting user, or - if enabled by the operator - the "send as" permission, which allows them to send E-Mails as the granting user.
A deputy can also be appointed across context boundaries, subject to the deployment-wide trust-zone policy. See Cross-Context Collaboration.
Configuration
To enable the deputy permission feature, the open-xchange-deputy package needs to be enabled in your chart's values.yaml:
core-mw:
packages:
status:
open-xchange-deputy: enabled
Enable deputy permissions
To enable deputy permission management the com.openexchange.deputy.enabled property needs to be set to true, which is false by default. That property is fully config-cascade-aware. After the feature is enabled, the user will gain access to a new deputy permission management menu in the App Suite UI.
Behavior
Deputy permissions do overwrite possibly existent permissions. Moreover, granted deputy permissions cannot be changed/deleted via regular permission dialogue, but only via deputy permission management by the granting user.
The setting com.openexchange.deputy.simplePermissionMode controls whether deputy permissions may only be assigned to users (not groups) and may only contain such permission rights for viewer, editor and author as App Suite UI would grant those permission rights.
Currently, deputy permissions for the following modules can be granted:
- Calendar
Furthermore for the mail module, the granting user of the deputy permission can decide whether the deputy can sent mails using the granting user's mail account. If granted, mails can be send by the deputy "on behalf of" the granting user. To indicate that a deputy and not the granting user responded, the Sender header filled with the deputy's mail address will be set within the mail. Whereby the From header will be set to granting user's default sender address. E.g.:
From: Granting user <grantinguser@example.org>
Sender: Deputy <deputy@example.org>
In case the deputy has been given write permissions to the granting user's calendar, outgoing notification and/or iTIP mails (see also the iTIP article) will automatically be decorated with the "on behalf" relationship. This applies to the outgoing mails as well as for the generated iCAL files sent along the mails. E.g.:
ORGANIZER;CN=Granting user;SENT-BY="mailto:deputy@example.org";EMAIL=grantinguser@example.org:mailto:grantinguser@example.org
Sending as the granting user
Instead of "on behalf of", the granting user can let the deputy send E-Mails as the granting user through the sendAs attribute of the deputy permission. The E-Mail then carries the granting user as From and no Sender header, so recipients cannot tell that the deputy sent it:
From: Granting user <grantinguser@example.org>
sendOnBehalfOf and sendAs are mutually exclusive:
- Granting both at once is rejected with
DEPUTY-0015. - An update that sets one of them to
truewithout passing the other one clears the other one, so clients do not need to know the stored form in order to switch it. - Setting
sendOnBehalfOftofalsedoes not revokesendAs; to revoke any sending right, set both tofalse. Provisioning systems and clients that do not knowsendAsshould be checked for this.
Apart from the missing Sender header, sendAs behaves like sendOnBehalfOf: it is not affected by com.openexchange.deputy.simplePermissionMode, which only restricts the module permissions, and a deputy permission granted to a group (possible through RMI, gRPC and SCIM) lets every member of the group send as the granting user. If the granting user grants the same deputy both forms through different deputy permissions, e.g. one directly and one through a group, "send as" takes precedence.
Sending as the granting user has to be enabled by the operator through com.openexchange.deputy.sendAsEnabled (default false), which is evaluated for the granting user and announced to clients as capability deputy_send_as:
- While it is disabled, granting
sendAsis rejected withDEPUTY-0016. Passing back an already storedsendAsunchanged still works, so editing an existing deputy keeps working. - Disabling it takes effect on existing grants immediately: a grant of
sendAsis then effective assendOnBehalfOf, and the deputy's reverse listing reports it that way. The stored grant is kept and takes effect again once the property is enabled; no database changes are needed. - Administrative provisioning (SOAP, RMI, gRPC, SCIM) is not restricted by the property.
- Grants of
sendAsprovisioned while the property is disabled take effect as soon as it is enabled, also when it is enabled for the first time. They can be listed beforehand, e.g. withSELECT cid, user, entity FROM deputy WHERE sendAs = 1in every context database schema. - The notification mail to the deputy names the form that is effective when the deputy permission is granted or changed, i.e. "on behalf of" while the property is disabled. Enabling the property later sends no new notification.
When sending, the Middleware only accepts the form the deputy actually holds:
- A deputy allowed to send as the granting user who adds a
Senderheader is rejected withMSG-0129, also for a raw message sent throughmail?action=newand formail?action=resend, unless the granting user's address is also the address of one of the deputy's own mail accounts. - A deputy only allowed to send on behalf of the granting user who omits the
Senderheader is rejected withMSG-0134. Previous versions rejected this case with the genericMSG-0056. - The granting user's address is accepted as
Fromonly. Using it asSenderis rejected withMSG-0056.
If mail?action=transport cannot resolve the account for a mail with a Sender header, e.g. because the deputy permissions cannot be looked up, it keeps falling back to the default account's transport as in previous versions, except for a deputy allowed to send as the granting user: then, or if the deputy permissions cannot be looked up at all, the mail is rejected instead of being sent on behalf of the granting user.
Saving a draft through the mail compose API is not blocked if the deputy permissions cannot be looked up: the draft is saved to the deputy's primary account, and sending it checks the granting user's address again. A draft saved through the legacy mail?action=new is checked like a mail being sent, so it is rejected if the deputy permissions cannot be looked up.
Replying to or forwarding a mail from the granting user's shared Inbox pre-fills the form the deputy holds, i.e. without a Sender for "send as". The reverse listings (action=reverse and action=reverseIds) report sendAs next to sendOnBehalfOf and disclose the granting user's addresses (grantorAddresses) for both forms. A mail sent as the granting user through the Mobile API carries that user's display name, not the deputy's.
Note that the SMTP server has to accept the granting user's address as From for the deputy's login without a Sender header, just as it has to accept it with one for "on behalf of".
The flag is stored in the new column sendAs of table deputy. During a rolling upgrade, nodes of an older version do not know this column: they treat a deputy permission that grants neither a module nor "send on behalf of" as empty and delete it as soon as they read it. A deputy who opens App Suite on such a node is enough to lose a grant of "send as" without any module. Editing a deputy through such a node changes sendOnBehalfOf only and leaves a stored sendAs untouched, so the result may not be what the granting user chose. If com.openexchange.deputy.preferRecreateInsteadOfUpdate is enabled, such a node re-creates the deputy permission instead and resets sendAs: the deputy may then send E-Mails on behalf of the granting user at most. If such a node sets sendOnBehalfOf on a deputy permission that grants "send as", both flags are stored and the permission acts as "send as"; an updated node that re-creates it rejects the update with DEPUTY-0015 until the granting user chooses one of the two forms. A SCIM PUT or PATCH that turns on neither form resolves such a permission to "send as". Such deputy permissions can be found with SELECT cid, user, entity FROM deputy WHERE sendAs = 1 AND sendOnBehalfOf = 1 in every context database schema; any update that sets one of the two forms to true resolves them. Therefore, enable com.openexchange.deputy.sendAsEnabled and provision sendAs (SOAP, RMI, gRPC, SCIM) only once all nodes run a version that knows sendAs. The same applies after a rollback to a version that does not know sendAs: the column is then ignored, deputies granted only "send as" can no longer send E-Mails for the granting user, and such deputy permissions without any module are deleted. To prevent that, run UPDATE deputy SET sendOnBehalfOf = 1, sendAs = 0 WHERE sendAs = 1 in every context database schema before rolling back: the deputies then send E-Mails on behalf of the granting user, no deputy permission looks empty to a node of the previous version, and "send as" has to be granted anew after upgrading again.
A deputy allowed to send as the granting user may also bounce one of that user's mails (mail?action=bounce), which sends the stored mail once more to its recipients. The mail then keeps its Reply-To, while a bounce of an own mail or one sent on behalf of the granting user sets the bouncing user's primary address there as before; if the deputy permissions cannot be looked up, the bounce is rejected.
"Send as" applies to E-Mails only. Notification and iTIP mails a deputy triggers in the granting user's calendar are always decorated with the "on behalf" relationship as described above, also if the deputy permission grants sendAs.
Known limitations
Sending as the granting user only omits what the Middleware itself writes into the mail. Technical traces of the deputy remain possible:
- The deputy authenticates at the mail transport server, which may record that in its own headers.
- The envelope sender (
Return-Path) is the deputy's primary address if com.openexchange.smtp.setSMTPEnvelopeFrom is enabled (defaultfalse). - The
X-Originating-IPandX-Originating-Clientheaders, if configured, describe the deputy's client.
Access to classified appointments
By default, a deputy sees the granting user's appointments that are marked as confidential or private like any other user the calendar is shared with: confidential appointments are anonymized to opaque blocks titled "Private", private ones are not shown at all (see the classification section of the calendar implementation details). The granting user can additionally allow the deputy to see confidential appointments with all details through the optional classifiedAccess attribute of the deputy permission. Like sendOnBehalfOf, it is an attribute of the deputy permission as a whole, but it exclusively concerns the calendar: it controls the visibility of classified appointments in the covered calendar folders and has no meaning for any other module:
none(default) - classified appointments are anonymized or hidden as for any other shareeconfidential- appointments marked as confidential are shown with all details
Appointments marked as private always stay hidden from deputies, so users keep a way to have appointments nobody else gets to see.
The attribute is set next to sendOnBehalfOf when granting or updating a deputy permission through the HTTP API (PUT /ajax/deputy?action=new respectively action=update), and is reported back by the listing actions. When updating, the attribute is only changed if it is present in the request, so the right is revoked by sending none explicitly. A level that cannot be granted is rejected with DEPUTY-0014, an unknown value with SVL-0010. E.g.:
{
"userId": 4,
"folderMode": "default",
"classifiedAccess": "confidential",
"modulePermissions": {
"calendar": {
"permission": 257
}
}
}
The right applies to the calendar folders covered by the deputy permission (according to its folder mode) and does not extend to calendars the granting user shared through the regular permission dialog. Together with the granted folder permission, the deputy can then also edit and delete confidential appointments, mark appointments as confidential or back as public, and create confidential appointments in those folders. Attachments of confidential appointments follow the same rule, as do their details in free/busy results and conflict checks performed by the deputy. The appointments keep their private / confidential event flags, so clients can still indicate their classification.
Note that granting, changing or revoking this right does not modify the appointments themselves. Clients synchronizing the shared calendar incrementally (CalDAV, Exchange ActiveSync) therefore only pick up appointments that became visible or invisible through such a change with their next full synchronization.
Incoming scheduling mails from the shared inbox can be managed by the deputy as well in case author permissions are available for the granting user's default calendar folder. However, in order to analyze them properly, full iMIP emails are required - the context-internally used notification mails are not sufficient to discover the "on behalf" relationship correctly. Therefore, it is recommended to configure the property com.openexchange.calendar.useIMipForInternalUsers to true if this delegation feature is being used.
Requirements
To grant deputy permission to the primary mail account's Inbox folder, the mail account is required to be an IMAP account that supports the RFC 2086 ACL and RFC 5464 METADATA extensions, and supports the /shared/vendor/vendor.open-xchange/deputy METADATA key.
For further reading on METADATA and METADATA keys, read for example the Dovecot IMAP METADATA documentation
To grant deputy permission for the Calendar, Contacts or Tasks module, the granting user additionally needs the readcreatesharedfolders module access (capability read_create_shared_folders) besides the access for the module itself. These grants are applied to the granting user's own private folders through the regular folder update path, which rejects sharing a private folder by a user lacking that access. A module the granting user cannot share is not offered for a deputy permission; requesting it anyway is answered with DEPUTY-0006 ("Deputy provider disabled for module ..."). This does not apply to Drive.
Access combinations tailored to functional mailboxes frequently omit readcreatesharedfolders - if a deputy permission for Calendar, Contacts or Tasks is expected but unavailable, check the granting user's access combination first.
Provisioning
With v8.29 of the Open-Xchange Server, deputy permissions can also be managed through the "http://soap.admin.openexchange.com/OXDeputyPermissionsService" SOAP end-point.
To set module permissions of the calendar module, the module id calendar can be used within respective modulePermissions element. For the mail module, this would be identifier mail. The optional sendAs element (next to sendOnBehalfOf, appended at the end of the element sequence) lets the deputy send E-Mails as the granting user as described above. The optional classifiedAccess element of the deputy permission (none or confidential, next to sendOnBehalfOf) grants the deputy access to the granting user's confidential appointments in the covered calendar folders as described above; it has no effect on other modules. Like through the HTTP API, an unknown value is rejected (as invalid data) rather than being interpreted as none, and a level that cannot be granted fails with DEPUTY-0014.
However, using that SOAP API requires that primary mail server is a Dovecot IMAP server with DoveAdm REST API enabled. Hence, the Middleware's connector for that DoveAdm REST API needs to be enabled.
Example doveadm.properties file:
# Enable
com.openexchange.dovecot.doveadm.enabled=true
# Connection settings
com.openexchange.dovecot.doveadm.endpoints=https://127.0.0.1:8080/doveadm/v1
com.openexchange.dovecot.doveadm.endpoints.totalConnections=100
com.openexchange.dovecot.doveadm.endpoints.maxConnectionsPerRoute=0 (max. connections per route is then determined automatically by specified end-points)
com.openexchange.dovecot.doveadm.endpoints.readTimeout=20000
com.openexchange.dovecot.doveadm.endpoints.connectTimeout=5000
# Secret
com.openexchange.dovecot.doveadm.apiSecret=secret
Since DoveAdm REST API does not provide querying the namespace information for the folder prefixes for personal, shared/user and public namespaces, those prefixes need to be manually specified through following properties to leverage additional features such as auto-subscription/auto-unsubscription of shared/unshared folders for the target user:
com.openexchange.deputy.provider.imap.doveadm.personalNamespacecom.openexchange.deputy.provider.imap.doveadm.sharedNamespacecom.openexchange.deputy.provider.imap.doveadm.publicNamespace
Example for such a section in deputy.properties file:
com.openexchange.deputy.provider.imap.doveadm.personalNamespace=/
com.openexchange.deputy.provider.imap.doveadm.sharedNamespace=shared/
com.openexchange.deputy.provider.imap.doveadm.publicNamespace=public/
Granting a Cross-Context Deputy via SOAP
A deputy can also be appointed when the deputy resides in a different context than the granting user, subject to the deployment-wide trust-zone policy. This uses the very same grant operation of the OXDeputyPermissionsService as a regular deputy - the only difference is that the deputy's context is supplied explicitly:
- the
contextanduserelements identify the granting user, whose calendar and/or inbox is delegated; - the
deputyPermissionidentifies the deputy byuserId, and - for a cross-context deputy - additionally bycontextId, the context the deputy resides in.
A positive contextId that differs from the granting user's context marks the deputy as cross-context; omitting it (or supplying 0) keeps the regular same-context behavior. Such a grant is admitted only if the trust zones of the granting user's context and the deputy's context intersect, otherwise it is rejected by the cross-context authority.
The following request lets user 4 in context 1 appoint user 7 from context 5 as a deputy, with read-write access to the calendar and read access to the inbox plus "send on behalf of". The per-module values are the standard App Suite folder/object permission bits (e.g. 2 = read, 4 = read/write/delete all, 8 = create subfolders, 128 = admin):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://soap.admin.openexchange.com" xmlns:xsd="http://dataobjects.soap.admin.openexchange.com/xsd" xmlns:xsd1="http://dataobjects.rmi.admin.openexchange.com/xsd">
<soapenv:Header/>
<soapenv:Body>
<soap:grant>
<soap:deputyPermission>
<xsd:userId>7</xsd:userId>
<xsd:contextId>5</xsd:contextId>
<xsd:sendOnBehalfOf>true</xsd:sendOnBehalfOf>
<xsd:classifiedAccess>confidential</xsd:classifiedAccess>
<xsd:modulePermissions>
<xsd:moduleId>calendar</xsd:moduleId>
<xsd:folderPermission>4</xsd:folderPermission>
<xsd:readPermission>4</xsd:readPermission>
<xsd:writePermission>4</xsd:writePermission>
<xsd:deletePermission>4</xsd:deletePermission>
<xsd:admin>false</xsd:admin>
</xsd:modulePermissions>
<xsd:modulePermissions>
<xsd:moduleId>mail</xsd:moduleId>
<xsd:folderPermission>2</xsd:folderPermission>
<xsd:readPermission>4</xsd:readPermission>
<xsd:writePermission>0</xsd:writePermission>
<xsd:deletePermission>0</xsd:deletePermission>
<xsd:admin>false</xsd:admin>
</xsd:modulePermissions>
</soap:deputyPermission>
<soap:context>
<xsd:id>1</xsd:id>
</soap:context>
<soap:user>
<xsd:id>4</xsd:id>
</soap:user>
<soap:auth>
<xsd1:login>oxadmin</xsd1:login>
<xsd1:password>secret</xsd1:password>
</soap:auth>
</soap:grant>
</soapenv:Body>
</soapenv:Envelope>
The call returns the identifier of the newly granted deputy permission. The auth credentials are the administrative credentials for the granting user's context (or the master admin). A regular, same-context deputy is granted with the identical request, simply leaving out the contextId element.
Entity information in deputy listings
The deputy HTTP API listing endpoints enrich every returned permission with an entityInfo block — the same server-resolved display information (identifier, type, display_name, contact.email1, …) that the Shared Accounts API provides — so a client can render a deputy (and, in the reverse listing, the grantor) without resolving the user itself.
This is primarily aimed at cross-context entities: when a deputy or grantor lives in a different context, its bare numeric user id (userId / grantorId, reported as 0) is meaningless in the requesting user's context and the client has no directory to resolve it against. For such a foreign entity the qualified identifier (<id>@<contextId>) is the stable key, and the bare numeric entity is omitted from entityInfo. For a group deputy no entityInfo is emitted, as a group is always context-local and thus resolvable by the client itself.
GET /deputy?action=all(the deputies granted by the session user) — each entry carries anentityInfoblock describing the deputy entity (the user appointed as deputy).GET /deputy?action=reverse(who appointed the session user as a deputy) — each entry additionally carries agrantorEntityInfoblock describing the granting user; the entry's ownentityInfocontinues to describe the deputy entity (here: the requesting user).
Example action=reverse entry for a cross-context grantor — the bare grantorId is masked to 0, and the grantor is identified and rendered solely from the qualified grantorIdentifier and the resolved grantorEntityInfo:
{
"deputyId": "d3a1b2c4-…",
"grantorId": 0,
"grantorIdentifier": "4@1",
"grantorEntityInfo": {
"identifier": "4@1",
"type": "user",
"display_name": "Granting User",
"contact": { "email1": "grantinguser@example.org" }
},
"sendOnBehalfOf": true
}